PHP下載文件、限速舷夺、X-sendfile

一、普通文件下載

①laravel框架HTTP響應(yīng)的download方法

$pathToFile = 'myfile.csv';//參數(shù)一:絕對路徑
$downloadName = 'downloadFile.csv';//參數(shù)二:下載后的文件名
//download 參數(shù)三:HTTP頭信息
return response()->download($pathToFile, $downloadName);

②PHP實現(xiàn)

 $pathToFile = 'myfile.csv';//文件絕對路徑
 $downloadName = 'downloadFile.csv';//下載后的文件名

 //輸入文件標(biāo)簽
 Header("Content-type: application/octet-stream");
 Header("Accept-Ranges: bytes");
 Header("Accept-Length: " . filesize($pathToFile));
 Header("Content-Disposition: filename=" . $downloadName);

 //輸出文件內(nèi)容
 $file = fopen($pathToFile, "r");
 echo fread($file, filesize($pathToFile));
 fclose($file);
 //或
 //readfile($pathToFile);

其中fread()與readfile()的區(qū)別可以參考https://segmentfault.com/q/10...
但是有時候為了節(jié)省帶寬售貌,避免瞬時流量過大而造成網(wǎng)絡(luò)堵塞给猾,就要考慮下載限速的問題

二、下載文件限速

  $pathToFile = 'myfile.csv';//文件絕對路徑
  $downloadName = 'downloadFile.csv';//下載后的文件名
  $download_rate = 30;// 設(shè)置下載速率(30 kb/s)
  if (file_exists($pathToFile) && is_file($pathToFile)) {
      header('Cache-control: private');// 發(fā)送 headers
      header('Content-Type: application/octet-stream');
      header('Content-Length: ' . filesize($pathToFile));
      header('Content-Disposition: filename=' . $downloadName);
      flush();// 刷新內(nèi)容
      $file = fopen($pathToFile, "r");
      while (!feof($file)) {
          print fread($file, round($download_rate * 1024));// 發(fā)送當(dāng)前部分文件給瀏覽者
          flush();// flush 內(nèi)容輸出到瀏覽器端
          sleep(1);// 終端1秒后繼續(xù)
      }
      fclose($file);// 關(guān)閉文件流
  } else {
      abort(500, '文件' . $pathToFile . '不存在');
  }

此時出現(xiàn)一個問題颂跨,當(dāng)$download_rate>1kb時敢伸,文件正常下載;當(dāng)$download_rate<1kb時恒削,文件要等一會兒才下載池颈,究其原因是因為buffer的問題。

  • buffer是一個內(nèi)存地址空間,Linux系統(tǒng)默認(rèn)大小一般為4096(1kb),即一個內(nèi)存頁钓丰。主要用于存儲速度不同步的設(shè)備或者優(yōu)先級不同的設(shè)備之間傳辦理數(shù)據(jù)的區(qū)域躯砰。舉個例子,你打開文本編輯器編輯一個文件的時候携丁,你每輸入一個字符琢歇,操作系統(tǒng)并不會立即把這個字符直接寫入到磁盤,而是先寫入到buffer梦鉴,當(dāng)寫滿了一個buffer的時候李茫,才會把buffer中的數(shù)據(jù)寫入磁盤。同樣的道理肥橙,當(dāng)執(zhí)行echo,print的時候魄宏,輸出并沒有立即通過tcp傳給客戶端瀏覽器顯示,而是將數(shù)據(jù)寫入php buffer。php output_buffering機制快骗,意味在tcp buffer之前娜庇,建立了一新的隊列,數(shù)據(jù)必須經(jīng)過該隊列方篮。當(dāng)一個php buffer寫滿的時候名秀,腳本進程會將php buffer中的輸出數(shù)據(jù)交給系統(tǒng)內(nèi)核交由tcp傳給瀏覽器顯示。所以藕溅,數(shù)據(jù)會依次寫到這幾個地方echo/pring -> php buffer -> tcp buffer -> browser匕得。資料:http://blog.csdn.net/superhos...
  • 在沒有開啟緩存時,腳本輸出的內(nèi)容都在服務(wù)器端處于等待輸出的狀態(tài),flush()可以將等待輸出的內(nèi)容立即發(fā)送到客戶端汁掠。
  • 開啟緩存后略吨,腳本輸出的內(nèi)容存入了輸出緩存中,這時沒有處于等待輸出狀態(tài)的內(nèi)容考阱,你直接使用flush()不會向客戶端發(fā)出任何內(nèi)容翠忠。而ob_flush()的作用就是將本來存在輸出緩存中的內(nèi)容取出來,設(shè)置為等待輸出狀態(tài)乞榨,但不會直接發(fā)送到客戶端秽之,這時你就需要先使用ob_flush()再使用flush(),客戶端才能立即獲得腳本的輸出吃既。
  • 以及這篇文章同樣講述了ob_flush()和flush()的區(qū)別http://www.laruence.com/2010/...

但是這種方法將文件內(nèi)容從磁盤經(jīng)過一個固定的 buffer 去循環(huán)讀取到內(nèi)存考榨,再發(fā)送給前端 web 服務(wù)器,最后才到達(dá)用戶鹦倚。當(dāng)需要下載的文件很大的時候河质,這種方式將消耗大量內(nèi)存,甚至引發(fā) php 進程超時或崩潰震叙,接下來就使用到X-Sendfile掀鹅。

三、X-Sendfile

  • X-Sendfile 是一種將文件下載請求由后端應(yīng)用轉(zhuǎn)交給前端 web
    服務(wù)器處理的機制媒楼,它可以消除后端程序既要讀文件又要處理發(fā)送的壓力淫半,從而顯著提高服務(wù)器效率,特別是處理大文件下載的情形下匣砖。

我是用的nginx,所以apache請參考https://tn123.org/mod_xsendfile/
①首先在配置文件中添加

location /download/ {
  internal;
  root   /some/path;//絕對路徑
}

  • internal 表示這個路徑只能在 Nginx 內(nèi)部訪問昏滴,不能用瀏覽器直接訪問防止未授權(quán)的下載
  • 注意添加在location / {...}的前面
  • 這樣你在代碼中使用時猴鲫,文件路徑就可以寫成“/download/myfile.csv”

②重啟Nginx,寫代碼

$pathToFile = 'myfile.csv';//文件絕對路徑
$downloadName = 'downloadFile.csv';//下載后的文件名
$download_rate = 30;// 設(shè)置下載速率(30 kb/s)
if (file_exists($pathToFile) && is_file($pathToFile)) {
    return (new Response())->withHeaders([
      'Content-Type'        => 'application/octet-stream',
      'Content-Disposition' => 'attachment;filename=' . $downloadName,
      'X-Accel-Redirect'    => $pathToFile,//讓Xsendfile發(fā)送文件
      'X-Sendfile'          => $pathToFile,
      'X-Accel-Limit-Rate'  => $download_rate,
    ]);
}else {
    abort(500, '文件' . $pathToFile . '不存在');
}

image.png

如果你還想了解更多關(guān)于X-sendfile,請自行查閱

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谣殊,一起剝皮案震驚了整個濱河市拂共,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌姻几,老刑警劉巖宜狐,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蛇捌,居然都是意外死亡抚恒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門络拌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俭驮,“玉大人,你說我怎么就攤上這事』炻埽” “怎么了遗遵?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長逸嘀。 經(jīng)常有香客問我车要,道長,這世上最難降的妖魔是什么崭倘? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任翼岁,我火速辦了婚禮,結(jié)果婚禮上绳姨,老公的妹妹穿的比我還像新娘登澜。我一直安慰自己,他們只是感情好飘庄,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布脑蠕。 她就那樣靜靜地躺著,像睡著了一般跪削。 火紅的嫁衣襯著肌膚如雪谴仙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天碾盐,我揣著相機與錄音晃跺,去河邊找鬼。 笑死毫玖,一個胖子當(dāng)著我的面吹牛掀虎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播付枫,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼烹玉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了阐滩?” 一聲冷哼從身側(cè)響起二打,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎掂榔,沒想到半個月后继效,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡装获,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年瑞信,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片穴豫。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡喧伞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情潘鲫,我是刑警寧澤翁逞,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站溉仑,受9級特大地震影響挖函,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜浊竟,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一怨喘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧振定,春花似錦必怜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至卑惜,卻和暖如春膏执,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背露久。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工更米, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毫痕。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓征峦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親消请。 傳聞我的和親對象是個殘疾皇子眶痰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • PHP的輸出緩沖區(qū) 什么是緩沖區(qū)?簡單而言,緩沖區(qū)的作用就是,把輸入或者輸出的內(nèi)容先放進內(nèi)存,而不顯示或者讀取.至...
    桖辶殤閱讀 2,012評論 3 12
  • php.ini設(shè)置,上傳大文件: post_max_size = 128Mupload_max_filesize ...
    bycall閱讀 6,736評論 3 64
  • 更改ip和dnsVi /etc/sysconfig/network-scripts/ifcfg-eth0vi /...
    Xwei_閱讀 1,800評論 0 3
  • 不知道從什么時候開始,好像所有事情的完成都有了一個截止日期梯啤,如同食品的保質(zhì)期,過了就沒用了存哲。 什么時候干上自己喜歡...
    沫比閱讀 222評論 0 0
  • 剽悍晨讀:?快速打造一場優(yōu)質(zhì)演講因宇,只需掌握這3招? 演講能力,講過很多次了祟偷,在晨讀里面察滑。出現(xiàn)過了也有比較多,其他個...
    小秦哥哥閱讀 140評論 0 7