Jack Humphries
Jack Humphries

Reputation: 13267

PHP won't show page and download

I'm trying to show a HTML page with PHP right before it downloads a file. I understand that I can't redirect to a different page and download a file at the same time, but why wouldn't this work?

echo "<html>...Example web page...</html>";

$download = '../example.zip'; //this is a protected file

header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename=example.zip');
readfile($download);

The file downloads, but it never shows the HTML page that is echoed. But if I remove the download, the page shows.

Upvotes: 0

Views: 362

Answers (4)

user849137
user849137

Reputation:

Because you cannot output anything before pushing custom headers out, I would suggest using JS to redirect to the download, which usually keeps you on the same page (as long as you're just disposing the zip content and nothing else).

So, try this:

$download = 'example.zip';

echo '<head> <script type="text/javascript"> function doRedirect(){window.location = "'.$download.'"}</script>

</head><html><script type="text/javascript"> doRedirect() </script> <...Example web page...</html>';

Or if you need a timer on it:

echo '<head> <script type="text/javascript"> function doRedirect(){window.location = "'.$download.'"}</script>

</head><html><script type="text/javascript"> 
setTimeout(doRedirect,1000);//wait one second</script> <...Example web page...</html>';

EDIT:

If you want to hide the file path, I would suggest making a download script, which JS will redirect to.

So basically, do exactly what you're doing, then use JS to point to it. Like this:

Download.php:

//use an ID or something that links to the file and get it using the GET method (url params)

    $downloadID = $_GET['id'];
    
    //work out the download path from the ID here and put it in $download
if ( $downloadID === 662 )
{
    $download = 'example.zip';//...
 }   
    header('Content-Type: application/zip');
    header('Content-Disposition: attachment; filename=$download');
    readfile($download);

And then in your main HTML file, use JS to point to it, with the correct ID:

<head> <script type="text/javascript"> function doRedirect(){window.location = "Download.php?id=662"}</script>

</head><html><script type="text/javascript"> doRedirect() </script> <...Example web page...</html>

Upvotes: 0

uınbɐɥs
uınbɐɥs

Reputation: 7351

As has already been said, you cannot send headers after output is already sent.

So, this may work for you:

header('Refresh: 5;URL="http://example.com/download.php"');
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename=example.zip');
readfile($download);

http-equiv in <meta http-equiv="refresh" means the name and value is equivalent to an HTTP header, so it does the same thing the Refresh: header.

Download any file from SourceForge, and you will see a JavaScript implementation (Your download will start in 5 seconds...).

Upvotes: 0

Tim Lytle
Tim Lytle

Reputation: 17624

You can't set header information after content is sent to the browser. If you're actually getting the download - there's likely some output caching going on someplace.

For what you're trying to accomplish, you may want to show the HTML content, and use a <meta> tag or JavaScript to redirect to the download script. I believe most browsers will start the download while keeping the last loaded page visible to the user (which should be essentially what you want to do).

<meta http-equiv="refresh" content="1;URL='http://example.com/download.php'">

Or:

<script type="text/javascript">
  window.location = "http://example.com/download.php"
</script>

Upvotes: 1

xdazz
xdazz

Reputation: 160883

There is a simple principle:

Remember that header() must be called before any actual output is sent, either by normal HTML tags, blank lines in a file, or from PHP.

The solution is to prepare two page, one for show the html content, one for download.

In page 1, using javascript to set a timer to redirect to the download link after several time.

For example, "After 5 second, the download will begin.".

Upvotes: 0

Related Questions