Php 强制下载PDF文件,损坏的文件

Php 强制下载PDF文件,损坏的文件,php,file,corrupt,force-download,Php,File,Corrupt,Force Download,我有一个问题已经出现了很多次,但我似乎找不到解决我的问题的办法!我试图在不在浏览器中打开的情况下将pdf文件发送到客户端,该文件会下载,但打开时会损坏,并且原始文件中丢失了相当多的字节。我已经尝试了几种下载文件的方法,但我会告诉你我使用过的最新方法,希望能得到一些反馈 我也在一个文本编辑器中打开了下载的PDF,上面没有php错误 我也知道readfile()的速度要快得多,但出于测试目的,我非常希望任何东西都能正常工作,所以我使用了while(!feof())方法 无论如何,这里的代码(摘自):

我有一个问题已经出现了很多次,但我似乎找不到解决我的问题的办法!我试图在不在浏览器中打开的情况下将pdf文件发送到客户端,该文件会下载,但打开时会损坏,并且原始文件中丢失了相当多的字节。我已经尝试了几种下载文件的方法,但我会告诉你我使用过的最新方法,希望能得到一些反馈

我也在一个文本编辑器中打开了下载的PDF,上面没有php错误

我也知道readfile()的速度要快得多,但出于测试目的,我非常希望任何东西都能正常工作,所以我使用了while(!feof())方法

无论如何,这里的代码(摘自):

还要注意的是文件大小的差异:

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

确保没有运行任何压缩输出缓冲处理程序,例如ob_gzhandler。我也遇到过类似的情况,我必须禁用输出缓冲才能正常工作

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

它通过对输出的块进行编码来工作。然后,输出是一个编码块流

每个块都需要获得一些字节才能进行编码,因此输出会有一点缓冲,直到有足够的字节可用为止

但是,在脚本结束时,您会丢弃剩余的缓冲区,而不是刷新它

使用而不是
ob_clean()
,文件将完全通过,并且不会损坏

如果在输出缓冲区完成工作之前没有销毁输出缓冲区,则可以使用
ob\u 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;
$file=\uuuuuu DIR\uuuuuuuuu.'/somepdf.pdf';
$basename=basename($file);
$length=sprintf(“%u”,文件大小($file));
标题(“内容描述:文件传输”);
标题(“内容类型:应用程序/八位字节流”);
标题('Content-Disposition:attachment;filename=“.”.$basename.'”);
标题(“内容传输编码:二进制”);
标题(“连接:保持活动”);
标题('Expires:0');
标头('Cache-Control:必须重新验证,后检查=0,前检查=0');
标题(“Pragma:public”);
标题('Content-Length:'.$Length);

ob_end_flush();// 在找到问题的解决方案之前,我曾用内容处置(contentdisposition)来推动PDF下载两天。我的PDF文件也比较小,而且已经损坏——但是,我可以在Windows预览中打开它们——只是Adobe不能。经过多次故障排除,我发现Adobe希望文件的前1024个字节中包含%PDF。在创建标题之前,我在php代码中执行所有文件类型检查。在标题和PDF文件被修复之前,我删除了大部分代码

您可能没有像我那样设置它,但可能是同一个问题:


您是否尝试过
readfile()
?@DavidC799:如果您想讨论前面问题的答案,请在此处留下评论。不只是在这里输入一些代码并告诉我们“它不工作”。请记住,只有其他人接受了这个答案,这并不意味着代码也必须适用于您。出于测试目的,请将代码减少到最低限度以引发问题。例如,没有函数,只有硬编码的文件名。使用readfile。@barbashov是的,我尝试过几种不同的方法。@DavidC799将
内容类型更改为
应用程序/pdf
可能会有帮助吗?顺便问一下,标题中返回的
Content length
值是多少?我确实是!既然你提到了这一点,我确实看到其他人在另一篇帖子中提到了这一点。我会尝试一些事情,让你知道事情的进展。对不起,麻烦了!成功!非常感谢你的帮助,总是这么简单:(@DavidC799:好吧,看看其他的问题,网站上的大多数答案你都已经找到了;)@hakre-Yea,很抱歉浪费你的时间嘿@DavidC799:我不认为你浪费了任何人的时间,这是一个有效的、不明显的问题,很好地解释了这一点。我可以证实哈克尔的代码确实按照预期工作;感谢您的详细解释,所以我刚刚检查了PHP中的readfile()源代码,您应该(如果可以的话)始终使用它,而不是像问题中那样使用fopen/缓冲读取
readfile()
对于文件下载输出来说要优越得多,因为它可以利用SAPI中的优势,而这在userland代码中是不可能的。
$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;