2013-07-27 14 views
1

視頻我現在有這樣的代碼:流與PHP

function Stream($file) 
{ 
header_remove(); 
$arr = get_headers($file); 
foreach ($arr as &$value) {if((strpos($value,'Content-Type')!== false)){header($value);}} 

    if (isset($_SERVER['HTTP_RANGE'])) { 
     rangeDownload($file); 
    } 
    else { 
header('HTTP/1.1 206 Partial Content'); 
header("Content-Length:1"); 
    //foreach ($arr as &$value) {if((strpos($value,'Content-Length')!== false)){header($value);}} 
//header("Content-Range:bytes 21056-21056/243957100"); 
     readfile($file); 
    } 
} 

function rangeDownload($file) { 

    $fp = @fopen($file, 'rb'); 

    $size = filesize($file); // File size 
    $length = $size;   // Content length 
    $start = 0;    // Start byte 
    $end = $size - 1;  // End byte 
    // Now that we've gotten so far without errors we send the accept range header 
    /* At the moment we only support single ranges. 
    * Multiple ranges requires some more work to ensure it works correctly 
    * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 
    * 
    * Multirange support annouces itself with: 
    * header('Accept-Ranges: bytes'); 
    * 
    * Multirange content must be sent with multipart/byteranges mediatype, 
    * (mediatype = mimetype) 
    * as well as a boundry header to indicate the various chunks of data. 
    */ 
    header("Accept-Ranges: 0-$length"); 
    // header('Accept-Ranges: bytes'); 
    // multipart/byteranges 
    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 
    if (isset($_SERVER['HTTP_RANGE'])) { 

     $c_start = $start; 
     $c_end = $end; 
     // Extract the range string 
     list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); 
     // Make sure the client hasn't sent us a multibyte range 
     if (strpos($range, ',') !== false) { 

      // (?) Shoud this be issued here, or should the first 
      // range be used? Or should the header be ignored and 
      // we output the whole content? 
      header('HTTP/1.1 416 Requested Range Not Satisfiable'); 
      header("Content-Range: bytes $start-$end/$size"); 
      // (?) Echo some info to the client? 
      exit; 
     } 
     // If the range starts with an '-' we start from the beginning 
     // If not, we forward the file pointer 
     // And make sure to get the end byte if spesified 
     if ($range0 == '-') { 

      // The n-number of the last bytes is requested 
      $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; 
     } 
     /* Check the range and make sure it's treated according to the specs. 
     * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html 
     */ 
     // End bytes can not be larger than $end. 
     $c_end = ($c_end > $end) ? $end : $c_end; 
     // Validate the requested range and return an error if it's not correct. 
     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"); 
      // (?) Echo some info to the client? 
      exit; 
     } 
     $start = $c_start; 
     $end = $c_end; 
     $length = $end - $start + 1; // Calculate new content length 
     fseek($fp, $start); 
     header('HTTP/1.1 206 Partial Content'); 
    } 
    // Notify the client the byte range we'll be outputting 
    header("Content-Range: bytes $start-$end/$size"); 
    header("Content-Length: $length"); 

    // Start buffered download 
    $buffer = 1024 * 8; 
    while(!feof($fp) && ($p = ftell($fp)) <= $end) { 

     if ($p + $buffer > $end) { 

      // In case we're only outputtin a chunk, make sure we don't 
      // read past the length 
      $buffer = $end - $p + 1; 
     } 
     set_time_limit(0); // Reset time limit for big files 
     echo fread($fp, $buffer); 
     flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. 
    } 

    fclose($fp); 

} 

我可以看到,所有3個請求,並且文件下載開始的又不是出現在流取消的視頻畫面。我試圖模仿標準apache標題沒有成功,我試圖讓它提供最廣泛的支持(如內容類型檢測)的視頻內容。

+0

爲什麼不編輯舊問題並要求重新審覈? –

+0

我在這段代碼中看不到有3個請求的原因。你還沒有告訴過的故事的其他部分是什麼? – Sven

+0

沒有故事,chrome似乎在打開一條小河時發出3個請求,自己測試一下。 – user2625259

回答

0

問題出在範圍下載函數中。在這個函數中你的標題是正確的,但是你打印的是完整的文件作爲響應。

這些更改應該可以解決您的問題。

// Notify the client the byte range we'll be outputting 
header("Content-Range: bytes $start-$end/$size"); 
header("Content-Length: $length"); 

這裏您需要查找在content-range標頭中指定的文件開始。

fseek($fp,$start) /* MISSING CODE */ 

插入上面的行應該可以解決您的問題。

// Start buffered download 
$buffer = 1024 * 8; 
while(!feof($fp) && ($p = ftell($fp)) <= $end) { 

    if ($p + $buffer > $end) { 

     // In case we're only outputtin a chunk, make sure we don't 
     // read past the length 
     $buffer = $end - $p + 1; 
    } 
    set_time_limit(0); // Reset time limit for big files 
    echo fread($fp, $buffer); 
    flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. 
} 

fclose($fp); 
0

我不得不通過同樣的事情來完成我被要求做的工作。我沒有問題使它適用於Chrome/Firefox,但是我在Mac/iPad上遇到了Safari問題。我引用了多個來源並嘗試了很多東西,最後我拋出了我必須得到的所有東西,然後決定嘗試使用此問題中的代碼修復問題,因爲它與我已有的代碼很相似,但不同的程度足以讓我更清晰。

下面是使用原始問題代碼作爲基礎的最終工作版本,但有必要的修復程序可以幫助我。希望這可以幫助別人。

if (isset($_SERVER['HTTP_RANGE'])) { 
    header('Content-Type: video/'.$ext); // reference your own mime variable here 
    $fp = @fopen($filepath, 'rb'); 

    $size = filesize($filepath); // File size 
    $length = $size;   // Content length 
    $start = 0;    // Start byte 
    $end = $size - 1;  // End byte 
    // Now that we've gotten so far without errors we send the accept range header 
    /* At the moment we only support single ranges. 
    * Multiple ranges requires some more work to ensure it works correctly 
    * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 
    * 
    * Multirange support annouces itself with: 
    * header('Accept-Ranges: bytes'); 
    * 
    * Multirange content must be sent with multipart/byteranges mediatype, 
    * (mediatype = mimetype) 
    * as well as a boundry header to indicate the various chunks of data. 
    */ 
    header("Accept-Ranges: 0-$length"); 
    // multipart/byteranges 
    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 
    $c_start = $start; 
    $c_end = $end; 
    // Extract the range string 
    list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); 
    // Make sure the client hasn't sent us a multibyte range 
    if (strpos($range, ',') !== false) { 
    // (?) Shoud this be issued here, or should the first 
    // range be used? Or should the header be ignored and 
    // we output the whole content? 
    header('HTTP/1.1 416 Requested Range Not Satisfiable'); 
    header("Content-Range: bytes $start-$end/$size"); 
    // (?) Echo some info to the client? 
    exit; 
    } 
    // If the range starts with an '-' we start from the beginning 
    // If not, we forward the file pointer 
    // And make sure to get the end byte if spesified 
    if ($range == '-') { 
    // The n-number of the last bytes is requested 
    $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; 
    } 

    /* Check the range and make sure it's treated according to the specs. 
    * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html 
    */ 
    // End bytes can not be larger than $end. 
    $c_end = ($c_end > $end) ? $end : $c_end; 
    // Validate the requested range and return an error if it's not correct. 
    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"); 
    // (?) Echo some info to the client? 
    exit; 
    } 
    $start = $c_start; 
    $end = $c_end; 
    $length = $end - $start + 1; // Calculate new content length 
    header('HTTP/1.1 206 Partial Content'); 
    // Notify the client the byte range we'll be outputting 
    header("Content-Range: bytes $start-$end/$size"); 
    header("Content-Length: $length"); 

    // Start buffered download 
    $buffer = 1024 * 8; 
    fseek($fp,$start); 
    while(!feof($fp) && ($p = ftell($fp)) <= $end) { 
    if ($p + $buffer > $end) { 
     // In case we're only outputtin a chunk, make sure we don't 
     // read past the length 
     $buffer = $end - $p + 1; 
    } 
    set_time_limit(0); // Reset time limit for big files 
    echo fread($fp, $buffer); 
    flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. 
    } 

    fclose($fp); 
} 

這是我用的,有幾個變量除外它建立的文件路徑和視頻擴展/ MIME類型之前,整個代碼。這已經在Chrome(最新版本),Firefox(最新版本),Macbook Pro上的Safari 7.0.6,iOS 7上的Safari上測試過。