Symfony 5 REST场景下将Base64文件反序列化为带校验的DTO File对象
解决方案
核心是自定义Symfony序列化器的反序列化规则,自动将Base64字符串转换为File对象,具体实现步骤如下:
步骤1:创建自定义Base64文件反序列化器
在src/Serializer/Normalizer目录下新建Base64FileNormalizer.php,代码如下:
<?php namespace App\Serializer\Normalizer; use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; class Base64FileNormalizer implements NormalizerInterface, DenormalizerInterface { /** * 反序列化:将base64字符串转为File对象 */ public function denormalize($data, string $type, string $format = null, array $context = []) { // 处理base64前缀(如data:image/png;base64,) if (str_starts_with($data, 'data:')) { [$prefix, $data] = explode(',', $data); } // 解码base64内容 $fileContent = base64_decode($data, true); if (false === $fileContent) { throw new \InvalidArgumentException('无效的Base64文件内容'); } // 生成临时文件 $tmpFilePath = tempnam(sys_get_temp_dir(), 'symfony_upload_'); file_put_contents($tmpFilePath, $fileContent); return new File($tmpFilePath); } /** * 仅对File类型、字符串输入生效 */ public function supportsDenormalization($data, string $type, string $format = null) { return $type === File::class && is_string($data); } /** * 序列化反向逻辑,不需要可直接返回空 */ public function normalize($object, string $format = null, array $context = []) { return null; } public function supportsNormalization($data, string $format = null) { return $data instanceof File; } }
注:如果使用PHP版本低于8.0,把str_starts_with替换为strpos($data, 'data:') === 0即可。
步骤2:注册反序列化器到Symfony服务
修改config/services.yaml,添加如下配置:
services: # 其他原有服务配置保持不变 App\Serializer\Normalizer\Base64FileNormalizer: tags: - { name: serializer.normalizer, priority: 100 }
设置priority:100是为了让该自定义规则优先级高于系统默认的反序列化规则,优先处理File类型的反序列化。
步骤3:原有代码无需修改,直接使用
配置完成后,原有的反序列化逻辑会自动将请求中的Base64格式photo字段转为File对象,PostService中的#[Assert\Image]校验可以正常执行。
注意事项
- 生成的临时文件会在请求结束后自动被系统清理,如果需要持久化存储图片,需要在PostService的业务逻辑中将临时文件移动到指定的持久化目录。
- 如果需要限制上传文件的大小、格式,直接在Dto的
#[Assert\Image]注解中添加对应参数即可,无需修改反序列化器逻辑。
内容的提问来源于stack exchange,提问作者Slimu
相关产品推荐
相关产品推荐

