Force download using PHP, then redirect

I know that this question has been asked many times, but I can not find the answer according to my needs.

I need to find a way to force the download of the file, and then, after the start of the download, redirect to the "thank you for downloading" page.

So far, I:

<?php ob_start(); $token = $_POST['validationCode']; if(isset($token)){ $connect = mysql_connect('localhost', 'root', 'root'); $db = mysql_select_db('mydb'); if (!$connect || !$db){ die('Connect Error (' . mysql_connect_errno() . ') ' . mysql_connect_error()); } $sql = mysql_query("SELECT * FROM emailaddresses WHERE token='$token'"); $result = mysql_fetch_array($sql); if($result){ header('Location: complete.php'); header('Content-type: application/mp3'); header('Content-Disposition: attachment; filename=track.mp3'); $f = file_get_contents('downloads/track.mp3'); print $f; $sql = "UPDATE emailaddresses SET download=1 WHERE token='$token'"; $result = mysql_query($sql); } else{ echo "There was a problem downloading the file" . mysql_error(); } } ob_end_flush(); ?> 

It is important to hide the location of the download file, otherwise I would just create an HTML link for the file.

I obviously can't put the redirect header under the other headers, as it just won't work. I can’t figure out where to go further than opening this pop-up and directing the main window to the thank you page, but this is a LAST resort.

Can anybody give any suggestions?

Greetings

Rich

+4
source share
3 answers
  • You cannot hide the location of the file. This will be clearly visible to anyone who is enough to find it, because the browser needs to know the URL to download the file.
  • You cannot do this with two header redirects in a row, as you said. You can redirect to another page after some timeout using Javascript.

There really is not much choice. If your main goal is to hide the url, then this is the loser. For good usability, you usually use the equal link on the page ("Download does not start? Click here ..."), as the user may accidentally cancel the redirect at the most inopportune time to permanently kill the download.


You cannot output anything but the file itself in the same request / response. You can try multi-part HTTP responses as suggested by @netcoder, but I'm not quite sure how well this is supported. Just start by assuming that there is one “lost” request / response in which only the file is uploaded and nothing else happens. The way they usually work with this restriction is as follows:

  • The user clicks the download link or submits a form with his email address or everything necessary to start the download process.
  • The server returns "Thank you for downloading from us! Your download will begin soon ...".
  • This page contains a Javascript or <meta> refresh or HTTP Refresh header, which causes the file URL to be delayed redirects.
  • The "Thank you" page will be "redirected" to the file location, but since this leads to the download of the file, the page will not noticeably change, the download will start.

See http://download.com for an example of this in action.

You can make a download location for a script file that returns a file only if the user is allowed to download the file. You can transfer a temporary token between the "Thank you" page and the file download page to make sure the download is allowed.

+5
source

The only way in PHP that I know (for downloading, and then for redirecting) is to use an HTTP response with several parts. Something like that:

 define('MP_BOUNDARY', '--'.sha1(microtime(true))); header('Content-Type: multipart/x-mixed-replace; boundary="'.MP_BOUNDARY.'"'); flush(); echo "Content-Type: application/zip\r\n"; echo "Content-Disposition: attachment; filename=foo.zip\r\n"; echo "\r\n"; readfile('foo.zip'); echo MP_BOUNDARY; flush(); echo "Content-Type: text/html\r\n"; echo "\r\n"; echo '<html><script type="text/javascript">location.href="http://www.google.ca";</script></html>'; echo MP_BOUNDARY.'--'; flush(); 

In your case, you can simply display the contents of the "Thank you for downloading" page, rather than redirecting JavaScript.

I'm not sure if it works on all / main browsers or not.

+1
source

Well, firstly, the browser needs to know the location of the file to download it. Anyone who opens a standard browser, such as Firebug, will be able to see the URL of your file in text format.

Now, I suppose, you want to protect your file from unauthorized downloads. If this is what you want, there is a way to use the session.

On the first page, you put your code to check if the download is allowed. Then you will enter a current session with something that identifies the file. Everything that is unique to the file will be done, for example, by the database identifier.

 $_SESSION['download_key'] = time(); 

Then you redirect to a page with an html meta-tag like this

 <meta http-equiv="refresh" content="5;/download.php?file=download_key" /> 

This is the page where you say: "Thank you, wonderful guy for downloading my wonderful file." Note that you can also put the contents of the "content" attribute in the header file if you wish, for example

 header('Refresh: 5;/download.php?file=download_key'); 

Note that 5 is the number of seconds until the download file dialog box appears.

Then on download.php you will do the following:

1- Check which file was requested with $ _GET ['file'].

2- Then you check if the download_key file exists in the session. If not, you exit the script this way

 if (!isset($_SESSION['download_key'])) die('Unauthorized'); 

3- Then you check if the time stamp is older than any arbitrary time limit. Here from 30 s

 if ($_SESSION['download_key'] - time() > 30) die('Unauthorized'); 

4- Finally, if everyone exits, you send such a file

 header('Content-disposition: attachment; filename=myfile.ext'); header('Content-type: bin/x-file-type'); //Change for the correct mimetype readfile('myfile.ext'); 

After reading the file, you put the code to set the download to 1 in the database.

And that he, the secure file download and anyone using the URL, would be welcomed with large “unauthorized” text.

I would also like to add that if you have a large file (more than a few kilobytes), you might be better off disabling output buffering, as this would mean that php will keep a copy of the file in memory for the entire download period. Using the readfile function, php will send it to the browser when it reads it on disk and, therefore, will use less memory (and will start sending data earlier).

EDIT: What makes it work:

I actually reversed the sequence: the visitor is first redirected to the thank you page containing the Refresh header / tag. The magic of the Refresh header is that it redirects AFTER the content is loaded. After viewing the thank you page, the browser, after seeing this heading, wait for the specified time, showing the page, and then redirected to download. After redirecting, the browser sees that its file will be downloaded and instead of changing the page, it simply displays the download file dialog box. As soon as the user clicks OK, the download will begin, but he will remain on the same page.

In short, you do not need to redirect after downloading the file, since you are already on the thank you page! I don’t think you can even redirect it after downloading the file. See what happens when you click on a link pointing to a direct file on a web server. The browser requests to download, but does not disable navigation. As soon as the download starts, you can happily move away from the page with the link. When the download is finished, you may be on a completely different website. That’s why you can only show a thank you page. But if you put a zero for the title / update tag, the download prompt will appear immediately after the page loads, so it’s almost the same as if they were at the same time (in the eyes of the visitor)

+1
source

Source: https://habr.com/ru/post/1347016/


All Articles