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

PHPExcel 讀取 Excel 檔案完整實作:日期轉換、編碼處理、多版本相容

     編輯:PHP 綜合知識

前置準備

  • 下載 PHPExcel (已停止維護,**新專案強烈建議使用 PhpSpreadsheet**),或 `composer require phpoffice/phpspreadsheet`。
  • 確認 PHP 安裝 `xml`、`zip`、`gd` 擴展。

核心程式碼

<?php
require_once 'PHPExcel.php'; // 或 vendor/autoload.php (PhpSpreadsheet)

/** Excel 日期序號轉 Gregorian 日期 (月/日/年) */
function excelDateToGregorian($serial) {
    // Excel 以 1900-01-01 為序號 1,但有 1900 年閏年 Bug,需減 25569 對齊 Unix 時間戳
    $jd = GregorianToJD(1, 1, 1970); // Unix epoch 轉 Julian Day
    $gregorian = JDToGregorian($jd + intval($serial) - 25569);
    return $gregorian; // 格式: "月/日/年"
}

$filePath = 'test.xlsx';

$phpExcel = new PHPExcel();
$reader = new PHPExcel_Reader_Excel2007(); // .xlsx

// 相容 .xls (Excel 97-2003)
if (!$reader->canRead($filePath)) {
    $reader = new PHPExcel_Reader_Excel5(); // .xls
    if (!$reader->canRead($filePath)) {
        die('不支援的 Excel 格式');
    }
}

$phpExcel = $reader->load($filePath);
$sheet = $phpExcel->getSheet(0); // 第一個工作表

$highestColumn = $sheet->getHighestColumn(); // 如 'F'
$highestRow = $sheet->getHighestRow();       // 如 100

// 從第 2 列開始 (第 1 列為標題)
for ($row = 2; $row <= $highestRow; $row++) {
    for ($col = 'A'; $col <= $highestColumn; $col++) {
        $cell = $sheet->getCellByColumnAndRow(ord($col) - 65, $row);
        $val = $cell->getValue();

        // 假設第 1 欄 (A) 為日期
        if ($col === 'A') {
            echo excelDateToGregorian($val) . "\t";
        } else {
            // 編碼轉換:若輸出亂碼,將 UTF-8 轉目標編碼 (如 GB2312)
            echo iconv('UTF-8', 'GB2312//IGNORE', $val) . "\t";
        }
    }
    echo "<br>\n";
}
?>

關鍵技術點解析

1. Excel 日期序號轉換原理

  • Excel 內部以 **序號** 儲存日期:1 = 1900-01-01 (實際為 1899-12-31 因閏年 Bug)。
  • Unix 時間戳起始 1970-01-01。
  • 轉換公式:`JulianDay(1970-01-01) + 序號 - 25569` → `JDToGregorian()` 取得「月/日/年」。
  • PhpSpreadsheet 內建 `PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($serial)` 更簡便。

2. 字元編碼處理

  • PHPExcel/PhpSpreadsheet 內部統一使用 **UTF-8**。
  • 若終端/頁面編碼為 GB2312/Big5,需 `iconv('UTF-8', 'GB2312//IGNORE', $val)` 轉換。
  • `//IGNORE` 忽略無法轉換字元,避免中斷。

3. 多版本相容策略

$readers = [
    new PHPExcel_Reader_Excel2007(), // .xlsx (OOXML)
    new PHPExcel_Reader_Excel5(),    // .xls (BIFF)
    new PHPExcel_Reader_CSV(),       // .csv
];
foreach ($readers as $reader) {
    if ($reader->canRead($filePath)) {
        $phpExcel = $reader->load($filePath);
        break;
    }
}
if (!isset($phpExcel)) die('無法識別格式');

4. 記憶體優化 (大檔案)

  • `$reader->setReadDataOnly(true)`:僅讀取資料,忽略樣式、圖表,大幅降低記憶體。
  • 分塊讀取:`$reader->setLoadSheetsOnly(['Sheet1'])` 只載入指定工作表。
  • 超大檔 (>10MB) 建議改用 `PhpSpreadsheet` 的 `Xlsx` reader 配合 `ReadFilter` 逐列處理,或轉 CSV 後用 `fgetcsv` 流式讀取。

遷移至 PhpSpreadsheet (現代專案必做)

<?php
require 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Shared\Date;

$spreadsheet = IOFactory::load('test.xlsx');
$sheet = $spreadsheet->getActiveSheet();

foreach ($sheet->getRowIterator(2) as $row) {
    $cellIterator = $row->getCellIterator();
    $cellIterator->setIterateOnlyExisting(false); // 含空儲存格

    foreach ($cellIterator as $cell) {
        $col = $cell->getColumn(); // 'A', 'B'...
        $val = $cell->getValue();

        if ($col === 'A' && Date::isDateTime($cell)) {
            // 內建日期判斷與轉換
            $dateTime = Date::excelToDateTimeObject($val);
            echo $dateTime->format('Y-m-d') . "\t";
        } else {
            echo $val . "\t";
        }
    }
    echo PHP_EOL;
}
?>

結語

PHPExcel 雖已停止維護,但既有專案仍廣泛使用。掌握「日期序號轉換、編碼處理、多版本相容、記憶體優化」四大核心,能穩定處理 Excel 匯入需求。**新專案請直接使用 PhpSpreadsheet**,享受 PSR-4、命名空間、型別提示、持續維護等現代化優勢。

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