主页/PHP笔记/PHP问答/框架Symfony/如何在Symfony中验证上传的文件

如何在Symfony中验证上传的文件

Bug编译狮

Bug编译狮

在Symfony中验证上传的文件是一个常见的需求,可以通过多种方式实现。以下是几种常见的方法:

方法一:使用 FileValidator

FileValidator 是 Symfony 提供的一个用于验证文件是否符合特定条件的类。

  1. 创建实体类

    namespace AppEntity;
    
    use SymfonyComponentValidatorConstraints as Assert;
    use SymfonyComponentHttpFoundationFileFile;
    
    class Document
    {
       /**
        * @var File|null
        *
        * @AssertFile(
        *     maxSize = "2M",
        *     mimeTypes = {"application/pdf", "image/jpeg"},
        *     mimeTypesMessage = "Invalid file type.",
        *     maxFiles = 1,
        *     allowEmpty = false,
        *     errorMessage = "Please upload a valid document."
        * )
        */
       private $file;
    
       public function getFile(): ?File
       {
           return $this->file;
       }
    
       public function setFile(?File $file): self
       {
           $this->file = $file;
           return $this;
       }
    }
  2. 创建控制器

    namespace AppController;
    
    use AppEntityDocument;
    use AppFormDocumentType;
    use SymfonyBundleFrameworkBundleControllerAbstractController;
    use SymfonyComponentHttpFoundationRequest;
    use SymfonyComponentHttpFoundationResponse;
    use SymfonyComponentRoutingAnnotationRoute;
    use SymfonyComponentValidatorValidatorInterface;
    
    #[Route('/document')]
    class DocumentController extends AbstractController
    {
       private $validator;
    
       public function __construct(ValidatorInterface $validator)
       {
           $this->validator = $validator;
       }
    
       #[Route('/upload', name: 'document_upload')]
       public function upload(Request $request): Response
       {
           $form = $this->createForm(DocumentType::class);
           $form->handleRequest($request);
    
           if ($form->isSubmitted() && $form->isValid()) {
               $document = $form->getData();
               // 处理上传的文件
               $fileName = uniqid().'.'.$document->getFile()->guessExtension();
               $document->getFile()->move('uploads/documents', $fileName);
    
               // 保存文档到数据库或其他存储位置
               // ...
    
               return $this->redirectToRoute('document_success');
           }
    
           return $this->render('document/upload.html.twig', [
               'form' => $form->createView(),
           ]);
       }
    
       #[Route('/success', name: 'document_success')]
       public function success(): Response
       {
           return new Response('Document uploaded successfully!');
       }
    }
  3. 创建表单类型

    namespace AppForm;
    
    use SymfonyComponentFormAbstractType;
    use SymfonyComponentFormExtensionCoreTypeFileType;
    use SymfonyComponentOptionsResolverOptionsResolver;
    
    class DocumentType extends AbstractType
    {
       public function buildForm(FormBuilderInterface $builder, array $options): void
       {
           $builder
               ->add('file', FileType::class, [
                   'label' => 'Upload Document',
               ])
           ;
       }
    
       public function configureOptions(OptionsResolver $resolver): void
       {
           $resolver->setDefaults([
               'data_class' => Document::class,
           ]);
       }
    }

方法二:使用 FileTypeConstraint

你可以直接在实体类中使用 FileTypeConstraint 来定义文件的验证规则。

  1. 创建实体类

    namespace AppEntity;
    
    use SymfonyComponentValidatorConstraints as Assert;
    use SymfonyComponentHttpFoundationFileFile;
    
    class Document
    {
       /**
        * @var File|null
        *
        * @AssertFile(
        *     maxSize = "2M",
        *     mimeTypes = {"application/pdf", "image/jpeg"},
        *     mimeTypesMessage = "Invalid file type.",
        *     maxFiles = 1,
        *     allowEmpty = false,
        *     errorMessage = "Please upload a valid document."
        * )
        */
       private $file;
    
       public function getFile(): ?File
       {
           return $this->file;
       }
    
       public function setFile(?File $file): self
       {
           $this->file = $file;
           return $this;
       }
    }
  2. 创建控制器

    namespace AppController;
    
    use AppEntityDocument;
    use AppFormDocumentType;
    use SymfonyBundleFrameworkBundleControllerAbstractController;
    use SymfonyComponentHttpFoundationRequest;
    use SymfonyComponentHttpFoundationResponse;
    use SymfonyComponentRoutingAnnotationRoute;
    use SymfonyComponentValidatorValidatorInterface;
    
    #[Route('/document')]
    class DocumentController extends AbstractController
    {
       private $validator;
    
       public function __construct(ValidatorInterface $validator)
       {
           $this->validator = $validator;
       }
    
       #[Route('/upload', name: 'document_upload')]
       public function upload(Request $request): Response
       {
           $form = $this->createForm(DocumentType::class);
           $form->handleRequest($request);
    
           if ($form->isSubmitted() && $form->isValid()) {
               $document = $form->getData();
               // 处理上传的文件
               $fileName = uniqid().'.'.$document->getFile()->guessExtension();
               $document->getFile()->move('uploads/documents', $fileName);
    
               // 保存文档到数据库或其他存储位置
               // ...
    
               return $this->redirectToRoute('document_success');
           }
    
           return $this->render('document/upload.html.twig', [
               'form' => $form->createView(),
           ]);
       }
    
       #[Route('/success', name: 'document_success')]
       public function success(): Response
       {
           return new Response('Document uploaded successfully!');
       }
    }
  3. 创建表单类型

    namespace AppForm;
    
    use SymfonyComponentFormAbstractType;
    use SymfonyComponentFormExtensionCoreTypeFileType;
    use SymfonyComponentOptionsResolverOptionsResolver;
    
    class DocumentType extends AbstractType
    {
       public function buildForm(FormBuilderInterface $builder, array $options): void
       {
           $builder
               ->add('file', FileType::class, [
                   'label' => 'Upload Document',
               ])
           ;
       }
    
       public function configureOptions(OptionsResolver $resolver): void
       {
           $resolver->setDefaults([
               'data_class' => Document::class,
           ]);
       }
    }

通过以上方法,你可以在 Symfony 中轻松地验证上传的文件,并根据需要进行进一步的操作。

黑板Bug讲师

黑板Bug讲师

概览

文件上传是Web应用程序中的常见功能,Symfony,一个流行的PHP框架,提供了处理文件上传的强大支持。然而,仅仅上传文件往往不够。我们还需要确保这些文件安全,符合特定标准,并不会对我们的应用造成任何损害。验证是实现可靠和安全的文件上传的关键。在本教程中,我们将探讨如何使用Symfony来验证上传的文件。

我们将涵盖从设置项目、配置文件上传到确保这些文件符合您特定要求的大小、类型以及其他属性的所有内容。所以,让我们开始吧。

先决条件

Composer 全球安装,用于管理依赖项。

您系统上已安装 PHP 7.4 或更高版本。

对Symfony框架的基本理解。

开始使用

设置Symfony项目

composer create-project symfony/skeleton my_project_name
cd my_project_name
composer require symfony/web-server-bundle --dev
composer require symfony/form
composer require symfony/validator

在进入项目目录并安装必要组件之后,您需要为文件上传创建一个表单类型。

创建文件上传表单

// src/Form/UploadFileType.php
namespace AppForm;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormExtensionCoreTypeFileType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolver;

class UploadFileType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('upload_file', FileType::class, [
                'label' => 'Upload File',
                // unmapped means that this field is not associated to any entity property
                'mapped' => false,
                // make it optional so you don't have to re-upload the file
                // whenever you edit the details
                'required' => false,
            ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            // ... set your default options here
        ]);
    }
}

在您提交的表单类型设置好之后,我们现在转向验证上传的文件。

实施文件验证

Symfony 使用的是 Symfony。Validator组件用于验证表单。您可以通过在表单字段上或使用注解、YAML、XML 或 PHP 的方式,直接对数据类进行约束。

让我们直接对表单类型应用一些约束条件。

// src/Form/UploadFileType.php

// ... previous code
use SymfonyComponentValidatorConstraintsFile;

// ... inside the buildForm method
$builder
    // ... previous field definitions
    ->add('upload_file', FileType::class, [
        'label' => 'Upload File',
        'mapped' => false,
        'constraints' => [
            new File([
                'maxSize' => '1024k',
                'mimeTypes' => [
                    'application/pdf',
                    'application/x-pdf',
                ],
                'mimeTypesMessage' => 'Please upload a valid PDF document',
            ])
        ],
    ]);

现在,让我们看看如何在控制器中处理表单提交并进行验证。

处理表单提交和文件验证

// src/Controller/SomeController.php
namespace AppController;

use SymfonyComponentHttpFoundationRequest;
use AppFormUploadFileType;

// ... other use statements

class SomeController extends AbstractController
{
    public function new(Request $request)
    {
        $form = $this->createForm(UploadFileType::class);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $file = $form['upload_file']->getData();

            if ($file) {
                $originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
                // Move the file to the directory where brochures are stored
                try {
                    $file->move(
                        $this->getParameter('brochures_directory'),
                        $originalFilename
                    );
                } catch (FileException $e) {
                    // ... handle exception if something happens during file upload
                }
            }
            // ... persist the other form data if needed
            return $this->redirect($this->generateUrl('some_route'));
        }

        return $this->render('some/new.html.twig', [
            'form' => $form->createView(),
        ]);
    }
}

这个简单的例子展示了如何通过设置文件类型和大小的限制来确保文件上传。然而,验证并不止于此。你可以进一步创建自定义验证规则,检查文件的内容等。

结论。

在本指南中,我们已经介绍了如何设置Symfony项目、创建文件上传表单、指定验证规则以及处理提交时的验证检查。记住,验证文件的目标不仅是遵守你设定的规则,还要确保应用的安全性,防止潜在有害文件被上传。

文件验证在Symfony中既灵活又强大,掌握它可以显著提升用户体验和应用的安全性。请多多练习不同类型的文件类型和验证场景,以提高处理Symfony中的文件上传的能力。

长工码奴1523

长工码奴1523

在 Symfony 中验证上传的文件是一种常见的需求,尤其是在处理动态内容时。以下是如何使用 Symfony 的 Filesystem 和 File 安全框架来验证和管理文件。

1. 验证文件类型

首先,你需要定义哪些类型的文件可以被上传。你可以通过自定义 File 类型的构造函数参数来实现这一点:

class MyFileType extends AbstractType {
    public function buildView(FormView $view, FormInterface $form, array $options): void {
        $view->vars['file_type'] = $options['file_type'];
    }
}

然后,你需要在控制器方法中实例化这个类并传入正确的类型:

public function uploadAction(Request $request) {
    $fileType = new MyFileType(['image/jpeg', 'image/png']);
    return $this->uploadFile($request, $fileType);
}

private function uploadFile(Request $request, MyFileType $type): Response {
    // ...
}

2. 文件大小限制

为了防止用户上传过大或过小的文件,你可以设置一个范围。这可以通过访问 $request 对象中的 files 属性来完成,并根据其键(如 'myfile')检查文件大小:

if ($request->isMethod('POST')) {
    $maxSizeBytes = 500 * 1024 * 1024; // 5MB
    if (count($request->files->all()) === 1 && $request->files->get('myfile') !== null) {
        $uploadedFile = $request->files->get('myfile');
        if ($uploadedFile instanceof UploadedFile) {
            if (!$uploadedFile->isValid() || !$uploadedFile->getSize() <= $maxSizeBytes) {
                throw new BadRequestHttpException(sprintf('The file size must be less than %d bytes.', $maxSizeBytes));
            }
        } else {
            throw new BadRequestHttpException('Invalid file.');
        }
    }
}

3. 文件扩展名验证

除了文件类型和大小之外,你还可能需要验证文件扩展名。这可以通过将文件扩展名添加到 $fileType 实例中来实现:

$uploadedFile = $request->files->get('myfile');
if ($uploadedFile instanceof UploadedFile) {
    $type = $type->build(array(
        'extension' => $uploadedFile->getClientOriginalExtension(),
        'name'      => $uploadedFile->getClientOriginalName()
    ));
}

示例代码

假设我们有一个名为 UploadController.php 的控制器,其中包含了上述功能:

<?php

namespace AppController;

use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingAnnotationRoute;
use SymfonyComponentValidatorConstraintsFile;
use SymfonyComponentValidatorContextExecutionContextInterface;
use SymfonyComponentValidatorConstraintViolationList;

class UploadController extends AbstractController
{
    /**
     * @Route("/upload", name="app_upload")
     */
    public function uploadAction(Request $request)
    {
        $fileType = new MyFileType(['image/jpeg', 'image/png']);
        return $this->uploadFile($request, $fileType);
    }

    private function uploadFile(Request $request, MyFileType $type): Response
    {
        $maxSizeBytes = 500 * 1024 * 1024; // 5MB
        if (count($request->files->all()) === 1 && $request->files->get('myfile') !== null) {
            $uploadedFile = $request->files->get('myfile');

            if ($uploadedFile instanceof UploadedFile) {
                if (!$uploadedFile->isValid() || !$uploadedFile->getSize() <= $maxSizeBytes) {
                    throw new BadRequestHttpException(sprintf('The file size must be less than %d bytes.', $maxSizeBytes));
                }

                $context = $this->createValidatorContext();
                $violations = $this->validateFile($uploadedFile, $type, $context);

                foreach ($violations as $violation) {
                    $this->addViolation($violation, $context);
                }

                if (!empty($violations)) {
                    throw new BadRequestHttpException('Validation errors occurred.');
                }
            } else {
                throw new BadRequestHttpException('Invalid file.');
            }
        }

        return new Response('File uploaded successfully!');
    }

    private function validateFile(UploadedFile $file, MyFileType $type, ExecutionContextInterface $context): ConstraintViolationList
    {
        $constraint = $type->build();

        if ($file->getClientMimeType() != $constraint->getExtension()) {
            $context->addViolationAt(
                $constraint->getName(),
                [
                    'message' => sprintf('File extension "%s" is not allowed.', $file->getClientOriginalExtension())
                ]
            );
        }

        return $context->getValidator()->validate($file, $constraint);
    }
}

在这个例子中,我们创建了一个名为 MyFileType 的自定义类型,用于验证文件类型和大小。然后,我们在 uploadFile() 方法中使用了这些特性来验证上传的文件。如果验证失败,我们将抛出异常并返回错误消息。