Downloading files over SSL with Internet Explorer

June 22nd, 2009

Everybody loves Internet Explorer, especially web developers. Rather than being a boring, predictable browser that does what you expect, there’s always a little quirk to keep you on your toes. There’s always some intriguing idiosyncrasy that ensures your day is not wasted by actually writing productive code, but instead spent trawling the statistical noise of Google in search of enlightenment.

Today I was informed by a customer that they couldn’t download a PDF document from a website I’d created for them. The PDF document was being accessed via the site’s administrative section, and was being downloaded via SSL. Of course, the predictably boring Firefox, Chrome, Safari and Operas of the world had no problems downloading the document, but Internet Explorer said this:

Internet Explorer cannot download [filename] from [website.com]

Internet Explorer was not able to open this Internet site. The requested site is either unavailable or cannot be found. Please try again later.

The reason for this annoyance is that on the server, PHP automatically sets a “Cache-Control” HTTP header with a value of “Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0″ if you’re using sessions. This is usually a good thing, and ensures you always get an un-cached version of your dynamically generated pages, however in the case of downloading attachments, things go a little bit wrong. Here’s what happens:

  1. Client makes a request for a page over SSL
  2. Server says: You can’t cache this response
  3. Server starts sending a PDF document
  4. Client tries to store response in a temporary file until the whole PDF document has been downloaded
  5. Internet Explorer remembers that it’s been asked not to cache the file. Since we’re using SSL, it must be really important, so throws the error message above.
  6. All other browsers ignore the “cache-control” header and temporarily store the document anyway.

A few sites are claiming that this is a bug, but KB316431 says this behaviour is by design. The purist in me admits (rather grudgingly) that Microsoft might be right here, and they have implemented things correctly. This doesn’t please my client however, who still can’t download his PDF.

So we need a solution. The obvious answer is to get rid of the “no-cache” part of our headers. If you’re using PHP sessions however, it’s not that simple. Just adding:

< ?php
  header("Cache-Control: private, max-age=1, pre-check=1");
?>

won’t work, as PHP’s session handling automatically adds it’s own “cache-control” header, and removes any others. The answer is as follows:

< ?php
  // Get rid of anything in the output buffer
  ob_clean(); 

  // Determine the size of the download
  $filesize = filesize($filename);

  // Close and save any session variables
  session_write_close();

  // Write some headers, including a modified "cache-control"
  header("Cache-Control: private, max-age=1, pre-check=1");
  header("Pragma: none");
  header("content-type: application/x-pdf");
  header("content-disposition: attachment; filename=\"downloaded-file.pdf\"");
  header("content-length: $filesize");

  // Send the file contents to the output buffer
  readfile($filename);

  // And we're done
  exit(0);
?>

The key here is to close the user session, preventing your “cache-control” header from being over-written by PHP automatically.

À bientôt!

5 Responses to “Downloading files over SSL with Internet Explorer”

  1. Rich Says:

    Thanks for this post, it helped me fix an annoying problem.
    One small correction to your post is the line:
    $filesize = sizeof($filename);
    should read:
    $filesize = filesize($filename);
    Also, content-size didn’t work for me. I needed to make it Content-Length
    and I used content-disposition: inline so that the adobe reader plugin could handle the file.
    Thanks for a great post.

  2. RRP Says:

    Rich,

    Thanks for spotting those bugs – they were probably caused by attempting to write code when it’s way past my bedtime. I’ve updated the post accordingly.

  3. Steve Says:

    Great post! Your advice was perfect and helped me resolve an otherwise baffling issue.

    Thanks :)

  4. Mike Says:

    Thanks for helping me out. I installed a secure server and transferred our internal site across. Everything worked except the downloaded pdf files generated by the system using fpdf.
    I added two lines

    header(“Cache-Control: private, max-age=1, pre-check=1″);
    header(“Pragma: none”);

    to each file and they work like a treat.

    Many thanks

    Mike

  5. Онлайн сексшоп XL: Севастополь Says:

    думаете Николай очень разгневан этими фразами

Leave a Reply