Reputation: 58067
I am working on a website where the visitor should be able to download a pdf file. (There are three links to choose from but that is irrelevant) I wanted to know how to make it so that the visitor can simply click the link and not have to
right click > Save (target) As...
I am open to PHP and or Javascript solutions. Thanks.
EDIT: Can I use javascript to call the PHP and save the file via AJAX?
EDIT2: I used Nirmal's solution in the end, since it was the simplest to change for all three files. I didn't need to make 3 files for the three PDF's and I didn't need to hand code the switch. BalusC gets the check though since his/her code was up first and does the trick too.
Upvotes: 3
Views: 15401
Reputation: 1299
If you don't want to mess with server side code and if this is a low priority thing for you, you can use HTML5 download
attribute.
Example:
<a href="myfile.pdf" download>Download</a>
However this is not supported by all browser. As per w3schools, following browsers are supported:
Chrome (14+), Firefox(20+), Opera (15+).
You can also specify filename by giving value to download attr:
<a href="myfile.pdf" download="NewName.pdf">Download</a>
Upvotes: 2
Reputation: 1108567
All you basically need to do is to set the Content-Disposition
header to attachment
to get a 'Save As' dialogue. Here's a kickoff PHP example:
<?php
header('Content-Type: application/pdf');
header('Content-Disposition: attachment;filename="foo.pdf"');
readfile('/path/to/foo.pdf');
?>
You can't and don't want to do this with Javascript.
Important note: due to a poor feature, in MSIE the default filename in 'Save As' dialogue won't be derived from the content-disposition
header, it will instead be the last part of the pathinfo in the request URL. To workaround this, append the PDF filename to the link, e.g. http://example.com/pdf/foo.pdf
. You can even make use of it in PHP to read the in the pathinfo specified PDF file. Here's a basic example of pdf.php
:
<?php
$file_name = $_SERVER['PATH_INFO'];
$file = '/path/to/pdf/files' . $file_name;
if (file_exists($file)) {
header('Content-Type: application/pdf');
header('Content-Disposition: attachment;filename="' . basename($file_name) . '"');
header('Content-Length: ' . filesize($file));
readfile($file);
} else {
header('HTTP/1.1 404 Not Found');
}
?>
This however assumes that you've MultiViews
on so that /pdf/
will go through this PHP file, or at least a RewriteRule
from /pdf/
to /pdf.php/
.
The major advantage of this approach is that you don't need to change the code whenever you want to add a new PDF file or change the PDF file name.
You can even make it more generic by automatically determining and setting the correct content type:
<?php
$file_name = $_SERVER['PATH_INFO'];
$file = '/path/to/all/files' . $file_name;
if (file_exists($file)) {
header('Content-Type: ' . mime_content_type($file_name));
header('Content-Disposition: attachment;filename="' . basename($file_name) . '"');
header('Content-Length: ' . filesize($file));
readfile($file);
} else {
header('HTTP/1.1 404 Not Found');
}
?>
Name it files.php
or so and then you have a generic PHP downloader which you can access by for example http://example.com/files/foo.pdf
, http://example.com/files/bar.zip
, etcetera.
Hope this helps.
Upvotes: 13
Reputation: 28056
Rather than having to write PHP wrapper scripts, if you are using Apache, you can do this with a .htaccess file in the folder containing the PDFs:
<Files *.pdf>
Header set Content-Disposition attachment
</Files>
Apparently some versions of IE / Adobe Reader don't respect the Content-Disposition
header. You can work around these with ForceType application/octet-stream
<Files *.pdf>
ForceType application/octet-stream
Header set Content-Disposition attachment
</Files>
Upvotes: 3
Reputation: 9549
The following code may help you:
<?php
if(isset($_GET['docid'])){
switch($_GET['docid']){
case '1':
$file = 'complete/path/to/pdf/file1';
break;
case '2':
$file = 'complete/path/to/pdf/file2';
break;
case '3':
$file = 'complete/path/to/pdf/file3';
break;
default:
exit;
}
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;
}
}
Save this code as a php file (say, download.php) and call it from the link. What the script does is that it reads the pdf file and outputs it to the buffer. The headers will force the disposition as download.
To call the first pdf, href to '/path/to/download.php?docid=1'
To call the second pdf, href to '/path/to/download.php?docid=2'
To call the third pdf, href to '/path/to/download.php?docid=3'
So, you don't need AJAX to do the work.
Upvotes: 1
Reputation: 8470
You can add an HTTP header to do that, there is an example in the PHP Docs (See example one)
Upvotes: 1
Reputation: 526523
Try using PHP to serve the file while first sending a header of Content-type: application/octet-stream
.
Upvotes: 1