Force download PHP - not downloading the whole file - php

I have a problem with forcing download of some mp3/zip files.
The problem is that some users experiences that the whole file isn't downloaded, and i can't figure out why..
if(is_file($file_name))
{
/*
Do any processing you'd like here:
1. Increment a counter
2. Do something with the DB
3. Check user permissions
4. Anything you want!
*/
// required for IE
if(ini_get('zlib.output_compression')) { ini_set('zlib.output_compression', 'Off'); }
// get the file mime type using the file extension
switch(strtolower(substr(strrchr($file_name,'.'),1)))
{
case 'mp3': $mime = 'audio/mpeg'; break;
case 'zip': $mime = 'application/zip'; break;
default: $mime = 'application/force-download';
}
header('Pragma: public'); // required
header('Expires: 0'); // no cache
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Last-Modified: '.gmdate ('D, d M Y H:i:s', filemtime ($file_name)).' GMT');
header('Cache-Control: private',false);
header('Content-Type: '.$mime);
header('Content-Disposition: attachment; filename="'.basename($file_name).'"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($file_name)); // provide file size
header('Connection: close');
readfile($file_name); // push it out
exit();
}
here is my code..
Any ideas?

Thanks for all of your help,
but i found another solution to my problem, and used mod_xsendfile instead. It has done the job for me :)

Related

How to force download zip file in codeigniter

I am trying to create a simple digital store web application using codeigniter.
I would like to use the force download helper function so that the real url of the file will not be known by the user.
I tried following the documentation in the codeignter - it works but the file get corrupted.
Here is my code
//* Get the website name
$site = $this->Settings_model->getApllicationInfo();
$sitename = $site->set_site_name;
//* Prepare file for downloading
$filename = $sitename.'-'.$item_info->item_id.'-'.$item_info->item_name;
$locate = './static/files/zips/'.$file;
force_download($locate, $filename);
It downloads the file but it get broken please help me or give me any other suggestion I can use.
Use below function to download the file
function auto_download($path, $name) {
if(is_file($path)) {
if(ini_get('zlib.output_compression')) { ini_set('zlib.output_compression', 'Off'); }
$this->load->helper('file');
$mime = get_mime_by_extension($path);
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Last-Modified: '.gmdate ('D, d M Y H:i:s', filemtime ($path)).' GMT');
header('Cache-Control: private',false);
header('Content-Type: '.$mime);
header('Content-Disposition: attachment; filename="'.basename($name).'"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($path));
header('Connection: close');
readfile($path);
exit();
}
}
I hope you are using file extension on the filename you supply for the first argument to force_download(). Because Codeigniter uses MIME-type. I hope it will work for you

Save Mysql data in xls using php

I want to export data in xls format using PHP. But instead of download information, they are displayed in my web page.
//connection to database
//building of all information -> ($righe)
header("Content-type: application/vnd.ms-excel");
header("Content-disposition: esporta_utenti.xls");
print $righe;
exit();
$righe is my tuple
header('Pragma: public'); // required
header('Expires: 0'); // no cache
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Last-Modified: '.gmdate ('D, d M Y H:i:s', filemtime ($file_name)).' GMT');
header('Cache-Control: private',false);
header('Content-Type: '.$mime); // file mime type
header('Content-Disposition: attachment; filename="'.basename($file_name).'"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($file_name)); // provide file size
header('Connection: close');
readfile($file_name); // push it out
exit();
This code was originally Published here http://davidwalsh.name/php-force-download . And can be referred for a detailed explanation of the Code.

force file download code work on localhost but not working on actual server in php

I'm php programmer of beginner. I have write code to download file of any type.
When I click on download link it goes to download.php file. I work on local server but not working on server.
My code is:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream'); //application/force-download
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
//header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit();
Is my code wrong or does server need some settings?
this is code tested online its working fine. u can try this
$folder_name = $_GET['fol_name'];
$file_directory = "../img/files/$folder_name"; //Name of the directory where all the sub directories and files exists
$file = $_GET['file_name']; //Get the file from URL variable
$file_array = explode('/', $file); //Try to seperate the folders and filename from the path
$file_array_count = count($file_array); //Count the result
$filename = $file_array[$file_array_count-1]; //Trace the filename
$file_path = dirname(__FILE__).'/'.$file_directory.'/'.$file; //Set the file path w.r.t the download.php... It may be different for u
if(file_exists($file_path)) {
header("Content-disposition: attachment; filename={$filename}"); //Tell the filename to the browser
header('Content-type: application/octet-stream'); //Stream as a binary file! So it would force browser to download
readfile($file_path); //Read and stream the file
}
else {
echo "Sorry, the file does not exist!";
}
thank u !!
by using code written by me. this problem is solved.
if anybody have same issue. please try this code. it works for me very good.
$file_name ='../img/files'.DS.$_GET['file'];
if(is_file($file_name)) {
if(ini_get('zlib.output_compression')) {
ini_set('zlib.output_compression', 'ON');
}
switch(strtolower(substr(strrchr($file_name, '.'), 1))) {
case 'pdf': $mime = 'application/pdf'; break; // pdf files
case 'zip': $mime = 'application/zip'; break; // zip files
case 'jpeg': $mime = 'image/jpeg'; break;// images jpeg
case 'jpg': $mime = 'image/jpg'; break;
case 'mp3': $mime = 'audio/mpeg'; break; // audio mp3 formats
case 'doc': $mime = 'application/msword'; break; // ms word
case 'avi': $mime = 'video/x-msvideo'; break; // video avi format
case 'txt': $mime = 'text/plain'; break; // text files
case 'xls': $mime = 'application/vnd.ms-excel'; break; // ms excel
default: $mime = 'application/force-download';
}
header('Content-Type:application/force-download');
header('Pragma: public'); // required
header('Expires: 0'); // no cache
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Last-Modified: '.gmdate ('D, d M Y H:i:s', filemtime ($file_name)).' GMT');
header('Cache-Control: private',false);
header('Content-Type: '.$mime);
header('Content-Disposition: attachment; filename="'.basename($file_name).'"');
header('Content-Transfer-Encoding: binary');
//header('Content-Length: '.filesize($file_name)); // provide file size
header('Connection: close');
readfile($file_name);
exit();
}
thank u!!!
I recently got this problem and discovered that this was being caused by ob_clean();
and flush(); These are causing the program to download garbage.
I tried various combinations to flush the buffer and the only one which worked on the hosting server was
ob_end_clean();
print $object->body;
It might work with echo as well but i didn't try it
use this
public function loadfile($fl)
{
$mime = 'application/force-download';
header('Pragma: public'); // required
header('Expires: 0'); // no cache
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private',false);
header('Content-Type: '.$mime);
header('Content-Disposition: attachment; filename="'.basename($fl).'"');
header('Content-Transfer-Encoding: binary');
header('Connection: close');
readfile($fl); // push it out
exit();
}

Chrome has "Failed to load PDF document" error message on inline PDFs

I have a problem with reading pdf file in Chrome by using PHP.
The following code is how I do in PHP
$path = "actually file path";
header("Pragma: public");
header("Expires: 0");
header("Content-type: $content_type");
header('Cache-Control: private', FALSE);
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Disposition: inline; filename=\"$filename\"");
header('Content-Transfer-Encoding: binary');
header('Content-Length' . filesize($path));
ob_clean();
flush();
readfile($path);
In here, I set the Content-Disposition to inline. Because I want to display the pdf file if user browser have build-in pdf viewer plugin. As you may know, Chrome has build-in pdf viewer.
The problem is I have bunch of pdf files on the server. Only some of them can be viewed by Chrome. I can't figure out why others can not work the same way. I have checked the permission of each files. It looks like not the permission problem.
Is there anyone know what the problem is? Thank you.
I've been wrestling with this same issue. This is as close as I got to consistent results across browsers. I think that the reason you could be having problems is if some PDF's are too large for readfile() to handle correctly. Try this:
$file = "path_to_file";
$fp = fopen($file, "r") ;
header("Cache-Control: maxage=1");
header("Pragma: public");
header("Content-type: application/pdf");
header("Content-Disposition: inline; filename=".$myFileName."");
header("Content-Description: PHP Generated Data");
header("Content-Transfer-Encoding: binary");
header('Content-Length:' . filesize($file));
ob_clean();
flush();
while (!feof($fp)) {
$buff = fread($fp, 1024);
print $buff;
}
exit;
I had similar issue but I noticed the order matters. Seems that ; filename= must have quotes around it, Content-Disposition: attachment Try this:
$file = "/files/test.pdf";
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
$mime = finfo_file($finfo, $file);
header('Pragma: public');
header('Expires: 0');
header('Content-Type: $mime');
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename="'.basename($file).'"'));
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Length' . filesize($file));
ob_clean();
flush();
readfile($file);
i've fixed this way
$path = 'path to PDF file';
header("Content-Length: " . filesize ( $path ) );
header("Content-type: application/pdf");
header("Content-disposition: inline; filename=".basename($path));
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
ob_clean();
flush();
readfile($path);
Had the same problem, chrome didn't display the inline PDF, stuck at loading. The solution was to add header('Accept-Ranges: bytes').
My complete code:
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="'.$title.'"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($file));
header('Accept-Ranges: bytes');
header('Expires: 0');
header('Cache-Control: public, must-revalidate, max-age=0');
For me adding the following header fixed this annoying Chrome bug (?):
header('HTTP/1.1 200 OK');
After hours wasted this...i added comments to point out that #Kal has the only solution that worked. But somehow that's not enough...this is such an impossible and frustrating problem when Chrome does this:
Error Failed to load PDF document. Reload
Here is the diff that ended the torture.
- // Waste time with chrome:
- header("Content-type:application/pdf");
- header("Content-Disposition:attachment;filename=$file_basename");
- readfile($file);
exit();
---------------------------
+ // Deliver the file:
+ header('Pragma: public');
+ header('Expires: 0');
+ header('Content-Type: $mime');
+ header('Content-Description: File Transfer');
+ header('Content-Disposition: attachment; filename="'.basename($file).'"');
+ header('Content-Transfer-Encoding: binary');
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+ header('Content-Length'.filesize($file));
+ ob_clean();
+ flush();
+ readfile($file);
exit();
For about thirty minutes i fooled with various variations of this...but i could not pin it down to "Add HTTP 200", not to "add bytes", not to "quote your filename", not to "separate the file ending". None of those worked.
(Thank you again #Kal).
I was having this issue, struggled for almost 6 hours and finally got it working. My solution is similar to the above answers but the above answers are not completed. There are three steps to solve this issue.
Step 1.
Go to php.ini file and add this line.
output_buffering = False
Step 2.
This error comes if you are opening a large PDF file. So, to solve this, just before adding headers, make sure you put these two lines.
set_time_limit(0);
ini_set('memory_limit', '100M'); //the memory limit can be more or less depending on your file
Step 3.
Add below headers and the code to read the file, so the final code would like this.
set_time_limit(0);
ini_set('memory_limit', '100M');
$file = "path/to/file.pdf";
header('Content-Type: application/pdf');
header('Content-Disposition: inline;
filename="yourfilename.pdf"'); //not the path but just the name
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize($file));
header('Accept-Ranges: bytes');
header('Expires: 0');
header('Cache-Control: public, must-revalidate, max-age=0');
ob_clean();
flush();
readfile($file);
exit();
100% working solution. If you have any issues, let me know :)

PHP Force Download Causing 0 Byte Files

I'm trying to force download files from my web server using PHP.
I'm not a pro in PHP but I just can't seem to get around the problem of files downloading in 0 bytes in size.
CODE:
$filename = "FILENAME...";
header("Content-type: $type");
header("Content-Disposition: attachment;filename=$filename");
header("Content-Transfer-Encoding: binary");
header('Pragma: no-cache');
header('Expires: 0');
set_time_limit(0);
readfile($file);
Can anybody help?
Thanks.
You're not checking that the file exists. Try using this:
$file = 'monkey.gif';
if (file_exists($file))
{
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}else
{
echo "File does not exists";
}
And see what you get.
You should also note that this forces a download as an octet stream, a plain binary file. Some browsers will struggle to understand the exact type of the file. If, for example, you send a GIF with a header of Content-Type: application/octet-stream, then the browser may not treat it like a GIF image. You should add in specific checks to determine what the content type of the file is, and send an appropriate Content-Type header.
I use the following method in phunction and I haven't had any issues with it so far:
function Download($path, $speed = null)
{
if (is_file($path) === true)
{
$file = #fopen($path, 'rb');
$speed = (isset($speed) === true) ? round($speed * 1024) : 524288;
if (is_resource($file) === true)
{
set_time_limit(0);
ignore_user_abort(false);
while (ob_get_level() > 0)
{
ob_end_clean();
}
header('Expires: 0');
header('Pragma: public');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Type: application/octet-stream');
header('Content-Length: ' . sprintf('%u', filesize($path)));
header('Content-Disposition: attachment; filename="' . basename($path) . '"');
header('Content-Transfer-Encoding: binary');
while (feof($file) !== true)
{
echo fread($file, $speed);
while (ob_get_level() > 0)
{
ob_end_flush();
}
flush();
sleep(1);
}
fclose($file);
}
exit();
}
return false;
}
You can try it simply by doing:
Download('/path/to/file.ext');
You need to specify the Content-Length header:
header("Content-Length: " . filesize($filename));
Also, you shouldn't send a Content-Transfer-Encoding header. Both of the HTTP/1.0 and HTTP/1.1 specs state that "HTTP does not use the Content-Transfer-Encoding (CTE) field of RFC 1521".
This problem as same as my website project. This code I've used:
<?php
$file = $_SERVER["DOCUMENT_ROOT"].'/.../.../'.$_GET['file'];
if(!file)
{
// File doesn't exist, output error
die('file not found');
}
else
{
//$file_extension = strtolower(substr(strrchr($file,"."),1));
$file_extension = end(explode(".", $file));
switch( $fileExtension)
{
case "pdf": $ctype="application/pdf"; break;
case "exe": $ctype="application/octet-stream"; break;
case "zip": $ctype="application/zip"; break;
case "doc": $ctype="application/msword"; break;
case "xls": $ctype="application/vnd.ms-excel"; break;
case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
case "gif": $ctype="image/gif"; break;
case "png": $ctype="image/png"; break;
case "jpeg":
case "jpg": $ctype="image/jpg"; break;
default: $ctype="application/force-download";
}
nocache_headers();
// Set headers
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public"); // required for certain browsers
header("Content-Description: File Transfer");
header("Content-Type: $ctype");
header("Content-Disposition: attachment; filename=".$file.";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($file));
readfile($file);
}
?>
I think the problem is on the server setting like PHP setting or cache setting, but I don't have any idea to do this my opinion.
i am doing this to download a PDF ...
$filename = 'Application.pdf';
header("Content-Type: application/pdf");
header("Content-Disposition: attachment; filename=$filename");
echo $pdf;
i think you are missing the last row, where you actually send the file contents of whatever you have in $file.
Pablo
The file opened ok for me when I changed the directory to the file location.
$reportLocation = REPORTSLOCATION;
$curDir = getcwd();
chdir($reportLocation);
if (file_exists($filename)) {
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Length: ' . filesize($filename));
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate');
header('Pragma: public');
ob_clean();
flush();
readfile($filename);
}
chdir($curDir);
The trick is to check with file_exists to confirm the correct path.
The big confusion is that for PHP paths you don't need to start with '/' to say your website start path.
'/folder/file.ext' #bad, needs to know the real full path
in php / is the website main path already, you don't need to mention it. Just:
'folder/file.ext' #relative to the / website
This will work with file_exists, header filename, readfile, etc...
if script work work for small files but for huge files return 0 byte file. you must increate memory_limit via php.ini
also you can add the following line before your code
ini_set('memory_limit','-1');

Categories