ThinkPHP 6 Excel导入必须用request()->file('字段名')获取think\File对象,依赖fileinfo扩展校验MIME;需用phpoffice/phpspreadsheet读取,先move()再加载,大文件分块读,日期需excelToDateTimeObject()转换,表头和数据须清洗。

ThinkPHP 6 的 Excel 导入不能直接用 input() 接收文件,必须走 request()->file(),且 PHP 必须启用 fileinfo 扩展,否则会报 Unable to determine mime type 错误。
如何正确获取上传的 Excel 文件
ThinkPHP 6 中上传文件不走传统表单数据流,$_FILES 或 input('file') 都拿不到有效句柄。必须用框架封装的 request()->file() 方法,并指定字段名(如 file):
-
request()->file('file')返回think\File对象,不是原始数组 - 若前端用
<input type="file" name="excel">,则此处必须写request()->file('excel'),名称要严格一致 - 未上传时返回
null,需先判空再调用validate()或move() - 验证 MIME 类型时,
validate(['ext' => ['xlsx', 'xls']])仅校验后缀,实际还需检查真实类型——依赖fileinfo扩展
用 PhpSpreadsheet 读取 Excel 数据(非 ThinkPHP 自带)
ThinkPHP 官方没有内置 Excel 解析能力,必须引入第三方库。推荐使用 phpoffice/phpspreadsheet(原 PHPExcel 维护分支),注意不要装错包(phpexcel 已废弃):
- 安装命令:
composer require phpoffice/phpspreadsheet - 读取时不要用
IOFactory::load()直接传临时路径,应先move()到可读目录,再用绝对路径加载 - 避免内存溢出:大文件(>5MB 或行数 >10k)建议用
ChunkReadFilter分块读,或改用toArray()前加setReadDataOnly(true) - 日期单元格默认读成数字(Excel 序列值),需用
PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject()转换
常见报错与绕过方式
导入失败往往卡在解析环节,而不是上传环节。典型错误和对应动作如下:
立即学习“PHP免费学习笔记(深入)”;
-
Could not open ... for reading! File does not exist.:move()失败或路径权限不对,检查runtime/upload/是否可写 -
Invalid cell coordinate:Excel 里有非法格式(如合并单元格跨空行、自定义格式乱码),加setReadDataOnly(true)可跳过样式解析 -
Class 'PhpOffice\PhpSpreadsheet\IOFactory' not found:Composer 自动加载失效,执行composer dump-autoload - 中文乱码:不是编码问题,是 PhpSpreadsheet 默认用 UTF-8,但 Excel 内容本身含 BOM 或 GBK 编码——此时应让 Excel 源文件保存为 UTF-8(无 BOM)格式
数据入库前的关键清洗点
Excel 表头常含空格、全角符号、换行符,直接当数据库字段名用会报错;内容也常有首尾空格、空行、注释行。必须在解析后、入库前处理:
- 表头标准化:
trim(str_replace(["\n", "\r", " ", " "], "", $header)) - 跳过空行:
if (empty(array_filter($row))) continue; - 数值型字段强制转类型:
is_numeric($val) ? (float)$val : $val,防止字符串 '123' 写进 int 字段失败 - 时间字段校验:
strtotime($val) === false则设为 null 或抛异常,别让无效时间进数据库
Excel 导入真正的难点不在代码量,而在于用户上传的文件永远比你预设的“标准格式”更离谱——合并单元格、隐藏列、公式结果、手动插入的空行……这些都得在解析层做防御性处理,而不是靠前端提示“请按模板填写”。



















