How to send a file to the browser as attachment if the meant file resides on a 3rd party server (without prior downloading or streaming)?
From another server without downloading to your server:
header('Location: http://thirdparty.com/file.ext');
Without downloading the file locally you have no authorization in the external server, so you have to tell the browser what to do, thus the redirect header, it will tell the server to go directly to the url provided, thus loading the download.
From your server you would do:
if (file_exists($file))
{
if(false !== ($handler = fopen($file, 'r')))
{
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)); //Remove
//Send the content in chunks
while(false !== ($chunk = fread($handler,4096)))
{
echo $chunk;
}
}
exit;
}
echo "<h1>Content error</h1><p>The file does not exist!</p>";
Taken from another question I have answered
http://php.net/manual/en/function.header.php#example-3655
If you want the user to be prompted to save the data you are sending, such as a generated PDF file, you can use the » Content-Disposition header to supply a recommended filename and force the browser to display the save dialog.
<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');
// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');
// The PDF source is in original.pdf
readfile('original.pdf');
?>
As the others have said, you have to set the Content-disposition header of the response to the file download request. However, you've said the file's on a 3rd party server. Unless you have control over how that server sends out the file, you can't change how the browser retrieves from that server.
You can, however, proxy the file so that your server downloads the file, then passes it on to the client with the appropriate headers. This means you've doubled your bandwidth bill, though, as you're having to both download the file AND upload it at the same time.
Just a note for those who face problems on names containing spaces (e.g. "test test.pdf").
In the examples (99% of the time) you can find
header('Content-Disposition: attachment; filename='.basename($file));
but the correct way to set the filename is quoting it (double quote):
header('Content-Disposition: attachment; filename="'.basename($file).'"' );
Some browsers may work without quotation, but for sure not Firefox and as Mozilla explains, the quotation of the filename in the content-disposition is according to the RFC
Filename with spaces truncated upon download - Mozillazine
If you want to provide files that are regularly handled by the browser (images, html, ...), you will have add a header to change the MIME type with something like:
header("Content-Type: application/force-download; name=filename");
If you don't have access to the third party server, you have no choice but to download the file yourself to provide it to the user by adding the header
Related
I want to serve an existing file to the browser in PHP.
I've seen examples about image/jpeg but that function seems to save a file to disk and you have to create a right sized image object first (or I just don't understand it :))
In asp.net I do it by reading the file in a byte array and then call context.Response.BinaryWrite(bytearray), so I'm looking for something similar in PHP.
Michel
There is fpassthru() that should do exactly what you need. See the manual entry to read about the following example:
<?php
// open the file in a binary mode
$name = './img/ok.png';
$fp = fopen($name, 'rb');
// send the right headers
header("Content-Type: image/png");
header("Content-Length: " . filesize($name));
// dump the picture and stop the script
fpassthru($fp);
exit;
?>
See here for all of PHP's filesystem functions.
If it's a binary file you want to offer for download, you probably also want to send the right headers so the "Save as.." dialog pops up. See the 1st answer to this question for a good example on what headers to send.
I use this
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;
}
I use readfile() ( http://www.php.net/readfile )...
But you have to make sure you set the right "Content-Type" with header() so the browser knows what to do with the file.
You can also force the browser to download the file instead of trying to use a plug-in to display it (like for PDFs), I always found this to look a bit "hacky", but it is explained at the above link.
This should get you started:
http://de.php.net/manual/en/function.readfile.php
Edit: If your web server supports it, using
header('X-Sendfile: ' . $filename);
where file name contains a local path like
/var/www/www.example.org/downloads/example.zip
is faster than readfile().
(usual security considerations for using header() apply)
For both my website and websites I create for clients I use a PHP script that I found a long time ago.
It can be found here: http://www.zubrag.com/scripts/download.php
I use a slightly modified version of it to allow me to obfuscate the file system structure (which it does by default) in addition to not allowing hot linking (default) and I added some additional tracking features, such as referrer, IP (default), and other such data that I might need should something come up.
Hope this helps.
Following will initiate XML file output
$fp = fopen($file_name, 'rb');
// Set the header
header("Content-Type: text/xml");
header("Content-Length: " . filesize($file_name));
header('Content-Disposition: attachment; filename="'.$file_name.'"');
fpassthru($fp);
exit;
The 'Content-Disposition: attachment' is pretty common and is used by sites like Facebook to set the right header
So, I need a little help here. I have a site which hosts some mp3s. When users click on the download url, it links directly to a file called downloadmp3.php, which goes 2 parameters in the url...the php file is included below, and it's basically supposed to FORCE the user to save the mp3. (not play it in the browser or anything).
That doesnt happen. Instead, it seems like the file is WRITTEN out in ascii to the browser. It seems like it's the actual mp3 file written out.
Here is my downloadmp3.php file...please, what's wrong in this code.
It works on my local LAMP (Bitnami Wampstack on windows)....that is, on my local testing environment, it sends the file to my broswer, and I can save it. When I upload it to the real server, it basically writes out the mp3 file.
Here is the culprit file, downloadmp3.php...please help
<?php
include 'ngp.php';
$file = $_GET['songurl'];
$songid = $_GET['songid'];
increasedownloadcount($songid);
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: audio/mpeg');
header('Content-Disposition: attachment; filename=' . basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
ob_clean();
flush();
readfile($file);
exit;
}
?>
By the way, this site only hosts mp3s - no other audio or file format. So, this downloadmp3.php script should ideally ask the user where they want to save this file.
Thanks for your help in advance.
I think the filename should be in quotes:
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
Change the content-type value to text/plain. With this browser wont recognize it and wont play the file. Instead it will download the file at clients machine.
Seems there is too many headers. I am sure they do SOMETHING... but this code works.
This code works with MP3 files.... downloads to a file. Plays without a problem.
if(isset($_GET['file'])){
$file = $_GET['file'];
header('Content-type: audio/mpeg');
header('Content-Disposition: attachment; filename=".$file.'"');
readfile('path/to/your/'.$file);
exit();
}
You can access it with ajax call, or this:
<a id="dl_link" href="download.php?file=<>file-you-wish-to-download<>" target="_blank">Download this file</a>
Hopefully this is of some use
I am trying to download uploaded files over https and, while the files themselves download, they cannot be viewed.
I have tried JPG, DOC and XLS files and all give the same problem and, in all cases, if I download via FTP they open perfectly and they open fine in the browser pre-download using the script.
Here is a subset of the script showing the code I am trying to use? Any idea why it downloads garbage?
$_file = sanitiseData($_GET['doc']);
$filename = '/doc_uploads/'.$_file;
if (file_exists($filename)) {
header('Content-type:image/jpg');
header('Content-Disposition: attachment; filename="'.$_file.'"');
echo file_get_contents($filename);
} else {
echo "The file $_file does not exist";
}
Here is a sample of the garbage when trying to view a downloaded JPG via browser:
����JFIF��;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 90 ��C ��C ��R�"�� ���}!1AQa"q2���#B��R��$3br� %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz��������������������������������������������������������������������������� ���w!1AQaq"2�B���� #3R�br� $4�%�&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz��������������������������������������������������������������������������?�P��q\�O�^�-�C�z�z����o�N��P;��.i�~k+Զ���|�7`�'e����G�>+���_�6�%�Ԓ��Y�w���P�~.�����2E�� ��"��ڗȌ��ms����[���?��%|"�R5�s�c������=?V��>���IG�=?V��>���I_Q#w����o���������o����������=?V��>���IG�=?V��>���I_Q#w����o���������o����������=?V��>���IG�=?V��>���I_Q#w����o���������o����������=?V��>���IG�=?V��>���I_Q#w����o���������o����������=?V��>���IG�=?V��>���I_Q#w����o���������o����������=?V��>���IG�=?V��>���I_Q#w����o���������o����������=?V��>���IG�=?V��>���I_Q#w����o���������o����������=?V��>���IG�=?V��>���I_Q#w����o���������o����������=?V��>���IG�=?V��>���I_Q#w����o���������o����������=?V��>���IG�=?V��>���I_Q#w����o���������o����������=GU��>���� �N�v������%|!E~�xO� �ỹx_P����j(�z����_
Your best bet is to use readfile(...). PHP's website has a nice example that should help you. I use it on my website and it works like a charm:
if (file_exists($file)) {
// Inform browser that this is a force-download
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
// Inform browser that data can be binary in addition to text
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
// Inform browser that this page expires immediately so that an update to the file will still work.
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
// Push actual file.
ob_clean();
flush();
readfile($file);
exit();
}
Single quotes are causing you to output the string "$filename" instead of the variable value $filename.
echo file_get_contents($filename);
Though we don't see the function sanitiseData(), we assume it is properly filtering out strings that could be used for path injection like ../.
Addendum:
I'll note that the correct MIME type for a jpeg is image/jpeg, rather than image/jpg. That is likely going to cause you problems too.
im working on a content management system for that i have to download a php file using php code without executing. any one can help me on this
it is some thing like ftp. i have added the options to upload, edit and download a file. it is working fine. but while downloading a php file it is executed instead of downloading...
What i tried is:
<?php
$file = $_REQUEST['file_name'];
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));
include_once($file);
exit;
}
?>
You have to load the files content, write the content to the request and set the headers so that it's parsed as force download or octet stream.
For example:
http://server.com/download.php?name=test.php
Contents of download.php:
<?php
$filename = $_GET["name"]; //Obviously needs validation
ob_end_clean();
header("Content-Type: application/octet-stream; ");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ". filesize($filename).";");
header("Content-disposition: attachment; filename=" . $filename);
readfile($filename);
die();
?>
This code works without any modification. Although it needs validation and some security features.
The server somehow identifies file that should be executed instead of downloaded. You have to exclude the .php file you want to download from that handling. The easiest is probably to rename the file to .php.txt.
Otherwise you should be able to configure the server to not process that particular file, or the path were it is located. How you do that depends on which server you are running.
If such php file is located on the same server/website, then just open it as normal file, e.g. $fileContents = file_get_contents($filename);
If file is on another server, you have few possible options:
1) Access it via FTP (if you have login details and access)
2) Have special URL Rewrite rule on that server which will instruct web server to send file as plain text instead of executing it (e.g. somefile.php.txt)
3) Have special script on that server and by passing file name as a parameter it will return content of that file (e.g. http://example.com/showfile.php?file=somefile.php)
This is how to download a php file instead of executing it.
Trust me it works! ..download the file php with own risk :)
<?php
function downloadThatPhp($nameOfTheFile)
{
header("Pragma: public");
header("Expires: 0"); // set expiration time
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/text/x-vCard");
header("Content-Disposition: attachment; filename=".basename($nameOfTheFile).";");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($nameOfTheFile));
#readfile($nameOfTheFile);
exit(0);
}
// and this how to use:
// download that php file with your own risk :)
$file = $_REQUEST['file_name'];
$downloadThis = "http://domain-name.com/".$file;
if (file_exists($file)) {
downloadThatPhp($downloadThis);
}
?>
Hope this helps you bro :)
You can read alot about it on php.net/header, but to force a download, you can use a force-download header. This comment is amazing, check it out! :-)
if someone is looking to do this in his/her .htaccess file:
Header set Content-Disposition attachment
AddType application/octet-stream .php
or
<FilesMatch "\.(?i:php)$">
ForceType application/octet-stream
Header set Content-Disposition attachment
</FilesMatch>
I want to serve an existing file to the browser in PHP.
I've seen examples about image/jpeg but that function seems to save a file to disk and you have to create a right sized image object first (or I just don't understand it :))
In asp.net I do it by reading the file in a byte array and then call context.Response.BinaryWrite(bytearray), so I'm looking for something similar in PHP.
Michel
There is fpassthru() that should do exactly what you need. See the manual entry to read about the following example:
<?php
// open the file in a binary mode
$name = './img/ok.png';
$fp = fopen($name, 'rb');
// send the right headers
header("Content-Type: image/png");
header("Content-Length: " . filesize($name));
// dump the picture and stop the script
fpassthru($fp);
exit;
?>
See here for all of PHP's filesystem functions.
If it's a binary file you want to offer for download, you probably also want to send the right headers so the "Save as.." dialog pops up. See the 1st answer to this question for a good example on what headers to send.
I use this
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;
}
I use readfile() ( http://www.php.net/readfile )...
But you have to make sure you set the right "Content-Type" with header() so the browser knows what to do with the file.
You can also force the browser to download the file instead of trying to use a plug-in to display it (like for PDFs), I always found this to look a bit "hacky", but it is explained at the above link.
This should get you started:
http://de.php.net/manual/en/function.readfile.php
Edit: If your web server supports it, using
header('X-Sendfile: ' . $filename);
where file name contains a local path like
/var/www/www.example.org/downloads/example.zip
is faster than readfile().
(usual security considerations for using header() apply)
For both my website and websites I create for clients I use a PHP script that I found a long time ago.
It can be found here: http://www.zubrag.com/scripts/download.php
I use a slightly modified version of it to allow me to obfuscate the file system structure (which it does by default) in addition to not allowing hot linking (default) and I added some additional tracking features, such as referrer, IP (default), and other such data that I might need should something come up.
Hope this helps.
Following will initiate XML file output
$fp = fopen($file_name, 'rb');
// Set the header
header("Content-Type: text/xml");
header("Content-Length: " . filesize($file_name));
header('Content-Disposition: attachment; filename="'.$file_name.'"');
fpassthru($fp);
exit;
The 'Content-Disposition: attachment' is pretty common and is used by sites like Facebook to set the right header