最近,在项目中尝试使用html5中的audio标签做web版的播放器,因为涉及到付费的音频,所以需要对用户权限做一些判断,然后动态输出mp3。但是,动态生成的mp3在chrome中无法正常拖动。
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"><title>Test</title> </head> <body> <audio src="http://localhost/demo/mp3.php" controls="controls"></audio> </body> </html>
header("Content-type:audio/mpeg"); header('Content-Length: ' . filesize("1.mp3")); echo file_get_contents("1.mp3");
将audio中的src修改成mp3源文件路径(在chrome中拖动正常):
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Test</title> </head> <body> <audio src="http://localhost/demo/1.mp3" controls="controls"></audio> </body> </html>
猜想,莫非audio播放mp3后缀的音频文件才能拖动进度条?
尝试配置apache解析后缀为mp3的php文件,将mp3.php改成mp3.mp3,问题依然存在。取消掉apache解析后缀为mp3文件的行为,将audio标签中的src修改为mp3源文件路径,利用chrome控制台查看audio标签如何请求以及响应。
1.mp3的请求信息:
请求头里面主要包含Range字段。 响应信息如下:Status Code:206 Partial Content。
响应头信息:
主要包含Accept-Ranges、Content-Range字段。 很明显,chrome请求mp3文件时采用的是断点续传。 当点击进度条时,相应的请求信息及响应信息如下:
当点击进度条时,chrome浏览器会发起一条http请求,依然采用断点续传。根据以上分析,若要使动态生成的mp3能拖动进度,就必须在php文件中实现断点续传,在php中构造相应的响应头即可。
最终,mp3.php代码如下:
<?php $file = "1.mp3"; $fileSize = filesize($file); $etag = md5(filemtime($file)); $fp = fopen($file, 'rb'); if (!$fp) { die('Could not open file'); } $start = 0; $end = $fileSize - 1; if (isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE'])) { //获取请求头中的Range字段 $range = explode('-', substr($_SERVER['HTTP_RANGE'], strlen('bytes='))); $start = $range[0]; if ($range[1] > 0) { $end = $range[1]; } //构造断点续传响应头 header('HTTP/1.1 206 Partial Content'); header('Status: 206'); header('Accept-Ranges: bytes'); header('Content-Range: bytes ' . $start. '-' . $end . '/' . $fileSize); header('Content-Length: ' . ($end - $start + 1)); } else { header('Content-Length: ' . $fileSize); } header('Content-Type: audio/mpeg'); header('Last-Modified: ' . date('D, d M Y H:i:s \G\M\T', filemtime($file))); header('ETag: "' . $etag . '"'); header('Expires: 0'); if ($start > 0) { fseek($fp, $start); //移动文件指针 } $bytesPosition = $start; while (!feof($fp) && $bytesPosition <= $end) { $chunk = 1024 * 1024 * 50; //每次读取50k if ($bytesPosition + $chunk > $end + 1) { $chunk = $end - $bytesPosition + 1; } $chunk = fread($fp, $chunk); if (!$chunk) { die('Could not read file'); } print($chunk); flush(); $bytesPosition += $chunk; } fclose($fp);