2010-11-10 63 views
3

我有一个带有文件下载选项的网站。然而,不是每个人都可以下载每个文件。例如,如果我以管理员身份登录,我可以下载所有文件,但如果我以客户身份登录,我只能下载某些文件。使用Apache和PHP的选择性文件下载权限

目前,所有这些文件都存储在Web根目录之外的目录中,因此用户不能手动下载。我制作了一个PHP脚本来管理文件的下载,但它非常麻烦。我试过几件事情:

1:

echo file_get_contents($file); 

2:

readfile($file); 

3:

if (($handle = fopen($file, "rb")) !== false) 
{ 
    while (!feof($handle)) 
    { 
    echo fread($handle, 4096); 
    } 
    fclose($handle); 
} 

我发现所有的这些方法与测试时是非常不可靠500MB文件。第一个和第二个都会因所有浏览器和随机百分比而失败。有时候他们在几兆字节后就已经失败了,而其他时候他们已经达到了80%。但最终他们会停止下载没有任何错误。

第三方法是最可靠的。它在Firefox中很好地下载(虽然速度太慢;当它来自本地主机时,速度大约为700KB/s,当它工作时读取文件的方法速度为25MB /秒)和Chrome,但在Internet Explorer中,它大部分都失败了。在IE中,它首先陷入“获取文件信息”而没有获得任何“打开/保存”对话框。当我取消并再次尝试时,我会看到一个“打开/保存”对话框。

我在网上搜索,我无法找到,实际工作以及任何令人满意的方法。最好我只是希望Apache能够处理文件下载,因为它始终可以毫无问题地正常工作。但我不想将所有文件放入公共目录,因为每个人都可以下载所有文件。

我有什么选择?有没有最好的方法?因为他们填补了脚本与文件的内容存储

+1

设置文件/ MIME头 - '<?标题('Content-type:application/pdf'); header('Content-Disposition:attachment; filename =“downloaded.pdf”'); // .. fread?>' – ajreal 2010-11-10 14:12:43

+1

如果您启用了Apache的deflate模块,请不要忘记关闭下载脚本。它让我头痛了几个小时,因为Firefox在下载时没有显示进度条。要关闭它,请将'SetEnv no-gzip'添加到.htaccess文件中。 – Lekensteyn 2010-11-10 14:29:15

+0

感谢您的提示,Lekensteyn,我看到它在另一个下载脚本示例中使用,以便及时检查是否启用了放气模块。我没有启用它。 – pbean 2010-11-10 15:06:49

回答

2

1)和2)将打破大文件。内存限制通常是32或64 MB,采取更高的内存是不明智的。

第三届方法应该很好地工作,因为它不填写该脚本的记忆;但是,请记住发送正确的content-typecontent-length标题。

还有就是传递文件通过PHP,我还没有与自己的工作,但似乎运作良好,X-Sendfile头的替代品。

+0

感谢您的建议。我意识到内存问题,所以我增加了我的php.ini中的内存限制(但是我可以想象PHP对大文件仍然有内部内存问题)。我只是使用Content-Length头的filesize()(我知道它在2GB +处打破,但我的文件限制无论如何都是500MB)。我使用application/octet-stream作为Content-Type。我将检查一下X-Sendfile的功能,看看它是否更好。 :) – pbean 2010-11-10 14:22:29

+0

内存确实是一个限制 - **执行时间**可能​​是另一个限制。继续检查你的php.ini文件,如果它适用于10Mb,它应该可能为500 :) – Konerak 2010-11-10 14:42:12

+0

啊,我忘了提及执行时间。我在PHP脚本中添加了一行来将执行时间设置为无限(因为我没有以任何方式在安全模式下运行)。你的注意,如果它工作10MB它应该工作500MB是有趣的,因为我的结果不同。文件1B - 〜20MB可以正常工作,但较大的文件(如200MB +)会变得越来越不可靠。 – pbean 2010-11-10 14:50:19

0

有几个选项,包括设置PHP头,强迫下载:

header('Content-Type: application/octet-stream'); 
header('Content-Disposition: attachment; filename="example.zip"'); 
header('Content-Transfer-Encoding: binary'); 

http://www.jonasjohn.de/snippets/php/headers.htm

或者你可以包括链接到问题的文件的iFrame ...不特别然而优雅。

这是一个有趣的教程也:

http://w-shadow.com/blog/2007/08/12/how-to-force-file-download-with-php/

+0

我已经使用了Content-Type和Content-Disposition头(显然),但是我将添加Content-Transfer-Encoding并查看结果如何。 – pbean 2010-11-10 14:20:10

+0

当然 - 我已经用另一篇可能感兴趣的文章来表扬 – SW4 2010-11-10 14:21:39