简体   繁体   中英

Any downsides to using header(“Location:…”) for file downloads?

I'm setting up MP3 downloads on my site, and want people to click a link in an email to download a ZIP file of MP3s. I'd like the URL they click to not point directly to the file, so that I don't reveal the actual location – I might also add a time limit to the download etc.

So I'd been using readfile($file_url) and trying a lot of header() options but wasn't getting very far. Then I read you can just use:

header("Location: " . $file_url);

This seems to work OK in the browsers I've tested. Is there any downside of doing it this way versus readfile($file_url)?

Thanks!

No serious issue, just you actually reveal actual location of the file (attacker may try to guess addresses of files he should not have access to), client will have to make additional request to the server (delaying download just a few miliseconds) and sometimes, webbrowser have a bad day and decides to not follow the relocation for various reasons.

On bright side, this way you don't need to process the file through PHP, saving a tiny bit of server's resources (which is very questionable as readfile() function is pretty optimalized, compared to processing a new http request)


Back to your original problem, when serving file for download through PHP, you don't need anything more then 3 lines from following example:

<?php
//code copied from http://php.net/manual/en/function.header.php
// We'll be outputting a PDF
header('Content-type: application/pdf');
// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');
// The PDF source is in files/originalfile.pdf
readfile('files/originalfile.pdf');
?>

Just make sure to not print any string (not even UTF8 BOM characters from your source code) before using Header() function <- frequent problem.

"Downsides" depends on what you're trying to accomplish.

By setting the Location header, you're sending a redirect. The browser, indeed, will receive a response with HTTP status code 302 ("Found") and the new URL of the resource. Basically, you're redirecting them to another resource.
In order for this to work, the resource you're redirecting them to must be publicly accessible. That is: it needs to be an existing document inside the "document root" of your server.

This approach has certain characteristics that, depending on your requirements, may be considered as downsides:

  1. As written above, the resource must be publicly accessible. So, you cannot have your MP3 files in a separate, non accessible folder. Indeed, suppose your document root is in /var/www/public , you may want to put these files in a non accessible folder, like /var/www/resources , and serve them only through your PHP scripts.
  2. Your users will receive the URL of the resource, and so they can access the resource directly, without passing through your PHP script.

If these "characteristics" are not good for you, then you may want to avoid using the Location header.

Some PHP code to serve MP3 files can be:

$file = 'local/path/to/your_audio_file.mp3'; // the path on the local file system - ie. don't use "http://www.example.com"!

header('Content-Description: File Transfer');
header('Content-Type: audio/mpeg'); // audio/mpeg is the correct mime type for mp3 files
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));
readfile($file);
exit; // Could be a good idea to exit at the end

Some of the headers may be redundant, but they're to assure the best cross-browser compatibility. I took them (and then adapted) from http://php.net/manual/en/function.readfile.php

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM