支援 **BIFF 7/8 (xls)** 及 **Office Open XML (xlsx)** 格式,純 PHP 實作,無需 COM 元件或 LibreOffice,適合 Linux 伺服器部署。專案地址:sourceforge.net/projects/phpexcelreader
iconv 或 mbstring 擴展(編碼轉換)utf8mb4 字元集project/ ├── test.php # 主程式 ├── includes/ │ ├── reader.php # 核心解析類 │ └── OLERead.php # OLE 容器解析 └── data.xls # 待匯入 Excel 檔
test.php<?php
require_once './includes/reader.php';
// 1. 實例化並設定輸出編碼
$data = new Spreadsheet_Excel_Reader();
$data->setOutputEncoding('utf-8'); // 內部轉為 UTF-8
// 2. 讀取 Excel 檔
$file = 'data.xls'; // 或 data.xlsx
if (!$data->read($file)) {
die("讀取失敗:檔案不存在或格式錯誤");
}
// 3. 連線資料庫 (PDO 推薦)
$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8mb4", "root", "1234");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 4. 遍歷第一個工作表 (sheets[0])
$sheet = $data->sheets[0];
$rows = $sheet['numRows'];
$cols = $sheet['numCols'];
echo "偵測到 $rows 列 x $cols 欄,開始匯入...<br>";
$stmt = $pdo->prepare("INSERT INTO `import_table` (col1, col2, col3) VALUES (?, ?, ?)");
$success = 0;
for ($i = 1; $i <= $rows; $i++) { // Excel 列索引從 1 開始
// 讀取儲存格值 (欄索引從 1 開始)
$val1 = $sheet['cells'][$i][1] ?? '';
$val2 = $sheet['cells'][$i][2] ?? '';
$val3 = $sheet['cells'][$i][3] ?? '';
// 跳過空白列
if (trim("$val1$val2$val3") === '') continue;
try {
$stmt->execute([$val1, $val2, $val3]);
$success++;
} catch (PDOException $e) {
echo "第 $i 列寫入失敗: " . $e->getMessage() . "<br>";
}
}
echo "匯入完成:成功 $success 筆<br>";
OLERead.php - OLE 容器解析負責解析 `.xls` 的 OLE 復合文件結構:
Workbook 資料流read($filename)、getWorkBook()reader.php - BIFF 格式解析解析 Excel 內部二進位記錄:
_parse():解析全域記錄 (SST 共享字串表、Format 格式、XF 樣式、BoundSheet 工作表資訊)_parsesheet():解析工作表記錄 (ROW、NUMBER、LABEL、FORMULA、RK、MULRK、BOOLERR 等)_encodeUTF16() 使用 iconv 或 mb_convert_encoding 將 UTF-16LE 轉目標編碼| 問題 | 原因與解決 |
|---|---|
| 中文亂碼 | 確認 setOutputEncoding('utf-8')、資料庫 charset=utf8mb4、PHP 檔案儲存為 UTF-8 without BOM |
| xlsx 讀取失敗 | 舊版僅支援 xls。新版已支援 xlsx,請更新至最新版或改用 PhpSpreadsheet |
| 日期變成數字 | Excel 日期儲存為序數。庫會自動偵測 XF 格式轉換,若失敗可手動:date('Y-m-d', ($val - 25569) * 86400) |
| 大檔案記憶體不足 | Reader 會將整檔載入記憶體。超過 10MB 建議改用 PhpSpreadsheet 的 ChunkReadFilter 分塊讀取 |
| 合併儲存格值為空 | 僅主儲存格有值,合併區域其他儲存格為空。需根據 mergedCells 資訊自行填補 |
PHPExcelReader 為舊專案,已停止維護。新專案請使用 **PhpSpreadsheet**(PHPExcel 繼任者):
composer require phpoffice/phpspreadsheet
<?php
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
$reader = new Xlsx();
$reader->setReadDataOnly(true); // 僅讀資料,不載入樣式,省記憶體
$spreadsheet = $reader->load("data.xlsx");
$sheet = $spreadsheet->getActiveSheet();
foreach ($sheet->getRowIterator() as $row) {
$cells = [];
foreach ($row->getCellIterator() as $cell) {
$cells[] = $cell->getValue();
}
// 寫入 DB...
}
優勢:支援 .xls/.xlsx/.ods/.csv、記憶體優化、活躍維護、Composer 安裝、命名空間、PHP 8 相容。
PHPExcelReader 為快速導入舊版 .xls 提供了零依賴的純 PHP 方案。但面對 .xlsx、大檔案、複雜格式,**PhpSpreadsheet 是現代標準選擇**。匯入流程核心:讀取 → 驗證/清洗 → 批次預處理寫入 → 記錄錯誤日誌,建議封裝為可複用的 Import Service 類別。