You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PHP强制下载PDF文件为空,文本文件正常,求解决方案

解决PHP强制下载二进制文件为空的问题

你的代码处理文本文件正常,但二进制文件(比如PDF)下载后为空,大概率是缺少关键HTTP头、存在意外输出,或是没正确处理输出缓冲区导致的。下面是修复后的完整代码,以及详细的问题解析:

修复后的代码

<?php
// 清空所有输出缓冲区,避免之前的内容干扰头信息发送
ob_clean();
flush();

$original_filename = "attachments/20180315.log";
$new_filename = "new_name." . pathinfo($original_filename, PATHINFO_EXTENSION);

// 提前校验文件状态,避免无意义的后续执行
if (!file_exists($original_filename) || !is_readable($original_filename)) {
    die("文件不存在或无法读取,请检查路径与权限");
}

// 自动获取文件的MIME类型,适配不同格式的二进制文件
$finfo = new Finfo(FILEINFO_MIME_TYPE);
$mime_type = $finfo->file($original_filename);
// 如果服务器禁用finfo,也可以用mime_content_type,或者直接用通用类型:$mime_type = 'application/octet-stream';

// 设置完整的HTTP响应头
header("Content-Type: $mime_type");
header("Content-Length: " . filesize($original_filename));
header("Content-Transfer-Encoding: binary");
header('Content-Disposition: attachment; filename="' . $new_filename . '"');
header('Pragma: no-cache');
header('Expires: 0');

// 以二进制模式读取并输出文件,适配大文件与二进制格式
$file_handle = fopen($original_filename, 'rb');
fpassthru($file_handle);
fclose($file_handle);

exit;
?>

关键修复点说明

  • 清空输出缓冲区ob_clean()flush()会清除PHP脚本执行前的所有缓冲内容(比如文件开头的空格、BOM字符,或是之前的调试输出)。如果在发送HTTP头前有任何输出,PHP会自动发送默认的Content-Type,直接导致二进制文件内容解析异常。
  • 设置正确的Content-Type:二进制文件需要匹配对应的MIME类型(比如PDF是application/pdf),用finfo自动获取是最可靠的方式;也可以直接用application/octet-stream作为通用二进制类型,确保浏览器以附件方式处理文件。
  • 替换readfile为fpassthru:部分服务器配置下,readfile可能因内存限制或缓冲机制导致输出截断;用fopen('rb')以二进制模式打开文件,再通过fpassthru直接输出内容,对二进制文件的兼容性更强。
  • 增加文件校验:提前检查文件是否存在、是否可读,能快速排查路径错误或权限问题,避免输出空文件。
  • 补充Expires头:明确告知浏览器不要缓存该下载内容,避免旧缓存干扰新文件的下载。

另外要注意:确保PHP脚本文件本身没有多余内容(比如<?php标签前的空格、?>标签后的字符),这些都会产生意外输出,破坏HTTP头的正常发送。

内容的提问来源于stack exchange,提问作者Amir-M

火山引擎 最新活动