views:

572

answers:

3

Folks, I know there have been lots of threads about forcing the download dialog to pop up, but none of the solutions worked for me yet.

My app sends mail to the user's email account, notifying them that "another user sent them a message". Those messages might have links to Excel files. When the user clicks on a link in their GMail/Yahoo Mail/Outlook to that Excel file, I want the File Save dialog to pop up.

Problem: when I right-click and do "Save As" on IE, i get a Save As dialog. When I just click the link (which many of my clients will do as they are not computer-savvy), I get an IE error message: "IE cannot download file ... from ...". May be relevant: on GMail where I'm testing this, every link is a "target=_blank" link (forced by Google).

All other browsers work fine in all cases.

Here are my headers (captured through Fiddler):

HTTP/1.1 200 OK
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Content-Length: 15872
Via: **** // proxy server name
Expires: 0
Date: Tue, 20 Oct 2009 22:41:37 GMT
Content-Type: application/vnd.ms-excel
Server: Apache/2.2.11 (Unix) DAV/2 mod_ssl/2.2.11 OpenSSL/0.9.8i mod_python/3.3.1 Python/2.5.2 SVN/1.4.6 mod_apreq2-20051231/2.6.0 mod_perl/2.0.4 Perl/v5.10.0
Cache-Control: private
Pragma: no-cache
Last-Modified: Tue, 20 Oct 2009 22:41:37 GMT
Content-Disposition: attachment; filename="myFile.xls"
Vary: Accept-Encoding
Keep-Alive: timeout=5, max=100

I want IE's regular left-click behavior to work. Any ideas?

+1  A: 

If your trying to get the file to download every time, change the content type to 'application/octet-stream'.

Try it without the pragma statement.

txyoji
+4  A: 

This will check for versions of IE and set headers accordingly.

// assume you have a full path to file stored in $filename
if (!is_file($filename)) {
  die('The file appears to be invalid.');
}

$filepath = str_replace('\\', '/', realpath($filename));
$filesize = filesize($filepath);
$filename = substr(strrchr('/'.$filepath, '/'), 1);
$extension = strtolower(substr(strrchr($filepath, '.'), 1));

// use this unless you want to find the mime type based on extension
$mime = array('application/octet-stream');

header('Content-Type: '.$mime);
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.sprintf('%d', $filesize));
header('Expires: 0');

// check for IE only headers
if (isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false))) {
  header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
  header('Pragma: public');
} else {
  header('Pragma: no-cache');
}

$handle = fopen($filepath, 'rb');
fpassthru($handle);
fclose($handle);
cballou
Thank you SOOO much. Saved my life! And I'm back to sane again :)
Alex
post-check and pre-check don't do what you think they do. You should take them out.
EricLaw -MSFT-
A: 

Your no-cache directives (Vary, Expires, Pragma) are causing the problem.

See http://blogs.msdn.com/ieinternals/archive/2009/10/02/Internet-Explorer-cannot-download-over-HTTPS-when-no-cache.aspx

EricLaw -MSFT-