PHP输出的有效图像总是“包含错误”,可能导致这种情况?

时间:2011-09-10 13:25:48

标签: php image

几个月前,我使用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);
    

    它还会将正确的图像数据保存到文件中。因此,数据在发送到用户的Web浏览器之前就已完好无损。

  • 标题正在正确发送。

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

我担心我在PHP或Apache上遇到与编码,缓冲,内容压缩等相关的配置相关问题。有谁知道我可以尝试解决这个问题吗?

编辑:

更改了要使用的脚本:

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

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

3 个答案:

答案 0 :(得分:3)

好吧,经过一些调查后,它变成了臭名昭着的字节顺序标记签名(当然,还有输出缓冲,它可以抑制错误)。 看来只是重新保存没有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);

答案 1 :(得分:1)

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

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

第三,虽然最佳做法是发送内容长度标题,但不需要发送它,所以我会删除它只是为了消除发送无效数据的问题的一个可能来源。

最后,如果您安装了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 );
}

答案 2 :(得分:1)

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

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

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

感谢Your Common SenseProtected提出问题

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