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


PHP: Downloaded binary file gets an additional byte (0x0a) at the end

PHP Version 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到下载的二进制文件?

您很可能在关闭?>之后有一个额外的空行,该空行正在与数据回显。结束的?>在PHP文件的末尾总是可选的。省略它是防止这类问题的好方法。

Content-Length变化的原因是因为HTTP服务器(或PHP?)忽略了它,并在将其发送到浏览器之前添加了一个新的以匹配实际的数据响应,所以我认为您可以忽略它。(如果你设法发送数据与错误的Content-Length,我发现浏览器可以行为非常奇怪)

PHP脚本中在结束的?>标记之后有一个换行符。这就是多余的换行符的来源。

避免这个问题的最好方法(顺便说一下,在SO上经常出现)是不使用关闭的?>。PHP不需要它,它有助于避免这个问题。

尝试在readfile后添加exit:

//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>";
}

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

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

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