处理多个Excel文件导入时,最怕的就是一个文件出错导致整个批次失败——用户一次性选择了3个.xlsx文件,每个文件结构一致但数据独立,必须逐个解析、清洗、分批插入,且彼此之间不能互相干扰。下面从上传、解析到入库,逐一拆解每个环节的陷阱与正确做法。 上传阶段:接收多个文件并校验格式 表单添加 mul
处理多个Excel文件导入时,最怕的就是一个文件出错导致整个批次失败——用户一次性选择了3个.xlsx文件,每个文件结构一致但数据独立,必须逐个解析、清洗、分批插入,且彼此之间不能互相干扰。下面从上传、解析到入库,逐一拆解每个环节的陷阱与正确做法。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
表单添加 multiple 属性是基本要求:,后端通过 request()->file('files') 获取文件数组。
遍历每个文件时,先提取真实后缀:pathinfo($file->getInfo()['name'], PATHINFO_EXTENSION),转大写后判断是否为 XLSX 或 XLS。注意,.csv、.txt 等非 Excel 格式必须拒绝——PhpSpreadsheet 默认不支持 CSV 读取,强行加载会直接报错,无需保留这种隐患。
对每个文件执行 $file->validate(['size' => 10 * 1024 * 1024, 'ext' => ['xlsx', 'xls']])->move(ROOT_PATH . 'uploads/excel/'),单个文件限制为 10MB,避免用户上传几百兆文件拖垮整个批次处理。
必须使用 pathinfo 获取真实扩展名,而不依赖 MIME 类型。某些系统会错误识别 .xls 文件为 application/octet-stream,导致验证通过但后续解析失败。
每个已成功移动的文件路径,按以下步骤处理:
使用 IOFactory::createReader($readerType),其中 $readerType = $ext === 'xlsx' 'Xlsx' : 'Xls'。切忌使用 IOFactory::load() 自动猜测格式——它会读取文件头尝试多种解析器,遇到 .xls 文件常误判为 .xlsx 导致解析崩溃,这一坑已有多人踩过。
调用 $reader->setReadDataOnly(true) 屏蔽样式、公式、注释等非数据内容,内存占用可降低 60% 以上,尤其适用于带条件格式的报表类Excel。
获取活动工作表后,使用 $worksheet->getRowIterator(1, 500) 每次最多读取 500 行。不设上限的话,10 万行 Excel 直接撑爆 PHP 内存,导致服务器挂死。
遍历每行单元格时,必须添加 $cellIterator->setIterateOnlyExistingCells(false)。否则Excel中间列为空时会跳过,后续列全部左移,字段错位——排查这类问题非常耗时。
组装行数据后,使用 array_filter($rowData) 判断是否全空,只保留至少有一个非空值的行。注意不要仅检查第一列,有些模板首列为序号,非空但其余列为空,这些无效行应被过滤。
每个文件解析出的所有有效行,按 400 行一组切片:$chunks = array_chunk($allRows, 400)。对每个 chunk,使用 Db::transaction(function () use ($chunk) { Db::name('user')->insertAll($chunk); }); 包裹——即使某个 chunk 插入失败(如唯一索引冲突),仅回滚当前 chunk,不影响同一文件的剩余数据。
外层不要用大事务包住所有文件。改用 foreach 遍历每个文件,每个文件单独 try/catch;捕获到 Throwable 时记录日志并继续处理下一个文件。绝不向上 throw,否则一个文件出错会导致后续所有文件跳过,用户只能重新上传全部。
第一行必须作为表头处理:用 $worksheet->getCellByColumnAndRow($col, 1)->getValue() 逐列读取,trim(str_replace(["n","r"], '', $header)) 清洗后匹配预设字段映射表,例如 ['用户姓名' => 'real_name', '手机号' => 'mobile']。未匹配上的列直接丢弃,防止Excel多出几列导致 insertAll 字段数与表结构不匹配——这种错误在线环境非常致命。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述