原理:php開啓緩存區輸出 --> php系統緩衝區(nginx, apache服務器) --> 瀏覽器緩衝區
因此,要實現邊查詢,邊下載效果,php, web服務器, 瀏覽器 三個方面的配置都不能少
apache配置: httpd.conf 由於默認開啓了mod_cgi.so模塊 在http.conf配置文件最後一行加上, 表示設置緩衝區的字節大小爲0,一旦有php輸出,就立馬響應瀏覽器輸出 FcgidOutputBufferSize 0 注意,nginx也有設置buffer的大小
<?php /** * 導出大數據抽象類 */ abstract class LargeExportAbstract { protected $filename = 'export.csv'; protected $chunkNum = 1000; private $fp; //是否安全導出 protected $isSafe = false; /**獲取Query查詢對象 * @return Query */ abstract public function getQuery(); /**設置安全導出, 既相關數據不可看 * @param bool|true $safe * @return $this */ public function setSafeModel($safe = true) { $this->isSafe = $safe; return $this; } /**第一行導出 * @return array */ public function beforeRow() { return []; } /**數據導出 * @param $row * @return mixed */ public function formatRow($row) { return $row; } protected function outPutStart() { $this->fp = fopen('php://output', 'a');//打開output流 } protected function outPutEnd() { fclose($this->fp); } /** * 創建IO */ protected function IOStart() { header('Content-Description: File Transfer'); header('Content-Type: application/vnd.ms-excel'); header('Content-Disposition: attachment; filename="'. $this->filename .'"'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('X-Accel-Buffering: no'); //適用於Nginx服務器環境 header('Pragma: public'); //使用流式輸出 $this->outPutStart(); //開啓緩衝區 @ob_clean(); //一旦有緩衝,立馬輸出 ob_implicit_flush(true); } /** * 關閉IO */ protected function IOend() { @ob_end_clean(); //關閉流式輸出 $this->outPutEnd(); exit(); } /** * 清空緩衝區, 內容進入下一層緩衝區 */ protected function flush() { @ob_flush(); @flush(); } /**向excel輸出一行數據 * @param $row */ public function put($row) { if ($this->fp) fputcsv($this->fp, $row); } /**導出 * @param string $filename 可選,文件名 */ public function export($filename = '') { if (!empty($filename)) { $this->filename = $filename; } //創建一個流式IO $this->IOStart(); //數據查詢前向瀏覽器輸出 $beforeRow = $this->beforeRow(); if (!empty($beforeRow)) { $this->put($beforeRow); } //數據分批查詢 $this->getQuery()->chunk((int)$this->chunkNum, function ($rows) { foreach ($rows as $row) { $row = $this->formatRow($row); //存放php緩存衝區 $this->put($row); } unset($rows); //php緩衝區釋放, 進入下一層緩衝區 $this->flush(); }); //關閉IO $this->IOend(); } /**原樣輸出,防止小數導出時爲空 如數字5.00,本應導出 5.00 ,實際導出了 5 * @param $value * @return string */ public function toText($value) { return $value."\t"; } }
<?php /* 查詢類服務 */ class RankStatisticService { protected $name; public function __construct($id, $inputs){ ... } public function getQuery(){ return GoodModel::where('name', $this->name); } } /**統計導出 * Class RankStatistic * @package App\Services\Activity\InviteActivity */ class RankStatisticExport extends LargeExportAbstract{ /**導出統計服務 * @var \App\Services\CpaData\CpaStatisticService */ protected $staticService; //活動數據 protected $activity; protected $chunkNum = 2; //導出文件名 protected $filename = '數據統計(排行榜).csv'; //是否安全導出 protected $isSafe = false; protected $headerRow = ['活動期數', '會員id', '會員所屬分組', '會員手機號', '邀請人數', '排名', '是否獲得獎勵', '獎品名稱', '收貨地址']; public function __construct($id, $inputs) { $this->staticService = (new RankStatisticService($id, $inputs)); $this->activity = $this->staticService->activityData(); } public function getQuery() { return $this->staticService->getQuery(); } public function beforeRow() { return $this->initRow($this->headerRow); } public function formatRow($v) { $row = [ "第{$this->activity->round}期", //期數 $v->user_id, //會員id $v->group_name, //會員手機號 $this->toText($v->mobile), //會員所屬分組 $v->vip_number, //開通權益會員數量 $v->user_rank, //排名 $v->reward_zh, //是否獲得獎勵 $v->reward_name, //獎品名稱 $v->addressDetail //收貨地址 ]; return $this->initRow($row); } /**格式化導出的數據 * @param $row * @return array */ protected function initRow($row) { //安全模式下,不導出手機號 if ($this->isSafe) { unset($row[3]); $row = array_values($row); } return $row; } } /* 客戶端調用 */ (new RankStatisticExport(1, [])->export();
利用上面的原理,最終的效果如下面視頻:
鏈接:https://pan.baidu.com/s/1vA_RnveMIUQO8FAQt774ig
提取碼:7pdj
複製這段內容後打開百度網盤手機App,操作更方便哦
php 大數據excel導出 buffer配置
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.