获取请求文件内容起始位
通过$_SERVER['HTTP_RANGE']或者TP5的request()->header('Range')方法来获取原始头
Range: bytes=0- //请求头原样
Range: bytes=0-1 //IOS请求头
/**
* 获取请求range
* @param string $range 请求头range值
* @return array $ret 请求内容范围 $ret['start'] 开始位,$ret['end']结束位
*/
private function getPlayRange($range)
{
$ret=[];
list($key, $offset) = explode('=', $range);
list($start, $end) = explode('-', $offset);
$ret=[
'start'=>$start,
'end'=>$end
];
return $ret;
}
获取文件内容
通过file_get_contents来读取文件内容
/**
* 获取文件流
* @param string $file 文件绝对路径
* @param int $offset 文件偏移值
* @param int $length 请求的文件长度
* @return $stream 文件内容
*/
private function getFileStream($file, $offset,$length)
{
//超时或超出大小可以修改PHP参数 memory_limit和max_execution_time
//set_time_limit(0)
$size = filesize($file);
//限制超出文件长度
if($offset+$length>=$size){
$length=$size;
}
return @file_get_contents($file, false, null, $offset, $length);
}
设置响应头
需要输出以下3个响应头
Content-Length: 27602948 // 本次响应文件长度
Content-Range: bytes 0-27602947/27602948 {偏移起始值}-{偏移结束值-1}/{文件总大小}
Content-Type: video/mp4
/**
* 获取响应头
* @param string $file 文件绝对路径
* @param int $offset 文件偏移值
* @param int $length 请求的文件长度
* @return array $header 响应头
*/
private function getVideoHeader($file, $offset,$length)
{
$size = filesize($file);
$end=0;
//设置返回长度范围
if($offset+$length>=$size){
$end=$size-1;
$length=$size-$offset;
}else{
$end=$offset+$length- 1;
}
$header = [
'Content-Length' => $length,
'Content-Range' => 'bytes ' . $offset . "-" . $end . "/" . $size,
'Content-Type' => 'video/mp4'
];
return $header;
}
/**
* 获取IOS响应头
* @param string $file 文件路径
* @param int $start 内容起始位置
* @param int $end 内容结束位置
* @return array $header 响应头
*/
private function getVideoHeaderByIOS($file, $start,$end)
{
$size = filesize($file);
$length=$end-$start+1;
$header = [
'Content-Length' => $length,
'Content-Range' => 'bytes ' . $start . "-" . $end . "/" . $size,
'Content-Type' => 'video/mp4'
];
return $header;
}
输出结果
这里需要返回206状态码
使用header()设置响应头返回文件内容
TP5可以使用response()方法响应;
response($stream, 206, $header);
try {
//获取视频流和视频头
if($range['end']!=''){
//兼容IOS IOS下请求头range回有开始位和结束位 PC和安卓则只有起始位
$stream = $this->getFileStream($file, $range['start'], $range['end']-$range['start']+1);
$header = $this->getVideoHeaderByIOS($file, $range['start'], $range['end']);
}else{
//每次读取长度
$length=1024*1024*5;
$stream = $this->getFileStream($file, $range['start'],$length);
$header = $this->getVideoHeader($file, $range['start'],$length);
}
} catch (Exception $e) {
exit($e->getMessage());
}
return response($stream, 206, $header);