request()->file()返回的是think\file对象而非$_files数组,需调用getoriginalname()、getextension()等方法操作,validate()必须紧邻move()调用且仅对下一次move生效。

request()->file() 返回的是 File 对象,不是 $_FILES 数组
很多人误以为 request()->file('xxx') 返回的是原生 $_FILES 数组,结果直接用 $file['name'] 访问报错。实际上它返回的是 \think\File 实例,所有操作都必须调用对象方法。
-
$file->getOriginalName()获取客户端原始文件名(含扩展名) -
$file->getExtension()只取扩展名,比如png,不带点 -
$file->getSize()返回字节数,不是字符串,可用于大小判断 -
$file->getMime()获取真实 MIME 类型(如image/jpeg),比扩展名更可靠 - 若想看完整底层信息,可用
$file->getInfo(),返回类似$_FILES的数组结构
上传失败时 getError() 返回的是中文提示,不是错误码
$file->getError() 不是返回 UPLOAD_ERR_OK 这类整数,而是直接拼接好的中文错误描述,比如 "上传文件大小超出限制" 或 "非法的文件类型"。这在调试时方便,但不适合做条件分支。
- 真正判断是否上传失败,应检查
$file是否为null,或调用$file->isValid()—— 它返回布尔值 - 不要写
if ($file->getError() !== ''),因为某些场景下即使没错误也可能返回空字符串 - 如果需要区分错误类型,建议用
try...catch包裹validate()和move(),捕获ValidateException
validate() 必须在 move() 之前调用,且规则不自动继承
validate() 是链式调用,但它的校验只对紧接下来的 move() 生效,不会“记住”规则。如果中间穿插了其他操作(比如先 getMime() 再 move()),校验可能被跳过。
- 正确写法:
$file->validate(['size' => 2097152, 'ext' => 'jpg,png'])->move('uploads') - 错误写法:
$file->validate([...]); $file->getMime(); $file->move(...)—— 此时 validate 未生效 - 注意
'type'键已被弃用,ThinkPHP 6+ 推荐用'mime'或直接靠checkMime()手动校验 - 如果用了
Filesystem::disk()->putFile(),则 validate 要提前调用在$file上,不能丢给 putFile 处理
流式处理大文件时别用 move(),改用 stream() + writeStream()
当上传超大文件(比如视频、日志包),move() 会把整个文件加载进内存再写入磁盘,容易触发内存溢出或超时。此时应绕过临时文件,直接读取上传流。
- 用
$file->getStream()获取原生 PHPresource流(非字符串) - 配合
Filesystem::disk('public')->writeStream($path, $stream)直接写入 - 务必手动关闭流:
fclose($stream),否则句柄泄漏 - 注意:此方式跳过了
validate()的大小和类型校验,需自行用fstat()和finfo_open()补充 - 常见坑:
getStream()后不能再调用move(),会报 “already moved” 错误
File 对象的生命周期、校验时机、流与文件路径的切换,这几个点一旦混淆,就会出现“明明写了 validate 却没生效”或“大文件上传一半就 500”的情况。最易被忽略的是:validate 不是设置属性,而是立即执行的校验动作,且仅绑定到下一个 move() 调用。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











