【问题标题】:Why can't I round-trip from .png image to base64-encoded, back to .png image w/ PHP?为什么我不能从 .png 图像到 base64 编码,返回到带有 PHP 的 .png 图像?
【发布时间】:2010-11-30 20:09:00
【问题描述】:

我正在尝试做的事情很简单,在我看来应该非常简单。结果并不令人鼓舞。我正在尝试做的事情:我有一个接收 base64 编码的 PNG 图像数据的网页。我可以并且已经通过适当的步骤成功地获取了这些数据,以在文件系统上创建图像。将此称为“脚本 A”:

$imageData = $_POST['png'];
$imageStr = base64_decode($imageData);
$image = imagecreatefromstring($imageStr);
imagepng($image, $somePath);

这很好用。但是我现在有一个新要求,就是稍后读取这个图像,对其进行 base64 编码,然后将其发布到脚本 A,然后脚本 A 将其写回文件系统,就像上面一样。调用第二个脚本,即读取数据并将其发送回脚本 A 的脚本“脚本 B”。当脚本 A 尝试对从脚本 B 收到的数据调用 imagepng 时,我收到了错误:

imagepng(): supplied argument is not a valid Image resource

还和我在一起吗?感人的。所以这对我来说意味着脚本 B 从文件系统读取 .png 数据、对其进行编码并将其发布到脚本 A 的方式存在问题。它的执行方式如下(此处没有错误处理)为了简洁起见,但没有发生错误)--

// Read in image file, base64-encode
$fd = fopen($somePath, 'rb');
$size = filesize($somePath);
$data = fread($fd, $size);
fclose($fd);
$encoded = base64_encode($data);

然后它使用 cURL 将“$encoded”作为参数发布到脚本 A。

现在,我在网上找到了无数这种方法的例子。我很确定它应该可以工作。它没有。我也尝试过使用 file_get_contents。还尝试使用 'imagecreatefrompng' 读取图像,然后使用输出缓冲区控制将图像捕获为流和 base64 编码......没有运气。最后我觉得上面的方法是最简单最常用的。

如果这篇文章太长和/或太难理解,我们深表歉意。很多活动部件就是全部。任何反馈将不胜感激。

干杯


更新:根据 Jon Skeet 的极好的建议,在我使用 MD5 逐步执行代码时检查图像字符串,我已经缩小了问题的范围 - 一旦我将图像写入脚本 B 中的文件系统,然后将其读回,它已经改变了。所以:

$imageStr = base64_decode($imageData);
$image = imagecreatefromstring($imageStr);
imagepng($image, $somePath);

...似乎在操纵数据,因为当我用普通的 fread() 读回它时,MD5 签名已经改变。我认为这是 imagepng 功能,也许它添加了元数据? php 文档对此并不清楚。如果是这种情况,我认为与其在 w/fread() 中读回图像,不如在编写图像时执行与我正在执行的操作相反的操作,例如:

$image = imagecreatefrompng($somePath);

...然后想办法直接获取图像的内容。不过我不知道该怎么做:它似乎需要一个像“imagepng($image)”这样的函数,w/oa 路径,来输出图像的内容......这就是我不想做的.

在这一点上,我认为问题是:

  1. 如何撤消(或反转)imagepng 似乎在做的事情,或者
  2. 如何直接输出图片资源的内容

【问题讨论】:

  • IMO,您可能想给一些帮助过您的人投票。
  • 啊...同意。学习我的方法,谢谢指点。

标签: php png base64


【解决方案1】:

我建议您通过在脚本 B 正在读取的文件系统上获取数据的 MD5 哈希值来进行实验,在读取它之后再一次,在解码后再次在脚本 A 中。这应该会告诉你哪一点正在改变数据。

就像一个想法 - 脚本 B 正在读取的文件系统上的数据是否绝对有效?

编辑:好的,根据您的编辑,看起来使用imagepng 正在更改内容。你真的需要使用imagepng吗?你真的对图像做任何事情吗? 听起来你基本上只是想将文件从脚本 B 发送到脚本 A...所以我会这样做,而不会将文件视为不透明二进制数据以外的任何内容。

【讨论】:

  • MD5 - 很好的建议,我会做一些测试并更新我的原始帖子。至于脚本 B 正在读取的文件系统上的数据,我认为是这样,因为图像在那里并且看起来很好。同样,我已经使用 imagecreatefrompng 成功读取了文件,如果存在损坏,我认为该函数会抱怨。
【解决方案2】:

您可能需要仔细检查是否在运行脚本 B 的系统上实际启用了 GD 的 PNG 支持。

应该是在这个时代,但是……

if (imagetypes() & IMG_PNG) {
    echo "PNG Support is enabled";
}

附:我很惊讶你不只是使用 HTML/PHP 的内置 file upload 机制。

cURL 可以通过以下方式上传文件:

$ch = curl_init();

// file is the field name, file names are prefixed with @
// In this example, $_FILES['file'] on the remote script would have this
// file's metadata
$data = array('file' => '@/home/user/test.png');

curl_setopt($ch, CURLOPT_URL, 'http://localhost/upload.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

curl_exec($ch);

【讨论】:

  • 感谢您的回复。 png 图像在文件系统上创建正常,我可以在浏览器中查看,并从带有 imagecreatefrompng 的文件系统中读取它。感谢卷曲提示。有一些业务逻辑要求要求我按照我目前的做法去做。 :)
【解决方案3】:

PHP 和 cURL 零经验,但您是否可能(不小心)将图像数据作为 GET 参数而不是 POST 传递(无论如何,这是我犯的第一个错误)?

我认为追踪错误的最简单方法是确保正确的 base64 编码是 a) 由脚本 B 生成和 b) 由脚本 A 接收,方法是将这些值打印出来并进行比较。这应该会告诉您问题出在哪里。

【讨论】:

  • 感谢您的回复 - 脚本 A 正在接收脚本 B 发送的数据,我已经确认了很多。我还确认了脚本 B 生成的数据正是脚本 A 接收的数据。
【解决方案4】:

我可以看到可能导致问题的一件事是您发布图像数据而不使用 urlencode/urldecode。

您的一些图像数据可能会被 PHP 的后期处理破坏,或者如果数据中的任何位置有换行符,则完全被遗漏。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-10
    • 2017-01-08
    • 2020-07-23
    • 2013-02-04
    • 2015-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多