ThinkPHP批量导入核心是建立可识别、分发、校验、回滚的统一流程:用魔数识别真实文件类型(非后缀),CSV用fgetcsv流式读取,Excel用PhpSpreadsheet按格式显式加载,统一字段映射、清洗、分批事务入库并清理临时文件。

ThinkPHP 实现 Excel 或 CSV 批量导入数据库,核心不是“选哪个库”,而是建立一套可识别、可分发、可校验、可回滚的统一流程。关键在于:不依赖文件后缀,用魔数判断真实类型;不混写解析逻辑,按格式拆分处理;不一次加载全量数据,用流式或分批控制内存;不直插原始值,必须字段映射+清洗+事务入库。
真实类型识别:别信后缀和 MIME,看文件头 4 字节
用户可能把 CSV 改成 .xlsx 后缀,或上传无扩展名文件。仅靠 $_FILES['file']['type'] 或 pathinfo($file, PATHINFO_EXTENSION) 会出错。正确做法是读取文件前 4 字节做魔数比对:
-
efbbbf→ UTF-8 BOM 开头,判定为 CSV(常见于 Excel 另存为 CSV) -
d0cf11e0→ 标准 .xls(OLE 复合文档结构) -
504b0304→ ZIP 格式开头,可能是 .xlsx 或 ZIP 包裹的 CSV(需进一步检查内部文件列表或扩展名辅助判断)
代码片段示例:
$handle = fopen($filePath, 'rb');<br>$magic = bin2hex(fread($handle, 4));<br>fclose($handle);<br>return match($magic) {<br> 'efbbbf' => 'csv',<br> 'd0cf11e0' => 'xls',<br> '504b0304' => $this->isXlsxByExtension($filePath) ? 'xlsx' : 'csv',<br>};
CSV 导入:优先用 fgetcsv 流式读取,尤其大文件
避免 file_get_contents + str_getcsv 一次性载入内存。fgetcsv 支持按行读取、自动处理引号与逗号嵌套,更安全高效:
- 打开文件后,先调用一次
fgetcsv()跳过表头行 - 循环中每次获取一行数组,用
array_filter($row)排除全空行 - 建立字段映射(如 Excel 表头“手机号”→数据库字段
mobile),再提取对应索引值 - 每 500 行封装一次批量插入,用 PDO 预处理语句执行,开启事务保障一致性
注意:若 CSV 是 GBK 编码,需用 stream_filter_append($handle, 'convert.iconv.GBK/UTF-8') 转码,否则中文入库乱码。
立即学习“PHP免费学习笔记(深入)”;
从 CSV 数据集生成图数据库加载器和三元组映射。将表格 CSV 数据转换为图数据库可直接使用的节点、边和三元组。
Excel 导入:用 PhpSpreadsheet,但要显式指定格式+跳过空行
不要直接用 IOFactory::load(),它会自动探测格式,易误判且慢。应根据魔数结果明确创建 Reader:
-
IOFactory::createReader('Xls')处理 .xls -
IOFactory::createReader('Xlsx')处理 .xlsx
读取时启用迭代器,逐行扫描并过滤空行:
- 调用
$worksheet->getRowIterator()获取行迭代器 - 对每行调用
$row->getCellIterator(),并设setIterateOnlyExistingCells(false)确保读取空白单元格 - 用
$cell->getValue() !== null判断是否为空单元格,整行为空则跳过
表头中文需映射为数据库字段名,例如 “订单编号” → order_sn,建议配置映射规则数组或从数据库字段注释自动匹配。
统一入库:校验、清洗、分批、清理一步到位
无论 CSV 还是 Excel,解析后的每行数据都走同一套业务逻辑:
- 字段校验:手机号是否符合正则、邮箱格式、必填项是否为空
- 数据清洗:去除首尾空格、转换“是/否”为 1/0、日期字符串转时间戳
- 分批事务插入:每 1000 行启一个事务,成功则提交,失败则回滚并记录错误行号
- 导入完成立即删除临时文件:
unlink($filePath),防止磁盘占满 - 返回结构化 JSON:
{ "success": true, "total": 2356, "inserted": 2350, "failed": 6, "errors": [...] }
不复杂但容易忽略。


















