request()->file() 返回 null 主因是表单缺失 enctype=”multipart/form-data”,导致 $_files 为空;需检查表单 enctype、字段名一致性,并用 dd(request()->allfiles()) 直接查看原始上传数据。

上传文件时 request()->file() 返回 NULL 怎么办
多数情况是表单没设对 enctype,laravel 根本收不到原始文件数据。request()->file() 不是“读取失败”,而是压根没收到——它只从 PHP 的 $_FILES 里取值,而 $_FILES 为空时就返回 null。
- 检查 HTML 表单是否带
enctype="multipart/form-data",漏了这个,后端永远拿不到文件 - 确认字段名和
request()->file('xxx')中的'xxx'完全一致(区分大小写、无空格) - 用
dd(request()->allFiles())直接看 PHP 原始上传数组,比猜request()->file()更可靠 - 如果用了 Vue/React 等前端框架发请求,别用
json.stringify发表单——必须用FormData实例,否则文件不会进$_FILES
Laravel store() 和 storeAs() 选哪个
关键区别在路径控制粒度:store() 只管目录,文件名由 Laravel 自动生成;storeAs() 连路径+文件名都由你定,但得自己防重名、保扩展名。
-
store('uploads')→ 自动存到storage/app/uploads/xxx.jpg,文件名是随机哈希,安全但不可预测 -
storeAs('uploads', 'avatar_'.$user->id.'.jpg')→ 路径+名字全控,适合头像、合同等需语义化命名的场景 - 注意:两个方法都默认走
local驱动,如果配置了S3,它们会自动切到对象存储,不用改代码 - 别直接拼接用户传的文件名进
storeAs(),比如request()->file('f')->getClientOriginalName()可能含../或非法字符,先用str()->slug()或uniqid()处理
上传大文件报 413 Request Entity Too Large
这不是 Laravel 报的错,是 nginx 或 apache 在请求进 PHP 前就拦下了。PHP 层面的 upload_max_filesize 和 post_max_size 还没机会生效。
- Nginx 需在 server 或 location 块加
client_max_body_size 20M;(单位必须带 M/G) - Apache 2.4+ 用
LimitRequestBody 20971520(字节数),放在.htaccess或虚拟主机配置里 - PHP 配置要同步调大:
upload_max_filesize = 20M和post_max_size = 22M(后者略大于前者) - 开发时用
phpinfo()确认实际生效的配置项,别只改php.ini却忘了重启 php-fpm 或 Apache
验证文件类型只靠 mimes 规则够不够
不够。MIME 类型是客户端传来的,可伪造;mimes 规则只是校验 $_FILES['xxx']['type'] 字段,毫无安全性可言。
- 真正可靠的校验得用
mimetypes(基于文件头 magic bytes),Laravel 8+ 支持:'file' => 'mimetypes:image/jpeg,image/png' - 更稳妥的做法是结合扩展名 + MIME 检查:
$file->extension() === 'jpg' && $file->getMimeType() === 'image/jpeg' - PDF、ZIP 等格式容易被伪装,建议上传后用
file --mime-type命令行或finfo_open()再验一次(尤其涉及用户下载或渲染的场景) - 别用
getMimeType()判断图片能否显示——有些 WebP 文件报告image/webp,但旧版 PHP GD 不支持,得试加载
事情说清了就结束。文件上传链条长,每个环节(前端表单、Web 服务器、PHP 配置、Laravel 验证、存储驱动)都可能卡住,出问题先分层定位,别一上来就翻文档找 store() 参数。