Laravel文件上传失败或存后无法访问,90%因enctype缺失、磁盘配置错误、未执行php artisan storage:link,或验证规则未用files.*通配符;$request->file()为null本质是HTTP层未发送文件,须严格检查form enctype、name一致性、多文件键名格式及Nginx/PHP大小限制。

直接说结论:Laravel 文件上传失败或存后无法访问,90% 是因为 enctype 漏了、磁盘配错、没跑 php artisan storage:link,或者验证规则写在数组键上却忘了用 files.* 通配符。
表单提交后 $request->file() 总是 null?
这不是 Laravel 的 bug,是 HTTP 协议层就拦下了——浏览器根本没发文件数据。
- 必须检查
<form></form>标签有没有enctype="multipart/form-data",漏一个字符都不行 -
name属性值(比如avatar)要和控制器里$request->file('avatar')的字符串完全一致,大小写、下划线、中划线都不能错 - 多文件上传时,
name="photos[]"对应的是$request->file('photos')(返回数组),不是$request->file('photos.0') - 临时加一行
dd($request->allFiles()),看输出是不是空数组——如果是,问题一定出在前端或 Nginx/Apache 配置(如client_max_body_size被限制)
store() 存进去了,但 Storage::url() 返回 404?
路径生成没问题,问题是 Web 服务器压根没权限读那个文件。
- 只用
public磁盘 + 必须执行php artisan storage:link,否则/storage/xxx路由永远 404 - 别用
local磁盘存公开文件,它默认指向storage/app,这个目录不在 Web root 下,Nginx 直接拒访 - 确认
config/filesystems.php里public磁盘的url配置匹配APP_URL,比如APP_URL=http://localhost:8000,那url就得是'url' => env('APP_URL').'/storage' - Linux 环境下注意软链接权限:
ls -l public/storage应显示指向../storage/app/public,且 Web 用户(如 www-data)有读取storage/app/public目录的权限
多文件上传怎么让每个都校验大小和类型?
不能只写 'files' => 'required|array',这只会校验“有没有传数组”,不校验里面每个文件。
- 必须用通配符规则:
'files.*' => 'required|file|mimes:jpeg,png,pdf|max:2048' -
mimes比extensions安全,它调用finfo_file()读文件头,防伪装(比如把 php 文件改成.jpg后缀) - 如果前端 name 是动态的(如
file-1649657296668-0[]),验证规则就得写成'file-1649657296668-0.*' => '...',不然规则不生效 - 验证通过后,
$request->file('files')返回的数组里每个元素都是合法UploadedFile实例,可直接遍历调用store()
为什么不能直接用 getClientOriginalName() 做文件名?
用户传来的原始文件名是不可信输入,可能含路径遍历(../../.env)、空字节、Unicode 控制字符,甚至触发 XSS(如果后续拼进 HTML)。
- 永远不要拼接
$file->getClientOriginalName()到存储路径里 - 推荐用
$file->store('uploads', 'public')—— 它自动哈希命名,安全又省事 - 真要保留原始扩展名,用
$file->guessExtension()(基于 MIME 类型推断,比后缀可靠) - 自定义文件名时,强制剥离所有非字母数字字符:
Str::slug(pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME)) . '.' . $file->guessExtension()
最常被跳过的其实是 storage:link 和 mimes 规则背后的 finfo 扩展依赖——PHP 没装 fileinfo,mimes 就退化成只看后缀,等于没验。


















