Skip to content

Latest commit

 

History

History
76 lines (61 loc) · 3.08 KB

File metadata and controls

76 lines (61 loc) · 3.08 KB

3.22 File uploads

The File constraint is validated in the browser as far as the File API allows. A file that is too large or has an unexpected mime type is reported before the upload starts instead of after a full round trip to the server:

<?php

// src/Form/ProfileType.php
namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints as Assert;

class ProfileType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->add('avatar', FileType::class, [
            'constraints' => [
                new Assert\File(
                    maxSize: '2M',
                    mimeTypes: ['image/png', 'image/jpeg'],
                ),
            ],
        ]);
    }
}

What is checked in the browser

Option Checked with
maxSize File.size
mimeTypes File.type, including the type/* wildcards
extensions the extension of File.name
filenameMaxLength the length of File.name in filenameCountUnit units
empty file a File.size of zero

The sizes are formatted the same way FileValidator formats them, so maxSizeMessage, mimeTypesMessage, extensionsMessage, disallowEmptyMessage and filenameTooLongMessage read exactly as they do in the server-side error.

A NotBlank constraint on the same field keeps working: the value of a file input is the list of selected files, so an empty list is an empty value.

What stays on the server

The browser cannot see the content of a file, only what the File API exposes, so these checks only happen after the form is submitted:

  • File.type is sniffed by the browser and is not always right. When the browser reports no type at all, the mime type check is skipped and the server has the last word.
  • extensions narrows the accepted mime types through the media type database of the symfony/mime component. In the browser only the extension itself is checked, the derived mime types are not.
  • filenameCharset, notFoundMessage, notReadableMessage and every upload*ErrorMessage describe conditions that only exist server side.

Client-side validation is a convenience, never a replacement: the server validates the upload again in every case.

Images

Image extends File in PHP, but its own options - maxWidth, minWidth, maxHeight, minHeight, maxRatio, minRatio, allowSquare and the rest - need the image to be decoded first, which the browser can only do asynchronously. They are not implemented, so an Image constraint is skipped in the browser and validated on the server only. Add a File constraint next to it to get the size and mime type checked before the upload.