PHP:下载的二进制文件在最后获得一个额外的字节(0x0a)

Posted

技术标签:

【中文标题】PHP:下载的二进制文件在最后获得一个额外的字节(0x0a)【英文标题】:PHP: Downloaded binary file gets an additional byte (0x0a) at the end 【发布时间】:2011-12-05 10:46:42 【问题描述】:

php 版本 5.2.17

我有以下用于下载二进制文件的 PHP 脚本:

<?php

$download_dir = '.';
$download_file = $_GET['get'];

$path = $download_dir.'/'.$download_file;

if(file_exists($path))

    $size = filesize($path);

    header('Content-Type: application/x-download');
    header('Content-Disposition: attachment; filename='.$download_file);
    header('Content-Length: '.$size);
    header('Content-Transfer-Encoding: binary');

    readfile($path);
else
    echo "<font face=$textfont size=3>";
    echo "<center><br><br>The file [<b>$download_file</b>] is not available for download.<br>";

?>

用于调用此脚本的 URL:

http://myserver/cur/downloads/test.php?get=FooBar_Setup.exe

下载正常,但下载的文件附加了一个额外的字节 (0x0a)。 响应的标头还显示了比请求文件的大小大一个字节的 Content-Length:

HTTP/1.1 200 OK
Date: Mon, 05 Dec 2011 10:29:32 GMT
Server: Apache/2.2
Content-Disposition: attachment; filename=FooBar_Setup.exe
Content-Length: 1417689
Content-Transfer-Encoding: binary
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/x-download

服务器上文件的大小为 1417688 字节。

我已验证 filesize($path) 返回正确的文件大小。似乎 PHP 用 filesize($path)+1 更改了 Content-Length 标头。 我在两个不同的文件中看到了这种行为。

如何防止 PHP 将 0x0a 附加到下载的二进制文件?

【问题讨论】:

您应该清理该文件名。人们可以使用该脚本下载他们想要的任何文件(包括脚本本身)。 尝试删除 ?> 或在 readfile() 函数后添加退出语句。 @SebastianPaaskeTørholm 非常大 +1。如此之大,以至于我觉得仅单击 +1 不足以说明这一点的重要性。 是的,当然应该对文件名进行清理。我只是想让这篇文章的脚本简短。不知道结束标记后的内容进入响应。 【参考方案1】:

您很可能在结束 ?&gt; 之后有一个额外的空白行,它与数据一起回显。关闭 ?&gt; 在 PHP 文件末尾始终是可选的。将其排除在外是防止此类问题的好习惯。

Content-Length 更改的原因是因为 HTTP 服务器(或 PHP?)忽略它并添加一个新的以匹配实际数据响应,然后再将其发送到浏览器,所以我认为你可以离开那出来。 (如果您确实设法使用错误的 Content-Length 发送数据,我发现浏览器会表现得非常很奇怪。)

【讨论】:

【参考方案2】:

您的 PHP 脚本在结束 ?&gt; 标记之后有一个换行符。这就是杂散换行符的来源。

避免此问题的最佳方法(顺便说一下,在 SO 上很多出现)是不使用结束 ?&gt;。 PHP 不需要它,它有助于避免这个问题。

【讨论】:

【参考方案3】:

尝试在读取文件后添加退出:

//ob_clean();
//flush();
readfile($path);
exit;

或者,如果当前文件中只有 1 块 php 代码,您可以删除 ?>:

<?php

$download_dir = '.';
$download_file = $_GET['get'];

$path = $download_dir.'/'.$download_file;

if(file_exists($path))

    $size = filesize($path);

    header('Content-Type: application/x-download');
    header('Content-Disposition: attachment; filename='.$download_file);
    header('Content-Length: '.$size);
    header('Content-Transfer-Encoding: binary');

    readfile($path);
    exit;

else
    echo "<font face=$textfont size=3>";
    echo "<center><br><br>The file [<b>$download_file</b>] is not available for download.<br>";

【讨论】:

【参考方案4】:

压缩也会导致额外的字节出现在下载的文件中。在脚本的顶部,添加:

ini_set("zlib.output_compression", "off");

为该 PHP 脚本禁用它。或者,或者另外,您可能想要验证您的 Web 服务器是否也没有压缩该脚本的输出。

【讨论】:

以上是关于PHP:下载的二进制文件在最后获得一个额外的字节(0x0a)的主要内容,如果未能解决你的问题,请参考以下文章

PHP如何将从二进制文件中读取的字节转换为数字

你能“编译”PHP 代码并上传一个二进制文件,它只会由字节码解释器运行吗?

使用php下载的文件打不开,自己用着没问题,客户用就不行?

matlab的bin文件高低字节转换

PHP:为啥强制 mime 下载会添加 2 个额外的空行?

在 Python 中将二进制数据写入文件