【问题标题】:Valid images output by PHP always "contain errors", what could be causing this?PHP 输出的有效图像总是“包含错误”,这可能是什么原因造成的?
【发布时间】:2017-01-08 05:02:50
【问题描述】:

几个月前,我使用 PHP 5.3 为客户编写了一个网站。它在我自己的 LAMP 网络服务器上完美运行。然而,当他试图将它安装在他自己的服务器(目前是在 CentOS 5 上运行 DirectAdmin 的 OVH 服务器)时,他遇到了一个我无法解决的问题。

网站可以存储通过表单上传的图片。图片在上传时会加水印并移动到网络服务器中的目录(一些元数据存储在数据库中,但这与此问题无关)。

为了将这些图像显示给用户,使用如下脚本:

header("Content-type: image/jpeg");
ob_start();
echo file_get_contents($path);
$size = ob_get_length();
$img = ob_get_contents();
ob_end_clean();
header ("Content-length: " . $size);
echo $img;

不幸的是,这总是返回一个损坏的图像(在 Firefox 中,“图像无法显示,因为它包含错误”)。现在,经过仔细测试,我知道:

  • 图像已正确上传到服务器。网络服务器中存储的图片数据是有效的,可以通过FTP作为普通图片获取。

  • 如果我将 $img 存储到前一个脚本最后一行之前的文件中,如下所示:

    $fh = fopen("test.jpg", "w");
    fwrite($fh, $img);
    fclose($fh);
    

    它也会将正确的图像数据保存到文件中。所以数据在发送到用户的网络浏览器之前是完整的。

  • 标头发送正确。

但是!如果我使用 text/plain header 而不是 image/jpeg,我可以看到返回的乱码与我使用记事本在本地打开文件时显示的乱码不同(或直接通过 apache 将图像作为文本文件发送)。在原始图像中,我可以看到一些 EXIF。在 PHP 生成的图像然后发送到用户的 Web 浏览器中,我仍然看到 JFIF 魔术代码(用于 JPEG 文件图像格式),但其余部分看起来不同。

恐怕我在 PHP 或 Apache 上遇到了与编码、缓冲、内容压缩或类似问题相关的配置问题。有谁知道我可以尝试解决这个问题吗?

编辑:

更改了要使用的脚本:

$img = file_get_contents($path);
$size = filesize($path);

问题仍然没有改变,但内容现在看起来与真实图像与从 PHP 发送的图像完全一样。根据标题,内容编码是 gzip。有什么想法吗?

【问题讨论】:

  • 不要滥用输出缓冲区来处理这样的事情。使用变量来存储图像。
  • 好吧,当时我使用这种方法是因为我获得的数据大小不正确。我改变了它,但它并没有解决这个问题。请随时在此处提出任何其他问题。

标签: php image


【解决方案1】:

好吧,经过一番调查,它变成了 PHP 脚本中臭名昭著的字节顺序标记签名(当然,与抑制错误的输出缓冲结合使用)。
看来只是重新保存没有BOM的文件就可以解决问题

有用吗?

header("Content-type: image/jpeg");
echo file_get_contents($path);

还是这个?

header("Content-type: image/jpeg");
readfile($path);

下载此图像(使用 wget 或在其上创建链接并使用“另存为”)并查看差异。它可能会阐明原因

是的。 ob 在这里完全没有任何关系。如果你想获得一个文件大小 - 有一个(惊喜!)它的功能

header("Content-type: image/jpeg");
header ("Content-length: " . filesize($path));
readfile($path);

【讨论】:

  • 不,没有任何区别。您可以随时在 cmets 中询问更多详细信息。但在被回应之前,我很清楚数据是否正确。
  • @Protected 好吧。然后保存那个奇怪的图像内容并尝试将其与原始图像进行比较
  • 没有任何区别了:/我更新了上面的问题。
  • CSDiff 说“没有可用的差异列表”。但是,由于某种原因,notepad2 报告其中一个文件(图像数据的文本版本)是 ANSI(原始文件),另一个是 UTF-8 签名(生成的文件)。这会导致 Notepad2 窗口中的字符之间出现一些明显的差异,但 ASCII 字符和行长似乎相同,因此可能只是查看器问题。
  • @Protected ha!而已! UTF-8 Signature 也是 Byte Order Mask 吧!它在您的 PHP 脚本中。不带此签名保存
【解决方案2】:

首先,如果您还没有确认,我会确认问题图像确实是 jpeg 而不是其他类型的图像。即使给定了错误的类型或扩展名,许多图像查看程序也会正确显示它们,但如果您为非 jpeg 发送 jpeg 类型,它仍然可能会导致问题。

其次,我会将 ob_start() 移到文件的第一行。

第三,虽然最好的做法是发送 Content-length 标头,但它不需要发送,所以我将删除它只是为了消除发送无效数据问题的一个可能来源。

最后,如果您安装了 GD 并且它符合您的使用要求,则此替代解决方案可能适合您。

ob_start();
$image = imagecreatefromjpeg( $path );
if (!$image ) {
    // error trapping / other logic here
}
ob_end_clean();
header( "Content-type: image/jpeg" );
@imagejpeg( $image );
if ( $image ) {
    imagedestroy( $image );
}

【讨论】:

    【解决方案3】:

    Your Common Sense在评论中给出了正确答案,但有点不清楚,所以我想我会发布它并详细说明一下:

    “哈!就是这样!UTF-8 签名也是字节顺序掩码!它在你的 PHP 脚本中。不用这个签名保存它”

    我确实花了几个小时试图弄清楚为什么图像没有在浏览器中显示 - 这个问题不仅与问题中的代码有关,而且在使用带有 readfile 和 file_get_contents 的 php 标头时也会出现。

    感谢Your Common SenseProtected 提出问题

    我通过更改放置代码的页面的编码来解决它 - UTF-8 似乎没问题,但 BOM(字节顺序掩码)必须去。您如何进行更改取决于您用于编辑的软件 - 我使用的是旧版本的 Dreamweaver,我可以在其中取消选中“页面属性”下的 BOM 使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-30
      • 2016-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-16
      相关资源
      最近更新 更多