I'm trying to provide a audio file through a browser using HTML5 audio tag:
<audio preload="auto">
<source src="<?php echo $song->getUrl('mp3'); ?>" type="audio/mpeg">
<source src="<?php echo $song->getUrl('ogg'); ?>" type="audio/ogg">
Please update your browser.
</audio>
I need to save traffic, so I thought about sending partial content this way:
$contentType = ($format == 'mp3') ? 'audio/mpeg' : 'audio/ogg';
$filePath = $song->getPath($format);
$fileLength = filesize($filePath);
$start = 0;
if(isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE'])) {
$http_range = explode('-', substr($_SERVER['HTTP_RANGE'], strlen('bytes=')));
$start = $http_range[0];
}
$remainingBytes = $fileLength - $start;
$length = min((512*1024), $remainingBytes);
$final = $start + $length;
header('HTTP/1.1 206 Partial Content');
header('Status: 206 Partial Content');
header('Content-Type: ' . $contentType);
header('Content-Disposition: inline;filename="listen.' . $format . '"');
header('Content-length: ' . $length);
header('Content-Transfer-Encoding: bytes');
header('Accept-Ranges: bytes');
header('Cache-Control: no-cache');
header('Content-Range: bytes ' . $start . '-' . $final . '/' . $fileLength);
echo file_get_contents($filePath, false, null, $start, $length);
The result of this is, in Chrome, the song being almost completely played (3.41 out of 3.47 seconds of a 9.1MB file). In firefox, the first 39 seconds played (I guess 512KB). In opera, a never-ending "loading" status.
I think you mistakenly calculate the size of the file
$contentType = ($format == 'mp3') ? 'audio/mpeg' : 'audio/ogg';
$filePath = $song->getPath($format);
$fileLength = filesize($filePath);
EDITED
$format
is file extension and not filepath AND
filesize($filePath); // Do not returns file size
Per RFC2616, a 206 Partial Content
response is only valid in response to an HTTP range request:
10.2.7 206 Partial Content
The server has fulfilled the partial GET request for the resource. The request MUST have included a Range header field (section 14.35) indicating the desired range, and MAY have included an If-Range header field (section 14.27) to make the request conditional.
Your script is generating a 206 response for a request which may very well not have been for partial content (or may have been for a different range than you're returning), and this is confusing web browsers. There is, in all likelihood, no logic in most browsers to make additional requests to get the rest of your content, as this situation should never arise.
Your script is also not correctly processing Range requests either! Ranges include a length, and multiple ranges may be present in a request. Again, see RFC2616 for details.