首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 匯入 Excel 檔案完整教學:Spreadsheet_Excel_Reader 實戰詳解

     編輯:PHP 相關知識

前言

Excel 作為商業資料交換通用格式,PHP 專案常需匯入 .xls/.xlsx 檔案。本文以經典 Spreadsheet_Excel_Reader 庫為例,詳細講解從安裝配置到資料讀取、編碼處理、錯誤處理的完整流程,並提供生產級程式碼範例。

一、環境準備與安裝

  1. 下載庫:Spreadsheet_Excel_Reader(支援 .xls,不支援 .xlsx)
  2. 解壓至專案目錄(如 vendor/Excel/)
  3. 確認 PHP 擴充套件:iconv 或 mbstring(編碼轉換必需)

二、核心程式碼詳解

<?php
require_once __DIR__ . '/vendor/Excel/reader.php';

// 1. 實例化讀取器
$data = new Spreadsheet_Excel_Reader();

// 2. 設定輸出編碼(關鍵:防止中文亂碼)
$data->setOutputEncoding('UTF-8');  // 現代專案建議 UTF-8

// 3. 可選:指定編碼轉換引擎(預設 iconv,可改 mbstring)
// $data->setUTFEncoder('mb');

// 4. 可選:設定行/列索引起始值(預設 1,改 0 符合陣列習慣)
// $data->setRowColOffset(0);

// 5. 可選:設定數值格式化
// $data->setDefaultFormat('%.2f');           // 預設兩位小數
// $data->setColumnFormat(4, '%.3f');         // 第 4 欄三位小數

// 6. 讀取 Excel 檔案
$filePath = __DIR__ . '/uploads/data.xls';
if (!$data->read($filePath)) {
    die('檔案讀取失敗:' . $filePath);
}

// 7. 取得資料維度
$rowCount = $data->sheets[0]['numRows'];
$colCount = $data->sheets[0]['numCols'];

echo "共 {$rowCount} 列,{$colCount} 欄\n";

// 8. 遍歷資料(索引從 1 開始,除非 setRowColOffset(0))
for ($i = 1; $i <= $rowCount; $i++) {
    $rowData = [];
    for ($j = 1; $j <= $colCount; $j++) {
        $cell = $data->sheets[0]['cells'][$i][$j] ?? '';
        $cellInfo = $data->sheets[0]['cellsInfo'][$i][$j] ?? [];
        
        // 進階:根據型別處理
        switch ($cellInfo['type'] ?? 'unknown') {
            case 'date':
                // Excel 日期為序數,需轉換
                $cell = date('Y-m-d', ($cell - 25569) * 86400);
                break;
            case 'number':
                // 可套用格式化
                break;
        }
        $rowData[] = $cell;
    }
    // 處理單行資料(如寫入資料庫)
    processRow($rowData);
}

function processRow(array $row) {
    // 實際業務邏輯:驗證、轉換、入庫
    // 範例:列印
    echo implode(', ', $row) . "\n";
}
?>

三、關鍵資料結構說明

讀取成功後,$data->sheets[0] 包含:

鍵名說明
numRows總行數
numCols總欄數
cells[i][j]第 i 行第 j 欄的格式化後值
cellsInfo[i][j]['type']型別:date/number/unknown
cellsInfo[i][j]['raw']原始未格式化值
cellsInfo[i][j]['colspan']橫向合併欄數
cellsInfo[i][j]['rowspan']縱向合併列數

四、常見問題與解決方案

4.1 中文亂碼

  • 確認 Excel 檔案實際編碼(通常為 GB2312/CP936 或 UTF-16LE)
  • setOutputEncoding('UTF-8') 配合 iconv/mbstring 自動轉碼
  • 若仍亂碼,嘗試 setUTFEncoder('mb') 強制使用 mbstring

4.2 日期讀取異常

Excel 日期儲存為「1900/1/1 起的天數序數」。轉換公式:

$unixTimestamp = ($excelSerial - 25569) * 86400;
$dateStr = date('Y-m-d', $unixTimestamp);

注意:Excel 錯誤地將 1900 視為閏年,1900/3/1 後日期需減 1 天修正。

4.3 記憶體耗盡(大檔案)

Spreadsheet_Excel_Reader 會將整個檔案載入記憶體。大檔案(>10MB)建議改用:

  • PhpSpreadsheet:支援 .xlsx、串流讀取(ReadFilter)、記憶體優化
  • Box/Spout:極低記憶體、串流讀寫、支援 .xlsx/.ods/.csv

4.4 .xlsx 不支援

本庫僅支援 .xls (BIFF 格式)。.xlsx 請使用 PhpSpreadsheet 或 Box/Spout。

五、生產級封裝建議

class ExcelImporter {
    private $reader;
    
    public function __construct(string $encoding = 'UTF-8') {
        $this->reader = new Spreadsheet_Excel_Reader();
        $this->reader->setOutputEncoding($encoding);
    }
    
    public function import(string $filePath, callable $rowHandler, array $options = []): int {
        if (!$this->reader->read($filePath)) {
            throw new \RuntimeException("無法讀取檔案: $filePath");
        }
        
        $sheet = $this->reader->sheets[0] ?? null;
        if (!$sheet) throw new \RuntimeException('檔案無工作表');
        
        $count = 0;
        $startRow = $options['start_row'] ?? 1; // 跳過標題列
        for ($i = $startRow; $i <= $sheet['numRows']; $i++) {
            $row = [];
            for ($j = 1; $j <= $sheet['numCols']; $j++) {
                $row[] = $sheet['cells'][$i][$j] ?? null;
            }
            // 過濾空行
            if (array_filter($row)) {
                $rowHandler($row, $i);
                $count++;
            }
        }
        return $count;
    }
}

// 使用範例
$importer = new ExcelImporter();
$imported = $importer->import('uploads/order.xls', function($row, $rowNum) {
    // $row[0] = 訂單號, $row[1] = 客戶, $row[2] = 金額...
    Order::create([
        'order_no' => $row[0],
        'customer' => $row[1],
        'amount'   => (float)$row[2],
    ]);
}, ['start_row' => 2]);

echo "成功匯入 {$imported} 筆訂單。";

六、現代替代方案推薦

庫支援格式記憶體效率功能豐富度學習曲線
PhpSpreadsheet.xls, .xlsx, .ods, .csv中(支援串流)極高(樣式、圖表、公式)中
Box/Spout.xlsx, .ods, .csv極高(純串流)中(核心讀寫)低
OpenSpout.xlsx, .ods, .csv極高中低
FastExcel.xlsx高低(Laravel 整合佳)極低

總結

Spreadsheet_Excel_Reader 是處理舊版 .xls 檔案的經典選擇,但不支援 .xlsx、記憶體效率低、維護狀態低。新專案強烈建議直接採用 PhpSpreadsheet(功能全)或 Box/Spout(效能極致)。無論選用何庫,核心流程皆為:實例化 → 設定編碼 → 讀取 → 遍歷轉換 → 業務入庫,並務必處理編碼、日期、合併儲存格、大檔案記憶體四大痛點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved