上传文件前必须设置enctype="multipart/form-data",否则request()->file()返回null;store()自动生成哈希名,storeAs()可指定路径和原名;图片校验需结合mimes、max及getimagesize()确保安全。

上传文件前必须验证 enctype="multipart/form-data"
表单没加这个属性,request()->file() 永远返回 null,Laravel 不会报错,但后端收不到任何文件。这是最常被跳过的一步。
正确写法:
- 只对含
的表单生效,纯文本表单不需要 - Blade 中用
@csrf保证 POST 安全,漏掉会 419 错误 - 如果用 Vue/React 管理表单,需手动设置
FormData并确保Content-Type不被浏览器自动覆盖
storeAs() 和 store() 的路径行为差异
store() 默认存到 storage/app/ 下,生成带哈希名的文件;storeAs() 允许指定完整路径和原始文件名,更适合头像、证件照等需保留原名的场景。
示例对比:
// 自动命名,返回类似 "qY3xZ2a.jpg"
$request->file('avatar')->store('avatars');
// 指定路径+原名,返回 "avatars/2024-user1.jpg"
$request->file('avatar')->storeAs('avatars', '2024-user1.jpg');
-
store()的第一个参数是子目录,不以/开头,也不影响磁盘根路径 -
storeAs()第二个参数若含子目录(如"avatars/2024/". $name),需确保上级目录存在,否则抛FileNotFoundException - 两种方法都依赖当前默认磁盘(
config/filesystems.php中'default'配置),不是硬编码storage_path()
用 Storage::link() 让 public 目录可访问 storage 文件
php artisan storage:link 命令本质是创建软链接:public/storage → ../storage/app/public。只有存到 public 磁盘的文件才能通过 URL 直接访问。
配置和使用要点:
// config/filesystems.php 中确保有:
'disks' => [
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
],
- 上传时显式指定磁盘:
$request->file('avatar')->store('avatars', 'public') - 生成访问 URL 必须用
Storage::url(),不能拼字符串:{{ Storage::url('avatars/photo.jpg') }}→ 输出/storage/avatars/photo.jpg - 运行
storage:link后,Linux/macOS 有效;Windows 需管理员权限或改用junction,否则链接无效
图片上传必须做 MIME 类型与尺寸校验
Laravel 的 mimes:jpeg,png,gif 只校验请求头中的 Content-Type,极易伪造。真正可靠的是读取文件头(fileinfo 扩展)或用 getimagesize()。
推荐组合校验方式:
$request->validate([
'avatar' => [
'required',
'file',
'mimes:jpeg,png,gif',
'max:2048', // KB
function ($attribute, $value, $fail) {
if (! @getimagesize($value->getPathname())) {
$fail('上传的文件不是有效图片。');
}
},
],
]);
-
max:2048控制的是文件大小,单位是 KB,不是字节 -
getimagesize()会真实解析文件头,比扩展名和 MIME 更可信,但对 SVG 等 XML 格式不适用(需额外判断) -
前端
accept="image/*"仅是提示,不可信,后端必须重复校验
图片缩略图、水印等进阶处理不在 Storage 范畴内,得靠 intervention/image 或 PHP-GD,那是另一层逻辑了。










