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




