Symfony框架中表单提交图片副本无法保存的问题求助
解决表单上传原图与独立副本的存储问题
问题原因
Symfony的UploadedFile对象通过clone复制后,两个实例仍指向同一个临时文件。调用move()方法时,原临时文件会被移动到目标目录,第二个实例再执行move()时会因找不到文件而失败。
解决方案
通过复制临时文件+创建新UploadedFile实例的方式,生成完全独立的副本对象,确保原图与副本互不影响。
修改控制器初始代码
替换原有的clone逻辑,手动创建独立的副本文件对象:
$album = new Album(); $form = $this->createForm(CreateAlbumType::class, $album); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $entityManager = $doctrine->getManager(); $albumName = $album->getAlbumName(); $coverFile = $form->get('cover')->getData(); // 1. 复制原图临时文件到新的临时路径 $tempPreviewName = uniqid() . '.' . $coverFile->guessExtension(); $tempPreviewPath = sys_get_temp_dir() . '/' . $tempPreviewName; copy($coverFile->getPathname(), $tempPreviewPath); // 2. 创建独立的UploadedFile实例作为副本 $coverFilePreview = new \Symfony\Component\HttpFoundation\File\UploadedFile( $tempPreviewPath, $coverFile->getClientOriginalName(), $coverFile->getClientMimeType(), $coverFile->getError(), true // 标记为手动创建的临时文件,确保框架自动清理 );
修改控制器结尾代码(添加尺寸处理+存储)
在存储副本前可修改尺寸,再执行存储:
$currentYear = date('Y'); $currentMonth = date('m'); $currentMonthPreview = $currentMonth . '_preview'; $uploadDirectoryMonth = 'images/' . $currentYear . '/' . $currentMonth; $uploadDirectoryPreview = 'images/' . $currentYear . '/' . $currentMonthPreview; if (!is_dir($uploadDirectoryMonth)) { mkdir($uploadDirectoryMonth, 0755, true); } if (!is_dir($uploadDirectoryPreview)) { mkdir($uploadDirectoryPreview, 0755, true); } $newFilename = $imageNumber . '.' . $coverFile->guessExtension(); $newFilenamePreview = $imageNumber . '_preview.' . $coverFilePreview->guessExtension(); // 存储原图 $coverFile->move($uploadDirectoryMonth, $newFilename); // 处理预览图尺寸(示例:缩放到300px宽) $previewImg = imagecreatefromstring(file_get_contents($coverFilePreview->getPathname())); $originalWidth = imagesx($previewImg); $originalHeight = imagesy($previewImg); $targetWidth = 300; $targetHeight = (int)($originalHeight / $originalWidth * $targetWidth); $previewResized = imagecreatetruecolor($targetWidth, $targetHeight); imagecopyresampled($previewResized, $previewImg, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); imagejpeg($previewResized, $coverFilePreview->getPathname(), 80); // 覆盖临时文件 imagedestroy($previewImg); imagedestroy($previewResized); // 存储修改后的预览图 $coverFilePreview->move($uploadDirectoryPreview, $newFilenamePreview); $album->setAlbumName($albumName); $album->setCoverPath($uploadDirectoryMonth . '/' . $newFilename); $album->setCoverPathPreview($uploadDirectoryPreview . '/' . $newFilenamePreview); $entityManager->persist($album); $entityManager->flush(); }
关键说明
- 手动复制临时文件后,两个
UploadedFile实例指向不同的文件,move()操作互不干扰 - 标记副本的
UploadedFile为手动临时文件(最后一个参数true),确保请求结束后框架自动清理临时文件 - 尺寸修改可根据需求调整,也可使用Imagine等图片处理库简化操作
内容的提问来源于stack exchange,提问作者Jegi
相关产品推荐
相关产品推荐

