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'],
),
],
]);
}
}| 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.
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.typeis 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.extensionsnarrows the accepted mime types through the media type database of thesymfony/mimecomponent. In the browser only the extension itself is checked, the derived mime types are not.filenameCharset,notFoundMessage,notReadableMessageand everyupload*ErrorMessagedescribe conditions that only exist server side.
Client-side validation is a convenience, never a replacement: the server validates the upload again in every case.
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.