PHPExcel读取Excel文件全指南:从入门到最佳实践
在Web开发中,Excel文件是数据交换的常见格式。PHP作为后端开发的主流语言之一,处理Excel文件是许多项目的刚需。PHPExcel(PHPExcel项目已停止维护,官方推荐迁移至PHPSpreadsheet)曾是PHP生态中最流行的Excel处理类库,支持读取、写入多种格式的Excel文件(.xls/.xlsx等)。
本文将详细讲解如何使用PHPExcel读取Excel文件,涵盖环境准备、基础读取、复杂数据类型处理、性能优化、常见问题及最佳实践,帮助开发者快速掌握Excel读取技能。
目录#
- 环境准备:安装与依赖配置
- 基础读取示例:.xls与.xlsx通用方案
- 进阶:读取不同类型的数据(文本/数字/日期/公式)
- 精准读取:指定工作表与单元格范围
- 批量处理:大文件内存优化技巧
- 常见问题与解决方案
- 最佳实践总结
- 替代方案:PHPSpreadsheet迁移指引
- 参考资料
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';方式二:手动下载源码#
- 从PHPExcel GitHub仓库下载最新源码包
- 解压后将
Classes目录复制到项目中 - 手动引入核心文件:
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格式并加载,内部会选择对应ReadergetActiveSheet():获取当前激活的工作表,也可通过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)#
- 解决方案:
- 开启
setReadDataOnly(true)模式 - 启用单元格缓存(如cache_to_phpTemp)
- 分块读取文件,避免一次性加载全量数据
- 临时调整PHP内存限制:
ini_set('memory_limit', '256M')
- 开启
问题2:中文乱码#
- 解决方案:
- 确保PHP文件编码为UTF-8
- 若Excel文件为GBK编码,读取后转码:
$cellValue = mb_convert_encoding($cellValue, 'UTF-8', 'GBK') - 建议将Excel保存为UTF-8编码的.xlsx格式
问题3:无法打开文件(File does not exist or is not readable)#
- 解决方案:
- 检查文件路径是否正确(绝对路径优先)
- 确保PHP进程对文件拥有读取权限(Linux下需设置
chmod 644) - 若文件在Windows下,注意路径分隔符使用
/或转义的\\
问题4:公式读取返回公式而非结果#
- 解决方案:使用
getCalculatedValue()替代getValue()获取公式计算结果,若公式依赖外部数据,需确保依赖单元格已加载。
7. 最佳实践总结#
- 优先使用IOFactory自动识别格式:避免手动指定Reader导致的格式兼容问题
- 大文件必做内存优化:开启只读模式+分块读取+单元格缓存
- 及时释放内存:处理完Excel文件后必须
unset($objPHPExcel) - 异常捕获:所有Excel操作包裹在
try-catch中,优雅处理文件不存在、格式错误等异常 - 仅读取必要数据:使用
RangeReadFilter限制读取范围,减少资源消耗 - 数据类型校验:读取日期、公式等特殊类型时,先判断数据类型再处理
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. 参考资料#
- PHPExcel官方文档:https://github.com/PHPOffice/PHPExcel/wiki
- PHPSpreadsheet官方文档:https://phpspreadsheet.readthedocs.io/
- PHPExcel API参考:https://phpoffice.github.io/PHPExcel/
- PHP扩展配置指南:https://www.php.net/manual/zh/extensions.php