54

What code do you need to add in PHP to automatically have the browser download a file to the local machine when a link is visited?

I am specifically thinking of functionality similar to that of download sites that prompt the user to save a file to disk once you click on the name of the software?

Community
  • 1
  • 1
kaybenleroll
  • 16,794
  • 16
  • 54
  • 66

5 Answers5

62

Send the following headers before outputting the file:

header("Content-Disposition: attachment; filename=\"" . basename($File) . "\"");
header("Content-Type: application/octet-stream");
header("Content-Length: " . filesize($File));
header("Connection: close");

@grom: Interesting about the 'application/octet-stream' MIME type. I wasn't aware of that, have always just used 'application/force-download' :)

Robert Swisher
  • 1,300
  • 11
  • 12
  • I'm not sure quite why, because this is new to me, but this script only worked right if I had the content-length line. – sehummel Aug 05 '11 at 20:13
  • This works great, but for some reason even though it shows the correct name and size my downloads randomly stop and say network error. Would anyone know why this is occuring? I know it isn't my wi-fi/actual network connection. – Griffin Garman Jan 09 '20 at 21:55
43

Here is an example of sending back a pdf.

header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
header('Content-Transfer-Encoding: binary');
readfile($filename);

@Swish I didn't find application/force-download content type to do anything different (tested in IE and Firefox). Is there a reason for not sending back the actual MIME type?

Also in the PHP manual Hayley Watson posted:

If you wish to force a file to be downloaded and saved, instead of being rendered, remember that there is no such MIME type as "application/force-download". The correct type to use in this situation is "application/octet-stream", and using anything else is merely relying on the fact that clients are supposed to ignore unrecognised MIME types and use "application/octet-stream" instead (reference: Sections 4.1.4 and 4.5.1 of RFC 2046).

Also according IANA there is no registered application/force-download type.

Community
  • 1
  • 1
grom
  • 15,842
  • 19
  • 64
  • 67
  • 1
    It works on PC but... "Unable to download. Content not supported" when I visit the download page on Android device. Why? – emeraldhieu Jul 12 '12 at 09:42
  • 1
    @Emerald214 No PDF Reader. Or no association for the PDF content type – grom Jul 13 '12 at 06:38
  • Especially if the targeted filetype is a .zip and all you're doing on the page is kicking off a file-download through PHP, you may want to add ```ob_clean();``` and ```ob_flush();``` before the code provided in the above answer; when trying to open a .zip natively in Windows, I had an issue wherein the OS reported .zip-archives acquired in this way were invalid, even though 7zip and other dedicated compressed-archive-format-handling tools could cope with them just fine. – Seldom 'Where's Monica' Needy Jul 09 '15 at 22:41
12

A clean example.

<?php
    header('Content-Type: application/download');
    header('Content-Disposition: attachment; filename="example.txt"');
    header("Content-Length: " . filesize("example.txt"));

    $fp = fopen("example.txt", "r");
    fpassthru($fp);
    fclose($fp);
?>
vdbuilder
  • 12,254
  • 2
  • 25
  • 29
  • 1
    It may work, but I wouldn't go so far as to call it "clean." For one, it involves typing the filename three times. Instead, I'd set the filename as a variable, that way your code isn't redundant and you reduce the chance for errors. – Mike Mar 31 '16 at 20:47
2

None of above worked for me!

Working on 2021 for WordPress and PHP:

<?php
$file = ABSPATH . 'pdf.pdf'; // Where ABSPATH is the absolute server path, not url
//echo $file; //Be sure you are echoing the absolute path and file name
$filename = 'Custom file name for the.pdf'; /* Note: Always use .pdf at the end. */

header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($file));
header('Accept-Ranges: bytes');
@readfile($file);

Thanks to: https://qastack.mx/programming/4679756/show-a-pdf-files-in-users-browser-via-php-perl

gtamborero
  • 2,898
  • 27
  • 28
0

my code works for txt,doc,docx,pdf,ppt,pptx,jpg,png,zip extensions and I think its better to use the actual MIME types explicitly.

$file_name = "a.txt";

// extracting the extension:
$ext = substr($file_name, strpos($file_name,'.')+1);

header('Content-disposition: attachment; filename='.$file_name);

if(strtolower($ext) == "txt")
{
    header('Content-type: text/plain'); // works for txt only
}
else
{
    header('Content-type: application/'.$ext); // works for all extensions except txt
}
readfile($decrypted_file_path);
Omidoo
  • 493
  • 1
  • 6
  • 14