On our platform (based on Laravel 5.1) we provide audio and video content to registered users. The media files are stored outside the docroot
of course.
So I use a method to provide the requested content. That works well on any browser and OS except Android (native or chrome). Android uses a byte range request for audio and video tags. The following code worked in the beginning and stopped working a while ago. I have no clue why. Any:
public function loadfile(Request $request, $type, $filename="")
{
$filepath = $mediadirectory . $filename;
if (File::isFile($filepath)) {
$file = File::get($filepath);
$mimetype = File::mimeType($filepath);
$size = File::size($filepath);
if ($mimetype=="audio/mpeg" || $mimetype=="video/mp4") {
$stream = fopen($filepath, "r");
$start = 0;
$length = $size;
$status = 200;
$headers = ['Content-Type' => $mimetype, 'Content-Length' => $size, 'Accept-Ranges' => 'bytes'];
if (false !== $range = $request->server('HTTP_RANGE', false)) {
list($param, $range) = explode('=', $range);
if (strtolower(trim($param)) !== 'bytes') {
header('HTTP/1.1 400 Invalid Request');
exit;
}
list($from, $to) = explode('-', $range);
if ($from === '') {
$end = $size - 1;
$start = $end - intval($from);
} elseif ($to === '') {
$start = intval($from);
$end = $size - 1;
} else {
$start = intval($from);
$end = intval($to);
}
$length = $end - $start + 1;
$status = 206;
$headers['Content-Range'] = sprintf('bytes %d-%d/%d', $start, $end, $size);
$headers['Connection'] = "keep-alive";
}
$response=new StreamedResponse(function() use ($stream, $start, $length) {
fseek($stream, $start, SEEK_SET);
echo fread($stream, $length);
fclose($stream);
}, $status, $headers);
return $response->send();
} else {
return response($file, 200)->header('Content-Type', $mimetype)->header('Content-Length', $size)->header('Content-Disposition', 'filename="' . $filename . '"');
}
}
}
The html is straight forward html5:
<audio controls preload="auto">
<source src="/loadfile/principiante.mp3" type="audio/mpeg">
</audio>