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

IT技术 php javascript base64 html5-canvas
2021-01-18 16:39:11

我正在使用 Nihilogic 的“Canvas2Image”JavaScript 工具将画布绘图转换为 PNG 图像。我现在需要的是使用 PHP 将这个工具生成的那些 base64 字符串转换为服务器上的实际 PNG 文件。

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

// 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 图像并将其存储在我的服务器上。请帮助!

6个回答

您需要从该字符串中提取 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不适用于.svg文件,mimetype:image/svg+xml
2021-03-11 16:39:11
@aldo 可能会发布一个包含代码和细节的新问题。仅凭该消息并且不查看您的代码或不知道图像是如何编码的以及它是如何发送到脚本的,这是不可能的。
2021-03-12 16:39:11
你的例子中有 $type 。这个值应该是多少?
2021-03-13 16:39:11
@Jon$type从爆炸中获得一个值,具体取决于它是 data:image/jpg 还是 data:image/png 等。
2021-03-14 16:39:11
我收到此错误:格式错误的 utf-8 字符可能编码不正确,我该怎么办?
2021-03-19 16:39:11

试试这个:

file_put_contents('img.png', base64_decode($base64string));

file_put_contents 文档

我的图像已成功保存。但是当我写图像的 url 时,我看到一个空白图像。我确定我的 dataURL 是正确的,因为我使用 window.open(dataURL) 进行了测试。为什么是空白图像?
2021-03-15 16:39:11
我试过这个,但它包括data:image/png;base64,破坏文件的 。
2021-03-17 16:39:11
不适用于问题中提供的示例,该示例不是 base64 内容,首先必须拆分为多个部分(请参阅已接受的答案)。
2021-03-20 16:39:11
@MichaelCalkins 也为我打破了它。draw010 的答案似乎是唯一能始终如一地工作的解决方案。
2021-03-22 16:39:11
如果您包含 ,data:image/png;base64,则您传递给的字符串base64_decode不是有效的 base64。您只需要发送数据,这就是 draw010 的答案所说明的。这个答案没有任何问题。你不能在不理解的情况下复制和粘贴,并期望它“正常工作”。
2021-04-06 16:39:11

我不得不用加号替换空格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);

希望有帮助。

你的线路$img = str_replace(' ', '+', $img);对我很有帮助,谢谢!为什么我之前必须将空格转换为“+”?
2021-03-15 16:39:11
是否需要以某种方式验证这些数据?就像您通常使用 $_FILES 数据一样?如果是这样怎么可能
2021-04-05 16:39:11

值得一提的是,讨论的主题记录在 RFC 2397 - “数据” URL 方案(https://www.rfc-editor.org/rfc/rfc2397

因此,PHP 有一种本地方式来处理此类数据 - “数据:流包装器”(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);
我喜欢这个答案,它应该有更多选票,它使用本机功能,没有肮脏的自制数据操作!虽然,对表演有任何想法吗?正如人们所料,它是否比preg_replace+file_put_contents
2021-03-10 16:39:11
@Bonswoar 谢谢。关于您的问题:在我看来,确保您的应用程序没有性能问题的最佳方法是在您的特定情况下衡量其性能(基于环境、预期和允许的文件大小等)。我们可以尝试在这里玩代码并在答案中显示数字,但事实是,对于您的具体情况,它可能带来的危害大于积极的结果。自己确定总是更好的(尤其是当我们谈论应用程序的性能关键部分时)。
2021-03-12 16:39:11

采用@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);
}