So, IE7 keeps logging my clients out if they try to download files from my website. The files are downloaded indirectly with a download script which uses something like:
private static function SendHeaders($theFileNameServer=NULL, $theFileNameClient, $theMimeType, $theSize)
{
$aBegin = 0;
$aEnd = $theSize;
// 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='.$theFileNameClient.';');
/*
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:'.($aEnd-$aBegin));
self::FlushX();
}
private static function FlushX(){
// check that buffer is actually set before flushing
if (ob_get_length()){
#ob_flush();
#flush();
#ob_end_flush();
}
#ob_start();
}
So, it seems the cache headers are somehow confusing IE7 and making it dump all cookies or something.
Any workaround for this problem? My login system works great in Firefox, Chrome etc.
Related
User on my site can download files. Sometimes these files are pretty large and I would like users to see download progress bar at their browsers.
I use the following code to give user a file:
header('Content-Type: text/xml');
header('Content-Disposition: attachment; filename='.$fileName);
header('Pragma: no-cache');
header('Content-Transfer-Encoding: binary');
header('Pragma: public');
header('Content-Length: '.filesize($fullFileName));
header("Content-Description: File Transfer");
$fileHandler = fopen($fullFileName, 'r');
while(!feof($fileHandler)){
echo fread($fileHandler, 2048);
}
fclose($fileHandler);
When I run this script browser(FireFox) freezes for some time, I can see loading colour circle and only after save/open dialog file appears. When I click on "save" button, file almost immediately is downloaded to my computer(while file is quite large - 50 Mb).
I want to have downloading system like on this site. Dialog for save/opean appears immediately when you click on any links. And after you can see downloading progress in your browser.
Are there any special headers to display progress bar in browser? How I should change my code?
I use the code below, and in Firefox it does give me the download time and progress:
// send headers first
header('Content-type: application/octet-stream');
header('Content-Transfer-Encoding: binary');
header('Content-disposition: attachment; filename='.$FileName);
header("Content-Length: ".filesize($Path));
// then use an easy way to flush and end all output buffers
while (#ob_end_flush());
// flush file
readfile($Path);
It should work if you specify Content-Length correctly. The only thing I find mildly weird in your code is the Content-Type: text/xml header. Note that I use Content-type: application/octet-stream.
I have a .dmg file on my IIS server. When downloading directly the file opens just fine, but when I serve the file via PHP like so
$mime_types['dmg'] ='application/x-apple-diskimage';
$filename = getfile($_GET['dc']);
$fakename = fakefilename($_GET['dc']);
$extension = fileexten($filename);
if(($filename!= false)&&($fakename!=false&& #fopen($filename,'r')==true)){
$mime = contenttype($extension);
set_time_limit(0);
header('Pragma: public');
header('Expires: 0');
header("Content-Type:".$mime);
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Disposition: attachment;filename='.$fakename.'.'.$extension);
header("Content-Transfer-Encoding: binary");
if (ob_get_length() > 0) {
ob_end_clean();
}
flush();
#readfile($filename);
}
I get an error on the mac saying 'disk image not recognized'
I've also tried setting the .dmg application/octet-stream but I still run into the same issue.
My guess is that that this is either a case in which the content type is not set correctly or in which the content length is incorrectly set. Check to see if $mime = contenttype($extension); returns the correct content type.
It would be useful to debug this with a web debugging proxy tool (like Fiddler or Charles) and post the entire response header, when accessing the file directly & when you access it via your PHP script.
UPDATE (based on the comments below):
The script had additional line breaks at the end of the file, which were being sent out in the response.
I am using the following code to present a file for download to the user... in this case it is a .csv file. Works great in all browsers, BUT in IOS it loads the file in the mobile safari browser. The exact same code works fine for a .zip file (although ios gives the warning it cannot download that type of file).
What gives? Does ios completely disregard the headers or what?
if (is_file($local_path.$file))
{
//get current ts
$now = time();
// set the headers and prevent caching
header('Pragma: public');
header('Expires: -1');
header('Cache-Control: public, must-revalidate, post-check=0, pre-check=0');
header('Content-Disposition: attachment; filename="'.$now.'_'.$file.'"');
// set the mime type based on extension
header('Content-Type: application/octet-stream');
header('Content-Length: '.filesize($local_path.$file).'');
//download
readfile($local_path.$file);
//delete file
unlink($local_path.$file);
}
I guess I have to break down and ask for help. (Should have done it 3 days ago!)
Here's what happens...
PHP reads session & post variables, builds a .csv file from a mysql query.
it attempts to open a 'Save As' dialog box and when that's done, jump to another page.
I'm using nested functions but when run, the dialog box seems to get run over and never appears.
separately the functions work fine.
when run, the 'save as' dialog box doesn't wait for user input
Can anyone see what I've done wrong or can you redirect my thinking?
$filename points to the created CSV file on the server
$suggname is a default filename users should see in the dialog box.
The code:
holdit($filename,$suggname);
function holdit($filename,$suggname) {
$fp=#fopen($filename, 'rb');
if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) {
header('Content-Type: "application/octet-stream"');
header('Content-Disposition: attachment; filename="'.$suggname.'"' );
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
header("Content-Length: ".filesize($filename));
} else {
header('Content-Type: "application/octet-stream"');
header('Content-Disposition: attachment; filename="'.$suggname.'"' );
header("Content-Transfer-Encoding: binary");
header('Expires: 0');
header('Pragma: no-cache');
header("Content-Length: ".filesize($filename));
}
fpassthru($fp);
fclose($fp);
jump();
}
function jump() {
header('Location: return_from_csv.php');
}
You are adding lots of headers to your HTTP response. One of those is Location which instructs the browser to redirect. Obviously it is interpreting that as a higher priority than your other headers.
Decide if you want to redirect or serve a file in your response and do one or the other.
I suspect you have misunderstood the Location header. Read this: http://en.wikipedia.org/wiki/HTTP_location
By the looks of things you are trying to serve the CSV file and then redirect to another page. Sorry, you cannot do this. An HTTP response does one thing and one thing only. You might consider opening your link to the CSV file in another window using the target attribute of <a>.
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