PHPExcel(現已併入 PhpSpreadsheet)是 PHP 操作 Excel 最經典的庫。本文以 ThinkPHP 2.x/3.x 為例,詳細演示如何部署 PHPExcel、封裝通用操作類、構建控制器與視圖,實現「Excel 導入入庫」與「資料導出下載」雙向流程。
ThinkPHP/Extend/Vendor/Excel/
├── PHPExcel.php
└── PHPExcel/ (核心目錄)
路徑:ThinkPHP/Extend/Library/ORG/Util/ExcelToArray.class.php
<?php
class ExcelToArray {
public function __construct() {
Vendor('Excel.PHPExcel');
Vendor('Excel.PHPExcel.IOFactory');
}
/**
* 讀取 Excel 轉為二維陣列
* @param string $filename 檔案路徑
* @param string $encode 編碼
* @param string $file_type xls|xlsx
* @return array
*/
public function read($filename, $encode, $file_type) {
$type = strtolower($file_type);
if ($type === 'xls') {
Vendor('Excel.PHPExcel.Reader.Excel5');
$reader = PHPExcel_IOFactory::createReader('Excel5');
} elseif ($type === 'xlsx') {
Vendor('Excel.PHPExcel.Reader.Excel2007');
$reader = PHPExcel_IOFactory::createReader('Excel2007');
} else {
throw new Exception('不支援的檔案格式');
}
$reader->setReadDataOnly(true);
$objPHPExcel = $reader->load($filename);
$sheet = $objPHPExcel->getActiveSheet();
$highestRow = $sheet->getHighestRow();
$highestCol = $sheet->getHighestColumn();
$colIndex = PHPExcel_Cell::columnIndexFromString($highestCol);
$data = [];
for ($row = 1; $row <= $highestRow; $row++) {
for ($col = 0; $col < $colIndex; $col++) {
$data[$row][] = (string)$sheet->getCellByColumnAndRow($col, $row)->getValue();
}
}
return $data;
}
/**
* 導出陣列資料為 Excel 下載
* @param array $data 二維陣列 [['username'=>..., 'password'=>..., 'sex'=>...], ...]
* @param string $name 下載檔名
*/
public function push($data, $name = 'Excel') {
$objPHPExcel = new PHPExcel();
// 文件屬性
$objPHPExcel->getProperties()
->setCreator('System')
->setLastModifiedBy('System')
->setTitle('Export')
->setSubject('Data Export')
->setDescription('Backup')
->setKeywords('excel')
->setCategory('result file');
// 寫入標題列(可動態生成)
$headers = ['username', 'password', 'sex'];
foreach ($headers as $i => $h) {
$objPHPExcel->setActiveSheetIndex(0)->setCellValueByColumnAndRow($i, 1, $h);
}
// 寫入資料
foreach ($data as $i => $row) {
$r = $i + 2;
$objPHPExcel->getActiveSheet()->setCellValue('A' . $r, $row['username'] ?? '');
$objPHPExcel->getActiveSheet()->setCellValue('B' . $r, $row['password'] ?? '');
$objPHPExcel->getActiveSheet()->setCellValue('C' . $r, $row['sex'] ?? '');
}
$objPHPExcel->getActiveSheet()->setTitle('Data');
$objPHPExcel->setActiveSheetIndex(0);
// 輸出下載
ob_end_clean();
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="' . $name . '.xls"');
header('Cache-Control: max-age=0');
$writer = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$writer->save('php://output');
exit;
}
}
路徑:Home/Lib/Action/ExcelAction.class.php
<?php
class ExcelAction extends Action {
public function __construct() {
import('ORG.Util.ExcelToArray');
}
public function index() {
$this->display();
}
/** 導入 Excel 入庫 */
public function add() {
$tmp = $_FILES['file_stu']['tmp_name'];
$ext = strtolower(pathinfo($_FILES['file_stu']['name'], PATHINFO_EXTENSION));
if (!in_array($ext, ['xls', 'xlsx'])) {
$this->error('請上傳 .xls 或 .xlsx 檔案');
}
$savePath = 'Uploads/';
if (!is_dir($savePath)) mkdir($savePath, 0777, true);
$file = date('YmdHis') . '.' . $ext;
if (!move_uploaded_file($tmp, $savePath . $file)) {
$this->error('上傳失敗');
}
$excel = new ExcelToArray();
$rows = $excel->read($savePath . $file, 'UTF-8', $ext);
$data = [];
foreach ($rows as $k => $v) {
if ($k === 1) continue; // 跳過標題列
$data[] = [
'username' => $v[0] ?? '',
'password' => $v[1] ?? '',
'sex' => $v[2] ?? '',
];
}
if (M('User')->addAll($data)) {
$this->success('導入成功');
} else {
$this->error('入庫失敗');
}
}
/** 導出資料 */
public function load() {
$data = M('User')->select();
$excel = new ExcelToArray();
$excel->push($data, 'UserTable');
}
}
路徑:Home/Tpl/Excel/index.html
<form method="post" action="__APP__/Excel/add" enctype="multipart/form-data"> <h3>導入 Excel:</h3> <input type="file" name="file_stu" /> <input type="submit" value="導入" /> </form> <form method="post" action="__APP__/Excel/load"> <input type="submit" value="導出" /> </form>
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(50) DEFAULT NULL, `password` varchar(50) DEFAULT NULL, `sex` tinyint(1) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
setReadDataOnly(true)、分塊讀取(PHPExcel_IOFactory::createReader 支援 setLoadSheetsOnly)getFormattedValue() 保留 Excel 顯示格式遵循本指南,你可以在半小時內為 ThinkPHP 專案新增穩健的 Excel 導入導出功能,並具備擴展至 CSV、ODS、PDF 等格式的基礎架構。