2013-05-21 30 views
0

我試圖從一個外部API傳遞一個大文件給用戶,(認爲100MB或更多)如何直接開始下載遠程大文件?

目前,我正在使用一些偏執的腳本(由於過去的失敗)到儘快下載腳本。

通過「下載」,我只是指瀏覽器上的下載觸發器,而不是文件的實際下載。只需要用戶可以選擇他想要保存文件的位置即可。

set_time_limit(0); 

apache_setenv('no-gzip', 1); 
ini_set('zlib.output_compression', 0); 
ini_set('output_buffering', 0); 
ini_set('implicit_flush', 1); 
for($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); } 
ob_implicit_flush(1); 

header('Content-Description: File Transfer'); 
header('Content-type: application/octet-stream'); 
header('Content-Transfer-Encoding: Binary'); 
header('Content-Disposition: attachment; filename="' . $filename . '"'); 
header('Cache-Control: private'); 

ob_flush(); 
flush(); 

$fh = fopen($external_api_url, 'rb'); 
while(!feof($fh)) 
{ 
    echo fread($fh, 512); 
    ob_flush(); 
    flush(); 
} 
fclose($fh); 

使用此腳本,在下載彈出窗口出現之前,50mb文件仍然需要20秒,而更大的文件需要更長的時間。

有什麼方法可以更快地啓動流?

編輯: 我也嘗試了fpassthru()和readfile(),但是這些需要40秒鐘才能獲得相同的50mb文件,這讓我覺得這種方式更好。我也玩過不同的讀取大小(512,256,64,其他幾個),但我沒有注意到它們之間的差異)

+0

如果你有PHP 5,你試過'$ contents = stream_get_contents($ fh); echo $ contents;'或'file_get_contents(...)'而不是'while'循環?此外,fread()實際上鼓勵您一次讀取8192個字節,因爲這是塊大小。 –

+0

@Arthur Stream_get_contents和file_get_contents在發送給用戶之前是否會等待整個文件被下載到PHP中?此外,我不知道8192 bute chunk的大小,這可以解釋爲什麼我嘗試的不同值(全部在這個數字下)給出了相同的結果。有沒有辦法降低塊大小? – Johan

回答

0

它需要這麼長時間才能讓瀏覽器觸發下載對話框的原因,是由於API需要很長時間才能返回其第一個數據塊,例如,在開始向您發送數據之前,它們可能正在將整個文件讀取到內存中,這可以解釋爲什麼更長的文件需要更長的時間才能啓動,即使您始終儘可能快地寫入前512個字節。

我試圖通過從本地文件讀取來本地模擬它,但在while循環之前有一個sleep(5);語句。

我能得到谷歌瀏覽器的任何數據之前可以開始下載,通過省略header('Content-type: application/octet-stream');線,試圖讀取該文件之前,仍然發出flush();電話。 (你已經在做這個第二部分)

但是,這似乎並不適用於Firefox 3.6,所以你可能需要不同的噱頭適用於不同的瀏覽器,除非你可以預測文件的第一個字符(看看BOM)並在任何事情之前回應,隨後將其從第一個fread()呼叫的開頭刪除。

我希望它有幫助!但基本上外部的API會讓你感到困擾。

+0

自從我爲它工作的那一刻起,外部API就讓我感到困惑。 :P但是,感謝anwser,我會盡快嘗試並回報:) – Johan

+0

它似乎工作得很好,我注意到與FireFox相同的問題並忽略了內容類型頭文件,FireFox會將其作爲html文件下載即使它是別的...也許我可以稍後再發送這個頭文件... – Johan