PHP header download (Laravel) - php

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));

Related

blank page when using php readfile() in wordpress template

I have a form which the user fills out with their details & serial number, the software installer is then downloaded, named as their input. e.g. serial.exe
Once the form is submitted I check the file exists and then attempt the file download:
$directory = get_template_directory();
$file = $directory . '/filename.exe';
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$Serial.'.exe"');
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));
readfile($file);
exit;
}
This causes the loading to freeze, nothing below this code is loaded but i can't see any errors & no file is generated.
If i change the file to a .png the code works.
I've also copied the same code to a php page outside of wordpress, the same code runs & downloads the file as desired.
Is it possible that Wordpress is somehow blocking the readfile() request because its an .exe?
EDIT:
It appears to be a problem with the size of the file, rather than the type of file.
A small .exe file has worked & is downloaded correctly.

PHP File download with original filename

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.

Incorrect Headers?

What I'm trying to do:
Im trying to push a jpg file to download witout user seeing the URL. In this case the file is located at: http://www.example.com/upload/asdasdsadpokdaspdso/36.jpg.
My current code:
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$download->name.'.jpg"');
readfile($weburl."/upload/".$hiddenpassage."/".$download->link);
My vars / db values:
$weburl = "http://wwww.example.com";
$hiddenpassage = "asdasdsadpokdaspdso";
$download->link = 36.jpg //not a var, just drom db.
$download->name = The First Test Product //not a var, just from db.
The problem:
When I get the download I open it and I get the following error:
The file “The First Test Product (28).jpg” could not be opened.
It may be damaged or use a file format that Preview doesn’t recognize.
Renaming .jpg to .txt:
http://pastebin.com/K9NGL5RP
Most of that is the content of the page I downloaded it from.
I think you need to specify the whole header (untested). Specially the Content-Length.:
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.$download->name.'.jpg');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($weburl."/upload/".$hiddenpassage."/".$download->link));
readfile($weburl."/upload/".$hiddenpassage."/".$download->link);
Hope this helps.

getting a file from outside the document root. PHP

I am currently storing docx files and pdf files in a user upload folder outside the doc root. I intend for these files to be downloaded via a db link to the heavily scrambled file name.
Previously I have only obtained data from files outside the root with PHP - is it possible to retrieve whole files from this area and if so how does one go about it.
<?php
$file_id = $_GET['id'];
$local_path = get_real_filelocation_from_id($file_id);
readfile($local_path);
The code for get_real_filelocation_from_id() is left as an exercise for the OP.
<?php
$get_file=$_GET['file_name'];
$file = '/path/to/uploads/'.$get_file;
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');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
?>
After many hours of searching I found this that seems to work. Unfortunately, although the symbolic link root seemed to be a good path to follow I am unsure of how to actually implement it - firebug goes into quirks mode when I try even the most basic script.

Creating a download link for .jpg file using PHP

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.

Categories