我目前有这段代码:
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)
问题在于范围下载功能。在此功能中,标题是正确的。但是您打印完整的文件作为响应。
这些更改可以解决您的问题。
// Notify the client the byte range we'll be outputting
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: $length");
在这里,您需要在内容范围标题中查找要开始的文件。
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);
答案 1 :(得分: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上进行了测试