請選擇 進入手機版 | 繼續訪問電腦版
搜索
熱搜: 活動 交友 discuz
查看: 3576|回復: 0

[PHP] HTTP續傳實作(Header Range): Output a file with HTTP range header in PHP (ex.mp4)

[複製鏈接]
發表於 2015-4-15 18:03:49 | 顯示全部樓層 |閱讀模式
HTTP streaming 使用PHP實作,我是參考原文:Output a file with HTTP range header in PHP

經我修改後,以下為我的Header Range Output Function:
  1. function http_range_header_output($filename, $filepath=NULL, $kbyte_range=16) {

  2.         $file['src'] = $filepath . $filename;

  3.         $file['extension'] = substr(strrchr($filename,'.'),1);

  4.         if ($file['extension'] == "mp3") {

  5.                 $mimeType = "audio/mpeg";

  6.         } else if ($file['extension'] == "mp4") {

  7.                 $mimeType = "video/mp4";

  8.         } else {

  9.                 $mimeType = 'octet-stream';
  10.         }

  11.         if (!file_exists($file['src'])) {

  12.                 header ("HTTP/1.1 404 Not Found");
  13.                 return;
  14.         }

  15.         $file['size']  = filesize($file['src']);
  16.         $file['time']  = date('r', filemtime($file['src']));

  17.         $fm = @fopen($file['src'], 'rb');
  18.         if (!$fm) {
  19.                 header ("HTTP/1.1 505 Internal server error");
  20.                 return;
  21.         }

  22.         $file['begin']  = 0;
  23.         $file['end']  = $file['size'] - 1;

  24.         if (isset($_SERVER['HTTP_RANGE'])) {

  25.                 if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {

  26.                         $file['begin'] = intval($matches[1]);

  27.                         if (!empty($matches[2])) {
  28.                                 $file['end']  = intval($matches[2]);
  29.                         }
  30.                 }
  31.         }
  32.        
  33.         if (isset($_SERVER['HTTP_RANGE'])) {
  34.                
  35.                 header('HTTP/1.1 206 Partial Content');

  36.         } else {

  37.                 header('HTTP/1.1 200 OK');
  38.         }

  39.         header("Content-Type: {$mimeType}");
  40.         header('Cache-Control: public, must-revalidate, max-age=0');
  41.         header('Pragma: no-cache');  
  42.         header('Accept-Ranges: bytes');
  43.         header('Content-Length:' . (($file['end'] - $file['begin']) + 1));

  44.         if (isset($_SERVER['HTTP_RANGE'])) {

  45.                 header("Content-Range: bytes {$file['begin']}-{$file['end']}/{$file['size']}");
  46.         }

  47.         header("Content-Disposition: inline; filename={$filename}");
  48.         header("Content-Transfer-Encoding: binary");
  49.         header("Last-Modified: {$file['time']}");

  50.         $cur = $file['begin'];
  51.         fseek($fm, $file['begin'], 0);

  52.         $file['byte_range'] = $kbyte_range * 1024;

  53.         while(!feof($fm) && $cur <= $file['end'] && (connection_status() == 0)) {

  54.                 print fread($fm, min($file['byte_range'], ($file['end'] - $cur) + 1));

  55.                 $cur += $file['byte_range'];

  56.                 // usleep(10000);
  57.         }
  58. }
複製代碼



另外找到一個實作,來自GitHub上的Support HTTP Header Range

這個寫法對我而言沒甚麼好修改的,所以直接轉貼至以下:
  1. <?php
  2. # Nginx don't have PATH_INFO
  3. if (!isset($_SERVER['PATH_INFO'])) {
  4.         $_SERVER['PATH_INFO'] = substr($_SERVER["ORIG_SCRIPT_FILENAME"], strlen($_SERVER["SCRIPT_FILENAME"]));
  5. }

  6. $request = substr($_SERVER['PATH_INFO'], 1);
  7. $file = $request;
  8. $fp = @fopen($file, 'rb');

  9. $size   = filesize($file); // File size
  10. $length = $size;           // Content length
  11. $start  = 0;               // Start byte
  12. $end    = $size - 1;       // End byte

  13. header('Content-type: video/mp4');
  14. header("Accept-Ranges: 0-$length");
  15. if (isset($_SERVER['HTTP_RANGE'])) {

  16.     $c_start = $start;
  17.     $c_end   = $end;

  18.     list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
  19.     if (strpos($range, ',') !== false) {
  20.         header('HTTP/1.1 416 Requested Range Not Satisfiable');
  21.         header("Content-Range: bytes $start-$end/$size");
  22.         exit;
  23.     }
  24.     if ($range == '-') {
  25.         $c_start = $size - substr($range, 1);
  26.     }else{
  27.         $range  = explode('-', $range);
  28.         $c_start = $range[0];
  29.         $c_end   = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
  30.     }
  31.     $c_end = ($c_end > $end) ? $end : $c_end;
  32.     if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
  33.         header('HTTP/1.1 416 Requested Range Not Satisfiable');
  34.         header("Content-Range: bytes $start-$end/$size");
  35.         exit;
  36.     }
  37.     $start  = $c_start;
  38.     $end    = $c_end;
  39.     $length = $end - $start + 1;
  40.     fseek($fp, $start);
  41.     header('HTTP/1.1 206 Partial Content');
  42. }

  43. header("Content-Range: bytes $start-$end/$size");
  44. header("Content-Length: ".$length);


  45. $buffer = 1024 * 8;
  46. while(!feof($fp) && ($p = ftell($fp)) <= $end) {

  47.     if ($p + $buffer > $end) {
  48.         $buffer = $end - $p + 1;
  49.     }
  50.     set_time_limit(0);
  51.     echo fread($fp, $buffer);
  52.     flush();
  53. }

  54. fclose($fp);
  55. exit();
  56. ?>
複製代碼
說要改的話,我認為一開始 $_SERVER['PATH_INFO'] 那段可以拿掉,直接input $file即可。

另外,header中的 Accept-Ranges 改為 bytes 才支援Firefox Seek (v37)。
您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則

本論壇為非營利之網路平台,所有文章內容均為網友自行發表,不代表論壇立場!若涉及侵權、違法等情事,請告知版主處理。


Page Rank Check

廣告刊登  |   交換連結  |   贊助我們  |   服務條款  |   免責聲明  |   客服中心  |   中央分站

手機版|中央論壇

GMT+8, 2020-9-28 17:27 , Processed in 0.087314 second(s), 17 queries .

Powered by Discuz!

© 2005-2015 Copyrights. Set by YIDAS

快速回復 返回頂部 返回列表