提供一个mp3 / ogg文件碎片到html5音频

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.