Shopware 6 PHP克隆媒体文件:重命名后仍遇文件名重复错误
需要备份指定媒体文件(以数组传入),代码已实现生成新UUID、复制属性并保存到数据库,但上传文件到对应数据库条目时失败,报错:Object { status: "500", code: "CONTENT__MEDIA_DUPLICATED_FILE_NAME", title: "Internal Server Error"...}
已尝试修改文件名,但问题依旧,相关PHP代码如下:
function makeBackup(array $images, Context $context) :bool { foreach ($images as $i) { $uuid = Uuid::randomHex(); $path = $this->urlGeneratorInterface->getRelativeMediaUrl($i); try { $this->publicFileSystem->read($path); $stream = $this->publicFileSystem->readStream($path); $metaData = stream_get_meta_data($stream); $oldFileNameWithPath = $metaData['uri']; }catch (UnableToReadFile $e){ echo "[ERROR] File $path does not exists. Continuing.\n"; continue; } $mimeType = mime_content_type($oldFileNameWithPath); $fileExtension = pathinfo($oldFileNameWithPath, PATHINFO_EXTENSION); $fileSize = filesize($oldFileNameWithPath); $fileName = pathinfo($oldFileNameWithPath, PATHINFO_FILENAME) . '_old.' . $fileExtension; $mediaFile = new MediaFile($fileName, $mimeType, $fileExtension, $fileSize); $backupMediaData = [ 'id' => $uuid, 'fileName' => $i->getFileName()."_old", 'mimeType' => $i->getMimeType(), 'fileSize' => $i->getFileSize(), // 'mediaFolderId' => $media->getMediaFolderId(), 'createdAt' => $i->getCreatedAt(), 'updatedAt' => $i->getUpdatedAt(), 'alt' => $i->getAlt(), 'title' => $i->getTitle()."_old", ]; $this->mediaRepository->create([$backupMediaData], $context); $this->fileSaver->persistFileToMedia( $mediaFile, pathinfo($oldFileNameWithPath, PATHINFO_FILENAME), $uuid, $context ); } return true; }
错误码CONTENT__MEDIA_DUPLICATED_FILE_NAME明确指向文件名重复,核心问题出在两处:
上传方法传入了原文件名
调用persistFileToMedia时,第二个参数传的是pathinfo($oldFileNameWithPath, PATHINFO_FILENAME)——也就是未加_old后缀的原文件名,这导致实际上传时还是用了和原文件一样的名称,自然触发重复错误。数据库记录与上传文件名不一致
backupMediaData中的fileName是$i->getFileName()."_old",而$mediaFile的文件名是原文件名_old.后缀。如果原文件对象的getFileName()包含后缀,这里会生成xxx.jpg_old的格式,和$mediaFile的xxx_old.jpg格式冲突,同时也可能和其他备份文件重名。
1. 统一文件名规则
确保数据库记录的文件名和上传时使用的文件名逻辑一致,避免格式冲突。
2. 修正上传方法的参数
将persistFileToMedia的第二个参数改为修改后的唯一文件名(不带后缀,多数媒体库会自动根据MediaFile的后缀拼接)。
修改后的关键代码片段:
// 统一生成带_old后缀的纯文件名(不带扩展名) $baseFileName = pathinfo($oldFileNameWithPath, PATHINFO_FILENAME) . '_old'; // 生成完整文件名(带扩展名) $fileName = $baseFileName . '.' . $fileExtension; $mediaFile = new MediaFile($fileName, $mimeType, $fileExtension, $fileSize); $backupMediaData = [ 'id' => $uuid, 'fileName' => $baseFileName, // 和上传逻辑保持一致,若系统要求带后缀则改为$fileName 'mimeType' => $i->getMimeType(), 'fileSize' => $i->getFileSize(), // 'mediaFolderId' => $media->getMediaFolderId(), 'createdAt' => $i->getCreatedAt(), 'updatedAt' => $i->getUpdatedAt(), 'alt' => $i->getAlt(), 'title' => $i->getTitle()."_old", ]; $this->mediaRepository->create([$backupMediaData], $context); // 传入修改后的纯文件名,确保上传时使用唯一名称 $this->fileSaver->persistFileToMedia( $mediaFile, $baseFileName, $uuid, $context );
额外注意事项
- 若批量备份的文件中存在原文件名已带
_old的情况,建议进一步添加UUID后缀(比如$baseFileName = pathinfo(...) . '_old_' . $uuid),彻底避免重复。 - 确认
persistFileToMedia方法的参数要求,部分库可能要求第二个参数是完整文件名,需根据实际情况调整。
内容的提问来源于stack exchange,提问作者user21851666

