我正在为电子商务网站创建一个受保护的文件下载系统。我正在使用 PHP 来验证用户是否已登录并在下载产品之前拥有该产品。我正在使用PHP.net 手册提供的示例,但在同时提供 PDF 和 PNG 文件时遇到了错误。
在开发过程中,它曾一度奏效。现在我们已经上线了,它似乎已经崩溃了……幸运的是,该网站目前还没有全力运行,所以现在这不是一个大问题。
怎么了:
您访问下载 URL。您被验证为产品的所有者,然后开始下载。一切似乎都很正常,查看标题一切看起来都很好。标头指出内容长度为“229542”(224.16kb),看起来不错。
问题:
下载完成后,文件大小只有 222字节。没有显示错误,也没有在文件或浏览器中发送 PHP 错误/警告/通知。就好像 PHP 正在被终止,但没有任何警告。即使我打开调试,我也看不到任何警告。
源文件看起来像这样(在 Notepad++ 中,它是 PDF,所以它是二进制文件)
下载后是这样的(只有7行,对比2554行)
我猜:
我相当肯定这个问题与标题有关。可能是插件造成的?这显示在 Chrome 的网络控制台中:
响应标头:
以下是响应标头。“连接:关闭”与我有关。我没有发送那个标题。我猜它是由exit
命令发送的。
Access-Control-Allow-Origin:*
Cache-Control:must-revalidate, post-check=0, pre-check=0
Connection:close
Content-Description:File Transfer
Content-Disposition:attachment; filename="workbook.pdf"
Content-Length:229542
Content-Transfer-Encoding:binary
Content-Type:application/pdf
Date:Tue, 03 Sep 2013 21:16:14 GMT
Expires:0
Pragma:public
Server:Apache
X-Powered-By:PleskLin
我也试过:
打开 PHP 调试以获得某种错误/警告,但我在浏览器或下载的文件源中没有得到任何有用的信息。
输出到浏览器,而不是流式传输。该文件仍然很短,我希望 PDF 会尝试在浏览器的 PDF 阅读器中显示 - 但它甚至没有尝试。只是一个带有一堆未知符号的白页。
使用 +rb 读取模式,使用
fopen( $file['file'], 'rb' ); echo fread( $fh, filesize( $file['file'] ) ); fclose( $fh );
使用
ignore_user_abort(true)
和set_time_limit(0)
无效(也尝试了 set_time_limit(10000) 以防万一,仍然没有)发送
.txt
文件。这行得通。我尝试了一个简单的 5 字节文本文件,然后又尝试了一个 86.3kb 文件。两者似乎都与他们进入时一样。所以它必须与二进制文件有关......
/* --- This is what the $file variable looks like:
$file = array(
[file] => /var/www/vhosts/my-website/uploads/workbook.pdf
[type] => application/pdf
[filesize] => 229542
[filename] => workbook.pdf
[upload_date] => 1377278303
);
*/
// Stream the file to the user
if (file_exists($file['file'])) {
header_remove(); // Remove any previously set header
header('Content-Description: File Transfer');
header('Content-Type: ' . $file['type']);
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $filesize);
ob_clean();
flush();
readfile($file['file']);
exit;
}