PHPExcel读取Excel文件全指南:从入门到最佳实践

在Web开发中,Excel文件是数据交换的常见格式。PHP作为后端开发的主流语言之一,处理Excel文件是许多项目的刚需。PHPExcel(PHPExcel项目已停止维护,官方推荐迁移至PHPSpreadsheet)曾是PHP生态中最流行的Excel处理类库,支持读取、写入多种格式的Excel文件(.xls/.xlsx等)。

本文将详细讲解如何使用PHPExcel读取Excel文件,涵盖环境准备、基础读取、复杂数据类型处理、性能优化、常见问题及最佳实践,帮助开发者快速掌握Excel读取技能。

目录#

  1. 环境准备:安装与依赖配置
  2. 基础读取示例:.xls与.xlsx通用方案
  3. 进阶:读取不同类型的数据(文本/数字/日期/公式)
  4. 精准读取:指定工作表与单元格范围
  5. 批量处理:大文件内存优化技巧
  6. 常见问题与解决方案
  7. 最佳实践总结
  8. 替代方案:PHPSpreadsheet迁移指引
  9. 参考资料

1. 环境准备:安装与依赖配置#

1.1 PHPExcel安装方式#

PHPExcel支持两种安装方式:Composer自动管理或手动下载源码。

方式一:Composer安装(推荐)#

PHPExcel已发布至Packagist,可通过Composer直接安装:

# 安装最新稳定版(注意:PHPExcel已停止维护,最新版本为1.8.1)
composer require phpoffice/phpexcel:~1.8

安装完成后,通过Composer自动加载器引入类库:

require 'vendor/autoload.php';

方式二:手动下载源码#

  1. PHPExcel GitHub仓库下载最新源码包
  2. 解压后将Classes目录复制到项目中
  3. 手动引入核心文件:
require_once 'Classes/PHPExcel.php';
require_once 'Classes/PHPExcel/IOFactory.php';

1.2 必要依赖扩展#

PHPExcel读取Excel文件需要以下PHP扩展支持,请确保在php.ini中开启:

  • php_zip:处理压缩格式的.xlsx文件
  • php_xml:解析Excel的XML结构
  • php_gd2:处理Excel中的图片(非必需,若无需读取图片可忽略)
  • php_mbstring:处理多字节字符(中文等非ASCII字符)

可通过phpinfo()查看扩展是否开启,若未开启需在php.ini中启用并重启服务。


2. 基础读取示例:.xls与.xlsx通用方案#

PHPExcel针对不同Excel格式提供了专属Reader:

  • .xls(Excel 97-2003):使用PHPExcel_Reader_Excel5
  • .xlsx(Excel 2007+):使用PHPExcel_Reader_Excel2007

更便捷的方式是使用PHPExcel_IOFactory自动识别文件格式,无需手动指定Reader。

2.1 通用读取示例代码#

<?php
require 'vendor/autoload.php'; // Composer自动加载
 
try {
    // 1. 自动识别文件格式并加载Excel文件
    $filePath = './data/sample.xlsx';
    $objPHPExcel = PHPExcel_IOFactory::load($filePath);
 
    // 2. 获取第一个工作表(默认激活的工作表)
    $worksheet = $objPHPExcel->getActiveSheet();
    echo '当前工作表名称:' . $worksheet->getTitle() . PHP_EOL;
 
    // 3. 获取工作表最大行号和列号
    $highestRow = $worksheet->getHighestRow();
    $highestColumn = $worksheet->getHighestColumn();
    echo '数据范围:A1:' . $highestColumn . $highestRow . PHP_EOL;
 
    // 4. 遍历所有单元格,读取数据
    echo '读取结果:' . PHP_EOL;
    for ($row = 1; $row <= $highestRow; $row++) {
        $rowData = [];
        // 将列号转为数字(如A→1,B→2)
        $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($highestColumn);
        for ($col = 0; $col < $highestColumnIndex; $col++) {
            // 获取单元格值
            $cellValue = $worksheet->getCellByColumnAndRow($col, $row)->getValue();
            $rowData[] = $cellValue;
        }
        print_r($rowData);
    }
 
    // 5. 释放内存(处理大文件时必须)
    unset($objPHPExcel);
} catch (Exception $e) {
    die('读取Excel文件失败:' . $e->getMessage());
}
?>

2.2 关键代码解释#

  • PHPExcel_IOFactory::load($filePath):自动检测Excel格式并加载,内部会选择对应Reader
  • getActiveSheet():获取当前激活的工作表,也可通过getSheetByName('Sheet1')指定工作表名称
  • getHighestRow()/getHighestColumn():获取数据区域的边界,避免遍历空单元格
  • getCellByColumnAndRow($col, $row):通过列索引(从0开始)和行号(从1开始)获取单元格
  • unset($objPHPExcel):PHPExcel加载文件后会占用大量内存,处理完成后必须手动释放

3. 进阶:读取不同类型的数据#

Excel中包含多种数据类型,PHPExcel会自动识别并转换为PHP对应类型,需针对不同类型做特殊处理。

3.1 读取日期类型数据#

Excel中的日期存储为序列号(1900-01-01为1,递增1天),需使用PHPExcel_Shared_Date类转换为PHP时间戳:

$cellValue = $worksheet->getCell('A2')->getValue();
// 判断是否为日期类型
if (PHPExcel_Shared_Date::isDateTime($worksheet->getCell('A2'))) {
    // 转换为PHP时间戳
    $timestamp = PHPExcel_Shared_Date::ExcelToPHP($cellValue);
    // 格式化为日期字符串
    $dateStr = date('Y-m-d H:i:s', $timestamp);
    echo '日期值:' . $dateStr . PHP_EOL;
}

3.2 读取公式计算结果#

默认情况下getValue()会返回公式本身(如=SUM(A1:B1)),若需读取公式计算结果,使用getCalculatedValue()

$cell = $worksheet->getCell('C1');
if ($cell->getDataType() === PHPExcel_Cell_DataType::TYPE_FORMULA) {
    // 获取公式计算结果
    $calculatedValue = $cell->getCalculatedValue();
    echo '公式结果:' . $calculatedValue . PHP_EOL;
}

3.3 读取数字与文本#

  • 数字类型:直接返回int/float类型,可通过getFormattedValue()获取格式化后的字符串(如货币、百分比)
  • 文本类型:直接返回字符串,若数字以文本格式存储(如身份证号),getValue()会返回字符串而非数字
// 获取格式化后的数字(如"1,234.56")
$formattedValue = $worksheet->getCell('B2')->getFormattedValue();
// 获取原始数字值(如1234.56)
$rawValue = $worksheet->getCell('B2')->getValue();

4. 精准读取:指定工作表与单元格范围#

4.1 读取指定工作表#

// 按工作表名称读取
$worksheet = $objPHPExcel->getSheetByName('用户数据');
// 按工作表索引读取(从0开始,0为第一个工作表)
$worksheet = $objPHPExcel->getSheet(1);
 
// 遍历所有工作表
$sheetCount = $objPHPExcel->getSheetCount();
for ($i = 0; $i < $sheetCount; $i++) {
    $worksheet = $objPHPExcel->getSheet($i);
    echo '工作表' . ($i+1) . ':' . $worksheet->getTitle() . PHP_EOL;
}

4.2 读取指定单元格范围#

使用PHPExcel_Reader_IReadFilter自定义读取规则,仅加载需要的行/列,大幅提升大文件读取性能:

<?php
// 自定义读取过滤器
class RangeReadFilter implements PHPExcel_Reader_IReadFilter {
    private $startRow;
    private $endRow;
    private $columns;
 
    public function __construct($startRow, $endRow, $columns) {
        $this->startRow = $startRow;
        $this->endRow = $endRow;
        $this->columns = $columns;
    }
 
    // 决定是否读取指定单元格
    public function readCell($column, $row, $worksheetName = '') {
        // 限制行范围且列在指定列表中
        if ($row >= $this->startRow && $row <= $this->endRow) {
            if (in_array($column, $this->columns)) {
                return true;
            }
        }
        return false;
    }
}
 
// 使用过滤器读取
$reader = PHPExcel_IOFactory::createReaderForFile('./data/large_data.xlsx');
// 仅读取第10-100行的A、B、C列
$filter = new RangeReadFilter(10, 100, ['A', 'B', 'C']);
$reader->setReadFilter($filter);
$objPHPExcel = $reader->load('./data/large_data.xlsx');
?>

5. 批量处理:大文件内存优化技巧#

处理超过10万行的大Excel文件时,PHPExcel默认会将整个文件加载到内存,易导致内存溢出,需通过以下方式优化:

5.1 开启只读模式#

仅读取数据,不加载格式、样式等非必要信息:

$reader = PHPExcel_IOFactory::createReaderForFile('./data/large_data.xlsx');
$reader->setReadDataOnly(true); // 仅读取原始数据
$objPHPExcel = $reader->load($filePath);

5.2 启用单元格缓存#

将单元格数据存储到磁盘或临时文件,减少内存占用:

// 使用PHP临时文件缓存单元格
PHPExcel_Settings::setCacheStorageMethod(
    PHPExcel_CachedObjectStorageFactory::cache_to_phpTemp,
    ['memoryCacheSize' => '8MB'] // 内存缓存阈值,超过后写入临时文件
);

5.3 分块读取文件#

结合RangeReadFilter分批次读取大文件,每次读取1000行处理后释放内存:

$batchSize = 1000; // 每次读取1000行
$totalRows = $worksheet->getHighestRow();
 
for ($startRow = 1; $startRow <= $totalRows; $startRow += $batchSize) {
    $endRow = min($startRow + $batchSize - 1, $totalRows);
    $filter = new RangeReadFilter($startRow, $endRow, ['A', 'B', 'C']);
    
    $reader->setReadFilter($filter);
    $objPHPExcel = $reader->load($filePath);
    
    // 处理当前批次数据
    processBatchData($objPHPExcel->getActiveSheet());
    
    // 释放内存
    unset($objPHPExcel);
}

6. 常见问题与解决方案#

问题1:内存溢出(Fatal error: Allowed memory size of ... bytes exhausted)#

  • 解决方案
    1. 开启setReadDataOnly(true)模式
    2. 启用单元格缓存(如cache_to_phpTemp)
    3. 分块读取文件,避免一次性加载全量数据
    4. 临时调整PHP内存限制:ini_set('memory_limit', '256M')

问题2:中文乱码#

  • 解决方案
    1. 确保PHP文件编码为UTF-8
    2. 若Excel文件为GBK编码,读取后转码:$cellValue = mb_convert_encoding($cellValue, 'UTF-8', 'GBK')
    3. 建议将Excel保存为UTF-8编码的.xlsx格式

问题3:无法打开文件(File does not exist or is not readable)#

  • 解决方案
    1. 检查文件路径是否正确(绝对路径优先)
    2. 确保PHP进程对文件拥有读取权限(Linux下需设置chmod 644
    3. 若文件在Windows下,注意路径分隔符使用/或转义的\\

问题4:公式读取返回公式而非结果#

  • 解决方案:使用getCalculatedValue()替代getValue()获取公式计算结果,若公式依赖外部数据,需确保依赖单元格已加载。

7. 最佳实践总结#

  1. 优先使用IOFactory自动识别格式:避免手动指定Reader导致的格式兼容问题
  2. 大文件必做内存优化:开启只读模式+分块读取+单元格缓存
  3. 及时释放内存:处理完Excel文件后必须unset($objPHPExcel)
  4. 异常捕获:所有Excel操作包裹在try-catch中,优雅处理文件不存在、格式错误等异常
  5. 仅读取必要数据:使用RangeReadFilter限制读取范围,减少资源消耗
  6. 数据类型校验:读取日期、公式等特殊类型时,先判断数据类型再处理

8. 替代方案:PHPSpreadsheet迁移指引#

PHPExcel于2017年停止维护,官方推荐使用PHPSpreadsheet(PHPExcel的继任者),支持PHP7.1+及PHP8.x,性能提升显著,功能更丰富。

PHPSpreadsheet读取Excel示例#

<?php
require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\IOFactory;
 
try {
    $spreadsheet = IOFactory::load('./data/sample.xlsx');
    $worksheet = $spreadsheet->getActiveSheet();
    
    foreach ($worksheet->getRowIterator() as $row) {
        $cellIterator = $row->getCellIterator();
        $cellIterator->setIterateOnlyExistingCells(false); // 遍历所有单元格
        foreach ($cellIterator as $cell) {
            echo $cell->getValue() . "\t";
        }
        echo PHP_EOL;
    }
    
    unset($spreadsheet);
} catch (Exception $e) {
    die('读取失败:' . $e->getMessage());
}
?>

核心差异#

  • 命名空间变更:从PHPExcel_*变为PhpOffice\PhpSpreadsheet\*
  • 性能优化:PhpSpreadsheet内存占用比PHPExcel降低约30%
  • 支持更多格式:如ODS、CSV、PDF等
  • 兼容PHP8.x:修复PHPExcel在高版本PHP中的兼容性问题

9. 参考资料#

  1. PHPExcel官方文档:https://github.com/PHPOffice/PHPExcel/wiki
  2. PHPSpreadsheet官方文档:https://phpspreadsheet.readthedocs.io/
  3. PHPExcel API参考:https://phpoffice.github.io/PHPExcel/
  4. PHP扩展配置指南:https://www.php.net/manual/zh/extensions.php