网页php后缀怎么变mp4播放_php动态生成mp4流媒体指南【指南】

PHP无法直接将.php后缀变为.mp4,关键在于正确设置Content-Type: video/mp4、Accept-Ranges: bytes等响应头,并用readfile()或fpassthru()输出合法MP4二进制流;动态生成MP4应调用ffmpeg,非PHP原生实现。

PHP 文件后缀(.php)本身不能“变成”.mp4,它只是服务器端脚本;真正能被浏览器直接播放的,是 PHP 脚本输出的符合 MP4 格式规范的二进制流,且响应头设置正确。关键不在改后缀,而在控制 HTTP 响应行为。

PHP 输出 MP4 流必须设置的响应头

浏览器是否触发视频播放,取决于 Content-TypeAccept-Ranges 等头部,而非文件扩展名。漏掉任一关键头,可能导致下载、空白、或无法拖动进度条。

  • Content-Type: video/mp4 —— 强制声明媒体类型
  • Accept-Ranges: bytes —— 支持分段请求(快进/拖拽必需)
  • Content-Length(静态文件)或省略(流式传输时用 Transfer-Encoding: chunked
  • 若启用缓存,加 Cache-Control: public, max-age=31536000;若禁止缓存(如动态生成),用 no-cache

readfile() 直接输出本地 MP4 文件(最常用)

适用于已存在磁盘上的 MP4 文件,PHP 充当“管道”。注意路径安全和 MIME 类型校验,避免任意文件读取漏洞。

header('Content-Type: video/mp4');
header('Accept-Ranges: bytes');
header('Content-Length: ' . filesize('/path/to/video.mp4'));
readfile('/path/to/video.mp4');

⚠️ 容易踩的坑:

立即学习“PHP免费学习笔记(深入)”;

  • 路径未校验:用户传入 file=../../etc/passwd 会导致敏感文件泄露
  • 未检查文件是否存在或是否为真实 MP4(可用 finfo_file() 验证)
  • 大文件下 readfile() 占用内存高,建议配合 set_time_limit(0)ob_end_flush()

fpassthru() + fopen() 实现流式输出(适合大文件或需要权限拦截)

readfile() 更可控,支持边读边发,内存占用低,也便于在读取前插入鉴权逻辑。

$file = '/path/to/video.mp4';
if (!is_readable($file)) {
    http_response_code(403);
    exit;
}
$fp = fopen($file, 'rb');
header('Content-Type: video/mp4');
header('Accept-Ranges: bytes');
header('Content-Length: ' . filesize($file));
fpassthru($fp);
fclose($fp);

⚠️ 注意点:

  • 必须用 rb 模式打开,否则 Windows 下可能因换行符转换损坏二进制流
  • 务必关闭 $fp,否则连接不释放,服务端资源泄漏
  • 如果前端需支持拖动,Accept-Ranges 头必须有,且不能依赖 Content-Length 做范围判断——PHP 本身不处理 Range 请求,需自行解析并 fseek

PHP 动态生成 MP4?基本不可行

MP4 是复杂容器格式,含 moov、mdat、stts 等多个 box 结构,时间戳、索引、编码参数必须严格对齐。PHP 没有原生 MP4 编码能力,也不推荐用纯 PHP 构造。

  • 真要动态合成(如加水印、拼接),调用 ffmpeg 命令行更可靠:exec("ffmpeg -i input.mp4 -vf 'drawtext=...' -f mp4 -y output.mp4 2>&1", $out)
  • 生成完再用上面的 readfile()fpassthru() 输出,不要试图在 PHP 中“拼 MP4 字节”
  • 实时流媒体(如 HLS/DASH)更不该由 PHP 主导,应交由 Nginx 的 ngx_http_mp4_module 或专用流媒体服务器(如 Wowza、Nginx-rtmp)处理

真正容易被忽略的是:浏览器对 MP4 的 range 请求默认会发两次(一次试探,一次正式),而很多 PHP 示例代码没处理 $_SERVER['HTTP_RANGE'],导致拖动失败——这不是 PHP 不能播 MP4,是它没按 HTTP 协议回应范围请求。