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);
}
Related
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
So I get this error when some of the video plays. When Chrome completely downloads the video, it stops playing with this error. Also the status of the request changes from 206 to (failed) and then Chrome sends some other requests with Range:bytes=2990775- and the server response is:
Accept-Ranges:bytes
Cache-Control:private
Connection:keep-alive
Content-Disposition:attachment; filename="About The Author.mp4"
Content-Length:0
Content-Range:bytes 2990775-2990775/2990776
Content-Transfer-Encoding:binary
Content-Type:video/mp4
Date:Tue, 14 Feb 2017 13:46:24 GMT
Last-Modified:Wed, 08 Feb 2017 05:43:27 GMT
Pragma:public
Server:Apache/2
Vary:User-Agent
X-Powered-By:PHP/5.4.45
I have another website on the same server and it works fine there.
Here is my PHP code:
$filesize = filesize($resource->path);
$matches = explode("-", substr($_SERVER['HTTP_RANGE'],6));
if (empty($matches[1]))
{
$matches[1] = $filesize - 1;
}
$offset = intval($matches[0]);
$length = intval($matches[1]) - $offset;
$file = fopen($resource->path, 'r');
fseek($file, $offset);
$data = fread($file, $length);
fclose($file);
header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes ' . $offset . '-' . ($offset + $length) . '/' . $filesize);
header('Pragma: public');
header('Last-Modified: '.gmdate ('D, d M Y H:i:s', filemtime ($resource->path)).' GMT');
header('Cache-Control: private',false);
header('Content-Type: ' . $mime);
header('Content-Length: ' . ($length + 1));
header('Content-Disposition: attachment; filename="' . $resource->filename . '"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
print($data);
Sorry for my bad english.
I've found the problem.
I changed $data = fread($file, $length); to $data = fread($file, $length + 1);.
I don't know why the requested length should be plus one but it solve'd the problem.
I am using the below code snippet to read mp4 files using PHP and play it in the video tag. This code works when I call the video as file(test.mp4) in the localhost allowing to move the seeker back and forth. But when I use Video Source as URL(http://techslides.com/demos/sample-videos/small.mp4) the video is playing but cannot move the seeker back and front.
$filename = 'http://techslides.com/demos/sample-videos/small.mp4';
$mimeType = 'video/mp4';
$ch = curl_init($filename);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
curl_setopt($ch, CURLOPT_NOBODY, TRUE);
$data = curl_exec($ch);
$size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
curl_close($ch);
// echo $size = filesize($filename);die;
$time = date('r', filemtime($filename));
$fm = #fopen($filename, '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('GET HTTP/1.1 206 Partial Content');
}
else
{
header('HTTP/1.1 200 OK');
}
header("Content-Type: video/mp4");
header('Accept-Ranges: bytes');
header("Content-Disposition: inline;");
header("Content-Range: bytes $begin-$end/$size");
header("Content-Transfer-Encoding: binary\n");
header('Cache-Control: public, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Content-Length:' . (($end - $begin) + 1));
if (isset($_SERVER['HTTP_RANGE']))
{
header("Content-Range: bytes $begin-$end/$size");
}
header('Connection: close');
$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;
usleep(1000);
}
i have tried do that before ,
it's not working because fseek() do not support http,
the file must be 'seekable' that mean you must get file from path
check this answer https://stackoverflow.com/a/21722576/5380308
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.
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.