使用 readfile() 强制下载文件,核心在于在输出文件内容前设置正确的 http 响应头。具体做法是调用 header() 函数设置 content-type、content-disposition 和 content-length,然后使用 readfile() 读取并输出文件流,最后用 exit 终止脚本以防止多余输出干扰。

readfile() 遇到空输入或无效路径会返回什么
当文件路径不存在或无法读取时,readfile() 不会抛出异常,而是返回 false 并在标准错误流中生成警告。此时必须通过检查返回值来避免向浏览器发送损坏的数据,确保下载流程的安全退出。

$filename = 'nonexistent.txt';
if (file_exists($filename)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($filename).'"');
header('Content-Length: ' . filesize($filename));
readfile($filename);
exit;
} else {
http_response_code(404);
echo "File not found";
}
如何防止 readfile() 输出被缓冲截断
大文件下载时,PHP 的输出缓冲可能导致 readfile() 分块传输失效,从而引发内存溢出或下载中断。解决方法是在输出前调用 ob_end_clean() 清除现有缓冲区,并使用 flush() 强制将数据推送到客户端,确保流式传输的稳定性。
立即学习“PHP免费学习笔记(深入)”;

$filename = 'large_video.mp4';
if (file_exists($filename)) {
// 清除所有输出缓冲
if (ob_get_level()) ob_end_clean();
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($filename).'"');
header('Content-Length: ' . filesize($filename));
header('Cache-Control: no-cache');
// 设置超时时间以防大文件处理过久
set_time_limit(0);
readfile($filename);
flush();
exit;
}
基于 Content-Disposition 参数实现自定义文件名下载
通过修改 Content-Disposition 头中的 filename 参数,可以强制浏览器以指定名称保存文件,即使原始文件名包含特殊字符或中文。这解决了跨平台下载时文件名乱码或扩展名丢失的问题,确保用户接收到的文件命名符合预期。



















