如何让具有所需权限的用户通过php下载文件?

发布于 2024-09-05 13:24:39 字数 730 浏览 10 评论 0原文

我有一个 php 文件,它充当我希望人们下载的所有文件的看门人,他们有足够的权限。

我使用的将文件扔给用户的代码是

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Content-disposition: attachment; filename=\"".$public_filename."\""); 
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: ".$f_filesize); 
readfile($file_path);

大多数文件都相当大.... 400mb-10GB。

什么是一个好方法来做到这一点,并保持真实位置+文件名的秘密,这样人们就不能直接链接到文件,而必须通过我的 download.php?file=ID gatewaykeeper 链接?

谢谢

编辑:我不是问如何进行用户身份验证,所有这些都已完成。我只是问我的做法在大规模上是否是一个好主意。如果我继续读取 10GB 文件,似乎可能会导致内存问题。

I have a php file that acts as a gatekeeper for all the files I want people to download, who ahve sufficient privilages.

The code I use throw the file to the user is

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header("Content-disposition: attachment; filename=\"".$public_filename."\""); 
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: ".$f_filesize); 
readfile($file_path);

Most files are fairly large.... 400mb-10GB.

What would be a good way to do this, and keep the true locations + filenames secret, so people cant just link to the files directly, but HAVE to link thru my download.php?file=ID gatekeeper?

Thanks

EDIT: Im not asking how to do user authentication, all that is done. Im just asking if my way of doing it, is a good idea on a large scale. Seems like it could cause memory problems if I keep reading 10GB files.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

醉殇 2024-09-12 13:24:39

好吧,让 php 发送大约 400Mb–10Gb 的文件并不好。您需要以某种方式让您使用的任何网络服务器实际提供文件服务。

这实际上取决于您需要它的安全程度。想到的最简单的解决方案(但远非最安全)是使用链接到原始文件的带有长随机名称的符号链接。一段时间后,符号链接就会过期并被删除。每个用户都会获得自己正在下载的文件的符号链接(或“令牌”)。我不确定这在 Windows 环境中如何发挥作用,但在 UNIX 上无论如何它都相当简单。

下面是一些伪代码:

if($user->isAllowedToDownload($file)){
    $token = md5($user->name . $file->name . time() . $someGoodRandomValue);
    symlink($file, $download_path . $token);
    header("Location: $download_url$token"); 
}

然后您需要一个 cron 作业来清除旧的符号链接。您还需要确保网络服务器设置为遵循符号链接,最好仅针对创建这些下载令牌的文件夹。

因此,当用户请求domain.com/download?file=bigfile.mp4时,会在网络服务器公共空间中创建一个符号链接,该链接指向网络服务器公共空间之外的真实文件。用户可能被重定向到domain.com/getFile/ab739babec890103bdbca72,这反过来又导致网络服务器提供该文件。现在,用户很难尝试猜测文件的 URL 是什么,这就是“安全性”。

Ok, having php send files of around 400Mb–10Gb is not good. You need to somehow let whatever webserver you're using actually serve the files.

This really comes down to how secure you need it to be. The easiest solution that comes to mind (but far from the most secure) is using symbolic links with long random names that link to the original file. After a certain time the symbolic links expire and are removed. Each user get their own symbolic link (or "token") to the file they're downloading. I'm not sure how this plays out in Windows-environment, but on unix it's fairly straightforward anyway.

Here's some pseudo code:

if($user->isAllowedToDownload($file)){
    $token = md5($user->name . $file->name . time() . $someGoodRandomValue);
    symlink($file, $download_path . $token);
    header("Location: $download_url$token"); 
}

Then you need a cron job that cleans out old symbolic links. You also need to make sure the webserver is set to follow symbolic links, preferably only for that folder where these download tokens are created.

So when the user maybe requests domain.com/download?file=bigfile.mp4 a symbolic link is created in the webservers public space that points to the real file outside the webservers public space. The user gets redirected to maybe domain.com/getFile/ab739babec890103bdbca72 which in turn causes the webserver to serve the file. Now it's very hard for users to try and guess what an URL is for a file, and that's the "security".

胡渣熟男 2024-09-12 13:24:39

您已经这样做了 - $public_filename 是您想要的名称,readfile($file_path) 部分是文件 - 它的位置未公开。除此之外,它可能位于文档根目录之上。

You're already doing that - the $public_filename is what you want it called, the readfile($file_path) part is the file - it's location isn't made public. Past that, it could be above the document root.

吃不饱 2024-09-12 13:24:39
  1. 将文件放在无法通过 HTTP 访问的位置。
  2. 创建文件 ID 和文件路径的数据库表。
  3. 通过文件 ID 链接到文件(如上所述,download.php?fileID=0000)。
  4. ???
  5. 利润。

作为以前(很多年前)这样做过的人,您需要考虑这将对您的服务器产生的内存影响。 readfile 函数当时不可用,因此出于内存考虑,您可能不需要执行任何特殊操作。

  1. Put the files somewhere that is not accessible via HTTP.
  2. Create a database table of file IDs with file paths.
  3. Link to the files via file ID (as you noted above, download.php?fileID=0000).
  4. ???
  5. Profit.

As someone who did this previously (many years ago), you need to consider the memory impact this will have on your server. The readfile function was not available then, so it is possible you may not need to do anything special for memory considerations.

ぃ双果 2024-09-12 13:24:39

您需要以某种方式对它们进行身份验证(HTML 表单、HTTP 基本身份验证,等等),然后设置一个 session 标志,您的 download.php 脚本可以检查该标志。请注意,这并不会阻止人们下载该文件,然后自行分发。

您应该配置您的网络服务器,以便无法直接访问真实文件。

它本身不会导致内存问题。 readfile 不会将文件读入内存。然而,使用 PHP产生开销。您可以使用 X-Sendfile 消除部分延迟。

You'll want to somehow authenticate them (an HTML form, HTTP basic auth, whatever), then set a session flag, which your download.php script can check. Note that this doesn't prevent people from downloading the file, then distributing it themselves.

You should configure your web server so the real files are not directly accessible.

It's not going to cause memory problems per se. readfile does not read the file into memory. However, using PHP will create overhead. You can eliminate some of this delay by using X-Sendfile.

风柔一江水 2024-09-12 13:24:39

您的方法将导致内存问题,但是可以分块读取和输出文件。您需要在 之后使用 flush() 函数echo 文件的每个块。您还可以花费更多的精力来恢复下载。但这仍然是一种需要大量 CPU 的方法。

更简单、更好的解决方案是使用 apache 和 lighttpd 通过其模块支持的“x-sendfile”标头标签。您所要做的就是在标头中指定文件名,类似于:

header('X-Sendfile: filename-on-your-file-system');

Lighttpd 的链接:

http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file

Your method will cause memory problems, however it is possible to read and output the file in chunks. You will need to use flush() function after you echo each chunk of file. You can also make resuming downloads to work with a little more effort. Still this is an CPU hungry approach.

The easier and better solution is to use "x-sendfile" header tag supported by both apache and lighttpd through their modules. All you'll have to do is just specify file name in your header, similar to this:

header('X-Sendfile: filename-on-your-file-system');

Link for lighttpd:

http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文