我使用简单的PHP代码进行了一次奇怪的行为。当我尝试使用正确的内容类型强制下载或打印图像时,输出文件已损坏。
似乎webserver(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(是的,为了与roundcube的兼容性问题我完成了从7.0降级到5.6)
更新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个额外字节。如果我直接调用它(通过删除注释),它就可以工作。
现在的问题是:如何去除wordpress添加的这些字节?
答案 0 :(得分:1)
为了帮助您找到不需要的空白,您可以使用get_included_files()跟踪加载的文件。此外,backtrace还可以对您的脚本所做的事情有所了解。
在许多情况下,它来自关闭文件末尾的PHP标记。由于它们是可选的,因此建议不要使用它们。
找到该空白区域的文件后,您只需加载您喜欢的文本编辑器并将其删除(您可能需要启用编辑器显示隐藏的字符功能)。
P.S。我了解这可能是简化代码以说明问题,但您可能需要尝试readfile()。
答案 1 :(得分:0)
$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;