Displaying large PDF files using PHP headers - php

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

Related

Not getting proper range value when using partial content header

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.

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);
}

Read MP4 files from a URL using PHP

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

Download file_get_contents response

I have the following jquery:
$(".download").click(function(){
$.post('get_bot.php', "url_code="+url_code, function (response) {
alert(response);
});
});
url_code is a variable that has the url for a json structure, here is a live example of the return:
https://services.sapo.pt/Codebits/botmake/01,02,03,04,05,06,07,08,I%20Rule!
Those numbers are parameters to generate different images.
On my get_bot.php page I'm doing:
$urlc=$_POST['url_code'];
$bot = file_get_contents($urlc);
header("content-type: image/png");
echo $bot;
I'm looking into ways on how to get a response as a .png file download, so when the user clicks .download there is a download window prompt with the .png file.
Passing in a correct url and echoing the file_get_content results seems to work fine (although if I try to right click and save the image, it actually saves the php file...)
Any help with this would be great, I'm not very experienced with json structures, so far I've only dealt with array structures, never an image output.
I'm aware I'm probably way off here on getting an actual result, but any pointers would be appreciated.
RFC2616 describes what you need to do. Basically, you need to add
Content-Disposition: attachment; filename="fname.ext"
To the header if I'm not mistaken.
EDIT
Here is a sample script. I've confirmed that this works on two of my servers with different setups.
<?php
header("content-type: image/jpg");
header("Content-Disposition: attachment; filename='pic.jpg'");
readfile('http://lorempixel.com/400/200/');
?>
Just use this function on your get_bot.php to start a download of a file instead of showing it in the browser (should work cross-browser):
function download($file, $path)
{
$size = filesize($path.$file);
#ob_end_clean();
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
header('Content-Type: application/force-download');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header("Content-Transfer-Encoding: binary");
header('Accept-Ranges: bytes');
header("Cache-control: no-cache, pre-check=0, post-check=0");
header("Cache-control: private");
header('Pragma: private');
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
if(isset($_SERVER['HTTP_RANGE']))
{
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");
} else {
$new_length=$size;
header("Content-Length: ".$size);
}
$chunksize = 1*(1024*1024);
$bytes_send = 0;
if ($file = fopen($path.$file, 'rb'))
{
if(isset($_SERVER['HTTP_RANGE']))
fseek($file, $range);
while
(!feof($file) &&
(!connection_aborted()) &&
($bytes_send<$new_length) )
{
$buffer = fread($file, $chunksize);
print($buffer);
flush();
$bytes_send += strlen($buffer);
}
fclose($file);
} else die('Error - can not open file.');
die();
}

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