How to force file download with PHP
Solution 1
Read the docs about built-in PHP function readfile
$file_url = 'http://www.myremoteserver.com/file.exe';
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"" . basename($file_url) . "\"");
readfile($file_url);
Also make sure to add proper content type based on your file application/zip, application/pdf etc. - but only if you do not want to trigger the save-as dialog.
Solution 2
<?php
$file = "http://example.com/go.exe";
header("Content-Description: File Transfer");
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"". basename($file) ."\"");
readfile ($file);
exit();
?>
Or, when the file is not openable with the browser, you can just use the Location
header:
<?php header("Location: http://example.com/go.exe"); ?>
Solution 3
header("Content-Type: application/octet-stream");
header("Content-Transfer-Encoding: Binary");
header("Content-disposition: attachment; filename=\"file.exe\"");
echo readfile($url);
is correct
or better one for exe type of files
header("Location: $url");
Solution 4
Display your file first and set its value into url.
index.php
<a href="download.php?download='.$row['file'].'" title="Download File">
download.php
<?php
/*db connectors*/
include('dbconfig.php');
/*function to set your files*/
function output_file($file, $name, $mime_type='')
{
if(!is_readable($file)) die('File not found or inaccessible!');
$size = filesize($file);
$name = rawurldecode($name);
$known_mime_types=array(
"htm" => "text/html",
"exe" => "application/octet-stream",
"zip" => "application/zip",
"doc" => "application/msword",
"jpg" => "image/jpg",
"php" => "text/plain",
"xls" => "application/vnd.ms-excel",
"ppt" => "application/vnd.ms-powerpoint",
"gif" => "image/gif",
"pdf" => "application/pdf",
"txt" => "text/plain",
"html"=> "text/html",
"png" => "image/png",
"jpeg"=> "image/jpg"
);
if($mime_type==''){
$file_extension = strtolower(substr(strrchr($file,"."),1));
if(array_key_exists($file_extension, $known_mime_types)){
$mime_type=$known_mime_types[$file_extension];
} else {
$mime_type="application/force-download";
};
};
@ob_end_clean();
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
header('Content-Type: ' . $mime_type);
header('Content-Disposition: attachment; filename="'.$name.'"');
header("Content-Transfer-Encoding: binary");
header('Accept-Ranges: bytes');
if(isset($_SERVER['HTTP_RANGE']))
{
list($a, $range) = explode("=",$_SERVER['HTTP_RANGE'],2);
list($range) = explode(",",$range,2);
list($range, $range_end) = explode("-", $range);
$range=intval($range);
if(!$range_end) {
$range_end=$size-1;
} else {
$range_end=intval($range_end);
}
$new_length = $range_end-$range+1;
header("HTTP/1.1 206 Partial Content");
header("Content-Length: $new_length");
header("Content-Range: bytes $range-$range_end/$size");
} else {
$new_length=$size;
header("Content-Length: ".$size);
}
$chunksize = 1*(1024*1024);
$bytes_send = 0;
if ($file = fopen($file, 'r'))
{
if(isset($_SERVER['HTTP_RANGE']))
fseek($file, $range);
while(!feof($file) &&
(!connection_aborted()) &&
($bytes_send<$new_length)
)
{
$buffer = fread($file, $chunksize);
echo($buffer);
flush();
$bytes_send += strlen($buffer);
}
fclose($file);
} else
die('Error - can not open file.');
die();
}
set_time_limit(0);
/*set your folder*/
$file_path='uploads/'."your file";
/*output must be folder/yourfile*/
output_file($file_path, ''."your file".'', $row['type']);
/*back to index.php while downloading*/
header('Location:index.php');
?>
Solution 5
In case you have to download a file with a size larger than the allowed memory limit (memory_limit
ini setting), which would cause the PHP Fatal error: Allowed memory size of 5242880 bytes exhausted
error, you can do this:
// File to download.
$file = '/path/to/file';
// Maximum size of chunks (in bytes).
$maxRead = 1 * 1024 * 1024; // 1MB
// Give a nice name to your download.
$fileName = 'download_file.txt';
// Open a file in read mode.
$fh = fopen($file, 'r');
// These headers will force download on browser,
// and set the custom file name for the download, respectively.
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
// Run this until we have read the whole file.
// feof (eof means "end of file") returns `true` when the handler
// has reached the end of file.
while (!feof($fh)) {
// Read and output the next chunk.
echo fread($fh, $maxRead);
// Flush the output buffer to free memory.
ob_flush();
}
// Exit to make sure not to output anything else.
exit;
john
Updated on July 08, 2022Comments
-
john almost 2 years
I want to require a file to be downloaded upon the user visiting a web page with PHP. I think it has something to do with
file_get_contents
, but am not sure how to execute it.$url = "http://example.com/go.exe";
After downloading a file with
header(location)
it is not redirecting to another page. It just stops. -
Fabio over 12 yearsfilename in your header shouldn't be
$file
(which contains the http part) but a valid filename. -
Gumbo over 12 yearsThere is no application/force-download media type; use application/octet-stream instead.
-
genesis over 12 years@Fabio: Will add more detials
-
john over 12 yearsThat was super easy. It worked. What is file-Get_contents for then? Just curious. Thanks.
-
genesis over 12 yearsto download it to your server
-
Pit Digger over 12 yearsI mean if its other than .exe file than only .Else this should work fine.
-
Mladen B. almost 11 yearsJust remove 'echo' prior to 'readfile()' since the return value is specified as "Returns the number of bytes read from the file. If an error occurs, FALSE is returned and unless the function was called as @readfile(), an error message is printed.". So you'll end up with the content of the file + integer number at the end of the content.
-
Ash about 9 yearsDont forget to flush ;-) ob_clean(); flush(); /* before */ readfile($file_url);
-
Axel A. García almost 8 yearsWhere did you get this from? It seems powerful
-
fralbo over 7 years@jundell-agbo interesting and for a crt file?
-
Daniel Williams over 6 yearsI just tried this and it killed my server. Wrote a massive number of errors to my logs.
-
Parziphal over 6 yearsIt would be useful to know what the logs were about.
-
Daniel Williams over 6 yearsYeah sorry, the log file got so big I had to just nuke it, so I didn't get to see.
-
Stranger over 6 yearsWelcome to StackOverflow. It's always advisable to include the code directly instead of adding a link to avoid the link issues.
-
Gavin about 6 yearsI was having to set up something like this on a server that I had very limited access to. My download script kept redirecting to the home page and I couldn't figure out why. Now I know the issue was a memory error and this code solved it.
-
Linga almost 6 yearsThis is working for a very big file also. Great solution. But` $chunksize = 1*(1024*1024);` is slow. I tried with multiple values and noticed that ` $chunksize = 8*(1024*1024);` is using all the available bandwidth.
-
GDY over 5 yearsSo if you have a 10GB big file php tries to load that whole file?
-
Arsha over 5 yearsIf you just use
ob_flush()
there might be the error: ob_flush(): failed to flush buffer. No buffer to flush. wrap around it withif (ob_get_level() > 0) {ob_flush();}
(Reference stackoverflow.com/a/9182133/128761 ) -
Arsha over 5 yearsAdd
fclose($fh);
at the end before exit. Addheader('Content-Length: ' . filesize($file));
to let user know file size. +1 your answer :) -
harry4516 over 5 yearsworks very nice ! But adds ' to the stored filename. Please use: filename=" . basename($file));
-
Marek Sebera over 5 years@harry4516 modified according to your finding
-
Khom Nazid almost 5 yearsYou have two variables in this code:
file_name
andfilePath
. Not very good coding practice. Especially without explanation. Linking to external tutorial not helpful. -
Parsa Yazdani almost 5 yearsWhat do you mean by the download is streamed?
-
Saud Qureshi almost 5 years@ParsaYazdani It means the downloaded data will be chunked. Please look onto the concept of streaming for more details. Note: this is not the only to stream (chunk) download the file in PHP. But it surely is one of the easiest methods.
-
ykay says Reinstate Monica over 4 yearsexit() should be called at the end to avoid any potential problems (speaking from experience :-)
-
Kamlesh about 4 yearsi am using an image http path as source of path but file is displayed in binary code instead of downloading by using your code. Not worked for me. Thanks.
-
Kamlesh about 4 yearsNot working dear in case of png image for me. Thanks.
-
Marek Sebera about 4 years@Kamlesh filename should not matter, this solution is filetype agnostic
-
Mark Howells-Mead over 2 yearsThe question asked for a PHP solution. This is an HTML solution.