必须使用 maatwebsite/excel:^4.0 适配 Laravel 10+ 和 PHP 8.1+,v4 支持自动发现无需手动注册;导入需限定 .xlsx/.csv、指定引擎及规范表头;导出应采用 stream() 流式处理、FromQuery 分批查询并清洗数据防公式注入。

composer require 时提示 maatwebsite/excel 不兼容 Laravel 10+
新版 Laravel(10+)默认使用 PHP 8.1+,而旧版 maatwebsite/excel v3.x 只支持到 Laravel 8,强行装会报依赖冲突或 Class "Maatwebsite\Excel\ExcelServiceProvider" not found 错误。
必须用官方推荐的 v4.x 版本,它原生适配 Laravel 10/11 和 PHP 8.1+:
- 运行
composer require maatwebsite/excel:^4.0(别漏^4.0,否则可能装错小版本) - v4 不再需要手动注册 Service Provider,Laravel 5.5+ 的自动发现机制会处理
- 如果项目禁用了包自动发现,才需手动在
config/app.php的providers数组里加Maatwebsite\Excel\ExcelServiceProvider::class
导入 Excel 时抛出 PhpSpreadsheet\Exception 或乱码中文列名
常见于上传了 .xls(Excel 97-2003)格式,或文件编码非 UTF-8,或表头含空格/特殊符号但没做清理。
实操建议:
- 强制限定只接受
.xlsx和.csv:在表单<input type="file">加accept=".xlsx,.csv" - 导入前先用
Excel::import()的第二个参数指定读取引擎:Excel::import(new UsersImport, $request->file('file'), null, \Maatwebsite\Excel\Excel::XLSX) - 在 Import 类的
headingRow()方法里返回1,确保读第一行为字段名;若首行有合并单元格,改用headingRow() { return 0; }并手动定义$heading数组 - 中文列名乱码?不是编码问题,是 PhpSpreadsheet 默认把表头转成小写并去空格——在
toModel()前用$row = array_change_key_case($row, CASE_LOWER);统一处理键名
导出大数据量(>5000 行)卡死或内存溢出
Excel::download() 默认把整张表加载进内存再吐给浏览器,数据一多就崩,错误通常是 Allowed memory size exhausted 或超时。
正确做法是流式导出(Streaming Export):
- 不用
Excel::download(),改用Excel::stream()—— 它边生成边输出,不缓存全量数据 - 在 Export 类里实现
FromQuery而非FromArray或FromCollection,让 Laravel 用游标分批查库 - 加上
ShouldQueue接口,配合队列跑导出任务(尤其要发邮件附带 Excel 时) - 避免在
map()里调用 N+1 查询,所有关联数据提前用with()预加载
导出的 Excel 打开提示“发现不可读内容”
本质是 XML 结构不合法,90% 是单元格里混入了未转义的 HTML 标签(比如用户输入了 <script></script>)、控制字符(如 \x00、\r\n 混用),或超长字符串(Excel 单元格上限 32767 字符)。
防御性处理方式:
- 在
map()或transform()里统一清洗字段:strip_tags($value)+str_replace(["\r", "\n"], ' ', $value) - 对可能超长的字段截断:
Str::limit($value, 32760, '...') - 导出 CSV 时更简单:用
WithStrictNullComparison避免空值被转成字符串"null",引发解析失败
真正麻烦的是 Excel 公式注入——如果导出字段来自用户输入,且以 =、+、-、@ 开头,Excel 会当成公式执行。务必在输出前加单引号前缀:''. $value


















