通过设置正确的http响应头(content-type、content-disposition)并直接读取文件内容输出,可以强制浏览器下载文件。为防止php源码泄露,必须在代码开头调用exit或die终止脚本执行,确保后续html或错误信息不会作为文件内容被下载。

如何配置响应头实现强制下载
强制下载的核心在于修改HTTP头部。Content-Type应设为application/octet-stream以告知浏览器这是二进制流,Content-Disposition设为attachment; filename=...指定文件名。这样浏览器会弹出保存对话框而不是尝试在页面中打开文件。

<?php
// 假设要下载的文件路径
$file = 'example.pdf';
if (file_exists($file)) {
// 1. 设置 MIME 类型
header('Content-Type: application/octet-stream');
// 2. 设置下载文件名,处理中文编码
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
// 3. 设置文件大小
header('Content-Length: ' . filesize($file));
// 4. 清空并关闭缓冲区
if (ob_get_level()) ob_end_clean();
// 5. 输出文件内容
readfile($file);
// 6. 关键:终止脚本,防止后续 HTML 被输出
exit;
} else {
http_response_code(404);
echo "File not found";
}
?>运行上述代码,浏览器将触发下载example.pdf。如果文件不存在,则返回404错误。由于使用了exit,即使后面有HTML代码也不会被包含在下载文件中。
立即学习“PHP免费学习笔记(深入)”;
如何防止PHP源码被下载泄露
防止源码泄露的关键是确保任何情况下都不会将PHP代码本身作为文本输出。除了使用exit外,还应避免直接输出未处理的变量或错误信息。如果文件路径由用户输入控制,必须验证其合法性,防止路径遍历攻击导致下载敏感文件如/etc/passwd或当前脚本自身。

<?php
// 安全增强版:防止源码泄露和路径遍历
$filename = $_GET['file'] ?? '';
// 1. 白名单验证文件名
$allowed_files = ['report.pdf', 'data.csv'];
if (!in_array($filename, $allowed_files)) {
die('Invalid file');
}
$file_path = '/var/www/files/' . $filename;
// 2. 检查文件是否存在且为普通文件
if (!is_file($file_path)) {
die('File not found');
}
// 3. 设置头部
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . htmlspecialchars($filename) . '"');
header('Content-Length: ' . filesize($file_path));
// 4. 输出并终止
readfile($file_path);
exit;
?>此版本通过白名单限制可下载文件,并使用htmlspecialchars防止文件名注入。同时,exit确保脚本在任何分支结束后都停止执行,杜绝源码泄露风险。
当文件路径包含特殊字符时如何处理
如果文件名包含空格、中文或特殊符号,直接使用可能导致下载失败或文件名乱码。此时需对文件名进行URL编码或使用RFC 5987标准格式。例如,中文文件名报告.pdf应编码为%E6%8A%A5%E5%91%8A.pdf或在Content-Disposition中使用filename*=UTF-8''...格式。
<?php
$file = '测试文件.txt';
header('Content-Type: application/octet-stream');
// RFC 5987 格式支持非ASCII字符
header('Content-Disposition: attachment; filename="' . urlencode($file) . '"; filename*=UTF-8\'\' . urlencode($file));
readfile($file);
exit;
?>该代码确保无论文件名包含何种字符,都能正确触发下载且文件名显示正常。核心仍是exit保证无多余输出。



















