ThinkPHP6实现视频流播放的核心是构建支持HTTP Range请求的代理接口,而非直接暴露public目录链接;需校验登录与权限、防止路径遍历、用fopen/fseek/fread分块输出并设置Accept-Ranges、Content-Range、206状态码等响应头,避免内存溢出。

ThinkPHP6 实现视频流播放,核心不是“返回一个文件链接”,而是构建一个支持 HTTP Range 请求 的代理接口。它让浏览器能分段加载、拖动进度条、边播边下——这和直接放 video 标签 src 指向 public 下的 MP4 有本质区别。
为什么不能直接用 public 目录直连?
原始视频文件放在 public 下,等于完全暴露路径,任何人都可下载;更严重的是,无法做权限控制(比如只允许登录用户看)、无法记录播放行为、无法适配防盗链或 CDN 回源策略。TP6 推荐把视频存到 runtime/video/ 或对象存储(如 OSS),再通过 PHP 接口读取并按需输出。
关键响应头必须设置正确
客户端发起带 Range 头的请求时,服务端要识别并返回对应字节段,同时声明协议能力:
- Accept-Ranges: bytes —— 告诉浏览器“我支持分段请求”
- Content-Range: bytes 0-1023/12345678 —— 明确当前返回哪一段、总大小多少
- Status 206 Partial Content —— 表示这不是完整文件响应,而是部分内容
- Content-Type 要匹配视频格式,如 video/mp4、video/webm
PHP 流式读取要避免内存溢出
不能 file_get_contents() 整个视频——几 GB 的文件会直接崩掉。正确做法是:
- 用 fopen() 打开文件,fseek() 定位到 Range 起始位置
- 用 fread() 分块读取(例如每次 8192 字节),echo 输出
- flush() 和 ob_flush() 配合确保实时推送,但 TP6 默认开启 output buffering,需注意关闭或手动刷新
- 大文件建议加 set_time_limit(0) 防止超时中断
权限与路径安全要前置处理
在读取文件前,必须完成校验逻辑:
- 检查用户是否登录、是否有该视频的观看权限(可结合 token 或 session)
- 验证请求的视频 ID 是否合法,防止路径遍历(如 ../../etc/passwd)
- 实际文件路径应由内部映射生成,不暴露真实目录结构
- 若视频存在 OSS,可用临时签名 URL + PHP 流式中转,兼顾安全与性能

















