Force file download with php using header() - php

I want the user to be able to download some files I have on my server, but when I try to use any of the many examples of this around the internet nothing seems to work for me. I've tried code like this:
<?php
$size = filesize("Image.png");
header('Content-Description: File Transfer');
header('Content-Type: image/png');
header('Content-Disposition: attachment; filename="Image.png"');
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: ' . $size);
readfile("Image.png");
I've even tried to use the most basic example I could find, like this:
<?php
header('Content-type: image/png');
header('Content-Disposition: attachment; filename="Image.png"');
readfile('Image.png');
When I've tested this I have removed all the other code I have and used an empty file with just this code to remove any faults created by external sources.
When I look in the console the file gets sent with the right headers i.e
'Content-Disposition: attachment; filename="Image.png"'
But the save dialog isn't displayed.
I've also tried with inline instead of attachment in the content disposition header but that didn't make a difference either, I've tested this in Firefox 8.0.1 Chrome 15.0.874.121 and Safari 5.1.1.

I’m pretty sure you don’t add the mime type as a JPEG on file downloads:
header('Content-Type: image/png');
These headers have never failed me:
$quoted = sprintf('"%s"', addcslashes(basename($file), '"\\'));
$size = filesize($file);
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $quoted);
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $size);

This worked for me like a charm for downloading PNG and PDF.
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$file_name.'"');
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_url)); //Absolute URL
ob_clean();
flush();
readfile($file_url); //Absolute URL
exit();

Based on Farhan Sahibole's answer:
header('Content-Disposition: attachment; filename=Image.png');
header('Content-Type: application/octet-stream'); // Downloading on Android might fail without this
ob_clean();
readfile($file);
This is all I needed for this to work. I stripped off anything that isn't required for this to work.
Key is to use ob_clean();

The problem was that I used ajax to post the message to the server, when I used a direct link to download the file everything worked fine.
I used this other Stackoverflow Q&A material instead, it worked great for me:
Ajax File Download using Jquery, PHP

its work for me
$attachment_location = "filePath";
if (file_exists($attachment_location)) {
header($_SERVER["SERVER_PROTOCOL"] . " 200 OK");
header("Cache-Control: public"); // needed for internet explorer
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: Binary");
header("Content-Length:".filesize($attachment_location));
header("Content-Disposition: attachment; filename=filePath");
readfile($attachment_location);
die();
} else {
die("Error: File not found.");
}

the htaccess solution
<filesmatch "\.(?i:doc|odf|pdf|cer|txt)$">
Header set Content-Disposition attachment
</FilesMatch>
you can read this page:
https://www.techmesto.com/force-files-to-download-using-htaccess/

Here is a snippet from me in testing... obviously passing via get to the script may not be the best... should post or just send an id and grab guid from db... anyhow.. this worked. I take the URL and convert it to a path.
// Initialize a file URL to the variable
$file = $_GET['url'];
$file = str_replace(Polepluginforrvms_Plugin::$install_url, $DOC_ROOT.'/pole-permitter/', $file );
$quoted = sprintf('"%s"', addcslashes(basename($file), '"\\'));
$size = filesize($file);
header( "Content-type: application/octet-stream" );
header( "Content-Disposition: attachment; filename={$quoted}" );
header( "Content-length: " . $size );
header( "Pragma: no-cache" );
header( "Expires: 0" );
readfile( "{$file}" );

Related

php file_put_contents save in local client real path [duplicate]

I want the user to be able to download some files I have on my server, but when I try to use any of the many examples of this around the internet nothing seems to work for me. I've tried code like this:
<?php
$size = filesize("Image.png");
header('Content-Description: File Transfer');
header('Content-Type: image/png');
header('Content-Disposition: attachment; filename="Image.png"');
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: ' . $size);
readfile("Image.png");
I've even tried to use the most basic example I could find, like this:
<?php
header('Content-type: image/png');
header('Content-Disposition: attachment; filename="Image.png"');
readfile('Image.png');
When I've tested this I have removed all the other code I have and used an empty file with just this code to remove any faults created by external sources.
When I look in the console the file gets sent with the right headers i.e
'Content-Disposition: attachment; filename="Image.png"'
But the save dialog isn't displayed.
I've also tried with inline instead of attachment in the content disposition header but that didn't make a difference either, I've tested this in Firefox 8.0.1 Chrome 15.0.874.121 and Safari 5.1.1.
I’m pretty sure you don’t add the mime type as a JPEG on file downloads:
header('Content-Type: image/png');
These headers have never failed me:
$quoted = sprintf('"%s"', addcslashes(basename($file), '"\\'));
$size = filesize($file);
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $quoted);
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $size);
This worked for me like a charm for downloading PNG and PDF.
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$file_name.'"');
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_url)); //Absolute URL
ob_clean();
flush();
readfile($file_url); //Absolute URL
exit();
Based on Farhan Sahibole's answer:
header('Content-Disposition: attachment; filename=Image.png');
header('Content-Type: application/octet-stream'); // Downloading on Android might fail without this
ob_clean();
readfile($file);
This is all I needed for this to work. I stripped off anything that isn't required for this to work.
Key is to use ob_clean();
The problem was that I used ajax to post the message to the server, when I used a direct link to download the file everything worked fine.
I used this other Stackoverflow Q&A material instead, it worked great for me:
Ajax File Download using Jquery, PHP
its work for me
$attachment_location = "filePath";
if (file_exists($attachment_location)) {
header($_SERVER["SERVER_PROTOCOL"] . " 200 OK");
header("Cache-Control: public"); // needed for internet explorer
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: Binary");
header("Content-Length:".filesize($attachment_location));
header("Content-Disposition: attachment; filename=filePath");
readfile($attachment_location);
die();
} else {
die("Error: File not found.");
}
the htaccess solution
<filesmatch "\.(?i:doc|odf|pdf|cer|txt)$">
Header set Content-Disposition attachment
</FilesMatch>
you can read this page:
https://www.techmesto.com/force-files-to-download-using-htaccess/
Here is a snippet from me in testing... obviously passing via get to the script may not be the best... should post or just send an id and grab guid from db... anyhow.. this worked. I take the URL and convert it to a path.
// Initialize a file URL to the variable
$file = $_GET['url'];
$file = str_replace(Polepluginforrvms_Plugin::$install_url, $DOC_ROOT.'/pole-permitter/', $file );
$quoted = sprintf('"%s"', addcslashes(basename($file), '"\\'));
$size = filesize($file);
header( "Content-type: application/octet-stream" );
header( "Content-Disposition: attachment; filename={$quoted}" );
header( "Content-length: " . $size );
header( "Pragma: no-cache" );
header( "Expires: 0" );
readfile( "{$file}" );

What is the correct syntax for defining filename with variables?

Regarding downloading files and defining the headers, I am having trouble assigning a dynamic filename to my files. When using the code below :
header("Content-Disposition: attachment; filename=test.csv");
A test.csv file is generated for download. However if I use this:
header('Content-Disposition: attachment; filename=' . $filename . '.csv');
It generates a .php file instead. Using this method also doesn't pass the Content-Disposition or filename to the header.
Full code:
session_start();
$file =$_SESSION['csvf'];
$filename = $file."_".date("Y-m-d_H-i",time());
header ( "Content-type: text/csv" );
header("Content-Disposition: attachment; filename=test.csv");
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
print($file);
exit ();
What is the correct syntax?
EDIT
Working Code after suggestions
session_start ();
$file = $_SESSION ['csvf'];
$filename =date ( "Y-m-d_H-i", time () );
header ( "Content-type: text/csv" );
header ( "Content-Disposition: attachment; filename=".$filename );
header ( 'Expires: 0' );
header ( 'Cache-Control: must-revalidate' );
header ( 'Pragma: public' );
header ( 'Content-Length: ' . filesize ( $file ) );
print ($file) ;
exit ();
I don't see the path to example.csv specified on your code, you need to give the full path to $file, i.e.:
$mySession = $_SESSION['csvf'];
//since $_SESSION['csvf'] contains the actual data you cannot use it for filename
$filename = date("Y-m-d_H-i",time()).".csv";
//write $mySession contents to file. Make sure this folder is writable
file_put_contents("/home/site/csvfolder/$filename", $mySession);
$file = "/home/site/csvfolder/$filename";
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-type: text/csv');
header('Content-Disposition: attachment; filename='.$filename);
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
Please Use Like as follows,I am using this for me.
header("Content-Type: application/vnd.ms-excel; charset=utf-8");
header("Content-Disposition: attachment; filename=".$fileName);
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
In place of application/vnd.ms-excel use your file format.It is for Microsoft Excel.
Try with this:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=test.csv');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
You can see more about download files with PHP here:
http://php.net/manual/en/function.readfile.php
Try With Below code , it's work for me
$file =$_SESSION['csvf'];
$filename = $file."_".date("Y-m-d_H-i",time()).".csv";
header ( "Content-type: text/csv" );
header("Content-Disposition: attachment; filename=".$filename);
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
print($file);
exit ();
Below is a snippet for a .zip file with some descriptions on some information that header requires, perhaps a good practice is to get the information and some validations before writing headers.
Another shorter example is also included,
// defines filename, type, path, size and a reference to file (handler)
// to set as values for file header
$filename = $survey_id . '.zip';
// define path to the file to be get file size on the next line
$filepath = [path to file]. '/' . $filename;
// used by 'Content-length'
$filesize = filesize($filepath);
// using fopen to get a file handler, 'r' for read, 'b' for binary (zip file)
$file_pointer = fopen($filepath, 'rb');
// check if file exists
if(is_file($filepath))
{
// valid file?
if($filesize && $file_pointer)
{
// some required header information to describe file, see [docs][1]
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: zip file");
header("Content-Type: application/zip");
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=" . $filename);
header("Content-Transfer-Encoding: binary");
header("Content-length: " . $filesize);
fpassthru($file_pointer);
// close
fclose($file_pointer);
}
}
Also, checkout readfile(), a shorter snippet below
<?php
$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('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
?>
Hope this helps!
Just escape your php properly like so:
header('Content-Disposition: attachment; filename=' . time() . '.export.csv');
This example will put a UNIX timestamp prepended to the file name. Of course you could get crazy with programmatically using variables or inbuilt php functions, but this is just the example.
Here is more of an example. This file name will be produced when running this php code.
2019-05-18-contacts-main-export-by-Garrick.csv
header('Content-Disposition: attachment; filename=' . date("Y-m-d") . '-contacts-main-export-by-' . $uidName . '.csv');

Download xlsx file using php

I need make xlsx file download from my site (but not from directly open file url like this: http://site.com/file.xlsx )
So, this is php code
$file = "somefile.xlsx";
header('Content-Description: File Transfer');
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
file is downloaded, his extension is .xlsx, but when trying open this file in ms excel, file not opened and I got error : excel cannot open the file.xlsx because the file format or file extension is not valid
Tell please, why this happened? where I am wrong?
After many years, I got same problem, and after searching, I got here again ))
This is solution, that worked for me:
$file = "somefile.xlsx";
// define file $mime type here
ob_end_clean(); // this is solution
header('Content-Description: File Transfer');
header('Content-Type: ' . $mime);
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" . basename($file) . "\"");
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
readfile($file);
You must be using this code in middle of some other file.
The problem with headers is they need to be set first on a page. They will not work if you have even 1 single space echoing before them. So you need to ob_clean() [clean the buffer] before you are setting headers
Try
ob_clean();
flush();
$file = "somefile.xlsx";
header('Content-Description: File Transfer');
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
Remove:
ob_clean();
flush();
Add at the end of code:
exit();
The issue is that flush() will also throw in your *.xlsx file content some garbage it has in it and that will corupt your file, even if you use ob_clean();
For a better understanding go to php.net and read the difference between flush(), ob_flush() and find that you didn't even need them in the first case. Therefore you won't need the ob_clean() too.
This works for me:
header('Content-Description: File Transfer');
header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
header("Content-Disposition: attachment; filename=\"".basename($fileLocation)."\"");
header("Content-Transfer-Encoding: binary");
header("Expires: 0");
header("Pragma: public");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header('Content-Length: ' . filesize($fileLocation)); //Remove
ob_clean();
flush();
readfile($fileLocation);

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 :)

How can the image and pdf files be made downloadable

Generally, browsers show the image and pdf files without embedding them in html. I need some codes to make these files not to show in the browsers but make them downloadable like doc files.
Please help me out with this.
This isn't up to you, it is up to the browser.
However, you can make a suggestion as to what to do with it by setting the content-disposition header...
header("Content-Disposition: attachment; filename=\"yourfilename.pdf\"");
Read the doc on the header() function: http://php.net/manual/en/function.header.php
In case this isn't clear... this is for whatever resource is returned by the PHP document. You may need a readfile() in there to do what you are trying to do.
Set a couple of headers:
$filename = ...;
$mime_type = ...; //whichever applicable MIME type
header('Pragma: public');
header('Expires: 0');
header("Content-Disposition: attachment; filename=\"$filename\"");
header("Content-Type: $mime_type");
header('Content-Length: ' . filesize($filename));
readfile($filename);
<?php
header('Content-disposition: attachment; filename=myfile.pdf');
header('Content-type: application/pdf');
readfile('myfile.pdf');
?>
You want to send a content type header to make the browser download the file.
If you aren't' generating it dynamically, you will need to read it off the disk first.
$fullPath = "/path/to/file/on/server.pdf";
$fsize = filesize($fullPath);
$content = file_get_contents($fullPath);
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header("Content-Type: application/pdf");
header("Content-Disposition: attachment; filename=\"".basename($fullPath)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$fsize);
echo $content;
try this one :
$file = 'youfile.fileextention';
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;

Categories