8000 [Validator] Add the option filenameMaxLength to the File constraint by ke20 · Pull Request #49417 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Validator] Add the option filenameMaxLength to the File constraint #49417

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Symfony/Component/Validator/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ CHANGELOG
* Add the `pattern` parameter in violations of the `Regex` constraint
* Add a `NoSuspiciousCharacters` constraint to validate a string is not a spoofing attempt
* Add the `countUnit` option to the `Length` constraint to allow counting the string length either by code points (like before, now the default setting `Length::COUNT_CODEPOINTS`), bytes (`Length::COUNT_BYTES`) or graphemes (`Length::COUNT_GRAPHEMES`)
* Add the `filenameMaxLength` option to the `File` constraint

6.2
---
Expand Down
8 changes: 8 additions & 0 deletions src/Symfony/Component/Validator/Constraints/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ class File extends Constraint
public const TOO_LARGE_ERROR = 'df8637af-d466-48c6-a59d-e7126250a654';
public const INVALID_MIME_TYPE_ERROR = '744f00bc-4389-4c74-92de-9a43cde55534';
public const INVALID_EXTENSION_ERROR = 'c8c7315c-6186-4719-8b71-5659e16bdcb7';
public const FILENAME_TOO_LONG = 'e5706483-91a8-49d8-9a59-5e81a3c634a8';

protected const ERROR_NAMES = [
self::NOT_FOUND_ERROR => 'NOT_FOUND_ERROR',
self::NOT_READABLE_ERROR => 'NOT_READABLE_ERROR',
self::EMPTY_ERROR => 'EMPTY_ERROR',
self::TOO_LARGE_ERROR => 'TOO_LARGE_ERROR',
self::INVALID_MIME_TYPE_ERROR => 'INVALID_MIME_TYPE_ERROR',
self::FILENAME_TOO_LONG => 'FILENAME_TOO_LONG',
];

/**
Expand All @@ -49,13 +51,15 @@ class File extends Constraint

public $binaryFormat;
public $mimeTypes = [];
public ?int $filenameMaxLength = null;
public array|string|null $extensions = [];
public $notFoundMessage = 'The file could not be found.';
public $notReadableMessage = 'The file is not readable.';
public $maxSizeMessage = 'The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}.';
public $mimeTypesMessage = 'The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}.';
public string $extensionsMessage = 'The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}.';
public $disallowEmptyMessage = 'An empty file is not allowed.';
public $filenameTooLongMessage = 'The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less.';

public $uploadIniSizeErrorMessage = 'The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.';
public $uploadFormSizeErrorMessage = 'The file is too large.';
Expand All @@ -76,11 +80,13 @@ public function __construct(
int|string $maxSize = null,
bool $binaryFormat = null,
array|string $mimeTypes = null,
int $filenameMaxLength = null,
string $notFoundMessage = null,
string $notReadableMessage = null,
string $maxSizeMessage = null,
string $mimeTypesMessage = null,
string $disallowEmptyMessage = null,
string $filenameTooLongMessage = null,

string $uploadIniSizeErrorMessage = null,
string $uploadFormSizeErrorMessage = null,
Expand All @@ -101,13 +107,15 @@ public function __construct(
$this->maxSize = $maxSize ?? $this->maxSize;
$this->binaryFormat = $binaryFormat ?? $this->binaryFormat;
$this->mimeTypes = $mimeTypes ?? $this->mimeTypes;
$this->filenameMaxLength = $filenameMaxLength ?? $this->filenameMaxLength;
$this->extensions = $extensions ?? $this->extensions;
$this->notFoundMessage = $notFoundMessage ?? $this->notFoundMessage;
$this->notReadableMessage = $notReadableMessage ?? $this->notReadableMessage;
$this->maxSizeMessage = $maxSizeMessage ?? $this->maxSizeMessage;
$this->mimeTypesMessage = $mimeTypesMessage ?? $this->mimeTypesMessage;
$this->extensionsMessage = $extensionsMessage ?? $this->extensionsMessage;
$this->disallowEmptyMessage = $disallowEmptyMessage ?? $this->disallowEmptyMessage;
$this->filenameTooLongMessage = $filenameTooLongMessage ?? $this->filenameTooLongMessage;
$this->uploadIniSizeErrorMessage = $uploadIniSizeErrorMessage ?? $this->uploadIniSizeErrorMessage;
$this->uploadFormSizeErrorMessage = $uploadFormSizeErrorMessage ?? $this->uploadFormSizeErrorMessage;
$this->uploadPartialErrorMessage = $uploadPartialErrorMessage ?? $this->uploadPartialErrorMessage;
Expand Down
10 changes: 10 additions & 0 deletions src/Symfony/Component/Validator/Constraints/FileValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,16 @@ public function validate(mixed $value, Constraint $constraint)
$sizeInBytes = filesize($path);
$basename = $value instanceof UploadedFile ? $value->getClientOriginalName() : basename($path);

if ($constraint->filenameMaxLength && $constraint->filenameMaxLength < $filenameLength = \strlen($basename)) {
$this->context->buildViolation($constraint->filenameTooLongMessage)
->setParameter('{{ filename_max_length }}', $this->formatValue($constraint->filenameMaxLength))
->setCode(File::FILENAME_TOO_LONG)
->setPlural($constraint->filenameMaxLength)
->addViolation();

return;
}

if (0 === $sizeInBytes) {
$this->context->buildViolation($constraint->disallowEmptyMessage)
->setParameter('{{ file }}', $this->formatValue($path))
Expand Down
4 changes: 4 additions & 0 deletions src/Symfony/Component/Validator/Constraints/Image.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public function __construct(
int|string $maxSize = null,
bool $binaryFormat = null,
array $mimeTypes = null,
int $filenameMaxLength = null,
int $minWidth = null,
int $maxWidth = null,
int $maxHeight = null,
Expand All @@ -115,6 +116,7 @@ public function __construct(
string $maxSizeMessage = null,
string $mimeTypesMessage = null,
string $disallowEmptyMessage = null,
string $filenameTooLongMessage = null,
string $uploadIniSizeErrorMessage = null,
string $uploadFormSizeErrorMessage = null,
string $uploadPartialErrorMessage = null,
Expand Down Expand Up @@ -144,11 +146,13 @@ public function __construct(
$maxSize,
$binaryFormat,
$mimeTypes,
$filenameMaxLength,
$notFoundMessage,
$notReadableMessage,
$maxSizeMessage,
$mimeTypesMessage,
$disallowEmptyMessage,
$filenameTooLongMessage,
$uploadIniSizeErrorMessage,
$uploadFormSizeErrorMessage,
$uploadPartialErrorMessage,
Expand Down
93AF
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ public function testNegativeMaxSize()
}

/**
* @dataProvider validExtensionProvider
* @dataProvider providerValidExtension
*/
public function testExtensionValid(string $name)
{
Expand All @@ -551,7 +551,7 @@ public function testExtensionValid(string $name)
$this->assertNoViolation();
}

private static function validExtensionProvider(): iterable
public static function providerValidExtension(): iterable
{
yield ['test.gif'];
yield ['test.png.gif'];
Expand All @@ -560,7 +560,7 @@ private static function validExtensionProvider(): iterable
}

/**
* @dataProvider invalidExtensionProvider
* @dataProvider provideInvalidExtension
*/
public function testExtensionInvalid(string $name, string $extension)
{
Expand All @@ -582,7 +582,7 @@ public function testExtensionInvalid(string $name, string $extension)
->assertRaised();
}

private static function invalidExtensionProvider(): iterable
public static function provideInvalidExtension(): iterable
{
yield ['test.gif', 'gif'];
yield ['test.png.gif', 'gif'];
Expand Down Expand Up @@ -658,5 +658,46 @@ public function testUploadedFileExtensions()
$this->assertNoViolation();
}

/**
* @dataProvider provideFilenameMaxLengthIsTooLong
*/
public function testFilenameMaxLengthIsTooLong(File $constraintFile, string $messageViolation)
{
file_put_contents($this->path, '1');

$file = new UploadedFile($this->path, 'myFileWithATooLongOriginalFileName', null, null, true);
$this->validator->validate($file, $constraintFile);

$this->buildViolation($messageViolation)
->setParameters([
'{{ filename_max_length }}' => $constraintFile->nameMaxLength,
])
->setCode(File::FILENAME_TOO_LONG)
->assertRaised();
}

public static function provideFilenameMaxLengthIsTooLong(): \Generator
{
yield 'Simple case with only the parameter "filenameMaxLength" ' => [
new File(filenameMaxLength: 30),
'The filename is too long. It should have {{ filename_max_length }} characters or less.',
];

yield 'Case with the parameter "filenameMaxLength" and a custom error message' => [
new File(filenameMaxLength: 20, filenameTooLongMessage: 'Your filename is too long. Please use at maximum {{ filename_max_length }} characters'),
'Your filename is too long. Please use at maximum {{ filename_max_length }} characters',
];
}

public function testFilenameMaxLength()
{
file_put_contents($this->path, '1');

$file = new UploadedFile($this->path, 'tinyOriginalFileName', null, null, true);
$this->validator->validate($file, new File(filenameMaxLength: 20));

$this->assertNoViolation();
}

abstract protected function getFile($filename);
}
0