如何从base64数据URI中保存PNG图像到服务器端

274

我正在使用Nihilogic的“Canvas2Image” JavaScript工具将canvas绘图转换为PNG图像。现在我需要做的是,使用PHP将该工具生成的base64字符串转换为实际的PNG文件并保存在服务器上。

简而言之,我目前所做的是在客户端使用Canvas2Image生成一个文件,然后通过AJAX检索base64编码数据并将其发送到服务器:

// Generate the image file
var image = Canvas2Image.saveAsPNG(canvas, true);   

image.id = "canvasimage";
canvas.parentNode.replaceChild(image, canvas);

var url = 'hidden.php',
data = $('#canvasimage').attr('src');

$.ajax({ 
    type: "POST", 
    url: url,
    dataType: 'text',
    data: {
        base64data : data
    }
});

此时,"hidden.php" 接收到了一个数据块,看起来像是data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABE...

从这一点开始,我有些困惑。从我所了解的信息中,我相信我应该使用PHP的imagecreatefromstring函数,但我不知道如何从base64编码的字符串中实际创建PNG图像并将其存储在我的服务器上。 请帮助!


你需要解析它。你可以从中提取图像类型,然后使用base64_decode将该字符串保存到文件中,根据你的图像类型。 - Constantin
@Constantine 你能具体说明一下吗? - Andrei Oniga
7
$data = $_REQUEST['base64data']; $image = explode('base64,',$data); file_put_contents('img.png', base64_decode($image[1]));这段代码是用来保存一个从前端传过来的经过Base64编码的图片,并将其解码并保存为png格式的文件。 - Constantin
你可以发布完整的代码,从快照开始到发送数据为止,这对我来说不起作用。 - Ofir Attia
尝试这个,对我有效。 $base64string = ''; $uploadpath = '你的上传目录路径'; $parts = explode(";base64,", $base64string); $imagebase64 = base64_decode($parts[1]); $file = $uploadpath . uniqid() . '.png'; file_put_contents($file, $imagebase64); - Piyush Sapariya
17个回答

545

您需要从该字符串中提取base64图像数据,解码它,然后可以将其保存到磁盘,您不需要GD,因为它已经是png。

$data = 'data:image/png;base64,AAAFBfj42Pj4';

list($type, $data) = explode(';', $data);
list(, $data)      = explode(',', $data);
$data = base64_decode($data);

file_put_contents('/tmp/image.png', $data);

作为一行代码:

$data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data));

一种高效的提取、解码和检查错误的方法是:

if (preg_match('/^data:image\/(\w+);base64,/', $data, $type)) {
    $data = substr($data, strpos($data, ',') + 1);
    $type = strtolower($type[1]); // jpg, png, gif

    if (!in_array($type, [ 'jpg', 'jpeg', 'gif', 'png' ])) {
        throw new \Exception('invalid image type');
    }
    $data = str_replace( ' ', '+', $data );
    $data = base64_decode($data);

    if ($data === false) {
        throw new \Exception('base64_decode failed');
    }
} else {
    throw new \Exception('did not match data URI with image data');
}

file_put_contents("img.{$type}", $data);

你的示例中有$type。那个值应该是什么? - Jon
1
@Jon $type会根据explode的结果被赋值,具体取决于它是"data:image/jpg"还是"data:image/png"等。 - drew010
我遇到了这个错误:malformed utf-8 characters possibly incorrectly encoded,我该怎么办? - aldo
1
@aldo 可能需要发布一个带有代码和详细信息的新问题。仅凭那条消息而不看您的代码或不知道图像如何编码以及如何发送到脚本中,很难给出确切的答案。 - drew010
非常酷的代码片段。谢谢! - MaZzIMo24
显示剩余3条评论

145

8
我尝试了这个方法,但是它包含了 data:image/png;base64, 这段内容,会导致文件无法使用。 - Michael J. Calkins
3
@MichaelCalkins 也使我不能使用,drew010 的答案似乎是唯一能始终正常工作的解决方案。 - David John Welsh
34
如果你包含了 data:image/png;base64,,那么你传递给 base64_decode 的字符串就不是有效的 base64 编码。你需要只发送数据,这是 drew010 回答所说明的内容。这个答案并没有问题。你不能只复制粘贴而不理解就指望它能“正常工作”。 - Cypher
5
对于问题中提供的示例,该方法不能正常工作,因为它不是一个base64内容,必须首先将其拆分成片段(请参见被接受的答案)。 - Benjamin Piette
我的图像已成功保存。但是当我写入图像的URL时,我看到了一张空白的图片。我确定我的dataURL是正确的,因为我使用window.open(dataURL)进行了测试。为什么会出现空白图片? - partho
显示剩余2条评论

56

为了让这个程序正常工作,我不得不使用加号符号替换空格 str_replace(' ', '+', $img);

以下是完整的代码

$img = $_POST['img']; // Your data 'data:image/png;base64,AAAFBfj42Pj4';
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
file_put_contents('/tmp/image.png', $data);

希望这能有所帮助。


4
你的代码行 $img = str_replace(' ', '+', $img); 对我很有帮助,谢谢! 为什么我要在之前将空格转换为“+”呢? - Sven
1
有必要以某种方式验证这些数据吗?就像您通常会使用 $_FILES 数据一样?如果需要,那么如何实现呢? - ii iml0sto1

26

值得一提的是,讨论的主题已经在RFC 2397 - "data" URL方案中有所记载(https://www.rfc-editor.org/rfc/rfc2397)

由于此原因,PHP有一种处理此类数据的本地方式 - "data: stream wrapper" (http://php.net/manual/en/wrappers.data.php)

因此,您可以轻松使用PHP流来操作您的数据:

$data = 'data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7';

$source = fopen($data, 'r');
$destination = fopen('image.gif', 'w');

stream_copy_to_stream($source, $destination);

fclose($source);
fclose($destination);

3
我喜欢这个答案,它应该有更多的投票。它使用本地函数,没有脏数据操作! 不过,你对性能有什么想法?它是否像人们期望的那样比 preg_replacefile_put_contents 更快? - Bonswouar
2
@Bonswouar 谢谢。关于你的问题:在我看来,确保应用程序没有性能问题的最佳方法是根据你的特定情况(基于环境、预期和允许的文件大小等)测量其性能。我们可以在这里尝试编写代码并在答案中显示数字,但事实是,在你的确切情况下,它可能会带来更多的伤害而不是积极的结果。最好自己确认一下(特别是如果我们正在谈论应用程序的性能关键部分)。 - Vladimir Posvistelik

14

借鉴@dre010的想法,我将其扩展到另一个函数,可以处理PNG、JPG、JPEG或GIF等任何图像类型,并为文件名赋予唯一的名称。

该函数将图像数据和图像类型分开处理。

function base64ToImage($imageData){
    $data = 'data:image/png;base64,AAAFBfj42Pj4';
    list($type, $imageData) = explode(';', $imageData);
    list(,$extension) = explode('/',$type);
    list(,$imageData)      = explode(',', $imageData);
    $fileName = uniqid().'.'.$extension;
    $imageData = base64_decode($imageData);
    file_put_contents($fileName, $imageData);
}

11

好的,您上面提供的解决方案取决于图像是否为jpeg文件。为了得到一个通用的解决方案,我使用了

$img = $_POST['image'];
$img = substr(explode(";",$img)[1], 7);
file_put_contents('img.png', base64_decode($img));

7

7

PHP已经有了一个相当好的处理base64->文件转换的方法。

我通常会使用以下方式编写代码来完成此操作:

$blob=$_POST['blob']; // base64 coming from an url, for example

//Now, let's save the image file:

file_put_contents('myfile.png',file_get_contents($blob));

这应该是被接受的答案,因为OP将base64字符串格式化为以data:image/png;base64,开头的URL。 - Puspam
尝试过在PNG文件上运行,效果很好,但是JPG文件在浏览器屏幕上无法显示。在Windows编辑器中可以打开,但是简单的img标签显示的是一张损坏的图片。 - undefined

6

这段代码适用,检查以下代码:

<?php
define('UPLOAD_DIR', 'images/');
$image_parts = explode(";base64,", $_POST['image']);
$image_type_aux = explode("image/", $image_parts[0]);
$image_type = $image_type_aux[1];
$image_base64 = base64_decode($image_parts[1]);
$file = UPLOAD_DIR . uniqid() . '.png';
file_put_contents($file, $image_base64);
?>

6
一行代码解决方案。
$base64string = 'data:image/png;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7';
file_put_contents('img.png', base64_decode(explode(',',$base64string)[1]));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接