|
HTTP streaming 使用PHP實作,我是參考原文:Output a file with HTTP range header in PHP,
經我修改後,以下為我的Header Range Output Function:- function http_range_header_output($filename, $filepath=NULL, $kbyte_range=16) {
- $file['src'] = $filepath . $filename;
- $file['extension'] = substr(strrchr($filename,'.'),1);
- if ($file['extension'] == "mp3") {
- $mimeType = "audio/mpeg";
- } else if ($file['extension'] == "mp4") {
- $mimeType = "video/mp4";
- } else {
- $mimeType = 'octet-stream';
- }
- if (!file_exists($file['src'])) {
- header ("HTTP/1.1 404 Not Found");
- return;
- }
- $file['size'] = filesize($file['src']);
- $file['time'] = date('r', filemtime($file['src']));
- $fm = @fopen($file['src'], 'rb');
- if (!$fm) {
- header ("HTTP/1.1 505 Internal server error");
- return;
- }
- $file['begin'] = 0;
- $file['end'] = $file['size'] - 1;
- if (isset($_SERVER['HTTP_RANGE'])) {
- if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
- $file['begin'] = intval($matches[1]);
- if (!empty($matches[2])) {
- $file['end'] = intval($matches[2]);
- }
- }
- }
-
- if (isset($_SERVER['HTTP_RANGE'])) {
-
- header('HTTP/1.1 206 Partial Content');
- } else {
- header('HTTP/1.1 200 OK');
- }
- header("Content-Type: {$mimeType}");
- header('Cache-Control: public, must-revalidate, max-age=0');
- header('Pragma: no-cache');
- header('Accept-Ranges: bytes');
- header('Content-Length:' . (($file['end'] - $file['begin']) + 1));
- if (isset($_SERVER['HTTP_RANGE'])) {
- header("Content-Range: bytes {$file['begin']}-{$file['end']}/{$file['size']}");
- }
- header("Content-Disposition: inline; filename={$filename}");
- header("Content-Transfer-Encoding: binary");
- header("Last-Modified: {$file['time']}");
- $cur = $file['begin'];
- fseek($fm, $file['begin'], 0);
- $file['byte_range'] = $kbyte_range * 1024;
- while(!feof($fm) && $cur <= $file['end'] && (connection_status() == 0)) {
- print fread($fm, min($file['byte_range'], ($file['end'] - $cur) + 1));
- $cur += $file['byte_range'];
- // usleep(10000);
- }
- }
複製代碼
另外找到一個實作,來自GitHub上的Support HTTP Header Range,
這個寫法對我而言沒甚麼好修改的,所以直接轉貼至以下:- <?php
- # Nginx don't have PATH_INFO
- if (!isset($_SERVER['PATH_INFO'])) {
- $_SERVER['PATH_INFO'] = substr($_SERVER["ORIG_SCRIPT_FILENAME"], strlen($_SERVER["SCRIPT_FILENAME"]));
- }
- $request = substr($_SERVER['PATH_INFO'], 1);
- $file = $request;
- $fp = @fopen($file, 'rb');
- $size = filesize($file); // File size
- $length = $size; // Content length
- $start = 0; // Start byte
- $end = $size - 1; // End byte
- header('Content-type: video/mp4');
- header("Accept-Ranges: 0-$length");
- if (isset($_SERVER['HTTP_RANGE'])) {
- $c_start = $start;
- $c_end = $end;
- list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
- if (strpos($range, ',') !== false) {
- header('HTTP/1.1 416 Requested Range Not Satisfiable');
- header("Content-Range: bytes $start-$end/$size");
- exit;
- }
- if ($range == '-') {
- $c_start = $size - substr($range, 1);
- }else{
- $range = explode('-', $range);
- $c_start = $range[0];
- $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
- }
- $c_end = ($c_end > $end) ? $end : $c_end;
- if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
- header('HTTP/1.1 416 Requested Range Not Satisfiable');
- header("Content-Range: bytes $start-$end/$size");
- exit;
- }
- $start = $c_start;
- $end = $c_end;
- $length = $end - $start + 1;
- fseek($fp, $start);
- header('HTTP/1.1 206 Partial Content');
- }
- header("Content-Range: bytes $start-$end/$size");
- header("Content-Length: ".$length);
- $buffer = 1024 * 8;
- while(!feof($fp) && ($p = ftell($fp)) <= $end) {
- if ($p + $buffer > $end) {
- $buffer = $end - $p + 1;
- }
- set_time_limit(0);
- echo fread($fp, $buffer);
- flush();
- }
- fclose($fp);
- exit();
- ?>
複製代碼 說要改的話,我認為一開始 $_SERVER['PATH_INFO'] 那段可以拿掉,直接input $file即可。
另外,header中的 Accept-Ranges 改為 bytes 才支援Firefox Seek (v37)。 |
|