2013-04-08 172 views
7

我有一个问题已经上升了很多次,但我似乎无法找到我的解决方案!我正在尝试向客户端发送一个pdf文件,而不是在浏览器中打开它,文件下载,但是当我打开它时它已损坏,并且丢失了原始文件中的相当多的字节。我已经尝试了几种下载文件的方法,但我只会向您展示我使用的最新版本,并希望获得一些反馈。强制下载一个PDF文件,损坏的文件

我也在文本编辑器中打开了下载的PDF,并且在顶部没有php错误,我可以看到!我也知道,readfile()更快,但为了测试的目的,我非常渴望得到任何工作,所以我使用while(!feof())方法!

反正足够的散漫,继承人的代码(从why my downloaded file is alwayes damaged or corrupted?拍摄):

$file  = __DIR__ . '/reports/somepdf.pdf'; 
$basename = basename($file); 
$length = sprintf("%u", filesize($file)); 

header('Content-Description: File Transfer'); 
header('Content-Type: application/octet-stream'); 
header('Content-Disposition: attachment; filename="' . $basename . '"'); 
header('Content-Transfer-Encoding: binary'); 
header('Connection: Keep-Alive'); 
header('Expires: 0'); 
header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
header('Pragma: public'); 
header('Content-Length: ' . $length); 

ob_clean(); 
set_time_limit(0); 
readfile($file); 

另外需要注意的是文件大小的区别:

Original: 351,873 bytes 
Downloaded: 329,163 bytes 
+1

你尝试'ReadFile的()'? – barbashov 2013-04-08 21:48:37

+0

@ DavidC799:如果你想讨论以前问题的答案,请在那里留言。不要只是在这里放一些代码,并告诉我们“它不工作”。请记住,只有其他人接受了该答案,但这并不意味着代码也必须适用于您。出于测试目的,请尽量减少代码以引发问题。例如。没有功能,只是一个硬编码的文件名。使用readfile。 – hakre 2013-04-08 21:51:35

+0

@barbashov是的我已经尝试了几种不同的方法。 – DavidC799 2013-04-08 21:53:41

回答

7

确保你没有运行任何压缩输出缓冲处理程序,如ob_gzhandler。我有一个类似的情况,我不得不禁用输出缓冲,以使其正常工作

+0

的确,我的确是!现在你提到它了,我确实看到有人在另一篇文章中提到过。将尝试一些事情,并让你知道它是如何去的。对不起,麻烦! – DavidC799 2013-04-08 21:55:22

+0

成功!非常感谢您的帮助,总是如此简单:( – DavidC799 2013-04-08 21:57:27

+0

@ DavidC799:好吧,刚刚阅读其他问题,网站上的大多数答案已经只需要找到它们;) – hakre 2013-04-08 21:57:58

6

您正在使用输出缓冲区上的ob_gzhandler

它通过gzencoding块的输出。然后输出是编码块的流。

每个块需要得到一些字节来获得编码,所以输出有点缓冲,直到有足够的字节可用。

但是,在脚本结尾处,您会丢弃剩余的缓冲区而不是将其刷新。

使用ob_end_flush()而不是ob_clean()并且文件完全通过并且没有损坏。

您将使用ob_gzhandler的传输编码,在文件上传没有任何问题的情况下,在您完成工作前不销毁输出缓冲区。

这也是一样的,如果任何其他输出缓冲工作分块将启用 。

示例代码:

$file  = __DIR__ . '/somepdf.pdf'; 
$basename = basename($file); 
$length = sprintf("%u", filesize($file)); 

header('Content-Description: File Transfer'); 
header('Content-Type: application/octet-stream'); 
header('Content-Disposition: attachment; filename="' . $basename . '"'); 
header('Content-Transfer-Encoding: binary'); 
header('Connection: Keep-Alive'); 
header('Expires: 0'); 
header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
header('Pragma: public'); 
header('Content-Length: ' . $length); 

ob_end_flush(); // <--- instead of ob_clean() 

set_time_limit(0); 
readfile($file); 

return; 

(FYI:即使实际上ob_end_flush();是没有必要的,重要的部分是不要只踢输出缓冲器之前它可以做它的工作)

+0

我可以确认hakre的代码确实按预期工作;感谢您的详细解释 – periklis 2013-04-08 22:29:28

+0

此外,我刚刚检查了PHP中的readfile()源代码,并且您应该(如果可以的话)始终使用它,而不是像在问题中那样执行fopen/buffered read。 'readfile()'远远优于文件下载输出,因为它可以在SAPI中利用用户级代码中不可能实现的优势。 – hakre 2013-04-08 22:36:57

-1

我在找到我的问题的解决方案之前,为了推送PDF下载两天而与使用内容处置进行了抗争。我的PDF文件尺寸和损坏也较小 - 但是,我可以在Windows预览中打开它们 - 而不是Adobe。经过许多故障排除之后,我发现Adobe预计文件的前1024个字节中包含%PDF。在创建头文件之前,我在我的php代码中进行了所有的文件类型检查。在标题和我的PDF文件修复之前,我拿出了大部分代码。

您可能没有设置它的方式我也一样,但也可能是同样的问题:

http://helpx.adobe.com/acrobat/kb/pdf-error-1015-11001-update.html