PHP后端读取文件给video标签返回视频地址

获取请求文件内容起始位

通过$_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);
原文地址:https://www.cnblogs.com/xinghan/p/10913695.html