This one should be easy, I think. I have a paginated image gallery, and under each image is a small link that says "Download Comp". This should allow people to quickly download the .jpg file (with a PHP generated watermark) to their computer.
Now, I know I can just link straight to the .jpg file, but that requires the user to have the image open in a new window, right click, Save As..., etc. Instead, I want the "Download Comp" link to initiate the download of the file immediately.
PHP.net seemed to suggest using readfile(), so each "Download Comp" link is being echoed as "?download=true&g={$gallery}&i={$image}".
Then at the top of the page I catch to see if the $_GET['download'] var isset, and if so, I run the following code:
if(isset($_GET['download'])) {
$gallery = $_GET['g'];
$image = $_GET['i'];
$file = "../watermark.php?src={$gallery}/images/{$image}";
header('Content-Description: File Transfer');
header('Content-Type: application/jpeg');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: public');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
}
The link takes a lonnnnnnnnng time, and then it brings up a dialog prompt asking you to Open or Save the file, but once you Save and try to open it, it says the file is corrupt and can't be opened.
Any ideas?
Don't set $file to a relative url. The readfile function will try to access the php file on the server. That is not what you want. In your case it looks like the watermark.php file will send the contents you want, so you could possibly just set up the environment it needs and include it.
<?php
if(isset($_GET['download'])) {
$gallery = $_GET['g'];
$image = $_GET['i'];
$_GET['src'] = "{$gallery}/images/{$image}";
header('Content-Description: File Transfer');
header('Content-Type: image/jpeg');
header('Content-Disposition: attachment; filename='.basename($image));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: public');
header('Pragma: public');
ob_clean();
include('../watermark.php');
exit;
}
Another (simpler) way is to modify watermark.php. Add a query parameter to make it send the proper headers to force a download and link to that
...
watermark.php:
<?php
if (isset($_GET['download']) && $_GET['download'] == 'true') {
header('Content-Description: File Transfer');
header('Content-Type: image/jpeg');
header('Content-Disposition: attachment; filename='.basename($src));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: public');
header('Pragma: public');
}
// continue with the rest of the file as-is
Also, you don't need the call to flush(). There should not be any output to send at that point, so it is not necessary.
header('Content-Type: image/jpeg');
Perhaps?
I think you might need to follow the call to readfile() with a call to exit() to make sure nothing else gets written to the output buffer.
This seems like a security issue.
What if someone enters:
$g = '../../../../../../';
$i = '../../sensitive file at root';
How about making .htaccess (if you are using apache) i for the gallery directory serve jpegs up as a download rather than normal.
Also, try file_get_contents() instead of readfile(). I find it works under more circumstances. I would also recommend you use ob_flush() after you output the image data. I've never needed to use ob_clean() or flush() to get this kind of thing to work.
And as Eric said, you may also want to put a call to exit() in there as well for good measure if it still isn't working just in case you are getting some junk data stuck at the end.
Related
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'm searching for a possibility to download a file with PHP and keep its original name.
This should work for direct links to a file ("foo.bar/test.zip") and for downloads who are proxied through PHP files ("foo.bar/download.php?fileid=12345" <- this would open a save-as prompt with test.zip as given name).
Is there a possibility in PHP that I could use to do this?
I tried different possibilities (fopen, cURL, file_get_content, etc.). But all possibilities I've found required me to manually set the new filename in order to save it locally.
Even better would be if I could proxy the remote file through my script (with it's original name!) to the client who is calling the script, without saving it temporarily.
I found the following snippet which accomplishes this exact thing
$fp = fopen($_POST["url"], 'rb');
foreach (get_headers($_POST["url"]) as $header)
{
header($header);
}
fpassthru($fp);
The file I get to download is of the right size but has the wrong name (it has the name of the called PHP script, in my case downloader.php instead of e.g. test.zip).
Any idea how to accomplish this would be very appreciated.
Thanks in advance!
May be something like this will help:
$quoted = sprintf('"%s"', addcslashes(basename($file), '"\\'));
$size = filesize($file);
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $quoted);
header('Content-Transfer-Encoding: binary');
header('Connection: Keep-Alive');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $size);
Just replace $file with the file you want to be downloaded.
I have a simple problem. I am trying to make header download (Save as dialog window) to download file from server. My code:
public function downloadBill()
{
$id = Input::get('post_id');
$db = DB::connection('smsservice');
$file_ = $db->table('bills')->where('id', $id)->pluck('blob');
$filename = 'download.txt';
File::put($filename, base64_decode($file_));
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($filename));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filename));
}
Save as dialog starts, and I can download file download.txt, but the file is emtpy 0 kb, which draws me to the conclusion that location of download is not equal to the location of the of saved "download.txt". I tried putting file to diferent locations, even on the D:\ disk as well, but I didn't manage to make it work. Can someone help me, please?
Laravel has a built-in method for returning a download response. response()->download($filePath);. This will handle everything needed for the file to be downloaded, automatically http://laravel.com/docs/5.1/responses#file-downloads
I'd also be inclined to use the storage_path() function to save the file into an explicitly known, suitable directory rather than letting PHP save it where it likes.
$filename = storage_path(sprintf('/downloads/%s.txt', $id));
Problem:
After download, the file doesn't contain the data.
i.e it become blank.
So please help me for this.
<?php
session_start();
include_once 'oesdb.php';
$id=$_REQUEST['id'];
if(isset($_REQUEST['id']))
{
$sql=executeQuery("SELECT * FROM file where id=$id");
$rows = mysql_fetch_array($sql);
$file =$rows['file'];
header('Content-Description: File Transfer');
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile('uploads/'.$file);
exit;
}
?>
Why not create a HTACCESS file in uploads folder then states
Allow From 127.0.0.1
Deny From All
Then just create a URL, use HTML5's new download feature, do something like this:
click to download
It saves time trying to use PHP to make a download script.
try replacing this:
$file =$rows['file'];
by this:
$file = "uploads/".$rows['file'];
and this:
readfile('uploads/'.$file);
by this
readfile($file);
if still not working put the value returned by the readfile function
IMPORTANT
Please take in consideration the sql injection issues (see comment of Ondřej Mirtes)
The problem is here:
header('Content-Length: ' . filesize($file));
Content-Length receives zero value and browser downloads zero-length file, as you told him. If $file is path relative to upload/, you should do this:
header('Content-Length: ' . filesize('upload/'.$file));
Be sure that filezise() returns correct size and readfile() realy outputs it.
But the other problem is that you mentioned UPLOAD folder and using uploads. They are not same and case is important. Also, may be using relative paths in 'uploads/'.$file is not a good idea, it is better to use absolute path. For example, '/var/www/upload/'.$file.
When I use this code to download this image (only used for testing purposes), I open the downloaded image, and all it gives me is an error. i tried it in chrome. opening it with windows photo viewer, it says that it can't display the picture because it is empty???
here is the code:
<?PHP
// Define the path to file
$file = 'http://www.media.lonelyplanet.com/lpi/12553/12553-11/469x264.jpg';
if(!file)
{
// File doesn't exist, output error
die('file not found');
}
else
{
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've had a chance to work it out. Your problem is two-fold.
First, remove the www. from the url.
Second, remove the call to filesize($file) which is throwing an error because PHP doesn't know the size of the file before it downloads the file. (really, just remove the whole line)
Removing these two things, I was successful.
Replace ob_clean() with ob_end_clean()
You're still buffering, so none of the image contents get to the browser.
If your intention is just the download the file from a third party on click of a link, you could use the new property download in the anchor tag.
The code will look something like
<a download href="path/to/the/download/file"> Clicking on this link will force download the file</a>
It works on firefox and chrome latest version. Should I mention that I didn't check it in IE? :P
Replace:
ob_clean();
flush();
readfile($file);
With:
echo file_get_contents($file);