Forcing download of excel file through Ajax request fails silently - php

I am trying to make a link that is clickable; when it's clicked on it forces a download (or even a Save As option would be nice) of an .xls file. This is what I have below.
When the link is clicked, there are no php log errors and it goes through this code. The file does exist as well. Are my headers wrong?
if (#file_exists("/tmp/report/{$php_session_id}.xls")) {
$filename = "/tmp/report/{$php_session_id}.xls";
$content_length = filesize($filename);
header("Pragma: public");
header("Expires: 0");
header("Content-type: application/vnd.ms-excel");
header("Content-length: {$content_length}");
header("Content-disposition: attachment; filename=\"missing_addresses.xml\"");
readfile($filename);
}
If the code is correct, is it possibly a server that is locked out of doing this?
Also, I am testing on Chrome for Mac (newest version)
UPDATE: I used AJAX which was the problem.

You can't initiate a download through Ajax; the response will simply vanish in the ether, as a normal Ajax response. (You could theoretically capture it, but you won't be able to write it to disk.)
Use
location.href = "source.php";
or
<a href='source.php' target='_blank'>
to direct the browser to the resource directly instead. It will automatically detect that it's a file to be downloaded, and initiate the download.

Related

How to Stop Header, so I can echo to screen from the same function (PHP)

I'm finding Headers a nightmare to get my head around, I have a file the user downloads which works fine. However I then whish to echo to the screen that xx file has been sent; but ofc this echo is just placed inside the sent file.
Full dowload code is as follows:
function download()
{
$orderNo = $_POST['orderNo'];
$lines = file('F:/xamptest/htdocs/UniProject/upload/Amazon output.txt');
$lineCount = count($lines);
if($orderNo>0&&$orderNo<=$lineCount)
{
$lineEx = explode("\t", $lines[($orderNo-1)]);
$file = fopen('Order.txt', 'w');
fwrite($file, $lineEx[8].PHP_EOL .$lineEx[17].PHP_EOL .$lineEx[18].PHP_EOL .$lineEx[19].PHP_EOL .$lineEx[20].PHP_EOL .$lineEx[21].PHP_EOL .$lineEx[22].PHP_EOL .$lineEx[23].PHP_EOL);
fclose($file);
$file = 'Order.txt';
ob_end_clean();
header("Cache-Control: private");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$file");
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: binary");
readfile($file);
echo "Current order, number: ".$orderNo."<br> Has been downloaded";
}
else
{
echo "Please enter a valid Order Number between 1 and ".$lineCount;
}
}
I can't seem to find how to stop the headers without using exit(); which then still means it won't show the echo, and any more use of ob_end_clean(); in any other ways causes the sent file to be empty. Only other thing I could think was having the echo in its own function, but as it runs at the same time the headers do it still places it in the file.
Many thanks for any help - Tom.
What you're dealing with is an HTTP request. The browser requests a URL with an HTTP request, the server sends a response. Click a link → browser sends request → server sends HTML page in response. Use Chrome, Safari or Firefox + Firebug and play around with the Network tab in their Web Inspector/development tools to get a real feeling for what's happening.
If you want to download a file, it works the same way. Only the server tells the browser through HTTP headers that this response is not an ordinary HTML page, but is supposed to be a file which it should save on disk.
As you should be able to see, there's no way to respond with a file download and an HTML page at the same time in one response. There's simply no way to do it. You have to output your HTML page with the message first, then link to the file download from there.

Retrieving output from a url. How do I force the dowload of a PDF from a url using php

I need to retrieve our reports from the jasperserver report engine as a PDF, then I want the PDF to be forced as a download, instead of being displayed inthe browser. The problem with displaying in the browser is we don't want the report parameters to be displayed to the end users in the url.
If I enter this URL path into the browser I get a PDF document that shows in the same browser window with all the report data:
https://mysite.com:8443/jasperserver/flow.html?_flowId=viewReportFlow&reportUnit=sample_report&output=pdf;
What I would prefer to have happen is for a download dialog box to be used and for the users to download the PDF to their computer, instead of it showing in the browser.
I've tried the following php code, but can't get it to work. I get a return value of false, but nothing in the server logs that shows an error.
ob_start();
header("Location: $src"); /* Redirect browser */
$report_contents = ob_get_contents();
ob_end_clean();
var_dump($report_contents);
I'm not really sure how to go about this...anyone got any ideas?
Thanks for the help.
You could buffer the file to the PHP server then output with force download:
header('Content-disposition: attachment; filename=huge_document.pdf');
header('Content-type: application/pdf');
readfile('https://mysite.com:8443/jasperserver/flow.html?_flowId=viewReportFlow&reportUnit=sample_report&output=pdf;');
See the notes about using readfile over an HTTP stream wrapper
http://php.net/manual/en/function.readfile.php
how about
$source=$url
header("Expires: 0");
header("Cache-Control: private");
header("Pragma: cache");
header("Content-length: $size");
header("Content-type: $type");
header("Content-Disposition: attachment; filename=$name");
readfile($source);
exit();

Save pdf to local server

I am creating a PDF file from raw binary data and it's working perfectly but because of the headers that I define in my PHP file it prompts the user either to "save" the file or "open with". Is there any way that I can save the file on local server somewhere here http://localhost/pdf?
Below are the headers I have defined in my page
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Type: application/pdf");
header("Content-Disposition: attachment; filename=$filename");
header("Content-Transfer-Encoding: binary");
If you would like to save the file on the server rather than have the visitor download it, you won't need the headers. Headers are for telling the client what you are sending them, which is in this case nothing (although you are likely displaying a page linking to you newly created PDF or something).
So, instead just use a function such as file_put_contents to store the file locally, eventually letting your web server handle file transfer and HTTP headers.
// Let's say you have a function `generate_pdf()` which creates the PDF,
// and a variable $pdf_data where the file contents are stored upon creation
$pdf_data = generate_pdf();
// And a path where the file will be created
$path = '/path/to/your/www/root/public_html/newly_created_file.pdf';
// Then just save it like this
file_put_contents( $path, $pdf_data );
// Proceed in whatever way suitable, giving the user feedback if needed
// Eg. providing a download link to http://localhost/newly_created_file.pdf
You can use output control functions. Place ob_start() at beginning of your script. At the end use ob_get_contents() and save the content to a local file.
After that you can use ob_end_clean() or ob_end_flush() depending on whether you want to output PDF to browser as well, or you would redirect user to some other page. If you use ob_end_flush() make sure you set the headers before flushing the data.

How to prevent file location from showing?

I am allowing users to upload documents to the server. However, i don't want them to obviously see where the files are being stored. What can i do that will allow them to still get the file but without seeing the file location.
You can use a PHP query to accomplish this, lets say you use the following URL:
http://mysite.com/files.php?file=xyz.pdf
In files.php you can check the get variable file and have a hard coded function that retrieves the file. You can do this many ways one by using headers to force a download or read the file into a var and print it's contents to the page. For say like a pdf reading the file and printing it to the page is the same as linking it to the file.
warning though: like with using headers do not print anything to the page except the file. I also recommend declairing you headers still if you read the file and print it so that the end user will not get the gobbly goop that is the source of the file i.e. jpg or pdf.
Oh no, I forgot a header warning, I have been running into a header problem ever since Adobe made the ISO for PDF's open source, depending on the application that produced the PDF and the browser from which the user is uploading the PDF from, the header will be anything from:
'application/pdf', 'application/x-download','application/octet-stream','application/octet','binary/octet-stream'
so be careful hard coding the upload section to a header type, I know this question is about downloads but i just thought i would throw that in there. Also using headers for downloads doesn't matter I would simply use the standard application/pdf there.
There are a few ways todo this but i prefer using .htaccess
So my link would look like http://example.com/files/filename.zip
extra parameters within the url could be used a username or password like:
http://example.com/files/bob/filename.zip
http://example.com/files/18d52c/filename.zip
Then thos could be checked against a database to see if user is allowed to download that specific file, much like you would use for instant downloads after payment.. but a basic method would be like so:
.htaccess
RewriteRule ^files/(.*)$ serve.php?file=$1
serve.php
<?php
if(isset($_GET['file'])){
$file=basename($_GET['file']);
//Protect the index.php && serve.php
if(basename($_GET['file'])=='index.php' || basename($_GET['file'])=='serve.php'){
header("HTTP/1.1 403 Forbidden");die();
}
$downloadFolder="original_location/";
if(file_exists($downloadFolder.$file)){
$fsize = filesize($downloadFolder.$file);
$ctype=finfo_file(finfo_open(FILEINFO_MIME_TYPE), $downloadFolder.$file);
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
if(strstr($_SERVER["HTTP_USER_AGENT"],"MSIE")==false) {
header("Content-Type: application/force-download");
header('Content-Description: File Transfer');
}else{
header("Content-Type: $ctype");
}
header("Content-Disposition: attachment; filename=\"".basename($file)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$fsize);
ob_clean();
flush();
readfile('original_location/'.$file);
}else{
header("HTTP/1.0 404 Not Found");
}
die();
}
header("HTTP/1.0 404 Not Found");
?>
original_location/index.php
header("HTTP/1.1 403 Forbidden");
Store it using some random unique ID that you can map to the real file, then serve it using a script that does readfile() on the actual file.
The http://php.net/readfile docs also have an example on how to force it being a download.

Illustrator opening as PDF

I am coding a file sharing application for my office. One strange problem I am going through is the Illustrator files being opened in PDF when you hit the download button.
This problem is triggered because the mime type of illustrator files is application/pdf. So the browser when it reads the file, triggers Acrobat to open the file. Is there any way I could instruct the browser to open the file in Illustrator?
Or is there any way to modify the mime type after uploading the file? The backend code is PHP.
Thank you for any help.
One way to do this is to force the browser to display the "download file"-dialog. So the user can decide what to do with the file.
This can be done via PHP-Headers. (http://www.php.net/manual/en/function.header.php#83384)
There is also an example on how to this (Post 83384):
<?php
// downloading a file
$filename = $_GET['path'];
// fix for IE catching or PHP bug issue
header("Pragma: public");
header("Expires: 0"); // set expiration time
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
// browser must download file from server instead of cache
// force download dialog
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
// use the Content-Disposition header to supply a recommended filename and
// force the browser to display the save dialog.
header("Content-Disposition: attachment; filename=".basename($filename).";");
/*
The Content-transfer-encoding header should be binary, since the file will be read
directly from the disk and the raw bytes passed to the downloading computer.
The Content-length header is useful to set for downloads. The browser will be able to
show a progress meter as a file downloads. The content-lenght can be determines by
filesize function returns the size of a file.
*/
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filename));
#readfile($filename);
exit(0);
?>
When using this example please consider that using
$filename = $_GET['path'];
is a big security problem. You should work with something like ID's instead or validate the input.
For example:
if($_GET['file'] == 1) {
$filename = foobar.pdf;
} elseif($_GET['file'] == 2) {
$filename = foo.pdf;
} else {
die();
}

Categories