PHP脚本返回MP4时浏览器播放而非下载,因Content-Type为video/mp4且缺Content-Disposition: attachment;强制下载需设置正确响应头、禁缓存、清输出缓冲并用readfile()输出后exit。

PHP 脚本返回 MP4 文件时浏览器不下载而是播放
直接访问 video.php 时浏览器自动播放而非下载,本质是响应头没控制好 MIME 类型和下载行为。PHP 本身不决定“是否下载”,真正起作用的是 Content-Type 和 Content-Disposition 响应头。
-
Content-Type: video/mp4会让浏览器尝试内建播放器渲染(尤其 Chrome/Firefox) - 必须显式设置
Content-Disposition: attachment; filename="xxx.mp4"才能触发下载 - 如果 PHP 脚本里用了
readfile()但没关缓存、没清输出缓冲,可能被截断或附加额外字符,导致 MP4 解析失败
用 PHP 输出真实 MP4 文件并强制下载的最小安全写法
核心是:关缓存、设对头、读文件、退出。不要 echo 任何东西,不要有 BOM,不要在 readfile() 后再输出。
header('Content-Type: video/mp4');
header('Content-Disposition: attachment; filename="demo.mp4"');
header('Content-Length: ' . filesize('/path/to/real-video.mp4'));
header('Cache-Control: no-cache');
header('Pragma: no-cache');
ob_end_clean(); // 清掉之前所有输出缓冲
readfile('/path/to/real-video.mp4');
exit;
为什么不能简单改 URL 后缀为 .mp4
只把 video.php 改成 video.mp4 并不能让 PHP 运行——除非 Web 服务器(如 Apache/Nginx)明确配置了让 .mp4 后缀走 PHP 解析器,这既危险又反模式:
- Apache 需加
AddHandler application/x-httpd-php .mp4,会暴露 PHP 解析漏洞风险 - Nginx 需配
location ~ \.mp4$ { fastcgi_pass ... },同样破坏静态资源直出逻辑 - CDN 或代理层可能直接缓存并返回空响应,因为它们默认信任
.mp4是静态二进制
更稳妥的伪装方式:用重写 + 真实 PHP 处理
保留 .php 后缀的逻辑,但 URL 看起来像 MP4,靠 Web 服务器重写隐藏真实路径。例如 Nginx 中:
立即学习“PHP免费学习笔记(深入)”;
location /videos/(\w+)\.mp4$ {
alias /var/www/php-proxy.php;
args "";
}
然后在 php-proxy.php 中解析 $_SERVER['REQUEST_URI'] 提取 ID,查数据库或拼路径,再按上文方式输出真实 MP4。这样 URL 是 /videos/abc123.mp4,实际走 PHP,但无后缀欺骗风险。
注意:alias 指向 PHP 文件时,Nginx 不会自动传 PATH_INFO,得手动解析 URI;Apache 则可用 RewriteRule ^/videos/(.*)\.mp4$ /proxy.php?id=$1 [L] 更清晰。











