【问题标题】:PHP: image corrupted if I force the downloadPHP:如果我强制下载,图像会损坏
【发布时间】:2016-06-07 11:41:21
【问题描述】:

我对一个简单的 PHP 代码有一个奇怪的行为。当我尝试使用正确的内容类型强制下载或打印图像时,输出文件已损坏。

似乎网络服务器 (apache) 在文件开头添加了两个字节(0x20 和 0x0A)。

这是代码:

$file = "image.png";
$image = file_get_contents($file);

// Test
file_put_contents("test.png", $image);

// Download
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));

echo $image;

我在同一台服务器上托管的其他网站上使用相同的代码没有问题。

问题仅在下载时出现,因为 test.png 可以正常工作。 text.png 的 MD5 校验和与原图相等。

这是 test.png 的十六进制代码。

这是下载后损坏文件的十六进制代码:

如您所见,开头有 2 个额外字节。如果我删除它们,文件将恢复正常工作。

我附上Wireshark的屏幕(如你所见不是浏览器问题):

我该如何解决?

服务器是带有 PHP-5.6 的 Ubuntu 16.04(是的,我已经从 7.0 降级到 5.6 以解决与 roundcube 的兼容性问题)

更新 1:我正在尝试查找文件中的某处是否有空格 + 换行符

更新 2:

首先:谢谢。

代码是 Wordpress 插件的一部分,下载是使用 AJAX 系统调用的。我写了一个简单的插件测试:

<?php
/*
Plugin Name: Test
Plugin URI: http://www.google.com
Description: Test
Author: Anon
Version: 4.0
*/
function downlod_test() {
echo "test";
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=prova.html');
die();   
}
function iopman_shared_download_doc_ajax() {
downlod_test();
}
add_action('wp_ajax_frontend_download_doc', 'iopman_shared_download_doc_ajax');

//downlod_test();
?>

如果我使用 /wp-admin/admin-ajax.php?action=frontend_download_doc 调用 downlod_test,它会添加 2 个额外字节。如果我直接调用它(通过删除 cmets),它可以工作。

那么现在的问题是:如何去掉wordpress添加的这些字节?

【问题讨论】:

  • x20 是一个空格,x0A 是一个换行符(又名\n)。也许这可以帮助您弄清楚它的来源。您显示的代码不应生成它们。
  • 如何剥离它们?使用 get_included_files()、debug_print_backtrace() 找到它们,然后在编辑器中加载文件并删除它们。

标签: php image corruption corrupt


【解决方案1】:
$file = "image.png";
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . basename($file));
header("Content-Encoding: gzip");
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header("Content-Length: " . filesize($file));
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
ob_get_clean();
readfile($file);
exit;

【讨论】:

  • Ali Khanusiya,你的标头代码是做什么的?问题出在哪里,如何解决?
  • @alexis 这个答案基本上建议使用ob_get_clean(); 忽略虚假空格,但他显然是missing a bit。如果您之前没有启动输出缓冲区,则无法清空输出缓冲区——这样做比仅修复问题要复杂得多。
  • 出于某种原因,这里的关键只是 ob_get_clean();。我最初使用 flush(); 的脚本决定停止工作。它添加了两个额外的换行符,我无法追踪它们的来源。我不知道有什么副作用,但至少它现在有效,等待更多调查。
【解决方案2】:

为了帮助您找到不需要的空白,您可以使用get_included_files() 跟踪加载的文件。此外,backtrace 还可以帮助您了解脚本的作用。

在许多情况下,它来自文件末尾的关闭 PHP 标记。由于它们是可选的,因此建议不要使用它们。

一旦找到该空白所在的文件,您只需在您喜欢的文本编辑器中加载并删除它们(您可能需要启用编辑器的 显示隐藏字符 功能)。 p>

附:我知道这可能是用于说明问题的简化代码,但您可能想试试readfile()

【讨论】:

    猜你喜欢
    • 2012-12-05
    • 2013-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-08
    相关资源
    最近更新 更多