Laravel多图上传需用循环+事务确保一致性:前端name带[]、enctype正确;后端校验photos.*、判空用is_array+count;事务中逐张存文件并批量insert,失败时清理已存文件。

要在Laravel中一次性上传多张图片并同步写入数据库记录,避免文件存一半、数据库少几条或路径错乱,必须绕过storeMultiple()这种不存在的方法,用真实可执行的循环+事务控制路径。
前端表单必须带方括号和multiple属性
在Blade模板里写,name末尾的[]不是可选项——它决定$request->file('photos')返回的是数组还是单个对象。漏掉方括号,后端永远只收到第一张图。
form标签必须声明enctype="multipart/form-data",否则浏览器根本不会发送文件二进制流,你连空数组都收不到。
后端接收与验证要按元素校验
验证规则必须写成'photos.*' => 'required|image|mimes:jpg,jpeg,png|max:2048',不能写'photos'——后者只校验数组是否存在,不检查每个文件是否合法。
如果用户没选任何文件,$request->file('photos')返回空数组[],不是null,所以判断时别用isset(),改用is_array($files) && count($files) > 0。
单次循环完成存储+入库(推荐)
第一步:开启数据库事务,防止中途失败导致文件残留或记录缺失。
第二步:遍历每个UploadedFile对象,为每张图生成唯一路径——比如'photos/' . now()->format('Y/m/d') . '/' . Str::uuid() . '.' . $file->extension()。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
第三步:调用$file->storeAs($path, $filename, ['disk' => 'public'])保存,返回实际存储路径字符串。这一步会自动处理重命名、目录创建和异常抛出。
第四步:收集所有路径和关联字段(如album_id、sort_order),组装成二维数组,最后用Photo::insert($batchData)批量写入。注意不要用createMany(),它跳过模型boot()里的自动填充逻辑。
【关键前提】必须确保$batchData中每行数据的键名与Photo模型fillable属性完全一致,否则insert()会静默丢弃字段。
事务失败后清理已传文件(补偿机制)
方法一:捕获DB::transaction()抛出的Exception,在catch块里遍历已保存的路径,逐个调用Storage::delete($path)清除。
方法二:改用先存文件再写库策略——先批量调$file->store()拿到全部路径,再开启事务插入数据库;失败时不删文件,靠后台任务扫描孤立文件清理。
注意:本地开发用local磁盘时,Storage::delete()删的是相对路径;切到S3时,它会发DELETE请求,速度慢且可能超时,建议加try/catch包裹。

















