TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Inspired by and partially taken from the Neos.Form package (www.neos.io)
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Mvc\Validation;
|
||||
|
||||
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
|
||||
|
||||
/**
|
||||
* Validator for countable types
|
||||
*
|
||||
* Scope: frontend
|
||||
* @internal
|
||||
*/
|
||||
final class CountValidator extends AbstractValidator
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
'minimum' => [0, 'The minimum count to accept', 'integer'],
|
||||
'maximum' => [PHP_INT_MAX, 'The maximum count to accept', 'integer'],
|
||||
];
|
||||
|
||||
/**
|
||||
* The given value is valid if it is an array or \Countable that contains the specified amount of elements.
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if (!is_array($value) && !($value instanceof \Countable)) {
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1475002976',
|
||||
'form'
|
||||
),
|
||||
1475002976
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$minimum = (int)$this->options['minimum'];
|
||||
$maximum = (int)$this->options['maximum'];
|
||||
$count = count($value);
|
||||
if ($count < $minimum || $count > $maximum) {
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1475002994',
|
||||
'form',
|
||||
[$minimum, $maximum]
|
||||
),
|
||||
1475002994,
|
||||
[$this->options['minimum'], $this->options['maximum']]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Mvc\Validation;
|
||||
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
|
||||
use TYPO3\CMS\Form\Utility\DateRangeValidatorPatterns;
|
||||
|
||||
/**
|
||||
* Validator for date ranges
|
||||
*
|
||||
* Scope: frontend
|
||||
*/
|
||||
final class DateRangeValidator extends AbstractValidator implements LoggerAwareInterface
|
||||
{
|
||||
use LoggerAwareTrait;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
'minimum' => ['', 'The minimum date formatted as Y-m-d or a relative date expression (e.g. "today", "-18 years")', 'string'],
|
||||
'maximum' => ['', 'The maximum date formatted as Y-m-d or a relative date expression (e.g. "today", "-18 years")', 'string'],
|
||||
'format' => ['Y-m-d', 'The format of the minimum and maximum option', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* @param mixed $value The value that should be validated
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
$options = $this->validateOptions();
|
||||
if ($options === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!($value instanceof \DateTime)) {
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1521293685',
|
||||
'form',
|
||||
[gettype($value)]
|
||||
),
|
||||
1521293685
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$minimum = $options['minimum'];
|
||||
$maximum = $options['maximum'];
|
||||
$format = $options['format'];
|
||||
$value->modify('midnight');
|
||||
|
||||
if ($minimum instanceof \DateTime && $value < $minimum) {
|
||||
$formattedMinimum = $minimum->format($format);
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1521293687',
|
||||
'form',
|
||||
[$formattedMinimum]
|
||||
),
|
||||
1521293687,
|
||||
[$formattedMinimum]
|
||||
);
|
||||
}
|
||||
|
||||
if ($maximum instanceof \DateTime && $value > $maximum) {
|
||||
$formattedMaximum = $maximum->format($format);
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1521293686',
|
||||
'form',
|
||||
[$formattedMaximum]
|
||||
),
|
||||
1521293686,
|
||||
[$formattedMaximum]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this validator is correctly configured.
|
||||
*
|
||||
* Returns the resolved options array on success, or null if a date
|
||||
* option is misconfigured. In the latter case a generic validation
|
||||
* error is added for the end user and the technical details are logged.
|
||||
*/
|
||||
private function validateOptions(): ?array
|
||||
{
|
||||
$options = $this->options;
|
||||
if (!empty($this->options['minimum'])) {
|
||||
$minimum = $this->parseDate($this->options['minimum']);
|
||||
if ($minimum === null) {
|
||||
$this->logger->error('DateRangeValidator: The option "minimum" ({value}) could not be converted to DateTime. Use format "{format}" or a relative expression (e.g. "today", "-18 years").', [
|
||||
'value' => $this->options['minimum'],
|
||||
'format' => $this->options['format'],
|
||||
]);
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1748345955',
|
||||
'form'
|
||||
),
|
||||
1748345955
|
||||
);
|
||||
return null;
|
||||
}
|
||||
$minimum->modify('midnight');
|
||||
$options['minimum'] = $minimum;
|
||||
}
|
||||
|
||||
if (!empty($this->options['maximum'])) {
|
||||
$maximum = $this->parseDate($this->options['maximum']);
|
||||
if ($maximum === null) {
|
||||
$this->logger->error('DateRangeValidator: The option "maximum" ({value}) could not be converted to DateTime. Use format "{format}" or a relative expression (e.g. "today", "-18 years").', [
|
||||
'value' => $this->options['maximum'],
|
||||
'format' => $this->options['format'],
|
||||
]);
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1748345955',
|
||||
'form'
|
||||
),
|
||||
1748345955
|
||||
);
|
||||
return null;
|
||||
}
|
||||
$maximum->modify('midnight');
|
||||
$options['maximum'] = $maximum;
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a date string as absolute format first, then fall back to relative expressions.
|
||||
*
|
||||
* Supports:
|
||||
* - Absolute dates matching the configured format (e.g. "2025-03-17")
|
||||
* - Any relative date expression accepted by PHP's DateTime parser
|
||||
* (e.g. "today", "-18 years", "last sunday", "first day of next month")
|
||||
*/
|
||||
private function parseDate(string $value): ?\DateTime
|
||||
{
|
||||
$date = \DateTime::createFromFormat($this->options['format'], $value);
|
||||
if ($date instanceof \DateTime) {
|
||||
return $date;
|
||||
}
|
||||
|
||||
return DateRangeValidatorPatterns::parseRelativeDateExpression($value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Mvc\Validation;
|
||||
|
||||
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
|
||||
|
||||
/**
|
||||
* Validator for empty values.
|
||||
*
|
||||
* Scope: frontend
|
||||
*/
|
||||
final class EmptyValidator extends AbstractValidator
|
||||
{
|
||||
/**
|
||||
* This validator always needs to be executed even if the given value is empty.
|
||||
* See AbstractValidator::validate()
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $acceptsEmptyValues = true;
|
||||
|
||||
/**
|
||||
* Checks if the given property ($propertyValue) is empty (NULL, empty string, empty array or empty object).
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if (!empty($value)) {
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1476396435',
|
||||
'form'
|
||||
),
|
||||
1476396435
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Mvc\Validation\Exception;
|
||||
|
||||
use TYPO3\CMS\Form\Exception;
|
||||
|
||||
class InvalidValidationOptionsException extends Exception {}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Mvc\Validation;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
|
||||
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
|
||||
use TYPO3\CMS\Form\Mvc\Property\TypeConverter\PseudoFile;
|
||||
use TYPO3\CMS\Form\Mvc\Validation\Exception\InvalidValidationOptionsException;
|
||||
|
||||
/**
|
||||
* Validator for countable types
|
||||
*
|
||||
* Scope: frontend
|
||||
* @internal
|
||||
*/
|
||||
final class FileSizeValidator extends AbstractValidator implements ObjectStorageElementValidatorInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
'minimum' => ['0B', 'The minimum file size to accept', 'string'],
|
||||
'maximum' => [PHP_INT_MAX . 'B', 'The maximum file size to accept', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* The given value is valid
|
||||
*
|
||||
* @param mixed $resource
|
||||
*/
|
||||
public function isValid(mixed $resource): void
|
||||
{
|
||||
$this->validateOptions();
|
||||
if ($resource instanceof FileReference) {
|
||||
$fileSize = $resource->getOriginalResource()->getSize();
|
||||
} elseif ($resource instanceof File) {
|
||||
$fileSize = $resource->getSize();
|
||||
} elseif ($resource instanceof PseudoFile) {
|
||||
$fileSize = $resource->getSize();
|
||||
} else {
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1505303626',
|
||||
'form'
|
||||
),
|
||||
1505303626
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$minFileSize = GeneralUtility::getBytesFromSizeMeasurement($this->options['minimum']);
|
||||
$maxFileSize = GeneralUtility::getBytesFromSizeMeasurement($this->options['maximum']);
|
||||
|
||||
$labels = ' Bytes| Kilobyte| Megabyte| Gigabyte';
|
||||
if ($fileSize < $minFileSize) {
|
||||
$formattedMinFileSize = GeneralUtility::formatSize($minFileSize, $labels);
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1505305752',
|
||||
'form',
|
||||
[$formattedMinFileSize]
|
||||
),
|
||||
1505305752,
|
||||
[$formattedMinFileSize]
|
||||
);
|
||||
}
|
||||
if ($fileSize > $maxFileSize) {
|
||||
$formattedMaxFileSize = GeneralUtility::formatSize($maxFileSize, $labels);
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1505305753',
|
||||
'form',
|
||||
[$formattedMaxFileSize]
|
||||
),
|
||||
1505305753,
|
||||
[$formattedMaxFileSize]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this validator is correctly configured
|
||||
*
|
||||
* @throws InvalidValidationOptionsException if the configured validation options are incorrect
|
||||
*/
|
||||
private function validateOptions(): void
|
||||
{
|
||||
if (!preg_match('/^(\d*\.?\d+)(B|K|M|G)$/i', $this->options['minimum'])) {
|
||||
throw new InvalidValidationOptionsException('The option "minimum" has an invalid format. Valid formats are something like this: "10B|K|M|G".', 1505304205);
|
||||
}
|
||||
if (!preg_match('/^(\d*\.?\d+)(B|K|M|G)$/i', $this->options['maximum'])) {
|
||||
throw new InvalidValidationOptionsException('The option "maximum" has an invalid format. Valid formats are something like this: "10B|K|M|G".', 1505304206);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Mvc\Validation;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\MimeTypeDetector;
|
||||
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
|
||||
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;
|
||||
use TYPO3\CMS\Form\Mvc\Property\TypeConverter\PseudoFile;
|
||||
use TYPO3\CMS\Form\Mvc\Validation\Exception\InvalidValidationOptionsException;
|
||||
|
||||
/**
|
||||
* Validator for mime types
|
||||
*
|
||||
* Scope: frontend
|
||||
*/
|
||||
final class MimeTypeValidator extends AbstractValidator implements ObjectStorageElementValidatorInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
'allowedMimeTypes' => [null, 'Allowed mime types (using */* IANA media types)', 'array', true],
|
||||
];
|
||||
|
||||
/**
|
||||
* The given $value is valid if it is a FileReference of the
|
||||
* configured type (one of the IANA media types)
|
||||
*
|
||||
* Note: a value of NULL or empty string ('') is considered valid
|
||||
*
|
||||
* @param mixed $resource The resource that should be validated
|
||||
*/
|
||||
public function isValid(mixed $resource): void
|
||||
{
|
||||
$this->validateOptions();
|
||||
|
||||
if ($resource instanceof FileReference) {
|
||||
$mimeType = $resource->getOriginalResource()->getMimeType();
|
||||
$fileExtension = $resource->getOriginalResource()->getExtension();
|
||||
} elseif ($resource instanceof File) {
|
||||
$mimeType = $resource->getMimeType();
|
||||
$fileExtension = $resource->getExtension();
|
||||
} elseif ($resource instanceof PseudoFile) {
|
||||
$mimeType = $resource->getMimeType();
|
||||
$fileExtension = $resource->getExtension();
|
||||
} else {
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1471708997',
|
||||
'form'
|
||||
),
|
||||
1471708997
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$allowedMimeTypes = $this->options['allowedMimeTypes'];
|
||||
if (!in_array($mimeType, $allowedMimeTypes, true)) {
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1471708998',
|
||||
'form',
|
||||
[$mimeType]
|
||||
),
|
||||
1471708998,
|
||||
[$mimeType]
|
||||
);
|
||||
} else {
|
||||
// The mime-type which was detected by FAL matches, but the file name does not match.
|
||||
// Example: myfile.txt is actually a PDF file (defined by mime-type), but .txt is not associated
|
||||
// for application/pdf, so this is not valid. The file extension of the uploaded file must match
|
||||
// the mime-type for this file.
|
||||
$assumedMimesTypeOfFileExtension = (new MimeTypeDetector())->getMimeTypesForFileExtension($fileExtension);
|
||||
if (empty(array_intersect($allowedMimeTypes, $assumedMimesTypeOfFileExtension))) {
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
'validation.error.1613126216',
|
||||
'form',
|
||||
[$fileExtension]
|
||||
),
|
||||
1613126216,
|
||||
[$fileExtension]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this validator is correctly configured
|
||||
*
|
||||
* @throws InvalidValidationOptionsException if the configured validation options are incorrect
|
||||
*/
|
||||
private function validateOptions(): void
|
||||
{
|
||||
if (!is_array($this->options['allowedMimeTypes'] ?? null) || $this->options['allowedMimeTypes'] === []) {
|
||||
throw new InvalidValidationOptionsException('The option "allowedMimeTypes" must be an array with at least one item.', 1471713296);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Mvc\Validation;
|
||||
|
||||
/**
|
||||
* Marker interface for validators that operate on individual elements
|
||||
* of a collection rather than on the collection itself.
|
||||
*
|
||||
* When ProcessingRule encounters an ObjectStorage value, validators are
|
||||
* by default called with the whole collection (preserving backwards
|
||||
* compatibility). Validators implementing this interface are called
|
||||
* once per element instead.
|
||||
*
|
||||
* Example: A MimeTypeValidator validates each file individually, while
|
||||
* a CountValidator checks the total number of items in the collection.
|
||||
*/
|
||||
interface ObjectStorageElementValidatorInterface {}
|
||||
Reference in New Issue
Block a user