讓PHP提供更好的檔案下載
一般來說, 我們可以通過直接讓URL指向一個位於Document Root下面的檔案, 來引導使用者下載檔案.
但是, 這樣做, 就沒辦法做一些統計, 許可權檢查, 等等的工作. 於是, 很多時候, 我們採用讓PHP來做轉發, 為使用者提供檔案下載.
1
2
3
4
5
|
$file = "/tmp/dummy.tar.gz" ;
header( "Content-type: application/octet-stream" );
header( `Content-Disposition: attachment; filename="` . basename ( $file ) . `"` );
header( "Content-Length: " . filesize ( $file ));
readfile( $file );
|
複製程式碼但是這個有一個問題, 就是如果檔案是中文名的話, 有的使用者可能下載後的檔名是亂碼.
於是, 我們做一下修改(參考: :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
$file = "/tmp/中文名.tar.gz" ;
$filename = basename ( $file );
header( "Content-type: application/octet-stream" );
//處理中文檔名
$ua = $_SERVER [ "HTTP_USER_AGENT" ];
$encoded_filename = urlencode( $filename );
$encoded_filename = str_replace ( "+" , "%20" , $encoded_filename );
if (preg_match( "/MSIE/" , $ua )) {
header( `Content-Disposition: attachment; filename="` . $encoded_filename . `"` );
} else if (preg_match( "/Firefox/" , $ua )) {
header( "Content-Disposition: attachment; filename*="utf8``" . $filename . `"` );
} else {
header( `Content-Disposition: attachment; filename="` . $filename . `"` );
} header( `Content-Disposition: attachment; filename="` . $filename . `"` );
header( "Content-Length: " . filesize ( $file ));
readfile( $file );
|
複製程式碼恩, 現在看起來好多了, 不過還有一個問題, 那就是readfile, 雖然PHP的readfile嘗試實現的儘量高效, 不佔用PHP本身的記憶體, 但是實際上它還是需要採用MMAP(如果支援), 或者是一個固定的buffer去迴圈讀取檔案, 直接輸出.
輸出的時候, 如果是Apache + PHP mod, 那麼還需要傳送到Apache的輸出緩衝區. 最後才傳送給使用者. 而對於Nginx + fpm如果他們分開部署的話, 那還會帶來額外的網路IO.
那麼, 能不能不經過PHP這層, 直接讓Webserver直接把檔案傳送給使用者呢?
今天, 我看到了一個有意思的文章: How I PHP: X-SendFile.
我們可以使用Apache的module mod_xsendfile, 讓Apache直接傳送這個檔案給使用者:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
$file = "/tmp/中文名.tar.gz" ;
$filename = basename ( $file );
header( "Content-type: application/octet-stream" );
//處理中文檔名 $ua = $_SERVER [ "HTTP_USER_AGENT" ];
$encoded_filename = urlencode( $filename );
$encoded_filename = str_replace ( "+" , "%20" , $encoded_filename );
if (preg_match( "/MSIE/" , $ua )) {
header( `Content-Disposition: attachment; filename="` . $encoded_filename . `"` );
} else if (preg_match( "/Firefox/" , $ua )) {
header( "Content-Disposition: attachment; filename*="utf8``" . $filename . `"` );
} else {
header( `Content-Disposition: attachment; filename="` . $filename . `"` );
} header( `Content-Disposition: attachment; filename="` . basename ( $file ) . `"` );
//讓Xsendfile傳送檔案 header( "X-Sendfile: $file" );
|
複製程式碼X-Sendfile頭將被Apache處理, 並且把響應的檔案直接傳送給Client.
Lighttpd和Nginx也有類似的模組, 大家有興趣的可以去找找看
本文轉自 3147972 51CTO部落格,原文連結:http://blog.51cto.com/a3147972/1230950,如需轉載請自行聯絡原作者
相關文章
- Laravel 中建立 Zip 壓縮檔案並提供下載Laravel
- PHP:檔案載入PHP
- Java 匯入資料到Excel並提供檔案下載介面JavaExcel
- 檔案下載
- PHP檔案的自動載入(autoloading)PHP
- PHP+Mysql統計檔案下載次數例項PHPMySql
- 00、下載檔案
- Ajax 下載檔案
- js 檔案下載JS
- HttpClient 下載檔案HTTPclient
- JAVA檔案下載Java
- Response下載檔案
- FastApi下載檔案ASTAPI
- 檔案程式設計、檔案下載程式設計
- PHP 如何上傳檔案和下載,你學會了嗎?PHP
- 15種下載檔案的方法
- 檔案的上傳與下載
- 下載檔案的15種方法
- ADNI的fMRI檔案下載教程
- SpringMVC檔案上傳下載(單檔案、多檔案)SpringMVC
- python之檔案下載Python
- 檔案上傳下載
- Flutter 下載檔案操作Flutter
- python 下載檔案demoPython
- 如何為夜遊專案提供更好的體驗效果
- a標籤與Blob下載檔案的區別和獲取檔案下載進度
- js下載檔案的實現方式JS
- JavaScript~檔案下載的幾種方式JavaScript
- 檔案下載(URL,文件流)
- CentOS 7映象檔案下載CentOS
- 檔案下載那點事
- 如何下載 Ubuntu 映象檔案?Ubuntu
- JAVA檔案上傳下載Java
- IDM下載度盤檔案
- Flutter實現檔案下載Flutter
- 使用 header 頭下載檔案Header
- 6.1檔案下載、讀取
- AJAX實現檔案下載----
- goroutine&waitgroup下載檔案GoAI