1

我正在为电子商务网站创建一个受保护的文件下载系统。我正在使用 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

我也试过:

  1. 打开 PHP 调试以获得某种错误/警告,但我在浏览器或下载的文件源中没有得到任何有用的信息。

  2. 输出到浏览器,而不是流式传输。该文件仍然很短,我希望 PDF 会尝试在浏览器的 PDF 阅读器中显示 - 但它甚至没有尝试。只是一个带有一堆未知符号的白页。

  3. 使用 +rb 读取模式,使用fopen( $file['file'], 'rb' ); echo fread( $fh, filesize( $file['file'] ) ); fclose( $fh );

  4. 使用ignore_user_abort(true)set_time_limit(0)无效(也尝试了 set_time_limit(10000) 以防万一,仍然没有)

  5. 发送.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;
}
4

2 回答 2

1

我知道这是一个较旧的线程,但我在这里为每个人提供了解决方案。

您的应用程序中有一个脚本正在压缩空格或其他字符。

ob_start("sanitize_output");

这就是我注意到的一种情况的问题。如果您关闭缓冲减少脚本(上面称为“sanitize_output”),那么您的 .pdf 将正常显示。您注意到被修剪的额外 2kb 可能是由于间距或剪切掉不需要的字符。

于 2015-07-05T15:43:33.763 回答
1

试试这个代码:只需给 $file 一个文件的相对路径并检查它。

<?php
// your file to download
$file = path/to/the/file;

header("Expires: 0");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

$ext = pathinfo($file, PATHINFO_EXTENSION);
$basename = pathinfo($file, PATHINFO_BASENAME);

header("Content-type: application/".$ext);
// tell file size
header('Content-length: '.filesize($file));
// set file name
header("Content-Disposition: attachment; filename=\"$basename\"");
readfile($file);
// Exit script. So that no useless data is output-ed.
exit;
?>

让 php 计算文件大小和日期等内容。通过数组馈送它时可能会发生错误,这是很安静的。

同样在这段代码中,我使用了 pathinfo 来自动设置内容类型和文件名。

于 2015-07-05T16:44:25.657 回答