6

我有一个 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 网守链接?

谢谢

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

4

5 回答 5

10

好的,让 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 是什么,这就是“安全性”。

于 2010-06-09T22:46:37.177 回答
2

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

于 2010-06-09T22:26:55.663 回答
1

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

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

它本身不会导致内存问题。readfile 不会将文件读入内存。但是,使用 PHP产生开销。您可以使用X-Sendfile消除一些这种延迟。

于 2010-06-09T22:25:55.750 回答
1
  1. 将文件放在无法通过 HTTP 访问的地方。
  2. 使用文件路径创建文件 ID 的数据库表。
  3. 通过文件 ID 链接到文件(如上所述,download.php?fileID=0000)。
  4. ???
  5. 利润。

作为以前(多年前)这样做的人,您需要考虑这将对您的服务器产生的内存影响。该readfile功能当时不可用,因此您可能不需要为内存考虑做任何特殊的事情。

于 2010-06-09T22:29:09.970 回答
1

您的方法会导致内存问题,但是可以分块读取和输出文件。在每个文件块之后,您都需要使用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

于 2010-06-09T23:32:35.103 回答