2011-04-08 93 views
16

我使用的是簡單的文件下載腳本:PHP,文件下載

if (file_exists($file)) { 
    header('Content-Description: File Transfer'); 
    header('Content-Type: application/octet-stream'); 
    header('Content-Disposition: attachment; filename='.basename($file)); 
    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: ' . filesize($file)); 
    ob_clean(); 
    flush(); 
    readfile($file); 
    exit; 
} 

它工作在我的LocalServer高達200MB。

當我在我的網站上試用這段代碼時,它下載了173KB而不是200MB的文件。

我檢查了一切,寫了一些自定義代碼(使用ob函數和fread代替readfile)但無法下載大文件。

謝謝你的回答。

  • 我使用的Apache 2.2,PHP 5.3
  • 所有PHP的設置來處理大文件都OK。 (執行時間,內存限制,...
+0

我的主機,dreamhost有時會殺死消耗太多cpu或資源的腳本。這可能是你的情況。 – nerkn 2011-04-08 13:18:34

回答

19

一個問題我有下面的代碼是你必須在輸出流的控制權,你讓PHP處理它不知道究竟是什麼背景裏的情形:

你應該做的是建立一個輸出系統,您可以控制和複製accros服務器。

例如:

if (file_exists($file)) 
{ 
    if (FALSE!== ($handler = fopen($file, 'r'))) 
    { 
     header('Content-Description: File Transfer'); 
     header('Content-Type: application/octet-stream'); 
     header('Content-Disposition: attachment; filename='.basename($file)); 
     header('Content-Transfer-Encoding: chunked'); //changed to chunked 
     header('Expires: 0'); 
     header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
     header('Pragma: public'); 
     //header('Content-Length: ' . filesize($file)); //Remove 

     //Send the content in chunks 
     while(false !== ($chunk = fread($handler,4096))) 
     { 
      echo $chunk; 
     } 
    } 
    exit; 
} 
echo "<h1>Content error</h1><p>The file does not exist!</p>"; 

這僅僅是基本的,但給它一個去!

又看了我的答覆這裏:file_get_contents => PHP Fatal error: Allowed memory exhausted

+0

謝謝。分塊發送正在所有服務器上正常工作。另外我發送的文件大小,實際上發送完整的文件大小,併發送大塊文件塊可能微不足道,但它現在很好。否則,對於大量下載,用戶將看不到完整的文件大小,這可能不利於可用性。 – jsonx 2011-04-10 13:52:40

+0

這完全取決於數據如何傳輸,例如流式傳輸和下載需要2種獨立的內容傳輸方法。高興地幫助 – RobertPitt 2011-04-10 21:23:25

+0

不應該'基地名稱($文件)'被編碼?如果它包含用http擰緊的字符呢? – 735Tesla 2014-01-02 00:07:39

0

你是否確信你的腳本can run long夠了,有足夠的內存?

你真的需要輸出緩衝?

3

看來ReadFile的可以有問題長文件。作爲@Khez問,它可能是在腳本運行時間過長。快速谷歌搜索導致分塊文件的幾個例子。

http://teddy.fr/blog/how-serve-big-files-through-php http://www.php.net/manual/en/function.readfile.php#99406

+0

所有設置都適用於大文件,執行時間,內存限制...... – jsonx 2011-04-08 13:46:19

+0

在第一個鏈接的read_chunked()函數中解決了這個問題。 – jsonx 2011-04-08 13:53:28

+0

read_chunked()在某些服務器上表現不一致 – jsonx 2011-04-10 13:46:34

0

真正的解決辦法是避免使用PHP腳本只是將文件發送到客戶端,這是矯枉過正,你的網絡服務器是更適合的任務。

大概你有通過PHP發送文件的原因,也許用戶必須先驗證身份?如果是這種情況,那麼您應該在lighttpd上使用X-Accel-Redirect(如果您使用的是nginx)或X-Sendfile(以前是X-LIGHTTPD-send-file)。

如果您使用的是Apache,我發現了一些mod_xsendfile的引用,但我從未親自使用它,如果您管理主機,我懷疑它是否已安裝。

如果這些解決方案是站不住腳的,我很抱歉,但我真的需要關於實際問題的更多信息:爲什麼您首先通過PHP發送這些文件?

+0

謝謝Zofrex,是的,在發送文件之前必須做一些驗證和其他一些操作。 mod_xsendfile看起來不錯,我會試試看。這可能是更清晰的解決方案。 – jsonx 2011-04-08 14:05:30

3

某些方案的一個解決方案是,您可以使用PHP腳本智能地決定從哪裏下載文件,但不是直接從PHP發送文件,而是可以將重定向返回給客戶端,然後包含直接鏈接由Web服務器單獨處理。

這可以通過兩種方式來完成:或者PHP腳本將文件複製到「下載區」,例如可能會通過其他背景/服務腳本定期從「舊」文件中清除該文件,或者暴露真正的永久性位置給客戶。

每種解決方案的情況當然都有缺點。在這個文件中,取決於請求文件的客戶端(curl,wget,GUI瀏覽器),他們可能不支持重定向,而在另一個文件中,這些文件非常暴露於外部世界,可以隨時讀取PHP腳本的(訪問)控制。