I want to download a file with android and so i stream the file with php with the following function
function stream($fileName,$fileSize,$fName){
//header("Pragma:public");
//header("Expires:0");
//header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
//header("Cache-Control:private",false);
header("Content-Disposition:attachment;filename=\"".$fName."\";");
header("Content-Type:application/octet-stream");
header("Content-Transfer-Encoding:binary");
header("Content-Length:".$fileSize);
readfile($fileName);
}
But the download does not work on an android device. On my computer, it isn't a problem. I already found a solution on http://www.digiblog.de/2011/04/android-and-the-download-file-headers/ but this didn't helped me here.
As mentioned in my blog posting that you cite, the success of your download on Android devices depends on multiple factors, which cannot be told by reading your code:
Your $fileName must contain an uppercase extension.
The pure URL that you call to download must contain all information needed for the download to start. No POST parameters may be involved, they will not be forwarded to the Android Download Manager and thus the download will fail. GET parameters (query string) are ok.
Also you did not obey the blog posting in all details:There is a semicolon after your Content-Disposition header which is fatal.
I also recommend to start with the Content-Type and Content-Disposition headers ONLY. When you got it working on Android, you can still add any other headers that you want to send. But do not forget to re-test on Android (multiple versions if possible) when you are complete. Android is really picky about some of those headers (or should I say "bitchy"?).
If all of this does not help you will have to provide some more information about your case. What exactly happens when you try it? What URL do you call. What are the parameters passed to your function?
Related
When generating a PDF in the browser programmatically (via PHP) the rendered PDF displays fine in both Firefox and Safari, but Chrome returns an ERR_INVALID_RESPONSE. It is a valid PDF - can be opened locally with Adobe Reader/Preview once saved from the working browsers, and will even open in Chrome once the PDF is saved from a different browser.
The PDF file is being read through file_get_contents(), is given a current timestamp and then passed to the browser. A workaround would involve saving the file to a temporary spot and redirecting the user (for Chrome, at least) but this is not ideal.
I've researched it and only been able to find bug reports dating from 2008.
I have an inkling it's a header error. After the PDF is generated, the following headers are sent to the browser (again working fine in FF, Safari and IE):
header('Content-type:application/pdf');
header("HTTP/1.1 200 OK");
I've also tried adding the following headers after searching on Stack Overflow, but to no avail:
header("Content-Transfer-Encoding: binary");
header('Accept-Ranges: bytes');
Are there missing headers that Chrome requires? Does anyone have experience with getting dynamically generated PDFs to display in Chrome?
EDIT: One of my more salient questions is what could be causing this to work fine locally in Chrome, but wouldn't work on a server environment.
In my case I had to add these 2 parameters to headers because wordpress was sending 404 code as it didn't recognize the url of my php function:
header("Content-type: application/pdf",true,200);
as stated in this answer on wordpress.stackexchange.
This forces the headers to replace (2nd param true) the 404 status code generated by wordpress as it does not recognize the custom url, and sets 200 OK (3rd param 200).
So it ended being something like this:
$pdf_name = "test.pdf";
$pdf_file = "/absolute/path/to/my/pdfs/on/my/server/{$pdf_name}";
header('Content-type: application/pdf',true,200);
header("Content-Disposition: attachment; filename={$pdf_name}");
header('Cache-Control: public');
readfile($pdf_file);
exit();
Try this
<?php
$filename = 'Physical Path to PDf file.pdf';
$content = file_get_contents($filename);
header("Content-type:application/pdf");
// It will be called downloaded.pdf
header("Content-Disposition:inline;filename='".basename($filename)."'");
header('Content-Length: '.strlen( $content ));
// The PDF source is in original.pdf
readfile($filename);
?>
<html>
<body>
...
...
...
Make sure that above header code is called before output of PHP script is
sent to browser.
I want to thank everyone for their answers.
It turns out this was not related to the headers. After attempting to change/remove headers in various ways (detecting encoding, trying with and without content-length, etc.) we decided to dig into the deeper httpd logs to see if anything was resolving differently for Chrome.
It turns out that mod_sec on our server was flagging the request (only from Chrome for some reason) as an attempt at a file injection attack and was returning a 403 forbidden response. Chrome displayed this as the ERR_INVALID_RESPONSE rather than a 403.
The hostname of the CDN was present in the request (we had ample checking at the endpoint to ensure that the file was indeed an allowed resource), and instead are building the URL out on the server instead.
My PHP script is outputting the contents of a .sql file, after it has been called by a POST request from my Delphi Desktop Client.
Here is what is happening:
My Desktop Client sends a POST request to my PHP Script.
The Script then calls mysqldump and generates a file - xdb_backup.sql
The Script then include "xdb_backup.sql"; which will print and return it to the Desktop Client, whereafter it deletes the SQL file.
The problem is, that the size of the SQL file can vary (for testing, I generated one that is 6 mb). I would like my desktop client to be able to show the progress, however the PHP script does not expose it's size, so I have no Progressbar.Max value to assign.
How can I make my PHP script let the Client know how big it is before the whole thing is over ?
Note: Downloading the SQL file is not an option, as the script has to destroy it. :)
You would do
$fsize = filesize($file_path);
where $file_path will be path to the generated file xdb_backup.sql,
to get the filesize in server and return headers with the following line attached.
header("Content-Length: " . $fsize);
Take a look at http://www.hotscripts.com/forums/php/47774-download-script-not-sending-file-size-header-corrupt-files-since-using-remote-file-server.html which explains a download php script.
You have to send a Content-Length header using header function. Something like this:
header('Content-Length: '.filesize('yourfile.sql'));
You may want to send the file using readfile instead of include.
You can set the Content-Length header with the size of xdb_backup.sql
I have written the following PHP function but still get the prompt to download the file:
function navigateToBytes($contentType, $bytes){
header('Content-Type: ' .$contentType);
//header('Content-Transfer-Encoding: binary'); // UPDATE: as pointed out this is not needed, though it does not solve the problem
header('Content-Length: '.strlen($bytes));
ob_clean();
flush();
echo $bytes;
}
An example of calling the function:
navigateToBytes('image/jpeg', $bytes); // UPDATE: turns out this does work, using image/tiff for tiff images is when the browser does not display the image
where $bytes are the bytes as read from the file.
Apologies all - turns out I was having the problem because the images I was testing were TIFF's (with the Content-Type correctly set to image/tiff) when I used a JPEG the browser would display the image!
Ultimately it is up to the browser to decide whether it can display the Content-Type you are sending.
For the record the only headers I needed to change was
Content-Type,
I should set
Content-Length
too unless I set
Transfer-Encoding: chunked
Try the HTTP header "Content-Disposition: Inline", however some browsers may try to save the user from seeing binary data. Here is a random blog article on that HTTP header:
http://dotanything.wordpress.com/2008/05/30/content-disposition-attachment-vs-inline/
That seems like correct behavior to me. The browser is a viewport for humans to view things in. Humans, by and large, don't want to view binary data. What do you think should happen?
Random Advice: If there's a site that's doing what you want to do, use curl to sniff the headers they're sending.
curl -I http://example.com/path/to/binary/file/that/displays/in/browser
and then use the exact same headers in your own script.
As a start, get rid of things that do not exist in HTTP (Content-Transfer-Encoding).
Then get an HTTP tracing tool, such as the Live HTTP headers plugin for Firefox, and compare "your" headers with those received for a working image.
In doubt, post the HTTP trace here.
OK, I've had a good read through the "Related Questions" section and I haven't found this answer.
I'm using an ajax request to force a php download. Things are working fine on the PHP end. Let's say I've got a stream of data called DATA. Now, I want to pop up a "Save as..." dialog.
The browser has received a string of hex values. Now, what do I do with this DATA on the client (javascript) side?
This is the PHP code that I'm using, per the link above:
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename=$file');
readfile($file);
I've tried
window.open(DATA) -> hex stream doesn't exist (of course)
submitting a form with the action as DATA -> same problem
BTW, If I echo the file from PHP then use window.open, it works sometimes. But not for txt files or jpgs etc.
I've seen this working on other sites - how are they doing it? Thanks in advance.
Here's the answer I was looking for:
window.open("downloadPage.php");
...which pops up a box every time. The problem with the ajax request was that the returned file stream was interpreted as XMLHttpRequestObj.reponseText.
The browser apparently interprets this differently and doesn't allow the download.
I am trying to build an application in which i have to stream the media files (audio and video) to the browser. I am reading the file through php and send the data to browser. I am using the following code.
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header("Content-Type: {$file->getMimetype()}");
header("Content-Disposition: inline; filename=".$filename.";");
header("Content-Length: ".strlen($file_content));
echo $file_content;
Every thing is working fine, except when i try to forward the video or audio, (I mean suppose current play location is 0:15 and it directly go to 1:25), media stops and when i press the play button again, it starts from the beginning.
I think the problem is with the buffering, but can't figure it out. Am i doing something wrong in header or something else is required.
Thanks.
I think you need to implement the Range header, so that the client can skip to a specific position in the file. You can probably find out what goes wrong by sniffing the request the player sends.
What you want is called "Content-Range requests"
Have a look here Resumable downloads when using PHP to send the file?
I came across this recently which may help you:
http://www.jasny.net/articles/how-i-php-x-sendfile/
Rather than passing the whole file through PHP (which eats up memory), you can use x-sendfile. This is an Apache module which allows you to run a PHP program, but pass control back to the web server to handle the actual file download once your code has done what it needs to do (authentication, etc).
It means that your PHP code doesn't have to worry about how the file is served; let the web server do what it's designed for.
Hope that helps.
Here is a good tutorial for it, you only want the PHP section but still:
http://www.devshed.com/c/a/PHP/Video-Streaming-PHP-Script-Tutorial/3/