PHP 不直接播放视频,仅生成带签名的临时 URL 供前端 标签直连云存储;禁用 readfile() 是因阻塞进程、不支持 range 分片、无法 CDN 缓存。

PHP 本身不直接“播放”视频,它只负责生成播放页、签发临时访问凭证、构造安全 URL。真正播放靠前端 标签或播放器,而视频文件必须从云存储(如阿里云 OSS、腾讯云 COS、七牛 Kodo)直出——PHP 绝不能做代理下载再吐给浏览器,否则带宽和并发全压在 PHP 服务上,必崩。
为什么不能用 PHP readfile() 输出视频流
云存储视频通常几 MB 到几 GB,PHP 进程会长时间占用、内存飙升、超时中断;Nginx/Apache 也无法对 PHP 输出做 range 请求分片(seek 拖动失效),用户拖不到中间帧;并发一高,PHP-FPM worker 被占满,整个站点卡死。
-
readfile()或fpassthru()会阻塞 PHP 进程,无法释放连接 - HTTP Range 请求需 Web 服务器原生支持,PHP 层模拟极难且不可靠
- CDN 缓存失效:PHP 动态响应无法被 CDN 缓存,失去加速意义
正确做法:PHP 签名 + 前端直连云存储
核心是让浏览器绕过 PHP,直接向云存储发起请求,但 URL 必须有时效性、权限控制,这就靠 PHP 生成带签名的临时 URL。不同厂商 SDK 签名逻辑不同,但思路一致:
- 构造标准 HTTP 请求路径(含 bucket、object key)
- 按云厂商规则计算签名(常含
Expires、Signature、AccessKeyId等参数) - 返回该 URL 给前端,由
直接加载
以阿里云 OSS 为例,使用官方 SDK:
use AlibabaCloud\OSS\OssClient; $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint); $signedUrl = $ossClient->signUrl($bucket, $objectKey, 3600); // 1小时有效期 // 返回 $signedUrl 给前端,例如:https://my-bucket.oss-cn-hangzhou.aliyuncs.com/video.mp4?Expires=171...&OSSAccessKeyId=xxx&Signature=yyy
前端 video 标签如何兼容签名 URL 和跨域
云存储默认禁止跨域请求,若你的域名是 example.com,而 OSS 域名是 xxx.oss-cn-hangzhou.aliyuncs.com,浏览器会拦截 video 加载。必须提前在 OSS 控制台配置 CORS 规则:
本文档主要讲述的是android rtsp流媒体播放介绍;实时流协议(RTSP)是应用级协议,控制实时数据的发送。RTSP提供了一个可扩展框架,使实时数据,如音频与视频,的受控、点播成为可能。数据源包括现场数据与存储在剪辑中数据。该协议目的在于控制多个数据发送连接,为选择发送通道,如UDP、组播UDP与TCP,提供途径,并为选择基于RTP上发送机制提供方法。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
立即学习“PHP免费学习笔记(深入)”;
- 允许来源:
https://example.com(不要写*,否则无法携带 cookies 或 Authorization) - 允许方法:
GET(video 只发 GET) - 暴露头:
Content-Length, Content-Range, ETag(拖动必需) - 最大缓存:
600秒
前端代码示例:
注意:务必用htmlspecialchars() 转义 URL,防止 XSS。
常见坑:签名过期、MIME 类型错误、跳转重定向失败
实际部署中,以下三点最容易导致视频黑屏或加载失败:
- OSS/COS 中对象未设置正确的
Content-Type(应为video/mp4、video/webm等),导致浏览器拒绝解析——上传时就要指定,不能依赖后缀自动推断 - PHP 服务器时间与云厂商服务器时间偏差 >15 分钟,签名直接被拒(OSS 要求时间差 ≤15min),用
ntpdate -u ntp.api.bz校时 - 用了私有读 bucket,但签名 URL 构造漏了
response-content-type参数,某些浏览器对无 MIME 的响应不触发 video 解码
调试时打开浏览器 Network 面板,点开 video 请求,看 status 是 403(签名错)、404(key 错)、还是 200 但 response header 缺 Content-Range —— 这说明 CORS 或 Content-Type 有问题。










