PHP输出的视频在iOS 12-13 Safari无法播放问题求助
iOS 12-13 Safari 无法播放PHP输出的MP4视频问题解决
问题场景
使用以下PHP类输出MP4视频文件时,多数浏览器(包括iOS15及以上版本的Safari)均可正常播放,但iOS12-13版本的Safari仅显示带叉号的播放图标,无控制台报错。直接访问视频文件的原始URL(如example.com/static/v/videotest.mp4)时,iOS12-13 Safari可正常播放,排除视频文件本身的问题。
原PHP代码:
class VideotestPage { function __construct($params) { $videoFile = '../static/v/videotest.mp4'; if (file_exists($videoFile)) { //Send the headers header('Content-Description: File Transfer'); header('Content-Type: video/mp4'); header('Content-Disposition: inline; filename="'.basename($videoFile).'"'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($videoFile)); //Send file readfile($videoFile); exit; } else { echo "404 - $videoFile."; } } }
问题根源
iOS12-13的Safari对视频流的播放有严格要求,必须支持范围请求(Range Requests)——浏览器会通过Range头请求视频的片段内容,而非一次性加载整个文件。原代码直接返回完整文件,未处理这类请求,导致旧版Safari无法解析视频流。此外,部分冗余的响应头也可能干扰浏览器的视频解析逻辑。
解决方案
修改PHP代码,添加范围请求处理逻辑,并调整响应头以适配旧版Safari:
class VideotestPage { function __construct($params) { $videoFile = '../static/v/videotest.mp4'; if (!file_exists($videoFile)) { http_response_code(404); echo "404 - $videoFile."; exit; } $fileSize = filesize($videoFile); $fileHandle = fopen($videoFile, 'rb'); // 处理浏览器的范围请求 $range = $_SERVER['HTTP_RANGE'] ?? ''; if (preg_match('/bytes=(\d+)-(\d+)?/', $range, $matches)) { $start = intval($matches[1]); $end = isset($matches[2]) ? intval($matches[2]) : $fileSize - 1; $length = $end - $start + 1; // 返回部分内容的响应头 http_response_code(206); header('Accept-Ranges: bytes'); header('Content-Length: ' . $length); header("Content-Range: bytes $start-$end/$fileSize"); } else { // 正常请求返回完整文件 http_response_code(200); header('Content-Length: ' . $fileSize); header('Accept-Ranges: bytes'); } // 设置视频播放必要的响应头 header('Content-Type: video/mp4'); header('Content-Disposition: inline; filename="' . basename($videoFile) . '"'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); // 定位到请求起始位置并输出内容 if (isset($start)) { fseek($fileHandle, $start); } fpassthru($fileHandle); fclose($fileHandle); exit; } }
修改说明
- 添加
Accept-Ranges: bytes头,明确告知浏览器支持范围请求 - 解析
HTTP_RANGE头,处理部分内容请求,返回206 Partial Content状态码及对应内容范围 - 使用
fseek+fpassthru替代readfile,更高效地处理文件片段输出 - 移除
Content-Description: File Transfer头,避免干扰浏览器的视频解析逻辑 - 提前判断文件是否存在,优化404响应逻辑
内容的提问来源于stack exchange,提问作者Maksim
相关产品推荐
相关产品推荐

