How to make PDF file downloadable in HTML link?
Solution 1
Instead of linking to the .PDF file, instead do something like
<a href="pdf_server.php?file=pdffilename">Download my eBook</a>
which outputs a custom header, opens the PDF (binary safe) and prints the data to the user's browser, then they can choose to save the PDF despite their browser settings. The pdf_server.php should look like this:
header("Content-Type: application/octet-stream");
$file = $_GET["file"] .".pdf";
header("Content-Disposition: attachment; filename=" . urlencode($file));
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Description: File Transfer");
header("Content-Length: " . filesize($file));
flush(); // this doesn't really matter.
$fp = fopen($file, "r");
while (!feof($fp))
{
echo fread($fp, 65536);
flush(); // this is essential for large downloads
}
fclose($fp);
PS: and obviously run some sanity checks on the "file" variable to prevent people from stealing your files such as don't accept file extensions, deny slashes, add .pdf to the value
Solution 2
This is a common issue but few people know there's a simple HTML 5 solution:
<a href="./directory/yourfile.pdf" download="newfilename">Download the pdf</a>
Where newfilename
is the suggested filename for the user to save the file. Or it will default to the filename on the serverside if you leave it empty, like this:
<a href="./directory/yourfile.pdf" download>Download the pdf</a>
Compatibility: I tested this on Firefox 21 and Iron, both worked fine. It might not work on HTML5-incompatible or outdated browsers. The only browser I tested that didn't force download is IE...
Check compatibility here: http://caniuse.com/#feat=download
Solution 3
Don't loop through every file line. Use readfile instead, its faster. This is off the php site: http://php.net/manual/en/function.readfile.php
$file = $_GET["file"];
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Content-Type: application/force-download");
header('Content-Disposition: attachment; filename=' . urlencode(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;
}
Make sure to sanitize your get variable as someone could download some php files...
Solution 4
Instead of using a PHP script, to read and flush the file, it's more neat to rewrite the header using .htaccess
. This will keep a "nice" URL (myfile.pdf
instead of download.php?myfile
).
<FilesMatch "\.pdf$">
ForceType applicaton/octet-stream
Header set Content-Disposition attachment
</FilesMatch>
Solution 5
I found a way to do it with plain old HTML and JavaScript/jQuery that degrades gracefully. Tested in IE7-10, Safari, Chrome, and FF:
HTML for download link:
<p>Thanks for downloading! If your download doesn't start shortly,
<a id="downloadLink" href="...yourpdf.pdf" target="_blank"
type="application/octet-stream" download="yourpdf.pdf">click here</a>.</p>
jQuery (pure JavaScript code would be more verbose) that simulates clicking on link after a small delay:
var delay = 3000;
window.setTimeout(function(){$('#downloadLink')[0].click();},delay);
To make this more robust you could add HTML5 feature detection and if it's not there then use window.open()
to open a new window with the file.
Comments
-
djmzfKnm over 3 years
I am giving link of a pdf file on my web page for download, like below
<a href="myfile.pdf">Download Brochure</a>
The problem is when user clicks on this link then
- If the user have installed Adobe Acrobat, then it opens the file in the same browser window in Adobe Reader.
- If the Adobe Acrobat is not installed then it pop-up to the user for Downloading the file.
But I want it always pop-up to the user for download, irrespective of "Adobe acrobat" is installed or not.
Please tell me how i can do this?
-
djmzfKnm over 15 yearsIs it really matter if i use the following code $file = $_GET["file"] .".pdf"; AS $file = $_REQUEST["file"] .".pdf";
-
djmzfKnm over 15 yearsWhere to wrote this code? which controller, i am new to PHP please explain.
-
djmzfKnm over 15 yearsI am facing another problem with this, that my file is located at /products/brochure/myfile.pdf I am giving $file variable as $file_path = $_SERVER['DOCUMENT_ROOT'].'/products/brochure/' . $file; but its downloading the file as "%2Fvar%2Fwww%2Fweb15%2Fweb%2Fproducts%2Fbrochure%2myfile.pdf"
-
djmzfKnm over 15 yearswhat i can do to make it downloaded with the name "myfile.pdf" only. I changed the header("Content-Disposition: attachment; filename=" . urlencode('myfile.pdf')); also, but still its not working.
-
Jose Garrido about 11 yearsThe readfile function is indeed faster. I personally recommend using this answer instead of the accepted one
-
eloyesp about 11 years@Prashant This is not PHP, it's Ruby on Rails.
-
Tommz about 11 yearsAm I the only one getting error that .pdf was damaged when I'm trying to open .pdf?
-
Nicholas Wilson over 10 years@TravisO
"Content-type: application/force-download"
isn't listed anywhere here: iana.org/assignments/media-types/application It's a completely bogus header. Please don't make up headers and send them. Could you update your answer. Thanks. -
TravisO over 10 yearsAfter Googling about it and double checking, it's removed
-
benebun over 10 yearsThis is a simple solution but unfortunately not very widely supported, esp. no support by IE caniuse.com/#feat=download
-
T_D over 10 yearsYep, I know right. That's why I have the side-note on compatibility. And according to your source both IE and Safari don't support this approach, or at least not yet :) Anyhow, if you want all browsers to force download I suggest checking some of the other answers instead...
-
TecBrat over 9 yearsWouldn't this make ALL your PDFs force download?
-
Rob W over 9 years@TecBrat Yes, but that was what the OP asked. If you want to limit to a few PDFs only, edit the
^\.pdf$
regular expression. -
Edwin Thomas over 9 years@TravisO I Got an Error, it is either not a supported file type or because the file has been damaged...
-
edelans over 9 yearsworks like a charm with chrome Version 39.0.2171.65 (64-bit) !
-
Joost about 9 yearsBe careful when using this code verbatim, though. This introduces a serious LFI vulnerability, as you're passing GET-variables directly into
fopen
. -
habakuk about 9 years@TecBrat or put the .htaccess file only in the subfolder where this behavior is needed.
-
Rory McCune over 8 yearsThis code is likely dangerous in another way. If you pass HTTP links to fopen, I think it'll go retrieve the file from another server. Could be used by an attacker to attempt to scan your internal network for exposed PDF files.
-
AviD over 8 yearsNot to mention how easy it would be to bypass any "sanity checks" you think you'll be doing to the "file" parameter. Path injection / directory traversal attacks are extremely likely.
-
valkirilov almost 8 yearsThe solution is easy but unfortunately not supported in IE and Safari.
-
Evan Donovan over 7 yearsIf I were going to use this code, instead of doing sanity checks, I would have a database of whitelisted files on my server that could be used with it. That's what various CMS do. As for @RоryMcCune's comment, I think it depends on how your PHP is set up. Imo, php.ini should be configured to prevent fopen from opening things from remote servers.
-
Evan Donovan over 7 years@Prashant: If you need a PHP example, look at the ones further up the thread, but please read the comments about how they could be insecure.
-
Evan Donovan over 7 yearsYou could also add to your code something that would check for an additional $_GET parameter that would act as a "secret key" - that way people couldn't craft arbitrary URLs since they wouldn't know the key you were using to permit the file to be served. It wouldn't be perfectly secure but it would be an improvement.
-
Abdulla Sirajudeen over 5 yearssays no permission to access
-
Suraj Kumar about 5 yearsYou should explain what you have provided in your code. Even in short form if not possible in details or not required in details.
-
divy3993 almost 4 yearsI think this answer is not valid today, when we have better alternative of HTML5 attribute
download
-
Aljohn Yamaro almost 3 yearsSorry, not working, it will replace the current URL of the browser to pdf url
-
jamesdlin about 2 yearsEven for browsers where it's supported, whether or not the
download
attribute triggers a download prompt depends on the user's browser settings. For example, even with Firefox 98, clicking a link to a.pdf
file by default opens it in the browser, regardless of thedownload
attribute. Other than being able to suggest a filename, thedownload
attribute doesn't seem to offer much benefit.