我有一个PHP脚本,可以充当用户和MP3之间的代理。这是为了防止外部嵌入或热链接,因此我可以计算每个MP3文件的播放次数。
我在Google Chrome和Safari(Opera,Firefox和Internet Explorer可以正常运行)中遇到问题,它们可以很好地播放MP3,但我也可以尝试,但只能搜索有限的次数。尝试几次后,播放器将自身变灰(本机chrome播放器)或显示错误(audio.js和JWPlayer 6)。我可以再次按播放,它将重新启动,但是在出现此类错误后,audio.js不会再次显示播放按钮。
JWPlayer在控制台中引发以下错误:
MediaError
code: 2
__proto__: MediaError
MEDIA_ERR_ABORTED: 1
MEDIA_ERR_DECODE: 3
MEDIA_ERR_ENCRYPTED: 5
MEDIA_ERR_NETWORK: 2
MEDIA_ERR_SRC_NOT_SUPPORTED: 4
在chromes原生播放器中,控制台报告“无法加载资源”,“我的服务器错误日志”未显示任何错误。
我当前使用的代码来自Los Cherone的答案: 使mp3可查找PHP
我以前的解决方案是不再使用此代码,但是在这里供参考:
<?php
$track = '/public_html/mp3-previews/' . $_GET['stream'];
if(file_exists($track)) {
header('Content-type: audio/mpeg');
header('Accept-Ranges: bytes');
header('Content-length: ' . filesize($track));
print file_get_contents($track);
} else {
echo "no file";
}
?>
两种代码均会导致此错误,但值得指出的是,两种代码均流音频,并且它们都允许我搜索几次。
我最初的想法是apache_request_headers函数引起了这个问题,因为我正在运行PHP 5.3,而我的主机正在将PHP作为Fast CGI运行。因此,对于Los Cherone的代码,我正在使用此替代方法,但是为什么我的第一次尝试也不起作用?
编辑:这不是问题。我已经更新了我的PHP版本,这仍然导致我遇到问题。
这是我的托管服务器示例:http : //tabbidesign.com/audio/
Los Cherone的代码和我自己的本地Apache服务器以及PHP 5.4.9的完美结合使用,不会发生此问题。这是示例:http : //tabbicat.info/proving/audio/
是什么原因造成的?
我设法解决了我的问题。
在尝试了其他传输方法之后,使用Fiddler分析了我的网络流量,并从上面的评论中获取了一些建议,我对代码进行了一些更改。
由于某种原因,脚本在如下所示的循环中未发送正确数量的字节:
if ($start) fseek($fp,$start);
while($length){
set_time_limit(0);
$read = 8192;
$length -= $read;
print(fread($fp,$read));
}
fclose($fp);
在Firefox,Opera和IE中没有问题的原因是,它们在播放期间缓存了整个文件,因此向后跳过就不再请求该文件。Webkit(Chrome和Safari)再次请求文件,每次发送内容范围。
$file_name = '/home/sites/public_html/mp3-previews/' . $_GET['stream'];
stream($file_name, 'audio/mpeg');
function stream($file, $content_type = 'application/octet-stream') {
@error_reporting(0);
// Make sure the files exists, otherwise we are wasting our time
if (!file_exists($file)) {
header("HTTP/1.1 404 Not Found");
exit;
}
// Get file size
$filesize = sprintf("%u", filesize($file));
// Handle 'Range' header
if(isset($_SERVER['HTTP_RANGE'])){
$range = $_SERVER['HTTP_RANGE'];
}elseif($apache = apache_request_headers()){
$headers = array();
foreach ($apache as $header => $val){
$headers[strtolower($header)] = $val;
}
if(isset($headers['range'])){
$range = $headers['range'];
}
else $range = FALSE;
} else $range = FALSE;
//Is range
if($range){
$partial = true;
list($param, $range) = explode('=',$range);
// Bad request - range unit is not 'bytes'
if(strtolower(trim($param)) != 'bytes'){
header("HTTP/1.1 400 Invalid Request");
exit;
}
// Get range values
$range = explode(',',$range);
$range = explode('-',$range[0]);
// Deal with range values
if ($range[0] === ''){
$end = $filesize - 1;
$start = $end - intval($range[0]);
} else if ($range[1] === '') {
$start = intval($range[0]);
$end = $filesize - 1;
}else{
// Both numbers present, return specific range
$start = intval($range[0]);
$end = intval($range[1]);
if ($end >= $filesize || (!$start && (!$end || $end == ($filesize - 1)))) $partial = false; // Invalid range/whole file specified, return whole file
}
$length = $end - $start + 1;
}
// No range requested
else $partial = false;
// Send standard headers
header("Content-Type: $content_type");
header("Content-Length: $length");
header('Accept-Ranges: bytes');
//header('Connection: keep-alive');
//header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
//header('Pragma: no-cache'); // HTTP 1.0.
//header('Expires: 0'); // Proxies.
// send extra headers for range handling...
if ($partial) {
header('HTTP/1.1 206 Partial Content');
header("Content-Range: bytes $start-$end/$filesize");
if (!$fp = fopen($file, 'rb')) {
header("HTTP/1.1 500 Internal Server Error");
exit;
}
if ($start) fseek($fp,$start);
print(fread($fp,$length));
fclose($fp);
}
//just send the whole file
else readfile($file);
exit;
}
我已经发送了Content-Length标头中请求的实际输出大小,并且删除了以8000字节为单位发送文件的循环。
现在,我可以确定,如果我尝试处理大文件,PHP肯定会用光内存,因为我要处理整个文件而不是8000字节的块,但是我每次只处理4MB的文件,所以现在可以了。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句