简体   繁体   English

使用标头(“ Location:…”)进行文件下载有什么缺点?

[英]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. 我正在网站上设置MP3下载,并希望人们单击电子邮件中的链接以下载MP3的ZIP文件。 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. 我希望他们单击​​的URL不要直接指向文件,以便不透露实际位置-我可能还会为下载等添加时间限制。

So I'd been using readfile($file_url) and trying a lot of header() options but wasn't getting very far. 因此,我一直在使用readfile($ file_url)并尝试许多header()选项,但步伐并不很快。 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)? 与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) 从好的方面来说,这种方式不需要通过PHP处理文件,从而节省了服务器的一小部分资源(与处理新的http请求相比,readfile()函数的优化程度非常高,这是非常可疑的)


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提供文件供下载时,您仅需以下示例中的3行即可:

<?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. 只需确保在使用Header()函数<-常见问题之前,不要打印任何字符串(甚至不显示源代码中的UTF8 BOM字符)。

"Downsides" depends on what you're trying to accomplish. “缺点”取决于您要实现的目标。

By setting the Location header, you're sending a redirect. 通过设置Location标头,您将发送重定向。 The browser, indeed, will receive a response with HTTP status code 302 ("Found") and the new URL of the resource. 实际上,浏览器将收到带有HTTP状态代码302(“已找到”)和资源的新URL的响应。 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. 因此,您不能将MP3文件放在单独的不可访问的文件夹中。 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. 确实,假设您的文档根目录位于/var/www/public ,您可能希望将这些文件放在一个不可访问的文件夹中,例如/var/www/resources ,并仅通过您的PHP脚本来提供这些文件。
  2. Your users will receive the URL of the resource, and so they can access the resource directly, without passing through your PHP script. 您的用户将收到资源的URL,因此他们可以直接访问资源,而无需通过您的PHP脚本。

If these "characteristics" are not good for you, then you may want to avoid using the Location header. 如果这些“特征”对您不利,那么您可能要避免使用Location标头。

Some PHP code to serve MP3 files can be: 一些用于提供MP3文件的PHP代码可以是:

$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 我从http://php.net/manual/en/function.readfile.php拿走(然后改编)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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