2010-11-10 57 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