PHPExcel使用體會
因為畢設導師智能分配系統的需要,系負責人在管理學生和導師時,希望可以使用Excel批量導入學生和導師的信息,學長的報課系統使用的是PHPExcel的類庫,於是我也抽空花了2天的時間學習了PHPExcel的最基礎的導入導出功能的實現,總結了自己的使用心得和一些常用的使用方法
一、類庫的引入
-
PHP我使用的是ThinkPHP5的框架,所以以TP5框架為例,這是項目的PHPExcel的目錄結構:
require_once 'extend/reader.php'; //Excel讀取 require_once 'extend/PHPExcel_1.8.0_doc/Classes/PHPExcel.php'; //Excel導入導出
二、Excel導入
-
調用Reader
require_once 'extend/reader.php';
-
創建Reader
$data = new \Spreadsheet_Excel_Reader();
-
設置在頁面中輸出的編碼方式
$data->setOutputEncoding('utf-8');
-
讀取上傳到當前目錄下實際路徑為$realPath的文件
$data->read($realPath);
-
設置PHP的報錯級別並返回當前的級別
error_reporting(E_ALL ^ E_NOTICE); 或error_reporting(E_ALL & ~E_NOTICE);
起初並不是很懂這句代碼的含義,經過查找資料后發現,在不同的PHP版本中,原本可能在低版本的PHP中運行正常的代碼,在較高版本的PHP中運行可能就會出現報錯,為了使程序能夠正常運行,需要在程序開頭加上這句代碼;error_reporting()設置PHP的報錯級別並返回當前的級別,以下是網絡上查找的一些資料,在做Excel導出的時候出現了一個bug很久都沒有解決,在TP5的交流群詢問之后被某位大佬問到:“你知道PHP的報錯等級嗎?你知道什么是未定義變量嗎?”查看錯誤報告之后發現確實出現了下面的第7條錯誤:
- 錯誤報告是按位的。或者將數字加起來得到想要的錯誤報告等級
- E_ALL - 所有的錯誤和警告
- E_ERROR - 致命性運行時錯
- E_WARNING - 運行時警告(非致命性錯)
- E_PARSE - 編譯時解析錯誤
- E_NOTICE - 運行時提醒
- 可能是有意的行為造成的(如:基於未初始化的變量自動初始化為一個空字符串的事實而使用一個未初始化的變量)
- E_CORE_ERROR - 發生於PHP啟動時初始化過程中的致命錯誤
- E_CORE_WARNING - 發生於PHP啟動時初始化過程中的警告(非致命性錯)
- E_COMPILE_ERROR - 編譯時致命性錯
- E_COMPILE_WARNING - 編譯時警告(非致命性錯)
- E_USER_ERROR - 用戶產生的出錯消息
- E_USER_WARNING - 用戶產生的警告消息
- E_USER_NOTICE - 用戶產生的提醒消息
-
循環處理Excel表格里的每一行數據並插入數據庫
for ($i=3; $i <=$data->sheets[0]['numRows'] ; $i++) { $insert = []; $insert['grade'] = $data->sheets[0]['cells'][$i][1]; $insert['serialNum'] = $data->sheets[0]['cells'][$i][2]; $insert['password'] = $data->sheets[0]['cells'][$i][2]; $insert['name'] = $data->sheets[0]['cells'][$i][3]; $insert['gender'] = $data->sheets[0]['cells'][$i][4]; $insert['college'] = $data->sheets[0]['cells'][$i][5]; $insert['department'] = $data->sheets[0]['cells'][$i][6]; $insert['gpa'] = $data->sheets[0]['cells'][$i][7]; $insert['rank'] = $data->sheets[0]['cells'][$i][8]; $insert['telephone'] = $data->sheets[0]['cells'][$i][9]; $insert['chosen'] = 0; //插入數據庫中 Db('user_student_'.$insert['grade'])->insert($insert); }
三、Excel導出
-
引入PHPExcel.php
require_once 'extend/PHPExcel_1.8.0_doc/Classes/PHPExcel.php';
-
創建一個新的Excel文件
$excel = new \PHPExcel();
-
先進行一般的Excel格式的處理
$excel->getActiveSheet()->getColumnDimension('A')->setWidth(9); //手動設置單元格寬度 $excel->getActiveSheet()->getColumnDimension('B')->setWidth(30); $excel->getActiveSheet()->getColumnDimension('C')->setWidth(9); $excel->getActiveSheet()->getRowDimension(2)->setRowHeight(35); //設置某一行高度 $excel->getActiveSheet()->getStyle('A1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER); //設置水平居中 $excel->getActiveSheet()->getStyle('A1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER); //設置水平居中 $excel->getActiveSheet()->getStyle('G')->getNumberFormat()->setFormatCode('000000000'); //設置文本格式 //設置邊框和水平垂直居中,PHPExcel貌似沒有對所有的單元格進行統一處理的功能,所以我定義里一個$styleArray,方便在往Excel中寫入數據時,同時對單元格進行格式的設置 $styleArray = [ 'alignment' => [ 'horizontal' => \PHPExcel_Style_Alignment::HORIZONTAL_CENTER, 'vertical' => \PHPExcel_Style_Alignment::VERTICAL_CENTER ], 'borders' => [ 'allborders' => [ 'style' => \PHPExcel_Style_Border::BORDER_THIN ] ] ]; $excel->getActiveSheet()->getStyle('A1')->applyFromArray($styleArray); $excel->getActiveSheet()->getStyle('A1')->getFont()->setBold(true); //設置字體加粗 $excel->getActiveSheet()->mergeCells('A1:H1'); //合並A1:F1單元格
-
對表格第一行標題的特殊處理
$excel->getActiveSheet()->mergeCells('A1:H1'); //合並A1:H1單元格 $excel->getActiveSheet()->setCellValue('A1',$insert[0]['grade'].'級'.$insert[0]['dep'].'導師分配結果'); $excel->getActiveSheet()->getStyle('A1')->getFont()->setBold(true); //加粗 $excel->getActiveSheet()->getStyle('A1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER); //設置水平居中 $excel->getActiveSheet()->getStyle('A1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER); //設置垂直居中
-
對表的標題行的特殊處理
$letter = ['A','B','C','D','E','F','G','H']; $tableHeader = ['序號','系別','專業導師','職稱','課題','學生姓名','學號','聯系方式']; //設置表頭數組,單獨處理 for ($i=0; $i <8 ; $i++) { $excel->getActiveSheet()->setCellValue($letter[$i].'2',$tableHeader[$i]); //設置單元格的值 $excel->getActiveSheet()->getStyle($letter[$i].'2')->applyFromArray($styleArray); //設置單元格格式:水平、垂直居中、加邊框 $excel->getActiveSheet()->getStyle($letter[$i].'2')->getFont()->setBold(true); //設置單元格字體加粗 }
-
在這次項目中碰到的比較奇葩的問題和處理辦法 - 某些單元格的動態合並:
第一種情況
如上圖,對於上圖這種格式的Excel寫入是比較簡單的,只需從數據庫中取出數據,逐條的插入進表格中,並作格式處理就好了$totalInsert = count($insert); //計算總插入數 for ($i=0; $i <$totalInsert ; $i++) { $excel->getActiveSheet()->setCellValue('A'.($i+3),($i+1)); $excel->getActiveSheet()->setCellValue('B'.($i+3),$insert[$i]['tdep']); $excel->getActiveSheet()->setCellValue('C'.($i+3),$insert[$i]['sname']); $excel->getActiveSheet()->setCellValue('D'.($i+3),$insert[$i]['snum']); $excel->getActiveSheet()->setCellValue('E'.($i+3),$insert[$i]['stele']); $excel->getActiveSheet()->setCellValue('F'.($i+3),$insert[$i]['tname']); $excel->getActiveSheet()->setCellValue('G'.($i+3),$insert[$i]['tposi']); $excel->getActiveSheet()->setCellValue('H'.($i+3),$insert[$i]['title']); $excel->getActiveSheet()->setCellValue('I'.($i+3),$insert[$i]['ttele']); } for ($j=0; $j <9 ; $j++) { $excel->getActiveSheet()->getStyle($letter[$j].'3'.':'.$letter[$j].($totalInsert+2))->applyFromArray($styleArray); //設置單元格格式:水平、垂直居中、加邊框 }
第二種情況
如上圖,對於初學PHPExcel的我來說,上圖的操作簡直是麻煩,我的做法是-
先設置兩個臨時變量
$oldTemp
和$newTemp
用來處理合並的單元格的范圍,例如合並A1:A6,$oldTemp
用來記錄合並的左范圍,$newTemp
用來記錄合並的右范圍,並且$newTemp = $oldTemp + 每個導師的學生數
,若學生數為0,則加1 -
先插入列F、G、H的數據,加樣式,然后對前面的列A、B、C、D、E先插值,再進行單元格合並,因為比如A1:A3合並,合並后的單元格名稱仍然為A1,合並的范圍為
$oldTemp : $newTemp-1
,然后交換$oldTemp
和$newTemp
-
不知道有沒有更好的處理辦法,對自己的處理辦法表示有點愚蠢。。
$oldTemp = 3; //臨時變量,用於處理合並單元格的范圍 $newTemp = 0; //臨時變量,用於處理合並單元格的范圍 for ($i=0; $i <$totalInsert ; $i++) { //循環插入數據,並作格式處理 if ($insert[$i]['stuNum'] == 0) { //判斷導師是否有學生,如果沒有學生,只需插入一行 $tempCount = $insert[$i]['stuNum'] + 1; } else { $tempCount = $insert[$i]['stuNum']; } for ($j=0; $j <$tempCount ; $j++) { //開始插入 if ($insert[$i]['stuNum'] != 0) { //逐一插入導師的學生信息 $excel->getActiveSheet()->setCellValue('F'.($j+$oldTemp),$insert[$i]['tstudentL'][$j]['sname']); $excel->getActiveSheet()->setCellValue('G'.($j+$oldTemp),$insert[$i]['tstudentL'][$j]['snum']); $excel->getActiveSheet()->setCellValue('H'.($j+$oldTemp),$insert[$i]['tstudentL'][$j]['stele']); } $excel->getActiveSheet()->getStyle('F'.($j+$oldTemp))->applyFromArray($styleArray); //設置單元格格式:水平、垂直居中、加邊框 $excel->getActiveSheet()->getStyle('G'.($j+$oldTemp))->applyFromArray($styleArray); //設置單元格格式:水平、垂直居中、加邊框 $excel->getActiveSheet()->getStyle('H'.($j+$oldTemp))->applyFromArray($styleArray); //設置單元格格式:水平、垂直居中、加邊框 } $excel->getActiveSheet()->setCellValue('A'.$oldTemp,($i+1)); //設置單元格的值 $excel->getActiveSheet()->setCellValue('B'.$oldTemp,$insert[$i]['dep']); $excel->getActiveSheet()->setCellValue('C'.$oldTemp,$insert[$i]['tname']); $excel->getActiveSheet()->setCellValue('D'.$oldTemp,$insert[$i]['position']); $excel->getActiveSheet()->setCellValue('E'.$oldTemp,$insert[$i]['title']); $newTemp = $oldTemp + $tempCount; if ($insert[$i]['stuNum'] != 1 && $insert[$i]['stuNum'] != 0) { for ($k=0; $k <5 ; $k++) { $excel->getActiveSheet()->mergeCells($letter[$k].$oldTemp.':'.$letter[$k].($newTemp-1)); //根據導師的學生數合並A、B、C、D、E列的單元格 } } for ($z=0; $z <5 ; $z++) { $excel->getActiveSheet()->getStyle($letter[$z].$oldTemp.':'.$letter[$z].($newTemp-1))->applyFromArray($styleArray); //設置單元格格式:水平、垂直居中、加邊框 } $oldTemp = $newTemp; }
-
-
直接輸出至瀏覽器,即下載至本地,只需直接加入代碼就行
$write = new \PHPExcel_Writer_Excel5($excel); header("Pragma: public"); header("Expires: 0"); header("Cache-Control:must-revalidate, post-check=0, pre-check=0"); header("Content-Type:application/force-download"); header("Content-Type:application/vnd.ms-execl"); header("Content-Type:application/octet-stream"); header("Content-Type:application/download");; header('Content-Disposition:attachment;filename='.'"'.$insert[0]['grade'].'級導師互選結果.xls"'); //可以對文件名進行處理 header("Content-Transfer-Encoding:binary"); $write->save('php://output');
四、實踐效果動圖
學生Excel導入:
Excel模版導出:
結果導出:
五、總結
-
期間遇到了很多的bug,不斷的上網找資料、找博客,學到了很多的知識,比如在一個''上剛了非常多的時間,最后找到錯誤的時候又喜又氣的,還有在往Excel中寫數據的時候,碰到一個未定義數組下標[0]的錯誤的時候,花了更多的時間,反反復復的檢查代碼愣是沒發現錯誤在哪里,躺在床上沒解決bug不甘心又下床苦尋,最后發現數據庫中的數據有一些是空的,直接插入會出錯,要做一些相應的處理
-
學到了新知識心里是驚喜的,不過我也是得去做下編譯實驗的。。