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

时间:2010-06-09 22:21:40

标签: php readfile downloading

我有一个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文件,它似乎可能会导致内存问题。

5 个答案:

答案 0 :(得分: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作业。您还需要确保将Web服务器设置为遵循符号链接,最好仅限于创建这些下载令牌的文件夹。

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

答案 1 :(得分:2)

你已经这样做了 - $public_filename是你想要的,readfile($ file_path)部分是文件 - 它的位置不公开。过去,它可能在文档根目录之上。

答案 2 :(得分:1)

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

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

本身不会导致内存问题。 readfile不会将文件读入内存。但是,使用PHP 创建开销。您可以使用X-Sendfile消除部分延迟。

答案 3 :(得分:1)

  1. 将文件放在无法通过HTTP访问的地方。
  2. 使用文件路径创建文件ID的数据库表。
  3. 通过文件ID链接到文件(如上所述,download.php?fileID = 0000)。
  4. ???
  5. 利润。
  6. 作为之前(很多年前)这样做的人,您需要考虑这将对您的服务器造成的内存影响。 readfile函数当时不可用,因此您可能不需要为内存考虑做任何特殊操作。

答案 4 :(得分:1)

您的方法会导致内存问题,但是可以以块的形式读取和输出文件。在echo每个文件块后,您需要使用flush()函数。您还可以稍微努力地恢复下载。这仍然是一种渴望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