如何使用file_get_contents获取m3u8文件?403错误排查
解决PHP请求m3u8时的403 Forbidden错误
问题场景
我编写了一段PHP代码,分三步发送GET请求获取m3u8文件内容:
- 获取有效的token
- 携带token拉取主m3u8的链接
- 通过拿到的链接获取最终m3u8内容
前两步都正常,但第三步请求返回了403 Forbidden错误。不过通过浏览器审查元素能正常获取到m3u8内容,PHP执行就失败了。
我的PHP代码
<?php //1. 创建有效的token以获取m3u8 $opts = array( 'http'=>array( 'method'=>"GET", 'header'=>"Referer: http://www.hotstar.com", "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:51.0) Gecko/20100101 Firefox/51.0" )); $context = stream_context_create($opts); $url = "http://www.hotstar.com/get_cdn_token.php"; $data = file_get_contents($url, false, $context); $values = json_decode($data, true); $url = $values['token']; //2. 携带token发送GET请求拉取主m3u8 $opts = array( 'http'=>array( 'method'=>"GET", 'header'=>"Referer: http://www.hotstar.com", "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:51.0) Gecko/20100101 Firefox/51.0" )); $context = stream_context_create($opts); $url = "https://secure-getcdn.hotstar.com/AVS/besc?hotstarauth=$url&action=GetCDN&appVersion=5.0.40&asJson=Y&channel=TABLET&id=1000055355&type=VOD"; $data = file_get_contents($url, false, $context); $values = json_decode($data, true); $link = $values['resultObj']['src']; //3. 获取m3u8内容 $opts = array( 'http'=>array( 'method'=>"GET", 'header'=>"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:51.0) Gecko/20100101 Firefox/51.0" )); $context = stream_context_create($opts); $url = "$link"; $data = file_get_contents($url, false, $context); echo $data; ?>
浏览器中正常获取的m3u8内容
#EXTM3U #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=241000,RESOLUTION=320x180,CODECS="avc1.66.30, mp4a.40.2",CLOSED-CAPTIONS=NONE https://staragvod1-vh.akamaihd.net/i/videos/plus/sns/1365/1000055355_,16,180,400,800,1300,2000,3000,4500,_STAR.mp4.csmil/index_1_av.m3u8?null=0&id=AgC0lfI2aGb2DFFZW1pBPartIAq++S+ee++3UM8jU49rfzGeMpTl2IaWB4PCyZ0c2yGZOtSqAhal4g%3d%3d #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=461000,RESOLUTION=416x234,CODECS="avc1.66.30, mp4a.40.2",CLOSED-CAPTIONS=NONE https://staragvod1-vh.akamaihd.net/i/videos/plus/sns/1365/1000055355_,16,180,400,800,1300,2000,3000,4500,_STAR.mp4.csmil/index_2_av.m3u8?null=0&id=AgC0lfI2aGb2DFFZW1pBPartIAq++S+ee++3UM8jU49rfzGeMpTl2IaWB4PCyZ0c2yGZOtSqAhal4g%3d%3d #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=861000,RESOLUTION=640x360,CODECS="avc1.66.30, mp4a.40.2",CLOSED-CAPTIONS=NONE https://staragvod1-vh.akamaihd.net/i/videos/plus/sns/1365/1000055355_,16,180,400,800,1300,2000,3000,4500,_STAR.mp4.csmil/index_3_av.m3u8?null=0&id=AgC0lfI2aGb2DFFZW1pBPartIAq++S+ee++3UM8jU49rfzGeMpTl2IaWB4PCyZ0c2yGZOtSqAhal4g%3d%3d #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1360000,RESOLUTION=720x404,CODECS="avc1.66.30, mp4a.40.2",CLOSED-CAPTIONS=NONE https://staragvod1-vh.akamaihd.net/i/videos/plus/sns/1365/1000055355_,16,180,400,800,1300,2000,3000,4500,_STAR.mp4.csmil/index_4_av.m3u8?null=0&id=AgC0lfI2aGb2DFFZW1pBPartIAq++S+ee++3UM8jU49rfzGeMpTl2IaWB4PCyZ0c2yGZOtSqAhal4g%3d%3d #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2060000,RESOLUTION=1280x720,CODECS="avc1.77.30, mp4a.40.2",CLOSED-CAPTIONS=NONE https://staragvod1-vh.akamaihd.net/i/videos/plus/sns/1365/1000055355_,16,180,400,800,1300,2000,3000,4500,_STAR.mp4.csmil/index_5_av.m3u8?null=0&id=AgC0lfI2aGb2DFFZW1pBPartIAq++S+ee++3UM8jU49rfzGeMpTl2IaWB4PCyZ0c2yGZOtSqAhal4g%3d%3d #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3060000,RESOLUTION=1600x900,CODECS="avc1.77.30, mp4a.40.2",CLOSED-CAPTIONS=NONE https://staragvod1-vh.akamaihd.net/i/videos/plus/sns/1365/1000055355_,16,180,400,800,1300,2000,3000,4500,_STAR.mp4.csmil/index_6_av.m3u8?null=0&id=AgC0lfI2aGb2DFFZW1pBPartIAq++S+ee++3UM8jU49rfzGeMpTl2IaWB4PCyZ0c2yGZOtSqAhal4g%3d%3d #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=4562000,RESOLUTION=1920x1080,CODECS="avc1.77.30, mp4a.40.2",CLOSED-CAPTIONS=NONE https://staragvod1-vh.akamaihd.net/i/videos/plus/sns/1365/1000055355_,16,180,400,800,1300,2000,3000,4500,_STAR.mp4.csmil/index_7_av.m3u8?null=0&id=AgC0lfI2aGb2DFFZW1pBPartIAq++S+ee++3UM8jU49rfzGeMpTl2IaWB4PCyZ0c2yGZOtSqAhal4g%3d%3d
PHP执行时的错误信息
Warning: file_get_contents(https://staragvod1-vh.akamaihd.net/i/videos/plus/sns/1365/1000055355_,16,180,400,800,1300,2000,3000,4500,_STAR.mp4.csmil/master.m3u8?hdnea=st=1515937603~exp=1515938203~acl=/*~hmac=c5f9294a198233a9751edbca51631c9cb12db63a08a69499c20d1208bd07aca8): failed to open stream: HTTP request failed! HTTP/1.0 403 Forbidden in **** on line 37
解决方案
核心原因
403 Forbidden错误通常是因为服务器验证请求的合法性失败——你的PHP请求头和浏览器的请求头不一致,服务器识别出这不是来自合法浏览器的请求,所以拒绝了。
看你的代码,第三步请求只带了User-Agent,但缺少了前两步都有的Referer头,这很可能是关键原因。另外,浏览器发送的请求头还包含Accept、Accept-Language等字段,这些也可能是服务器验证的一部分。
修改步骤
- 添加Referer头:给第三个请求加上和前两步一样的
Referer: http://www.hotstar.com,这是最关键的一步。 - 补全其他请求头:复制浏览器中请求m3u8时的完整请求头(可以通过开发者工具的Network标签查看),确保PHP请求和浏览器请求的头信息完全一致。
- 必要时添加Cookie:如果浏览器请求中带有Cookie,也要把Cookie字段加到PHP的请求头里。
修改后的第三步代码示例
//3. 获取m3u8内容 $opts = array( 'http'=>array( 'method'=>"GET", 'header'=>"Referer: http://www.hotstar.com\r\n" . "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:51.0) Gecko/20100101 Firefox/51.0\r\n" . "Accept: */*\r\n" . "Accept-Language: en-US,en;q=0.5\r\n" . "Accept-Encoding: gzip, deflate, br\r\n" . "Connection: keep-alive" ), // 如果HTTPS验证有问题,可以临时添加这个(不建议长期使用,最好配置正确的CA证书) 'ssl' => array( 'verify_peer' => false, 'verify_peer_name' => false, ) ); $context = stream_context_create($opts); $url = $link; $data = file_get_contents($url, false, $context); echo $data;
额外提示
- 如果你不确定浏览器的请求头,可以打开开发者工具(F12),在Network标签中找到获取m3u8的请求,查看
Request Headers部分,把所有字段都复制到PHP的header数组中。 - 某些CDN(比如Akamai)会验证请求的签名和来源,确保请求头和签名是匹配的,所以保持请求头和浏览器一致是关键。
内容的提问来源于stack exchange,提问作者waylan
相关产品推荐
相关产品推荐

