用 PhpSpreadsheet 替代已停更且不兼容 PHP 8.2+ 的 PHPExcel;读取需手动指定读取器(如'Xlsx'),设 setReadDataOnly(true);中文乱码需设输入编码,日期用 Date::isDateTime() 判断后转对象;大数据写入禁用样式、用 fromArray() 批量写,超5万行建议换 Spout。

直接上结论:用 PhpSpreadsheet,别碰 PHPExcel —— 它已停止维护,不兼容 PHP 8.2+,且在大文件、中文、日期处理上坑多雷密。
IOFactory::load() 读取失败?先看文件类型和扩展名是否匹配
IOFactory::load() 会根据文件扩展名自动选读取器,但容易翻车:
- 文件实际是
.xlsx,但后缀被改成.xls→ 报错Could not auto-detect file type - 上传时浏览器改了 MIME 类型(比如把
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet改成application/octet-stream)→ 读取器选错
解决办法是手动指定读取器:
use PhpOffice\PhpSpreadsheet\IOFactory;
$reader = IOFactory::createReader('Xlsx'); // 强制用 Xlsx 读取器
$reader->setReadDataOnly(true); // 只读值,跳过样式/公式(提速 + 避免乱码)
$spreadsheet = $reader->load($filePath);支持的读取器名必须大写准确:'Xlsx'、'Xls'、'Csv'、'Ods'。小写或拼错会抛出 InvalidArgumentException。
立即学习“PHP免费学习笔记(深入)”;
读取时中文乱码、日期变数字?关键在单元格值获取方式
$cell->getValue() 返回原始存储值,对中文、日期不友好:
- 中文字段可能返回空或乱码(尤其从 Windows Excel 保存的 ANSI 编码 CSV)
- 日期显示为类似
44562的序列号(Excel 序列日期)
正确做法:
- 中文乱码:读 CSV 时显式设置编码(
$reader->setInputEncoding('GBK')或'UTF-8'),xlsx 一般无此问题 - 日期识别:先用
\PhpOffice\PhpSpreadsheet\Shared\Date::isDateTime($cell)判断,再用$cell->getCalculatedValue()或Date::excelToDateTimeObject()转时间对象
if (\PhpOffice\PhpSpreadsheet\Shared\Date::isDateTime($cell)) {
$dateObj = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($cell->getValue());
$value = $dateObj->format('Y-m-d H:i:s');
} else {
$value = $cell->getCalculatedValue(); // 公式也走这里
}注意:getCalculatedValue() 比 getValue() 稍慢,但能统一处理公式、日期、数值格式。
写入大数据量 Excel 时内存爆掉?关掉样式 + 开流式写入
Spreadsheet 默认把整张表对象全加载进内存。10 万行 × 20 列就可能吃掉 500MB+ 内存。
必须做两件事:
- 创建时禁用样式缓存:
$spreadsheet->getProperties()->setCreator('')->setTitle('')->setDescription('');(减少元数据开销) - 写入用
fromArray()批量塞,别用setCellValue()循环单写(性能差 3–5 倍) - 超过 5 万行,考虑换
Spout:它不建对象模型,纯流式,内存恒定在 ~3MB
示例(安全写入):
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// 一次性写入二维数组(比循环快得多)
$header = ['姓名', '邮箱', '注册时间'];
$data = [
['张三', 'zhang@example.com', '2026-09-27'],
['李四', 'li@example.com', '2026-09-26'],
];
$sheet->fromArray(array_merge([$header], $data), null, 'A1');
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save('/tmp/export.xlsx');复杂点在于:不同来源的 Excel 行为不一致 —— 用户上传的文件可能混用 .xlsx/.xls/.csv,还带合并单元格、隐藏列、自定义格式。别指望一个 load() 调用通吃所有情况。真正上线前,必须拿真实用户上传样本跑几轮,重点测空单元格、跨行合并、超长文本截断、特殊字符(如换行符 \n)是否被转义。这些细节不提前踩,上线后就是半夜告警。



















