Not getting proper range value when using partial content header - php

I'm trying to playback an mp4 that resides outside my web root. Had no issue there except that I couldn't seek within the video. Research lead me to the http "206 partial content" header.
This is the php that serves the file:
const STORAGE_PATH = '/home/files/';
$filename = "my_video.mp4";
$file = STORAGE_PATH.$filename;
$size = filesize($file);
$begin = 0;
$end = $size - 1;
header('Content-Type: video/mp4');
header('Accept-Ranges: bytes');
if (isset($_SERVER['HTTP_RANGE'])){
$range = substr($_SERVER['HTTP_RANGE'], strpos($_SERVER['HTTP_RANGE'], '=')+1);
$range = explode('-', $range);
$begin = intval($range[0]);
$end = (isset($range[1]) && !empty($range[1])) ? intval($range[1]) : $size-1;
$length = $end - $begin + 1;
header('HTTP/1.1 206 Partial Content');
header("Content-Range: bytes $begin-$end/$size");
fseek($f, $begin);
}
$length = ($end - $begin) + 1;
header('Content-Length:' .$length);
header('Content-Disposition: inline; filename="'.$filename.'"');
//header('Content-Transfer-Encoding: binary');
//header('Expires: 0');
//header('Cache-Control: must-revalidate');
//header('Pragma: public');
echo fread($f, $length);
flush();
fclose($f);
exit();
When I load the page with the html5 video tag, it fails to load the video with the following console error:
net::ERR_CONTENT_LENGTH_MISMATCH 206 (Partial Content)
With chrome dev tools, it's showing the requested header is only sending the first range value but not the second.
Range: bytes=0-
In response, my script is sending back the entire range of the file since it's not finding a specific range from the server. I'm not sure where the problem is at this point.

Related

Displaying large PDF files using PHP headers

I took the following piece of code from github
function smartReadFile($location, $filename, $mimeType = 'application/pdf')
{
if (!file_exists($location))
{
header ("HTTP/1.1 404 Not Found");
return;
}
$size = filesize($location);
$time = date('r', filemtime($location));
$fm = #fopen($location, 'rb');
if (!$fm)
{
header ("HTTP/1.1 505 Internal server error");
return;
}
$begin = 0;
$end = $size - 1;
if (isset($_SERVER['HTTP_RANGE']))
{
if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches))
{
$begin = intval($matches[1]);
if (!empty($matches[2]))
{
$end = intval($matches[2]);
}
}
}
if (isset($_SERVER['HTTP_RANGE']))
{
header('HTTP/1.1 206 Partial Content');
}
else
{
header('HTTP/1.1 200 OK');
}
header("Content-Type: $mimeType");
header('Cache-Control: public, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Accept-Ranges: bytes');
header('Content-Length:' . (($end - $begin) + 1));
if (isset($_SERVER['HTTP_RANGE']))
{
header("Content-Range: bytes $begin-$end/$size");
}
header("Content-Disposition: inline; filename=$filename");
header("Content-Transfer-Encoding: binary");
header("Last-Modified: $time");
$cur = $begin;
fseek($fm, $begin, 0);
while(!feof($fm) && $cur <= $end && (connection_status() == 0))
{
print fread($fm, min(1024 * 16, ($end - $cur) + 1));
$cur += 1024 * 16;
}
}
It is working for smaller files. But in case of large files it isn't working properly. I tried with a 100MB file. The PDF is partially loaded that too with a black background. I don't know what's wrong in the code. I suspect I had to modify the headers, but I don't know what to add/replace. I have tried many alternatives given in many sites, but none of them worked.
Thank you for any help

Can't stream video file properly

I want to stream a video file of any length. But I struggle with creating my php script for this purpose.
I created one but when i seek the video it just breaks and the video goes back from beginning. Sometimes i get net::ERR_CONTENT_LENGTH_MISMATCH error. And cant figure out how to get things done. There is my code.
<?php
$filename = "song.mp4";
$file = fopen($filename, 'rb');
$filesize = filesize($filename);
$buffer = 5 * 1024;
header("Content-Type: video/mp4");
header("Cache-Control: no-cache");
header("Accept-Ranges: bytes");
if(isset($_SERVER['HTTP_RANGE'])){
$matches = array();
preg_match("/(\d+)/i", $_SERVER['HTTP_RANGE'], $matches);
$start = (int)$matches[1];
if(isset($matches[2])){
$end = $matches[2];
}else{
$end = $filesize - 1;
}
$length = $filesize - $start + 1;
fseek($file, $start);
header("Content-Length: " . $length);
header("Content-Range: bytes $start-$end/$filesize");
}else{
header("Content-Length: " . $filesize);
}
while(!feof($file)){
$data = fread($file, $buffer);
echo $data;
flush();
}
fclose($file);
fclose($log);
exit;
?>
I expect to get the full video streamed without any problems when i seek through.

android webview file download/php provides

Provides file downloads with PHP.
It works fine on the web, but it does not work properly in the app.
What is the reason why the header of the file is normally displayed but the file is not downloaded?
android webview download
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setMimeType(mimetype);
request.addRequestHeader("User-Agent", userAgent);
request.setDescription("Downloading file");
request.setTitle(URLUtil.guessFileName(url,contentDisposition,mimetype));
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(url,contentDisposition,mimetype));
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
headers
header('Content-Type: ' . $this->mimetype);
header('Content-Disposition: attachment; filename="' . $this->dl_filename . '"');
header("Content-Transfer-Encoding: binary");
header('Accept-Ranges: bytes');
/* The three lines below basically make the
download non-cacheable */
header("Cache-control: private");
header('Pragma: private');
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
// multipart-download and download resuming support
if(isset($_SERVER['HTTP_RANGE']) && !$this->force_single){
list($a, $range) = explode("=", $_SERVER['HTTP_RANGE'], 2);
list($range) = explode(",", $range, 2);
list($range, $range_end) = explode("-", $range);
$range = intval($range);
if(!$range_end){
$range_end = $size - 1;
}else{
$range_end = intval($range_end);
}
$new_length = $range_end - $range + 1;
header('HTTP/1.1 206 Partial Content');
header('Content-Length: ' . $new_length);
header('Content-Range: bytes ' . $range . '-' . $range_end . '/' . $size);
//set the offset range
$this->mt_range = $range;
}else{
$new_length = $size;
header("Content-Length: " . $size);
}
download file
if($file = fopen($filename, 'r')){
if(isset($_SERVER['HTTP_RANGE']) && !$this->force_single){
fseek($file, $this->mt_range);
}
//write the data out to the browser
while(!feof($file) && !connection_aborted() && $bytes_send < $block_size){
$buffer = fread($file, $chunksize);
echo $buffer;
flush();
$bytes_send += strlen($buffer);
}
fclose($file);
}

Audio is not playing for AWS s3 bucket video played through PHP Streaming file

I have uploaded video on AWS s3 bucket and all the content of s3 bucket is private, now i am creating cloudfront signed url and playing a video as PHP Stream.
Below is the code,
header('Content-Type: application/octetstream');
header('Content-Type: application/octet-stream');
header('Content-Type: ' . $audio_content);
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename="' . $file_name . '"');
header('Content-Length: ' . $size);
header('Cache-Control: public, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Accept-Ranges: bytes');
header('Content-Transfer-Encoding: binary');
// In case the file was streaming browser may request file in between
// for seeking file in middle, where audio file was not downloaded completely
// In such cases we send the proper content-range in bytes
if (isset($_SERVER['HTTP_RANGE']) && false)
{
if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches))
{
$begin = (int) $matches[1];
if ( ! empty($matches[2]))
{
$ending = (int) $matches[2];
}
}
header('HTTP/1.1 206 Partial Content');
}
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $begin;
$c_end = $ending;
list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (strpos($range, ',') !== false) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$ending/$size");
exit;
}
if ($range == '-') {
$c_start = $size - substr($range, 1);
}else{
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
}
$c_end = ($c_end > $ending) ? $ending : $c_end;
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $begin-$end/$size");
exit;
}
$begin = $c_start;
$ending = $c_end;
$length = $ending - $begin + 1;
fseek($file_pointer, $begin);
header('HTTP/1.1 206 Partial Content');
}
$intLength = $ending - ($begin + 1);
header('Content-Range: bytes ' . $begin . '-' . $ending . '/' . $size);
header('Content-Length: ' . $intLength);
// Stream the file
$file_pointer = fopen('php://output', 'w');
// If we had downloaded file incase where we did not get content length
// send that file directly instead of fresh new cURL request
$curl = curl_init($signedUrlCustomPolicy);
curl_setopt($curl, CURLOPT_FILE, $file_pointer);
curl_setopt($curl, CURLOPT_RANGE, $begin . '-' . $ending);
curl_exec($curl);
//fwrite($file_pointer, $resultData);
curl_close($curl);
Problem here is Audio is not playing in Mac Safari and iPhone Safari.

Using PHP smartReadFile to stream audio - not showing duration or seeking on iOS Safari

I'm using this smartReadFile PHP method I found online to stream audio to jQuery jPlayer. While this works great when playing from a browser, I can seek the track and the duration is displayed, but when I try on iOS Safari, the duration is unknown and I cannot seek, but it does play. Any ideas anyone? Much appreciated.
function _smartReadFile($location, $filename, $mimeType = 'application/octet-stream')
{
if (!file_exists($location))
{
header ("HTTP/1.1 404 Not Found");
return;
}
$size = filesize($location);
$time = date('r', filemtime($location));
$fm = #fopen($location, 'rb');
if (!$fm)
{
header ("HTTP/1.1 505 Internal server error");
return;
}
$begin = 0;
$end = $size - 1;
if (isset($_SERVER['HTTP_RANGE']))
{
if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches))
{
$begin = intval($matches[1]);
if (!empty($matches[2]))
{
$end = intval($matches[2]);
}
}
}
if (isset($_SERVER['HTTP_RANGE']))
{
header('HTTP/1.1 206 Partial Content');
}
else
{
header('HTTP/1.1 200 OK');
}
header("Content-Type: $mimeType");
header('Cache-Control: public, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Accept-Ranges: bytes');
header('Content-Length:' . (($end - $begin) + 1));
if (isset($_SERVER['HTTP_RANGE']))
{
header("Content-Range: bytes $begin-$end/$size");
}
header("Content-Disposition: inline; filename=$filename");
header("Content-Transfer-Encoding: binary");
header("Last-Modified: $time");
$cur = $begin;
fseek($fm, $begin, 0);
while(!feof($fm) && $cur <= $end && (connection_status() == 0))
{
print fread($fm, min(1024 * 16, ($end - $cur) + 1));
$cur += 1024 * 16;
}
}
Wasim,
Are you having this issue with all file types?
Perhaps setting the mimetype closer to the file type would help.
Example:
$file = '/music/song.mp3';
// Add the mimeTypes for mp3
_smartReadFile($file, basename($file), 'audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3');
Hope it helps out.

Categories