匯出資料到Excel的實用方案
實際工作場景中,經常需要將系統中資料匯出為Excel,便於產品和運營查閱和二次處理。本文詳細介紹了使用PHP匯出資料的方法。
PHP操作Excel主要有兩個第三方庫,一個是PHPExcel ,另外一個是PhpSpreadsheet 。其中PhpSpreadsheet是PHPExcel的升級版本。
PHPExcel本身支援超連結、樣式設定(字型、顏色、邊框線、對齊等)、行高列寬設定、表格凍結、公式、合併單元格、多表格等特性。從官方文件得知,PHPExcel支援PHP5.2版本,程式碼質量和效能會低於PhpSpreadsheet。另外PHPExcel從2015年便不再維護,因此很難從社群增加新特性和處理歷史缺陷。PHPExcel支援xls和xlsx兩種格式,xls是Microsoft Excel 2003以下版本支援的檔案,xlsx是Microsoft Excel 2007以後開始的。
PhpSpreadsheet是下一代的PHPExcel,支援PHP5.6及以上,可以處理Microsoft Excel和LibreOffice Calc。PhpSpreadsheet作為下一代的PHPExcel,目前得到社群持續維護。
基於本身業務特點,以及疑難問題的快速處理,最終選擇了PHPExcel作為匯出的基礎庫,並且採用xls檔案格式。PHPExcel庫因為歷史久遠,積累了很多其他使用者踩過的坑,也便於我們處理類似疑難問題。
下文所述的方法是將內容匯出為xls檔案格式。
處理中-內容的處理
處理多sheet
-
核心方法:$obj_phpexcel->createSheet($i);
$obj_phpexcel = new PHPExcel(); $sheet_datas;//實際資料 $sheet_name = 'test'; foreach($sheet_datas as $i => $sheet_data) { $obj_phpexcel->createSheet($i); $obj_phpexcel->setActiveSheetIndex($sheet_index); $obj_phpexcel->getActiveSheet()->setTitle($sheet_name); }
處理樣式
-
核心方法: $obj_phpexcel->getActiveSheet()->getStyle(‘A1’)->applyFromArray($style_array);
getStyle的引數為實際座標,比如A1,代表A列的第1行的單元格。applyFromArray的引數為樣式配置。
//樣式配置 $style_array = array( 'alignment' => array( 'horizontal' => PHPExcel_Style_Alignment::HORIZONTAL_GENERAL= 'general' PHPExcel_Style_Alignment::HORIZONTAL_LEFT= 'left' PHPExcel_Style_Alignment::HORIZONTAL_RIGHT= 'right' PHPExcel_Style_Alignment::HORIZONTAL_CENTER= 'center' PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS = 'centerContinuous' PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY= 'justify' 'vertical' => PHPExcel_Style_Alignment::VERTICAL_BOTTOM= 'bottom' PHPExcel_Style_Alignment::VERTICAL_TOP= 'top' PHPExcel_Style_Alignment::VERTICAL_CENTER= 'center' PHPExcel_Style_Alignment::VERTICAL_JUSTIFY = 'justify' 'rotation' => (int) 'wrap' => (boolean) 'shrinkToFit' => (boolean) 'indent' => (int) ) 'borders' => array( 'allborders' => array( 'style' => PHPExcel_Style_Border::BORDER_NONE= 'none'; PHPExcel_Style_Border::BORDER_DASHDOT= 'dashDot'; PHPExcel_Style_Border::BORDER_DASHDOTDOT= 'dashDotDot'; PHPExcel_Style_Border::BORDER_DASHED= 'dashed'; PHPExcel_Style_Border::BORDER_DOTTED= 'dotted'; PHPExcel_Style_Border::BORDER_DOUBLE= 'double'; PHPExcel_Style_Border::BORDER_HAIR= 'hair'; PHPExcel_Style_Border::BORDER_MEDIUM= 'medium'; PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT= 'mediumDashDot'; PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT= 'mediumDashDotDot'; PHPExcel_Style_Border::BORDER_MEDIUMDASHED= 'mediumDashed'; PHPExcel_Style_Border::BORDER_SLANTDASHDOT= 'slantDashDot'; PHPExcel_Style_Border::BORDER_THICK= 'thick'; PHPExcel_Style_Border::BORDER_THIN= 'thin'; 'color' => array( 'rgb' => PHPExcel_Style_Color::COLOR_BLACK= 'FF000000'; PHPExcel_Style_Color::COLOR_WHITE= 'FFFFFFFF'; PHPExcel_Style_Color::COLOR_RED= 'FFFF0000'; PHPExcel_Style_Color::COLOR_DARKRED= 'FF800000'; PHPExcel_Style_Color::COLOR_BLUE= 'FF0000FF'; PHPExcel_Style_Color::COLOR_DARKBLUE= 'FF000080'; PHPExcel_Style_Color::COLOR_GREEN= 'FF00FF00'; PHPExcel_Style_Color::COLOR_DARKGREEN= 'FF008000'; PHPExcel_Style_Color::COLOR_YELLOW= 'FFFFFF00'; PHPExcel_Style_Color::COLOR_DARKYELLOW= 'FF808000'; ) ) 'left' => // See 'allborders' 'top' => // See 'allborders' 'right' => // See 'allborders' 'bottom' => // See 'allborders' 'diagonal' => 'diagonaldirection' => ) 'fill' => array( 'type' => PHPExcel_Style_Fill::FILL_NONE= 'none'; PHPExcel_Style_Fill::FILL_SOLID= 'solid'; PHPExcel_Style_Fill::FILL_GRADIENT_LINEAR= 'linear'; PHPExcel_Style_Fill::FILL_GRADIENT_PATH= 'path'; PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN= 'darkDown'; PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY= 'darkGray'; PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID= 'darkGrid'; PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL= 'darkHorizontal'; PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS= 'darkTrellis'; PHPExcel_Style_Fill::FILL_PATTERN_DARKUP= 'darkUp'; PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL= 'darkVertical'; PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625= 'gray0625'; PHPExcel_Style_Fill::FILL_PATTERN_GRAY125= 'gray125'; PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN= 'lightDown'; PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY= 'lightGray'; PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID= 'lightGrid'; PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL= 'lightHorizontal'; PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS= 'lightTrellis'; PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP= 'lightUp'; PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL= 'lightVertical'; PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY= 'mediumGray'; 'rotation' => (double) 'startcolor' => // See 'borders' => 'allborders' => 'color' 'endcolor' => // See 'borders' => 'allborders' => 'color' 'color' => // See 'borders' => 'allborders' => 'color' ) 'font' => array( 'name' => 'Arial' 'Calibri' // etc. 'bold' => (boolean) 'italic' => (boolean) 'superScript' => (boolean) 'subScript' => (boolean) 'underline' => (boolean) 'strike' => (boolean) 'size' => (float) 'color' => // See 'borders' => 'allborders' => 'color' ) 'numberformat' => 'protection' => )
寫入資料
-
核心方法:$obj_phpexcel->getActiveSheet()->setCellValueExplicit(‘A1’, $value, $dtype);
dtype區分不同的資料型別,定義見PHPExcel\Cell\DataType.php
/* Data types */ const TYPE_STRING2= 'str'; const TYPE_STRING= 's'; const TYPE_FORMULA= 'f'; const TYPE_NUMERIC= 'n'; const TYPE_BOOL= 'b'; const TYPE_NULL= 'null'; const TYPE_INLINE= 'inlineStr'; const TYPE_ERROR= 'e';
處理超連結
核心方法:$obj_phpexcel->getActiveSheet()->getCell(‘A1’)->getHyperlink()->setUrl($URL);
處理公式
核心方法:$obj_phpexcel->getActiveSheet()->setCellValue(‘A1’, ‘=SUM(A10:E9)’);
合併單元格
核心方法:$obj_phpexcel->getActiveSheet()->mergeCells(‘A1:C1’);
列寬和行高
//列寬 $obj_phpexcel->getActiveSheet()->getColumnDimension($column_label)->setWidth($value); //行高 $obj_phpexcel->getActiveSheet()->getRowDimension($key)->setRowHeight($value);
表格凍結
核心方法:$obj_phpexcel->getActiveSheet()->freezePane(‘D2’);
其他問題
實際值、畫素值隱射
PHPExcel沒辦法將畫素值,轉化為Microsoft Excel實際的寬度和高度值。如果直接將畫素值設定為Excel的實際值,會導致內容存在差異。經過測試得知,Excel實際值和畫素值之間滿足線性關係。知道問題原因,處理起來便很簡單。
private function _get_excel_real_width($value) { return $value/7; }
橫座標處理
Excel的橫座標為A、B….、AA、AB型別,需要將PHP陣列下標轉化為Excel的橫座標。
private function _get_sheet_col_label($index) { if (isset($this->_col_label_map[$index])) { return $this->_col_label_map[$index]; } $abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; for ($i=0; $i < 600; $i++) { //最高支援600列 $a = (int)($i / 26); $b = $i % 26; $column_label = ''; if ($a == 0) { $column_label = $column_label . substr($abc, $b, 1); } else { $a = $a -1; $column_label = substr($abc, $a, 1) . substr($abc, $b, 1); } $this->_col_label_map[($i)] = $column_label; } return $this->_col_label_map[$index]; }
預設的樣式處理
Excel本身的表格框線無法通過PHPExcel設定,需要trick處理。另外Excel的樣式屬性與css樣式屬性也會有差異,需要注意下。
//設定Excel預設框線 $style_array = array( 'borders' => array( 'allborders' => array( 'style' => PHPExcel_Style_Border::BORDER_THIN, 'color' => array('rgb' => 'DDDDDD') ) ) );