使用PHP读取视频流,IOS系统无法观看的问题解决方法
背景
项目中遇到了付费视频资源的问题,为隐藏视频真实地址并对观看视频的用户做权限限制,于是就想到了使用php判断当前用户权限读取视频文件,客户端视频地址指向写好的php就好,但是经过简单的代码处理后,电脑和Android并没有发现问题,但是IOS系统播放的时候死活播放不了,进行一番研究之后,得出了解决方案。
场景复现
假设我们要做一个付费视频课程的项目,设计数据库数据结构如下:
1 |
|
然后新增一个页面(_getresource.php_)(在框架中可用 控制器/方法 代替) 这是比较常规的做法,使用file_get_contents()或者readfile();直接将文件读取出来,前端使用video标签读取视频文件并播放。
1 |
|
1 |
|
我最开始的想法就是这样,然后使用Chrome、Android进行测试也并没有发现问题,直到有一天,我拿出了IOS。。。点击 播放 ,然后出现了一个小叉叉,视频无法加载。 当时的我百思不得其解,于是开始在全网搜集资料,然后我发现并不是我一个人遇到了这个问题,经过搜索,最终我锁定了一片知乎上的帖子,根据答主所述原理,成功使用PHP解决了这个问题。 吃水不忘挖井人,原帖奉上:video标签在iPhone手机上不能播放?万能的知乎大神请指引我,实在没办法了
问题成因
chrome对视频的兼容性比较好,有时候请求资源,header里边的”Range”是”0-“,意思是请求获取该视频全部文件,而我们恰好将文件全部返回了,所以Chrome中可以正常使用。 但是在IOS中,无论是自带的safari还是IOS的微信浏览器都是用的safari内核,请求视频资源时都会先发起一个头部包含”Range:0-1” 的请求,目的是为了获取视频文件大小,如果用户不点开视频可以节省流量。 chorme的video请求: IOS的video请求日志记录 透过日志可以看到,IOS观看视频时,会先请求一个range:0-1, 此时我回一个length:2 ,bytes=0-1,IOS将会获取到视频大小等信息,以便进行分段请求。
解决问题
解决这个问题,其实只需要解析header里边的Range就可以了,比如Range:start-end ,表示获取start-end的所有数据,假设这个文件有 255个字节并且请求header中的Range: 0-,那么我们应该返回Content-Range:bytes 0-254/255。 特别注意:返回的end是广义的end,255个字节,end最大为254,如果请求Range:0-1, 那么我们应该返回前两个字节,而不是1个。 所以,根据规律,start和end都可以根据正则表达式匹配Header的Range可以获取到,读取长度 = end - start + 1,所以,可以将文件读取的部分修改为如下的样子。
1 |
|
基于TP封装的获取资源类
系统会根据method的不同而调用AssetLogic不同的方法,AssetLogic中可以进行权限判断以及返回视频/其他资源的真实地址、定制header等。 并且针对微信浏览器不能调起下载链接的问题,弄了个100s有效的下载码,提示用户从浏览器打开,打开后即可下载到相关资源。
1 |
|