Jump to content

Download works... following web page never appears


jhsachs

Recommended Posts

I'm working on a pair of scripts that (among other tasks) download a file to the user's browser. It's not working right, and I'm having trouble figuring out why.

 

The overall design is: the first script (I'll call it one.php) contains a form which displays a list of radio buttons representing actions that the site can perform. The user clicks a radio button, then a "submit" button. This loads two.php, which determines what action the the user selected, performs the action, and loads a page that contains another form. This form has a couple of "submit" buttons; one reloads one.php, and the other goes elsewhere.

 

Everything works right except when the user selects the "download a file" option. In that case two.php downloads the file (and that part works perfectly), then -- nothing. The page defined in two.php never appears. The browser just sits displaying the page from one.php as it was when the submit button was clicked.

 

I played with the code and found that if I comment out all of the download headers, so that the browser gets the raw contents of the downloaded file followed by an HTML page, the browser does just what I'd expect: it displays the file (represented as a stream of semi-binary garbage), followed by an HTML page. Something in the download headers is upsetting it... but I can't figure out what.

 

Here is the code that sends the headers:

 

      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) );
      if (ob_get_length() > 0) {
         ob_clean();
      }
      flush();
      readfile($file);
      flush();

Following that, the script includes a file that contains another block of PHP code, then the <!DOCTYPE> tag, with no intervening characters outside the PHP. (BTW, the PHP block contains nothing but comments!)

 

Can anyone suggest what's going wrong here?

Link to comment
Share on other sites

I'm not sure if you're confused with MIME headers, but browsers can/will only read a single HTTP response content-type header. Currently you're trying to send "application/octet-stream", followed by HTML which would need "text/html" -- I'm guessing anyway, you haven't shown much of your code.

 

This means you need to have separate requests for downloading the file and displaying the page, so that you can send separate responses back. You will need to display the page first though, because you can't return a location header (redirect after download) with a message-body. Then you need to request the file for download, which you can use a meta refresh tag to make the process seem instant (though I would include a hard link to the file just to be sure).

Link to comment
Share on other sites

Adam, thank you for wading in here. I'll study your post some more when I have time tonight, but so far it doesn't make much sense to me.

 

I'm quite aware that a Location header has to be the first text sent to the browser if it is to be executed, but I wasn't aware that the same applies to other headers; it's not clear which ones or how to make it happen in a case like this.

 

I'm having the most trouble with the explanation of how to make the browser do what I want by sending the page before the download. Perhaps you can write a script of the interaction (a script in the theatrical sense) to clarify this.

Link to comment
Share on other sites

Just to clarify: headers are sent before/ahead of the output. Once the first byte of output is sent, that triggers PHP to first send the headers. So obviously after that point the headers have been sent and you can't send any more. Think of it like a HTML document structure, you can't have a second <head> embedded within the <body>.

 

In order to achieve what you're after, you need to first take the user to the success/confirmation type page, and then fire off a second request (meta redirect, with hard link to be sure) to the file. The browser won't redirect away from the current page, but the download will start (or a pop-up asking what the user wants to do). If you make the redirect instant it should have just finished loading the page when the download starts.

 

Does that explain it better?

Link to comment
Share on other sites

That does indeed explain it better.

 

Last night and this morning I experimented and got a better understanding of it myself. My code is sort of working now -- it's doing the thing right, but it's still not doing exactly the right thing.

 

There are two remaining problems. The first one is that the whole idea of this (as defined by the client) was to download some content, then display a page which says in essence "You're done! Here are the things you can do next..." Now it displays the page that says "You're done!" before it downloads the page, making "You're done!"seem  confusing or foolish.

 

What I really want to do is download the file -- a process that is not completed until the user clicks "Save," if the browser is configured to prompt for a save location -- then display the "You're done!" page, without waiting for the user to click another button.

 

So far I don't see how the technique you showed me can be used to do that, and I'm a little concerned that there may not be a way to do it.

 

I ran across the second problem while looking for model code. I didn't find useful code -- I ended up adapting the code I'd already written -- but I did find this post, which cautions against using the technique that you described, and I have now adopted.

 

http://www.sitepoint.com/forums/showthread.php?606376-IE-problem-with-META-refresh-for-download

 

The reason given is that Internet Explorer reacts badly to the meta refresh tag when used with its default security settings. I tried this with IE8, and I got the most astonishing succession of confusing and intimidating  messages before IE finally let me download my file.

 

First, it advised me that "To help protect your security, Internet Explorer has restricted this site from showing certain content." I assumed the persona of a user who trusts the site more than they trust IE and told it to go ahead by clicking the message. It displayed a little context menu. I selected "Download blocked," which displayed a secondary menu, and I selected Download the file." It then loaded the page that says "You're done," which contains the meta refresh tag, and displayed the "To help protect your security..." message again. I went through the same rigmarole a second time and was rewarded by a blank page (the browser tab actually said "Blank Page"!) with a dialog box that said, "To display the webpage again, the web browser needs to resend the information you've previously submitted."I clicked the box's Retry button and got the "You're Done!" page again, with a dialog box that asked, "Do you want to open or save this file?" I clicked Save and was prompted for a location; then it downloaded the file.

 

This just isn't workable. If we can't find a way to make IE more cooperative, we'll have to find a completely different approach.

 

Link to comment
Share on other sites

Ah apologies for that. I haven't used the META refresh tag for a long time. You could try using a JavaScript redirect, but I'm not sure if that would trigger the same sort of messages? I don't have IE8 on my work computer, but you can test it yourself:

 

window.onload = function()
{
    // Redirect to download file after page has finished loading
    location.href = 'path/to/file.ext';
}

 

Again I would include a hard link just in-case.

Link to comment
Share on other sites

I tried an alternate means of loading the page, but I got the same result. It looks like this behavior is beyond program control.

 

I can make things better by providing detailed instructions, but I think we're going to have to depose download in favor of email as the preferred method of delivery.

 

Thanks for your assistance. I had to make it work, even if it doesn't work well, and you made that possible.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.