Download of large files does not work - php

Hey i have following code to download a large file but the download does stop everytime without finish the download
function download($file)
{
include('logger.php5');
$log = new Logging();
$log->lfile('download.log');
ini_set('max_execution_time', 86400);
//header('Location: '.$file);
$filesize = filesize($file);
$filename = pathinfo($file, PATHINFO_BASENAME);
$filext = pathinfo($file, PATHINFO_EXTENSION);
$mime = include('mime.php5');
$log->lwrite(ini_get('max_execution_time'));
$log->lwrite(sprintf('%s %s %s %s', $filename, $filext, $mime[$filext], human_filesize($filesize)));
$log->lclose();
#ob_end_clean();
session_write_close();
header("Content-Description: File Transfer");
header("Content-Type: ".$mime[$filext]);
header("Content-Disposition: ".
(!strpos($HTTP_USER_AGENT,"MSIE 5.5")?"attachment; ":"").
"filename=".$filename);
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$filesize);
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header('Pragma: public');
header('Expires: 0');
$done = readfile_chunked($file);
}
function readfile_chunked($filename,$retbytes=true) {
$chunksize = 1*(1024*1024); // how many bytes per chunk
$buffer = '';
$cnt =0;
// $handle = fopen($filename, 'rb');
$handle = fopen($filename, 'rb');
if ($handle === false) {
return false;
}
while (!feof($handle)) {
$buffer = fread($handle, $chunksize);
echo $buffer;
ob_flush();
flush();
if ($retbytes) {
$cnt += strlen($buffer);
}
}
$status = fclose($handle);
if ($retbytes && $status) {
return $cnt; // return num. bytes delivered like readfile() does.
}
return $status;
}
Each time i call the script the download start up but stops after 400MB, the file itself is 778MB big.
Someone can see a problem with the code?
UPDATE
after try to log the return value of readfile_chunkedit feels like the script gets stoped not the download itself. Because i cant get a log entry after the readfile_chunked call.

It could be a problem with the filesize function in PHP. There are known bugs for big file size reading and as you're sending it with the file as an header I would suggest you to try the script without using this line:
header("Content-Length: ".$filesize);
Oh and maybe you can take a look at this line:
header("Content-Transfer-Encoding: binary");
I think the encoding should be checked for each file. Like this:
$finfo = finfo_open(FILEINFO_MIME);
//check to see if the mime-type starts with 'text'
return substr(finfo_file($finfo, $filename), 0, 4) == 'text';
If it's a textfile you should use ASCII ofcourse. Has nothing to do with the question but I think it's an useful addition to your script :)

Related

Unable to view the download PDF file in browser in php

I have a download media function in which all type of media files gets downloaded. Below is the code
public function downloadMedia($file, $filename_direct = '', $extern = '', $exitHere = 1)
{
jimport('joomla.filesystem.file');
clearstatcache();
if (!$extern)
{
if (!JFile::exists($file))
{
return 2;
}
else
{
$len = filesize($file);
}
}
else
{
/* Return the size of a remote url or a local file specified by $url.
$thereturn specifies the unit returned (either bytes "", MiB "mb" or KiB
"kb"). */
$len = filesize($file);
}
$filename = basename($file);
$file_extension = strtolower(substr(strrchr($filename, "."), 1));
$ctype = $this->getMime($file_extension);
ob_end_clean();
// Needed for MS IE - otherwise content disposition is not used?
if (ini_get('zlib.output_compression'))
{
ini_set('zlib.output_compression', 'Off');
}
header("Cache-Control: public, must-revalidate");
header('Cache-Control: pre-check=0, post-check=0, max-age=0');
header("Expires: 0");
header("Content-Description: File Transfer");
header("Content-Type: " . $ctype);
header("Content-Length: " . (string) $len);
header('Content-Disposition: attachment; filename="' . $filename . '"');
// set_time_limit doesn't work in safe mode
if (!ini_get('safe_mode'))
{
#set_time_limit(0);
}
/*#readfile($file);
if ($exitHere == 1)
{
exit;
}*/
$fp = fopen($file, "r") ;
ob_clean();
flush();
while (!#feof($fp)) {
$buff = #fread($fp, $len);
print $buff;
}
exit;
}
Now the issue is, whenever I download the PDF file & clicked on downloaded file it shows an error in a browser like 'Failed to load PDF document.'
The downloaded PDF file is opened correctly only when if I open the file in adobe instead of opening it in browser.

readfile returns a corrupt zip download

I have the following code in my Phalcon application.
public function downloadAction($key = NULL) {
if ($key == NULL) {
return $this->respondDownloadFailed();
}
$url = Urls::findFirst("token = '".$key."'");
if ($url) {
$path = $url->getUrl();
$ext = pathinfo($path, PATHINFO_EXTENSION);
header("Content-type: application/".$ext);
header("Content-Disposition: attachment; filename=".$key.".".$ext);
header("Content-length: " . filesize($path));
header("Pragma: no-cache");
header("Expires: 0");
ob_clean();
flush();
readfile($path);
unlink($path);
die;
}
return $this->respondDownloadFailed();
}
Now, when the .zip is created on the server I can open and unzip it. However, when I download it through the code above, I get a zip file which then unarchives to a .cpgz file. When unarchiving that one, I get a .zip again. Any ideas as to what is going wrong?

Rename mp3 file and Download file in PHP

I have an issue while downloading an mp3 file in PHP. I need to download the file, also rename it. Below is the download.php file which contains the following code:
$file = $_GET['file'];
$flname = explode("/",$file);
$num = sizeof($flname);
$filenme = $flname[$num-1];
$name_of_file = $filenme;
header('Content-Description: File Transfer');
header('Content-type: application/mp3');
header('Content-Disposition: attachment; filename="'.basename($file).'"');
header('Content-Length: '.filesize($name_of_file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
readfile_chunked($file);
function readfile_chunked($file)
{
$chunksize = 1*(1024*1024); // how many bytes per chunk
$buffer = '';
$handle = fopen($filename, 'rb');
if ($handle === false)
{
return false;
}
while (!feof($handle))
{
$buffer = fread($handle, $chunksize);
print $buffer;
}
return fclose($handle);
}
I am getting the file path in $file:
$file = $_GET['file'];
where $file becomes:
$file = "localhost/project/mp3 file path";
Then I am exploding it to get the mp3 file name only (thus removing the path).
I don't know what the problem is, but it's always showing some 490 bytes in the download dialogue of Firefox even if file is of 1-2MB. Can someone explain what I'm doing wrong?
Thank you in advance.
Open the downloaded file in a text editor. It probably contains php errors that will tell you what exactly is going on. It might be an issue with the path or permissions of the file you are trying to download.

PHP-Downloadscript - download limit doesn´t work

when i use this phpcode to download a file with a downloadspeed of 300Kb/s i use this:
function readfile_chunked($dl_link, $filesize_file) {
$chunksize = 300*1024; #Buffersize in Byte
$data = '';
$handle = fopen($dl_link, 'rb');
while (!feof($handle)) {
$data = fread($handle, $chunksize);
sleep(1);
print $data;
#ob_flush();
#flush();
}
fclose($handle);
}
But it doesn´t work! :-(
When i start the Download, the speed is under one KB/s and it breaks and then resume, and so on.
When i take off this "sleep(1)" in the code above, then the download starts and all is good, but it runs with fullspeed. -> logical!
Why is this?
That looks mostly okay, however try the following:
function readfile_chunked($path, $speed)
{
if (is_file($path) !== true)
{
exit('not a local file');
}
header('Pragma: public');
header('Cache-Control: public, no-cache');
header('Content-Type: application/octet-stream');
header('Content-Length: ' . filesize($path));
header('Content-Disposition: attachment; filename="' . basename($path) . '"');
header('Content-Transfer-Encoding: binary');
$handle = fopen($path, 'rb');
while (!feof($handle))
{
echo fread($handle, $speed * 1024); sleep(1);
while (ob_get_level() > 0)
{
ob_end_flush();
}
flush();
}
fclose($handle);
}
readfile_chunked('/path/to/your/file.ext', 300);
You may want to try adding #ob_flush_end() at first to disable output buffering, and remove #ob_flush() in the loop. The delay may be because of the output buffering.
You may also try replacing print with echo. You may gain some performance improvement.
Also try a smaller chunk and use usleep instead for a shorter delay time.

There's some html content in a file which is downloaded using PHP scripts on firefox

I use the following to download a file with PHP:
ob_start();
$browser = id_browser();
header('Content-Type: '.(($browser=='IE' || $browser=='OPERA')?
'application/octetstream':'application/octet-stream'));
header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize(realpath($fullpath)));
//header("Content-Encoding: none");
if($browser == 'IE')
{
header('Content-Disposition: attachment; filename="'.$file.'"');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
} else
{
header('Content-Disposition: attachment; filename="'.$file.'"');
header('Cache-Control: no-cache, must-revalidate');
header('Pragma: no-cache');
}
//#set_time_limit( 0 );
ReadFileChunked(utf8_decode($fullpath));
ob_end_flush();
The source code of ReadFileChunked is:
function ReadFileChunked($filename,$retbytes=true)
{
$chunksize = 1*(1024*1024);
$remainFileSize = filesize($filename);
if($remainFileSize < $chunksize)
$chunksize = $remainFileSize;
$buffer = '';
$cnt =0;
// $handle = fopen($filename, 'rb');
//echo $filename."<br>";
$handle = fopen($filename, 'rb');
if ($handle === false) {
//echo 1;
return false;
}
//echo 2;
while (!feof($handle))
{
//echo "current remain file size $remainFileSize<br>";
//echo "current chunksize $chunksize<br>";
$buffer = fread($handle, $chunksize);
echo $buffer;
sleep(1);
ob_flush();
flush();
if ($retbytes) {
$cnt += strlen($buffer);
}
$remainFileSize -= $chunksize;
if($remainFileSize == 0)
break;
if($remainFileSize < $chunksize)
{
$chunksize = $remainFileSize;
}
}
$status = fclose($handle);
if ($retbytes && $status) {
return $cnt; // return num. bytes delivered like readfile() does.
}
return $status;
}
The question is :
The file downloaded will contiain some html tags which are the content of the html code generated by the php.
The error will happened when downloading the txt file with the file size smaller than 4096 bytes.
Please help me to slove this problem , thank you very much!
Chu
Have you tried using fpassthru rather than your custom function.
There's no need to use the $chunksize stuff in there. fread() automatically stops reading once it reaches the end of the file, even if the $chunksize would normally tell it to read more. As well, you should probably put your ob_flush() and flush() calls BEFORE the sleep(1). That way the data you've just placed in the output buffer can get sent off to the webserver without having to wait the one second needlessly.
In fact, you could replace the whole function with the following:
function ReadFileChunk($filename, $retbytes = true) {
$fh = fopen($filename, 'rb');
if (!$fh) {
return(false);
}
while($buf = fread($fh, 4096)) {
echo $buf;
ob_flush();
flush();
sleep(1);
}
$status = fclose($fh);
return( $retbytes ? filesize($filename) : $status);
}
But why bother rolling your own when readfile() already exists? It will handle the whole business of opening the file, and sending it in normal-sized pieces that won't exceed memory_limit.

Categories