php写直播源的代理
作者:焦点 来源:探索 浏览: 【大 中 小】 发布时间:2026-10-17 06:42:20 评论数:
用PHP做直播源代理,直播核心就一件事:把上游的代理流拉过来,再原样吐给下游。直播听起来简单,代理但真动手写,直播坑一个接一个。代理我最近帮朋友处理一个直播源跨域和防盗链的直播问题,顺手写了个代理脚本,代理跑了两个月还算稳,直播把过程记下来。代理
最直接的直播写法是用file_get_contents或curl把m3u8或ts文件读进来,然后header输出。代理但直播流不是直播静态文件,它是代理一段一段持续推送的。如果用curl一次性抓完再输出,直播客户端得等到全部结束才拿到数据,直播就变成了点播。所以必须边读边发。
我用的方法是curl配合CURLOPT_WRITEFUNCTION回调,每收到一块数据就echo出去,同时flush()。关键代码大概这样:
$ch = curl_init($url); curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) { echo $data; flush(); return strlen($data); }); curl_exec($ch); 但这里有个问题:PHP默认的输出缓冲会攒够一定大小才发。得先ob_end_clean()关掉缓冲,再ob_implicit_flush(true),否则你flush了也没用。我第一次测试时客户端一直卡着,查了半天才发现是输出缓冲没关干净。
另一个麻烦是防盗链。很多直播源会检查Referer和User-Agent,curl请求时得带上。我一般这样设:
curl_setopt($ch, CURLOPT_REFERER, 'https://example.com/'); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 ...'); 还有Origin头,有些CDN也认这个。如果上游返回403,先别急着怀疑代码,用curl -v在命令行试一下,对比浏览器开发者工具里的请求头,缺什么补什么。
m3u8的情况稍微复杂。如果直接代理m3u8文件,里面的ts分片地址可能是相对路径,客户端拿到后还是会去请求原始服务器,代理就白做了。解决办法是解析m3u8内容,把分片地址替换成代理地址。比如原始分片是segment1.ts,就替换成proxy.php?url=https://origin/segment1.ts。这样客户端所有请求都走你的代理。
但m3u8本身是不断更新的,直播的m3u8每次请求可能返回不同的分片列表。所以代理m3u8时不能缓存,每次都要实时拉取最新内容再替换。我试过用file_get_contents抓m3u8然后preg_replace替换,效果还行,但要注意编码和换行符,有些源用\r\n,有些用\n。
性能方面,PHP做流代理其实不太合适。每个客户端连接都会占用一个PHP进程,并发一高就撑不住。我用php-fpm测试,大概50个并发就开始排队了。如果只是个人用或者小规模,没问题;真要上量,还是得用Nginx的proxy_pass或者专门的流媒体服务器。不过PHP的好处是逻辑灵活,加鉴权、改地址、做统计都方便。
有个细节值得注意:set_time_limit(0)必须加,否则脚本跑几十秒就被杀了。还有ignore_user_abort(true),防止客户端断开后脚本还在傻傻地拉流。但即使加了这些,长时间运行的PHP进程还是可能内存泄漏,我一般会在脚本里加个计数器,处理够一定数量的分片就主动退出,让fpm重新拉起一个干净的进程。
最后说个实际遇到的坑:有些直播源返回的Content-Type是application/octet-stream,客户端可能不认。代理时最好根据文件扩展名或上游的Content-Type重新设置,ts文件设成video/mp2t,m3u8设成application/vnd.apple.mpegurl。这个不改,有些播放器直接黑屏。
代码不复杂,但每个环节都得试。我那个脚本现在还在跑,偶尔挂掉就重启一下,够用了。
