TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException;
|
||||
use TYPO3\CMS\Extbase\Validation\Exception\NoSuchValidatorException;
|
||||
|
||||
/**
|
||||
* An abstract composite validator consisting of other validators
|
||||
*/
|
||||
abstract class AbstractCompositeValidator implements ObjectValidatorInterface, \Countable
|
||||
{
|
||||
/**
|
||||
* This contains the supported options, their default values and descriptions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [];
|
||||
|
||||
protected array $options = [];
|
||||
|
||||
/**
|
||||
* @var \SplObjectStorage<ValidatorInterface>
|
||||
*/
|
||||
protected \SplObjectStorage $validators;
|
||||
protected ?ServerRequestInterface $request = null;
|
||||
protected \SplObjectStorage $validatedInstancesContainer;
|
||||
|
||||
public function setOptions(array $options): void
|
||||
{
|
||||
$this->initializeDefaultOptions($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new validator to the composition.
|
||||
*/
|
||||
public function addValidator(ValidatorInterface $validator): void
|
||||
{
|
||||
$this->validators->offsetSet($validator);
|
||||
}
|
||||
|
||||
public function getRequest(): ?ServerRequestInterface
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
public function setRequest(?ServerRequestInterface $request): void
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified validator.
|
||||
*
|
||||
* @throws NoSuchValidatorException
|
||||
*/
|
||||
public function removeValidator(ValidatorInterface $validator): void
|
||||
{
|
||||
if (!$this->validators->offsetExists($validator)) {
|
||||
throw new NoSuchValidatorException('Cannot remove validator because its not in the conjunction.', 1207020177);
|
||||
}
|
||||
$this->validators->offsetUnset($validator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of validators contained in this composition.
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->validators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the child validators of this Composite Validator
|
||||
*
|
||||
* @return \SplObjectStorage<ValidatorInterface>
|
||||
*/
|
||||
public function getValidators(): \SplObjectStorage
|
||||
{
|
||||
return $this->validators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the options for this validator
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a container to keep track of validated instances.
|
||||
*/
|
||||
public function setValidatedInstancesContainer(\SplObjectStorage $validatedInstancesContainer): void
|
||||
{
|
||||
$this->validatedInstancesContainer = $validatedInstancesContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize default options.
|
||||
* @throws InvalidValidationOptionsException
|
||||
*/
|
||||
protected function initializeDefaultOptions(array $options): void
|
||||
{
|
||||
// check for options given but not supported
|
||||
if (($unsupportedOptions = array_diff_key($options, $this->supportedOptions)) !== []) {
|
||||
throw new InvalidValidationOptionsException('Unsupported validation option(s) found: ' . implode(', ', array_keys($unsupportedOptions)), 1339079804);
|
||||
}
|
||||
// check for required options being set
|
||||
array_walk(
|
||||
$this->supportedOptions,
|
||||
static function (array $supportedOptionData, string $supportedOptionName, array $options): void {
|
||||
if (isset($supportedOptionData[3]) && !array_key_exists($supportedOptionName, $options)) {
|
||||
throw new InvalidValidationOptionsException('Required validation option not set: ' . $supportedOptionName, 1339163922);
|
||||
}
|
||||
},
|
||||
$options
|
||||
);
|
||||
// merge with default values
|
||||
$this->options = array_merge(
|
||||
array_map(
|
||||
static fn(array $value): mixed => $value[0],
|
||||
$this->supportedOptions
|
||||
),
|
||||
$options
|
||||
);
|
||||
$this->validators = new \SplObjectStorage();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Extbase\Error\Result;
|
||||
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
|
||||
|
||||
/**
|
||||
* A generic object validator which allows for specifying property validators.
|
||||
*/
|
||||
abstract class AbstractGenericObjectValidator extends AbstractValidator implements ObjectValidatorInterface
|
||||
{
|
||||
/**
|
||||
* @var array<string, \SplObjectStorage<ValidatorInterface>>
|
||||
*/
|
||||
protected array $propertyValidators = [];
|
||||
|
||||
/**
|
||||
* @var \SplObjectStorage
|
||||
*/
|
||||
protected $validatedInstancesContainer;
|
||||
|
||||
/**
|
||||
* Checks if the given value is valid according to the validator, and returns
|
||||
* the Error Messages object which occurred.
|
||||
*
|
||||
* @param mixed $value The value that should be validated
|
||||
*/
|
||||
public function validate(mixed $value): Result
|
||||
{
|
||||
if (is_object($value) && $this->isValidatedAlready($value)) {
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
$this->result = new Result();
|
||||
if ($this->acceptsEmptyValues === false || $this->isEmpty($value) === false) {
|
||||
if (!is_object($value)) {
|
||||
$this->addError('Object expected, %1$s given.', 1241099149, [gettype($value)]);
|
||||
} elseif ($this->isValidatedAlready($value) === false) {
|
||||
$this->markInstanceAsValidated($value);
|
||||
$this->isValid($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the property value to be used for validation.
|
||||
* In case the object is a doctrine proxy, we need to load the real instance first.
|
||||
*/
|
||||
protected function getPropertyValue(object $object, string $propertyName): mixed
|
||||
{
|
||||
if (ObjectAccess::isPropertyGettable($object, $propertyName)) {
|
||||
return ObjectAccess::getProperty($object, $propertyName);
|
||||
}
|
||||
throw new \RuntimeException(
|
||||
sprintf(
|
||||
'Could not get value of property "%s::%s", make sure the property is either public or has a getter get%3$s(), a hasser has%3$s() or an isser is%3$s().',
|
||||
get_class($object),
|
||||
$propertyName,
|
||||
ucfirst($propertyName)
|
||||
),
|
||||
1546632293
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified property of the given object is valid, and adds
|
||||
* found errors to the $messages object.
|
||||
*
|
||||
* @param \Traversable<ValidatorInterface> $validators
|
||||
*/
|
||||
protected function checkProperty(mixed $value, \Traversable $validators, string $propertyName): void
|
||||
{
|
||||
/** @var Result|null $result */
|
||||
$result = null;
|
||||
foreach ($validators as $validator) {
|
||||
if ($validator instanceof ObjectValidatorInterface) {
|
||||
$validator->setValidatedInstancesContainer($this->validatedInstancesContainer);
|
||||
}
|
||||
$currentResult = $validator->validate($value);
|
||||
if ($currentResult->hasMessages()) {
|
||||
if ($result == null) {
|
||||
$result = $currentResult;
|
||||
} else {
|
||||
$result->merge($currentResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($result != null) {
|
||||
$this->result->forProperty($propertyName)->merge($result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given value is valid according to the property validators.
|
||||
*/
|
||||
protected function isValid(mixed $object): void
|
||||
{
|
||||
foreach ($this->propertyValidators as $propertyName => $validators) {
|
||||
$propertyValue = $this->getPropertyValue($object, $propertyName);
|
||||
$this->checkProperty($propertyValue, $validators, $propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given object can be validated by the validator implementation
|
||||
*/
|
||||
public function canValidate(mixed $object): bool
|
||||
{
|
||||
return is_object($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given validator for validation of the specified property.
|
||||
*/
|
||||
public function addPropertyValidator(string $propertyName, ValidatorInterface $validator): void
|
||||
{
|
||||
if (!isset($this->propertyValidators[$propertyName])) {
|
||||
$this->propertyValidators[$propertyName] = new \SplObjectStorage();
|
||||
}
|
||||
$this->propertyValidators[$propertyName]->offsetSet($validator);
|
||||
}
|
||||
|
||||
protected function isValidatedAlready(object $object): bool
|
||||
{
|
||||
if ($this->validatedInstancesContainer === null) {
|
||||
$this->validatedInstancesContainer = new \SplObjectStorage();
|
||||
}
|
||||
if ($this->validatedInstancesContainer->offsetExists($object)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function markInstanceAsValidated(object $object): void
|
||||
{
|
||||
$this->validatedInstancesContainer->offsetSet($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all property validators - or only validators of the specified property
|
||||
*
|
||||
* @return ($propertyName is null ? array<string, \SplObjectStorage<ValidatorInterface>> : \SplObjectStorage<ValidatorInterface>)
|
||||
*/
|
||||
public function getPropertyValidators(?string $propertyName = null): array|\SplObjectStorage
|
||||
{
|
||||
if ($propertyName !== null) {
|
||||
return $this->propertyValidators[$propertyName] ?? [];
|
||||
}
|
||||
return $this->propertyValidators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set a container to keep track of validated instances.
|
||||
*/
|
||||
public function setValidatedInstancesContainer(\SplObjectStorage $validatedInstancesContainer): void
|
||||
{
|
||||
$this->validatedInstancesContainer = $validatedInstancesContainer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Http\UploadedFile;
|
||||
use TYPO3\CMS\Core\Type\File\FileInfo;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Error\Result;
|
||||
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
use TYPO3\CMS\Extbase\Validation\Error;
|
||||
use TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException;
|
||||
|
||||
/**
|
||||
* Abstract validator. Mother af most validators.
|
||||
*/
|
||||
abstract class AbstractValidator implements ValidatorInterface
|
||||
{
|
||||
/**
|
||||
* Specifies whether this validator accepts empty values.
|
||||
*
|
||||
* If this is TRUE, the validators isValid() method is not called in case of an empty value
|
||||
* Note: A value is considered empty if it is NULL or an empty string!
|
||||
* By default, all validators except for NotEmpty and the Composite Validators accept empty values.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $acceptsEmptyValues = true;
|
||||
|
||||
/**
|
||||
* Contains an array of property names used for translation handling of error messages.
|
||||
*/
|
||||
protected array $translationOptions = ['message'];
|
||||
|
||||
/**
|
||||
* This contains the supported options, their default values, types and descriptions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [];
|
||||
|
||||
protected array $options = [];
|
||||
protected Result $result;
|
||||
protected ?ServerRequestInterface $request = null;
|
||||
|
||||
public function setOptions(array $options): void
|
||||
{
|
||||
$this->initializeDefaultOptions($options);
|
||||
$this->initializeTranslationOptions($options);
|
||||
}
|
||||
|
||||
public function setRequest(?ServerRequestInterface $request): void
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given value is valid according to the validator, and returns
|
||||
* the error messages object which occurred.
|
||||
*
|
||||
* @param mixed $value The value that should be validated
|
||||
*/
|
||||
public function validate(mixed $value): Result
|
||||
{
|
||||
$this->result = new Result();
|
||||
if ($this->acceptsEmptyValues === false || $this->isEmpty($value) === false) {
|
||||
$this->isValid($value);
|
||||
}
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if $value is valid. If it is not valid, needs to add an error to result.
|
||||
*/
|
||||
abstract protected function isValid(mixed $value): void;
|
||||
|
||||
/**
|
||||
* Creates a new validation error object and adds it to $this->result
|
||||
*
|
||||
* @param string $message The error message
|
||||
* @param int $code The error code (a unix timestamp)
|
||||
* @param array $arguments Arguments to be replaced in message
|
||||
* @param string $title title of the error
|
||||
*/
|
||||
protected function addError(string $message, int $code, array $arguments = [], string $title = ''): void
|
||||
{
|
||||
$this->result->addError(new Error($message, $code, $arguments, $title));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new validation error object for a property and adds it to the proper sub result of $this->result
|
||||
*
|
||||
* @param string|array $propertyPath The property path (string or array)
|
||||
* @param string $message The error message
|
||||
* @param int $code The error code (a unix timestamp)
|
||||
* @param array $arguments Arguments to be replaced in message
|
||||
* @param string $title Title of the error
|
||||
*/
|
||||
protected function addErrorForProperty(string|array $propertyPath, string $message, int $code, array $arguments = [], string $title = ''): void
|
||||
{
|
||||
$propertyPath = is_array($propertyPath) ? implode('.', $propertyPath) : $propertyPath;
|
||||
$error = new Error($message, $code, $arguments, $title);
|
||||
$this->result->forProperty($propertyPath)->addError($error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the options of this validator
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
public function getRequest(): ?ServerRequestInterface
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* TRUE if the given $value is NULL or an empty string ('')
|
||||
*/
|
||||
final protected function isEmpty(mixed $value): bool
|
||||
{
|
||||
return $value === null || $value === '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates an error message using LocalizationUtility::translate() method. If the translate key does not
|
||||
* start with 'LLL:' and if no extension name is provided, the original translate key is returned.
|
||||
*/
|
||||
protected function translateErrorMessage(
|
||||
string $translateKey,
|
||||
string $extensionName = '',
|
||||
array $arguments = []
|
||||
): string {
|
||||
if ($extensionName === '' && !str_starts_with($translateKey, 'LLL:')) {
|
||||
return $translateKey;
|
||||
}
|
||||
|
||||
return LocalizationUtility::translate(
|
||||
$translateKey,
|
||||
$extensionName,
|
||||
$arguments
|
||||
) ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize default options.
|
||||
* @throws InvalidValidationOptionsException
|
||||
*/
|
||||
protected function initializeDefaultOptions(array $options): void
|
||||
{
|
||||
// check for options given but not supported
|
||||
if (($unsupportedOptions = array_diff_key($options, $this->supportedOptions)) !== []) {
|
||||
throw new InvalidValidationOptionsException('Unsupported validation option(s) found: ' . implode(', ', array_keys($unsupportedOptions)), 1379981890);
|
||||
}
|
||||
// check for required options being set
|
||||
array_walk(
|
||||
$this->supportedOptions,
|
||||
static function (array $supportedOptionData, string $supportedOptionName, array $options): void {
|
||||
if (isset($supportedOptionData[3]) && $supportedOptionData[3] === true && !array_key_exists($supportedOptionName, $options)) {
|
||||
throw new InvalidValidationOptionsException('Required validation option not set: ' . $supportedOptionName, 1379981891);
|
||||
}
|
||||
},
|
||||
$options
|
||||
);
|
||||
// merge with default values
|
||||
$this->options = array_merge(
|
||||
array_map(
|
||||
static fn(array $value): mixed => $value[0],
|
||||
$this->supportedOptions
|
||||
),
|
||||
$options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the provided value is either an instance of UploadedFile or an ObjectStorage containing only
|
||||
* UploadedFile instances.
|
||||
*/
|
||||
protected function ensureFileUploadTypes(mixed $value): void
|
||||
{
|
||||
if ($value instanceof UploadedFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($value instanceof ObjectStorage) {
|
||||
foreach ($value as $uploadedFile) {
|
||||
if (!$uploadedFile instanceof UploadedFile) {
|
||||
throw new \InvalidArgumentException('Value to validate must be an ObjectStorage of TYPO3\\CMS\\Core\\Http\\UploadedFile', 1722763902);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Value to validate must be a TYPO3\\CMS\\Core\\Http\\UploadedFile', 1712057926);
|
||||
}
|
||||
|
||||
protected function getFileInfo(string $filePath): FileInfo
|
||||
{
|
||||
return GeneralUtility::makeInstance(FileInfo::class, $filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes all registered translation options with custom translation options from the given options array
|
||||
*/
|
||||
protected function initializeTranslationOptions(array $options): void
|
||||
{
|
||||
foreach ($this->translationOptions as $translationOption) {
|
||||
if (property_exists($this, $translationOption)) {
|
||||
$this->$translationOption = $options[$translationOption] ?? $this->$translationOption;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Validator for alphanumeric strings
|
||||
*/
|
||||
final class AlphanumericValidator extends AbstractValidator
|
||||
{
|
||||
protected string $message = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.alphanumeric.notvalid';
|
||||
|
||||
protected $supportedOptions = [
|
||||
'message' => [null, 'Translation key or message for invalid value', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* The given $value is valid if it is an alphanumeric string, which is defined as [\pL\d]*.
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if (!is_string($value) || preg_match('/^[\pL\d]*$/u', $value) !== 1) {
|
||||
$this->addError($this->translateErrorMessage($this->message), 1221551320);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Validator for boolean values
|
||||
*/
|
||||
final class BooleanValidator extends AbstractValidator
|
||||
{
|
||||
protected string $notTrueMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.boolean.nottrue';
|
||||
protected string $notFalseMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.boolean.notfalse';
|
||||
|
||||
protected array $translationOptions = ['notTrueMessage', 'notFalseMessage'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
// The default is set to NULL here, because we need to be backward compatible here, because this
|
||||
// BooleanValidator is called automatically on boolean action arguments. If we would set it to TRUE,
|
||||
// every FALSE value for an action argument would break.
|
||||
// @todo with next patches: deprecate this BooleanValidator and introduce a BooleanValueValidator, like
|
||||
// in Flow, which won't be called on boolean action arguments.
|
||||
'is' => [null, 'Boolean value', 'boolean|string|integer'],
|
||||
'notTrueMessage' => [null, 'Translation key or message for not true value', 'string'],
|
||||
'notFalseMessage' => [null, 'Translation key or message for not false value', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Check if $value matches the expectation given to the validator.
|
||||
* If it does not match, the function adds an error to the result.
|
||||
*
|
||||
* Also testing for '1' (true), '0' and '' (false) because casting varies between
|
||||
* tests and actual usage. This makes the validator loose but still keeping functionality.
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
// see comment above, check if expectation is NULL, then nothing to do!
|
||||
if ($this->options['is'] === null) {
|
||||
return;
|
||||
}
|
||||
switch (strtolower((string)$this->options['is'])) {
|
||||
case 'true':
|
||||
case '1':
|
||||
$expectation = true;
|
||||
break;
|
||||
case 'false':
|
||||
case '':
|
||||
case '0':
|
||||
$expectation = false;
|
||||
break;
|
||||
default:
|
||||
$this->addError('The given expectation is not valid.', 1361959227);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($value !== $expectation) {
|
||||
if (!is_bool($value)) {
|
||||
$this->addError($this->translateErrorMessage($this->notTrueMessage), 1361959230);
|
||||
} else {
|
||||
if ($expectation) {
|
||||
$this->addError($this->translateErrorMessage($this->notTrueMessage), 1361959228);
|
||||
} else {
|
||||
$this->addError($this->translateErrorMessage($this->notFalseMessage), 1361959229);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Extbase\Error\Result;
|
||||
use TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage;
|
||||
use TYPO3\CMS\Extbase\Utility\TypeHandlingUtility;
|
||||
use TYPO3\CMS\Extbase\Validation\ValidatorResolver;
|
||||
|
||||
/**
|
||||
* A generic collection validator.
|
||||
*/
|
||||
final class CollectionValidator extends AbstractGenericObjectValidator
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
'elementValidator' => [null, 'The validator type to use for the collection elements', 'string'],
|
||||
'elementType' => [null, 'The type of the elements in the collection', 'string'],
|
||||
];
|
||||
|
||||
public function __construct(private readonly ValidatorResolver $validatorResolver) {}
|
||||
|
||||
/**
|
||||
* Checks if the given value is valid according to the validator, and returns
|
||||
* the Error Messages object which occurred.
|
||||
*/
|
||||
public function validate(mixed $value): Result
|
||||
{
|
||||
$this->result = new Result();
|
||||
|
||||
if ($this->acceptsEmptyValues === false || $this->isEmpty($value) === false) {
|
||||
if ((is_object($value) && !TypeHandlingUtility::isCollectionType(get_class($value))) && !is_array($value)) {
|
||||
$this->addError('The given subject was not a collection.', 1317204797);
|
||||
return $this->result;
|
||||
}
|
||||
if ($value instanceof LazyObjectStorage && !$value->isInitialized()) {
|
||||
return $this->result;
|
||||
}
|
||||
if (is_object($value)) {
|
||||
if ($this->isValidatedAlready($value)) {
|
||||
return $this->result;
|
||||
}
|
||||
$this->markInstanceAsValidated($value);
|
||||
}
|
||||
$this->isValid($value);
|
||||
}
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for a collection and if needed validates the items in the collection.
|
||||
* This is done with the specified element validator or a validator based on
|
||||
* the given element type.
|
||||
*
|
||||
* Either elementValidator or elementType must be given, otherwise validation
|
||||
* will be skipped.
|
||||
*/
|
||||
protected function isValid(mixed $value): void
|
||||
{
|
||||
foreach ($value as $index => $collectionElement) {
|
||||
if (isset($this->options['elementValidator'])) {
|
||||
$collectionElementValidator = $this->validatorResolver->createValidator($this->options['elementValidator']);
|
||||
} elseif (isset($this->options['elementType'])) {
|
||||
$collectionElementValidator = $this->validatorResolver->getBaseValidatorConjunction($this->options['elementType']);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if ($collectionElementValidator instanceof ObjectValidatorInterface) {
|
||||
$collectionElementValidator->setValidatedInstancesContainer($this->validatedInstancesContainer);
|
||||
}
|
||||
$this->result->forProperty((string)$index)->merge($collectionElementValidator->validate($collectionElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Extbase\Error\Result;
|
||||
|
||||
/**
|
||||
* Validator to chain many validators in a conjunction (logical and).
|
||||
*/
|
||||
final class ConjunctionValidator extends AbstractCompositeValidator
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->validators = new \SplObjectStorage();
|
||||
$this->validatedInstancesContainer = new \SplObjectStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given value is valid according to the validators of the conjunction.
|
||||
* Every validator has to be valid, to make the whole conjunction valid.
|
||||
*
|
||||
* @param mixed $value The value that should be validated
|
||||
*/
|
||||
public function validate(mixed $value): Result
|
||||
{
|
||||
$result = new Result();
|
||||
foreach ($this->getValidators() as $validator) {
|
||||
$result->merge($validator->validate($value));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Exclude;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintViolationInterface;
|
||||
use Symfony\Component\Validator\Validation;
|
||||
use TYPO3\CMS\Extbase\Error\Error;
|
||||
use TYPO3\CMS\Extbase\Error\Result;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
/**
|
||||
* Validator that decorates a Symfony Constraint.
|
||||
*/
|
||||
#[Exclude]
|
||||
final readonly class ConstraintDecoratingValidator implements ValidatorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private Constraint $constraint,
|
||||
) {}
|
||||
|
||||
public function validate(mixed $value): Result
|
||||
{
|
||||
$validator = Validation::createValidatorBuilder()->disableTranslation()->getValidator();
|
||||
$constraintViolationList = $validator->validate($value, $this->constraint);
|
||||
$result = new Result();
|
||||
|
||||
foreach ($constraintViolationList as $constraintViolation) {
|
||||
$arguments = array_values($constraintViolation->getParameters());
|
||||
$code = $this->convertConstraintViolationCode($constraintViolation->getCode());
|
||||
$messageTemplate = $this->convertConstraintViolationMessageTemplate($constraintViolation);
|
||||
|
||||
$result->addError(
|
||||
new Error(
|
||||
$this->translateErrorMessage($messageTemplate, $arguments),
|
||||
$code,
|
||||
$arguments,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert UUID-based violation code to an integer.
|
||||
*/
|
||||
private function convertConstraintViolationCode(?string $code): int
|
||||
{
|
||||
if ($code !== null && $code !== '') {
|
||||
$hash = hash('sha256', $code);
|
||||
$code = hexdec(substr($hash, 0, 8));
|
||||
}
|
||||
|
||||
return (int)$code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert named placeholders like {{ value }} to sprintf compatible placeholders like %1$s.
|
||||
*
|
||||
* Before: 'The value {{ value }} must follow the {{ format }} format.'
|
||||
* After: 'The value %1$s must follow the %2$s format.'
|
||||
*/
|
||||
private function convertConstraintViolationMessageTemplate(ConstraintViolationInterface $constraintViolation): string
|
||||
{
|
||||
$placeholderMap = [];
|
||||
|
||||
foreach (array_keys($constraintViolation->getParameters()) as $index => $placeholder) {
|
||||
$placeholderMap[$placeholder] = '%' . ($index + 1) . '$s';
|
||||
}
|
||||
|
||||
return strtr($constraintViolation->getMessageTemplate(), $placeholderMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<scalar|\Stringable> $arguments
|
||||
*/
|
||||
private function translateErrorMessage(string $translateKey, array $arguments = []): string
|
||||
{
|
||||
if (!str_starts_with($translateKey, 'LLL:')) {
|
||||
return $translateKey;
|
||||
}
|
||||
|
||||
return LocalizationUtility::translate($translateKey, null, $arguments) ?? '';
|
||||
}
|
||||
|
||||
public function setOptions(array $options): void
|
||||
{
|
||||
// Intentionally left blank.
|
||||
}
|
||||
|
||||
public function getOptions(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function setRequest(?ServerRequestInterface $request): void
|
||||
{
|
||||
// Intentionally left blank.
|
||||
}
|
||||
|
||||
public function getRequest(): ?ServerRequestInterface
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Validator for DateTime/DateTimeImmutable objects.
|
||||
*/
|
||||
final class DateTimeValidator extends AbstractValidator
|
||||
{
|
||||
protected string $message = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.datetime.notvalid';
|
||||
|
||||
protected $supportedOptions = [
|
||||
'message' => [null, 'Translation key or message for invalid value', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks if the given value is a valid DateTime object. If this is not
|
||||
* the case, the function adds an error.
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
$this->result->clear();
|
||||
if ($value instanceof \DateTimeInterface) {
|
||||
return;
|
||||
}
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
$this->message,
|
||||
'',
|
||||
[
|
||||
gettype($value),
|
||||
]
|
||||
),
|
||||
1238087674,
|
||||
[gettype($value)]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Extbase\Error\Result;
|
||||
|
||||
/**
|
||||
* Validator to chain many validators in a disjunction (logical or).
|
||||
*/
|
||||
final class DisjunctionValidator extends AbstractCompositeValidator
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->validators = new \SplObjectStorage();
|
||||
$this->validatedInstancesContainer = new \SplObjectStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given value is valid according to the validators of the
|
||||
* disjunction.
|
||||
*
|
||||
* So only one validator has to be valid, to make the whole disjunction valid.
|
||||
* Errors are only returned if all validators failed.
|
||||
*
|
||||
* @param mixed $value The value that should be validated
|
||||
*/
|
||||
public function validate(mixed $value): Result
|
||||
{
|
||||
$validators = $this->getValidators();
|
||||
if ($validators->count() > 0) {
|
||||
$result = null;
|
||||
foreach ($validators as $validator) {
|
||||
$validatorResult = $validator->validate($value);
|
||||
if ($validatorResult->hasErrors()) {
|
||||
if ($result === null) {
|
||||
$result = $validatorResult;
|
||||
} else {
|
||||
$result->merge($validatorResult);
|
||||
}
|
||||
} else {
|
||||
if ($result === null) {
|
||||
$result = $validatorResult;
|
||||
} else {
|
||||
$result->clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$result = new Result();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Validator for email addresses
|
||||
*/
|
||||
final class EmailAddressValidator extends AbstractValidator
|
||||
{
|
||||
protected string $message = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.emailaddress.notvalid';
|
||||
|
||||
protected $supportedOptions = [
|
||||
'message' => [null, 'Translation key or message for invalid value', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks if the given value is a valid email address.
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if (!is_string($value) || !$this->validEmail($value)) {
|
||||
$this->addError($this->translateErrorMessage($this->message), 1221559976);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking syntax of input email address
|
||||
*
|
||||
* @param string $emailAddress Input string to evaluate
|
||||
* @return bool Returns TRUE if the $email address (input string) is valid
|
||||
*/
|
||||
private function validEmail(string $emailAddress): bool
|
||||
{
|
||||
return GeneralUtility::validEmail($emailAddress);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Core\Http\UploadedFile;
|
||||
use TYPO3\CMS\Core\Resource\MimeTypeCompatibilityTypeGuesser;
|
||||
use TYPO3\CMS\Core\Resource\MimeTypeDetector;
|
||||
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||
|
||||
/**
|
||||
* Validator comparing file extension to the expected mime-type of a given UploadedFile
|
||||
* or ObjectStorage of UploadedFile objects.
|
||||
*/
|
||||
final class FileExtensionMimeTypeConsistencyValidator extends AbstractValidator
|
||||
{
|
||||
protected string $notAllowedMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.fileextensionmimetypeconsistency.notallowed';
|
||||
protected array $translationOptions = ['inconsistentMessage'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
'notAllowedMessage' => [null, 'Translation key or message for inconsistent mime-type for file extension', 'string'],
|
||||
];
|
||||
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
$this->ensureFileUploadTypes($value);
|
||||
|
||||
if ($value instanceof UploadedFile) {
|
||||
$this->validateUploadedFile($value);
|
||||
} elseif ($value instanceof ObjectStorage && $value->count() > 0) {
|
||||
$index = 0;
|
||||
foreach ($value as $uploadedFile) {
|
||||
$this->validateUploadedFile($uploadedFile, $index);
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function validateUploadedFile(UploadedFile $uploadedFile, ?int $index = null): void
|
||||
{
|
||||
$fileInfo = $this->getFileInfo($uploadedFile->getTemporaryFileName());
|
||||
$mimeType = $fileInfo->getMimeType();
|
||||
|
||||
// The file extension of the uploaded file must match the mime-type for this file.
|
||||
// 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.
|
||||
$fileExtension = pathinfo($uploadedFile->getClientFilename(), PATHINFO_EXTENSION);
|
||||
$assumedMimesTypeOfFileExtension = (new MimeTypeDetector())->getMimeTypesForFileExtension($fileExtension);
|
||||
|
||||
// pass, in case no assumed mime-type was found (e.g., for individual file extension)
|
||||
if ($mimeType === '' || $assumedMimesTypeOfFileExtension === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Example in case of "exe", which has over 9000 possible MIME types:
|
||||
// mime-db/db.json is only aware of "application/octet-stream", "application/x-msdos-program", "application/x-msdownload"
|
||||
// However, PHP detects this as "application/vnd.microsoft.portable-executable" (PHP 8.4+) or "application/x-dosexec" (PHP < 8.4)
|
||||
// DefaultConfiguration $GLOBALS['TYPO3_CONF_VARS']['SYS']['FileInfo']['mimeTypeCompatibility'] registers this (and some more),
|
||||
// so we also need these fallbacks to be evaluated.
|
||||
$mimeTypeCompatibility = (new MimeTypeCompatibilityTypeGuesser())->getMimeTypeCompatibilityList();
|
||||
$additionalMappedMimeType = $mimeTypeCompatibility[$mimeType][$fileExtension] ?? null;
|
||||
|
||||
if (!in_array($mimeType, $assumedMimesTypeOfFileExtension, true)
|
||||
&& !in_array($additionalMappedMimeType, $assumedMimesTypeOfFileExtension, true)
|
||||
) {
|
||||
$message = $this->translateErrorMessage(
|
||||
$this->notAllowedMessage,
|
||||
'',
|
||||
[$mimeType, $fileExtension]
|
||||
);
|
||||
$code = 1754045716;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Core\Http\UploadedFile;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||
use TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException;
|
||||
|
||||
/**
|
||||
* Validator file extensions of a given UploadedFile or ObjectStorage of UploadedFile objects.
|
||||
*/
|
||||
final class FileExtensionValidator extends AbstractValidator
|
||||
{
|
||||
protected string $notAllowedMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.fileextension.notallowed';
|
||||
protected array $translationOptions = ['notAllowedMessage'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
'allowedFileExtensions' => [null, 'Allowed file extensions', 'array'],
|
||||
'useStorageDefaults' => [null, 'Whether to use the default allowed file extension of the storage', 'bool'],
|
||||
'notAllowedMessage' => [null, 'Translation key or message for disallowed file extension', 'string'],
|
||||
];
|
||||
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
$this->ensureFileUploadTypes($value);
|
||||
$this->validateOptions();
|
||||
|
||||
if ($value instanceof UploadedFile) {
|
||||
$this->validateUploadedFile($value);
|
||||
} elseif ($value instanceof ObjectStorage && $value->count() > 0) {
|
||||
$index = 0;
|
||||
foreach ($value as $uploadedFile) {
|
||||
$this->validateUploadedFile($uploadedFile, $index);
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function validateUploadedFile(UploadedFile $uploadedFile, ?int $index = null): void
|
||||
{
|
||||
$allowedFileExtensions = [];
|
||||
if (!empty($this->options['useStorageDefaults'])) {
|
||||
$allowedFileExtensions = GeneralUtility::trimExplode(
|
||||
',',
|
||||
($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'] ?? '') . ','
|
||||
. ($GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'] ?? '') . ','
|
||||
. ($GLOBALS['TYPO3_CONF_VARS']['SYS']['miscfile_ext'] ?? ''),
|
||||
true
|
||||
);
|
||||
}
|
||||
if (is_array($this->options['allowedFileExtensions'] ?? null)) {
|
||||
$allowedFileExtensions = array_merge($allowedFileExtensions, $this->options['allowedFileExtensions']);
|
||||
}
|
||||
$allowedFileExtensions = array_map(mb_strtolower(...), $allowedFileExtensions);
|
||||
$fileExtension = pathinfo($uploadedFile->getClientFilename(), PATHINFO_EXTENSION);
|
||||
|
||||
if (!in_array($fileExtension, $allowedFileExtensions, true)) {
|
||||
$message = $this->translateErrorMessage(
|
||||
$this->notAllowedMessage,
|
||||
'',
|
||||
[$fileExtension]
|
||||
);
|
||||
$code = 1754043401;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this validator is correctly configured
|
||||
*/
|
||||
private function validateOptions(): void
|
||||
{
|
||||
$hasAllowedFileExtensions = is_array($this->options['allowedFileExtensions'] ?? null)
|
||||
&& $this->options['allowedFileExtensions'] !== [];
|
||||
$shallUseStorageDefaults = !empty($this->options['useStorageDefaults']);
|
||||
|
||||
if (!$hasAllowedFileExtensions && !$shallUseStorageDefaults) {
|
||||
throw new InvalidValidationOptionsException(
|
||||
'Either the option "allowedFileExtensions" must be an array with at least one item, '
|
||||
. 'or the option "useStorageDefaults" must be enabled.',
|
||||
1754043328
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Core\Http\UploadedFile;
|
||||
use TYPO3\CMS\Core\Resource\Security\FileNameValidator as CoreFileNameValidator;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||
|
||||
/**
|
||||
* Validates, that the given UploadedFile or ObjectStorage of UploadedFile objects does not contain a php
|
||||
* executable file by checking the given file extension.
|
||||
*/
|
||||
final class FileNameValidator extends AbstractValidator
|
||||
{
|
||||
protected string $message = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.denyphpupload.notallowed';
|
||||
|
||||
protected $supportedOptions = [
|
||||
'message' => [null, 'Translation key or message for invalid value', 'string'],
|
||||
];
|
||||
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
$this->ensureFileUploadTypes($value);
|
||||
|
||||
if ($value instanceof UploadedFile) {
|
||||
$this->validateUploadedFile($value);
|
||||
} elseif ($value instanceof ObjectStorage && $value->count() > 0) {
|
||||
$index = 0;
|
||||
foreach ($value as $uploadedFile) {
|
||||
$this->validateUploadedFile($uploadedFile, $index);
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function validateUploadedFile(UploadedFile $uploadedFile, ?int $index = null): void
|
||||
{
|
||||
if (!GeneralUtility::makeInstance(CoreFileNameValidator::class)->isValid($uploadedFile->getClientFilename())) {
|
||||
$message = $this->translateErrorMessage($this->message);
|
||||
$code = 1711367029;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Core\Http\UploadedFile;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||
use TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException;
|
||||
|
||||
/**
|
||||
* Validator for file size of a given UploadedFile or ObjectStorage of UploadedFile objects.
|
||||
*/
|
||||
final class FileSizeValidator extends AbstractValidator
|
||||
{
|
||||
protected string $lessMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.filesize.less';
|
||||
protected string $exceedMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.filesize.exceed';
|
||||
|
||||
protected array $translationOptions = ['lessMessage', 'exceedMessage'];
|
||||
|
||||
/**
|
||||
* @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'],
|
||||
'lessMessage' => [null, 'Translation key or message for value less than minimum', 'string'],
|
||||
'exceedMessage' => [null, 'Translation key or message for value exceeds maximum', 'string'],
|
||||
'byteSizeUnits' => [' Bytes| Kilobyte| Megabyte| Gigabyte', 'Byte size units string for "formatSize" function', 'string'],
|
||||
];
|
||||
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
$this->ensureFileUploadTypes($value);
|
||||
$this->validateOptions();
|
||||
|
||||
if ($value instanceof UploadedFile) {
|
||||
$this->validateUploadedFile($value);
|
||||
} elseif ($value instanceof ObjectStorage && $value->count() > 0) {
|
||||
$index = 0;
|
||||
foreach ($value as $uploadedFile) {
|
||||
$this->validateUploadedFile($uploadedFile, $index);
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function validateUploadedFile(UploadedFile $uploadedFile, ?int $index = null): void
|
||||
{
|
||||
$fileSize = $this->getFileInfo($uploadedFile->getTemporaryFileName())->getSize();
|
||||
|
||||
$minFileSize = GeneralUtility::getBytesFromSizeMeasurement($this->options['minimum']);
|
||||
if ($this->options['maximum'] !== PHP_INT_MAX . 'B') {
|
||||
$maxFileSize = GeneralUtility::getBytesFromSizeMeasurement($this->options['maximum']);
|
||||
} else {
|
||||
$maxFileSize = PHP_INT_MAX;
|
||||
}
|
||||
|
||||
$labels = htmlspecialchars($this->options['byteSizeUnits']);
|
||||
if ($fileSize < $minFileSize) {
|
||||
$message = $this->translateErrorMessage(
|
||||
$this->lessMessage,
|
||||
'',
|
||||
[GeneralUtility::formatSize($minFileSize, $labels)]
|
||||
);
|
||||
$code = 1708595754;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
if ($fileSize > $maxFileSize) {
|
||||
$message = $this->translateErrorMessage(
|
||||
$this->exceedMessage,
|
||||
'',
|
||||
[GeneralUtility::formatSize($maxFileSize, $labels)]
|
||||
);
|
||||
$code = 1708595755;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this validator is correctly configured
|
||||
*/
|
||||
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".', 1708595605);
|
||||
}
|
||||
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".', 1708595606);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Validator for floats.
|
||||
*/
|
||||
final class FloatValidator extends AbstractValidator
|
||||
{
|
||||
protected string $message = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.float.notvalid';
|
||||
|
||||
protected $supportedOptions = [
|
||||
'message' => [null, 'Translation key or message for invalid value', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* The given value is valid if it is of type float or a string matching the regular expression [0-9.e+-]
|
||||
*
|
||||
* @param mixed $value The value that should be validated
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if (is_float($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_string($value) || !str_contains($value, '.') || preg_match('/^[0-9.e+-]+$/', $value) !== 1) {
|
||||
$this->addError($this->translateErrorMessage($this->message), 1221560288);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
/**
|
||||
* A generic object validator which allows for specifying property validators.
|
||||
* This is used as default model validator.
|
||||
*/
|
||||
final class GenericObjectValidator extends AbstractGenericObjectValidator {}
|
||||
@@ -0,0 +1,191 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Core\Http\UploadedFile;
|
||||
use TYPO3\CMS\Core\Type\File\ImageInfo;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||
use TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException;
|
||||
|
||||
/**
|
||||
* Validator to validate image dimensions of a given UploadedFile or ObjectStorage of UploadedFile objects.
|
||||
*/
|
||||
final class ImageDimensionsValidator extends AbstractValidator
|
||||
{
|
||||
protected string $widthMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.imagedimensions.width.notvalid';
|
||||
protected string $heightMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.imagedimensions.height.notvalid';
|
||||
protected string $minWidthMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.imagedimensions.minwidth.notvalid';
|
||||
protected string $minHeightMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.imagedimensions.minheight.notvalid';
|
||||
protected string $maxWidthMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.imagedimensions.maxwidth.notvalid';
|
||||
protected string $maxHeightMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.imagedimensions.maxheight.notvalid';
|
||||
|
||||
protected array $translationOptions = [
|
||||
'widthMessage',
|
||||
'heightMessage',
|
||||
'minWidthMessage',
|
||||
'minHeightMessage',
|
||||
'maxWidthMessage',
|
||||
'maxHeightMessage',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
'width' => [null, 'The exact width of the image', 'int'],
|
||||
'height' => [null, 'The exact height of the image', 'int'],
|
||||
'minWidth' => [0, 'The minimum width of the image', 'int'],
|
||||
'maxWidth' => [PHP_INT_MAX, 'The maximum width of the image', 'int'],
|
||||
'minHeight' => [0, 'The minimum height of the image', 'int'],
|
||||
'maxHeight' => [PHP_INT_MAX, 'The maximum heigt of the image', 'int'],
|
||||
'heightMessage' => [null, 'Translation key or message for invalid height', 'string'],
|
||||
'widthMessage' => [null, 'Translation key or message for invalid width', 'string'],
|
||||
'minWidthMessage' => [null, 'Translation key or message for invalid minimum width', 'string'],
|
||||
'maxWidthMessage' => [null, 'Translation key or message for invalid maximum width', 'string'],
|
||||
'minHeightMessage' => [null, 'Translation key or message for invalid minimum height', 'string'],
|
||||
'maxHeightMessage' => [null, 'Translation key or message for invalid maximum height', 'string'],
|
||||
];
|
||||
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
$this->ensureFileUploadTypes($value);
|
||||
$this->validateOptions();
|
||||
|
||||
if ($value instanceof UploadedFile) {
|
||||
$this->validateUploadedFile($value);
|
||||
} elseif ($value instanceof ObjectStorage && $value->count() > 0) {
|
||||
$index = 0;
|
||||
foreach ($value as $uploadedFile) {
|
||||
$this->validateUploadedFile($uploadedFile, $index);
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function validateUploadedFile(UploadedFile $uploadedFile, ?int $index = null): void
|
||||
{
|
||||
$imageInfo = $this->getImageInfo($uploadedFile->getTemporaryFileName());
|
||||
if ($imageInfo->getWidth() === 0 || $imageInfo->getHeight() === 0) {
|
||||
// Silently ignore files, where the width or height could not be determined. Most likely no image file.
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($this->options['width']) && (int)$this->options['width'] !== $imageInfo->getWidth()) {
|
||||
$message = $this->translateErrorMessage(
|
||||
$this->widthMessage,
|
||||
'',
|
||||
[$this->options['width']]
|
||||
);
|
||||
$code = 1715964040;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->options['height']) && (int)$this->options['height'] !== $imageInfo->getHeight()) {
|
||||
$message = $this->translateErrorMessage(
|
||||
$this->heightMessage,
|
||||
'',
|
||||
[$this->options['height']]
|
||||
);
|
||||
$code = 1715964041;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)$this->options['minWidth'] > $imageInfo->getWidth()) {
|
||||
$message = $this->translateErrorMessage(
|
||||
$this->minWidthMessage,
|
||||
'',
|
||||
[$this->options['minWidth']]
|
||||
);
|
||||
$code = 1715964042;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)$this->options['minHeight'] > $imageInfo->getHeight()) {
|
||||
$message = $this->translateErrorMessage(
|
||||
$this->minHeightMessage,
|
||||
'',
|
||||
[$this->options['minHeight']]
|
||||
);
|
||||
$code = 1715964043;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)$this->options['maxWidth'] < $imageInfo->getWidth()) {
|
||||
$message = $this->translateErrorMessage(
|
||||
$this->maxWidthMessage,
|
||||
'',
|
||||
[$this->options['maxWidth']]
|
||||
);
|
||||
$code = 1715964044;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)$this->options['maxHeight'] < $imageInfo->getHeight()) {
|
||||
$message = $this->translateErrorMessage(
|
||||
$this->maxHeightMessage,
|
||||
'',
|
||||
[$this->options['maxHeight']]
|
||||
);
|
||||
$code = 1715964045;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getImageInfo(string $filePath): ImageInfo
|
||||
{
|
||||
return GeneralUtility::makeInstance(ImageInfo::class, $filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this validator is correctly configured
|
||||
*/
|
||||
private function validateOptions(): void
|
||||
{
|
||||
if ((int)$this->options['minWidth'] > (int)$this->options['maxWidth']) {
|
||||
throw new InvalidValidationOptionsException('The option "minWidth" must not be greater than "maxWidth"', 1716008127);
|
||||
}
|
||||
if ((int)$this->options['minHeight'] > (int)$this->options['maxHeight']) {
|
||||
throw new InvalidValidationOptionsException('The option "minHeight" must not be greater than "maxHeight"', 1716008128);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Validator for integers.
|
||||
*/
|
||||
final class IntegerValidator extends AbstractValidator
|
||||
{
|
||||
protected string $message = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.integer.notvalid';
|
||||
|
||||
protected $supportedOptions = [
|
||||
'message' => [null, 'Translation key or message for invalid value', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks if the given value is a valid integer.
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if (filter_var($value, FILTER_VALIDATE_INT) === false) {
|
||||
$this->addError($this->translateErrorMessage($this->message), 1221560494);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Core\Http\UploadedFile;
|
||||
use TYPO3\CMS\Core\Resource\MimeTypeDetector;
|
||||
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
|
||||
use TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException;
|
||||
|
||||
/**
|
||||
* Validator for mime types of a given UploadedFile or ObjectStorage of UploadedFile objects. Does also validate, if
|
||||
* the given file extension matches allowed file extensions for the detected mime type.
|
||||
*/
|
||||
final class MimeTypeValidator extends AbstractValidator
|
||||
{
|
||||
protected string $notAllowedMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.mimetype.notallowed';
|
||||
protected string $invalidExtensionMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validation.mimetype.invalidextension';
|
||||
|
||||
protected array $translationOptions = ['notAllowedMessage', 'invalidExtensionMessage'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
'allowedMimeTypes' => [null, 'Allowed mime types (using */* IANA media types)', 'array', true],
|
||||
'ignoreFileExtensionCheck' => [false, 'If set to "true", the file extension check is disabled. Be aware of security considerations when setting this to "true".', 'boolean'],
|
||||
'notAllowedMessage' => [null, 'Translation key or message for not allowed MIME type', 'string'],
|
||||
'invalidExtensionMessage' => [null, 'Translation key or message for invalid file extension', 'string'],
|
||||
];
|
||||
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
$this->ensureFileUploadTypes($value);
|
||||
$this->validateOptions();
|
||||
|
||||
if ($value instanceof UploadedFile) {
|
||||
$this->validateUploadedFile($value);
|
||||
} elseif ($value instanceof ObjectStorage && $value->count() > 0) {
|
||||
$index = 0;
|
||||
foreach ($value as $uploadedFile) {
|
||||
$this->validateUploadedFile($uploadedFile, $index);
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function validateUploadedFile(UploadedFile $uploadedFile, ?int $index = null): void
|
||||
{
|
||||
$fileInfo = $this->getFileInfo($uploadedFile->getTemporaryFileName());
|
||||
$mimeType = $fileInfo->getMimeType();
|
||||
|
||||
$allowedMimeTypes = $this->options['allowedMimeTypes'];
|
||||
$ignoreFileExtensionCheck = $this->options['ignoreFileExtensionCheck'];
|
||||
|
||||
if (!in_array($mimeType, $allowedMimeTypes, true)) {
|
||||
$message = $this->translateErrorMessage(
|
||||
$this->notAllowedMessage,
|
||||
'',
|
||||
[$mimeType]
|
||||
);
|
||||
$code = 1708538973;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$ignoreFileExtensionCheck && !$this->result->hasErrors()) {
|
||||
// The file extension of the uploaded file must match the mime-type for this file.
|
||||
// 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.
|
||||
$fileExtension = pathinfo($uploadedFile->getClientFilename(), PATHINFO_EXTENSION);
|
||||
$assumedMimesTypeOfFileExtension = (new MimeTypeDetector())->getMimeTypesForFileExtension($fileExtension);
|
||||
if (empty(array_intersect($allowedMimeTypes, $assumedMimesTypeOfFileExtension))) {
|
||||
$message = $this->translateErrorMessage(
|
||||
$this->invalidExtensionMessage,
|
||||
'',
|
||||
[$fileExtension]
|
||||
);
|
||||
$code = 1718469466;
|
||||
if ($index !== null) {
|
||||
$this->addErrorForProperty((string)$index, $message, $code);
|
||||
} else {
|
||||
$this->addError($message, $code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this validator is correctly configured
|
||||
*/
|
||||
private function validateOptions(): void
|
||||
{
|
||||
if (!is_array($this->options['allowedMimeTypes'] ?? false) || $this->options['allowedMimeTypes'] === []) {
|
||||
throw new InvalidValidationOptionsException('The option "allowedMimeTypes" must be an array with at least one item.', 1708526223);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Validator for not empty values.
|
||||
*/
|
||||
final class NotEmptyValidator extends AbstractValidator
|
||||
{
|
||||
/**
|
||||
* This validator always needs to be executed even if the given value is empty.
|
||||
* See AbstractValidator::validate()
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $acceptsEmptyValues = false;
|
||||
|
||||
protected string $nullMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.notempty.null';
|
||||
protected string $emptyMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.notempty.empty';
|
||||
|
||||
protected array $translationOptions = ['nullMessage', 'emptyMessage'];
|
||||
|
||||
protected $supportedOptions = [
|
||||
'nullMessage' => [null, 'Translation key or message for null value', 'string'],
|
||||
'emptyMessage' => [null, 'Translation key or message for empty value', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks if the given value ($propertyValue) is not empty (NULL, empty string, empty array or empty object).
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if ($value === null) {
|
||||
$this->addError($this->translateErrorMessage($this->nullMessage), 1221560910);
|
||||
}
|
||||
if ($value === '') {
|
||||
$this->addError($this->translateErrorMessage($this->emptyMessage), 1221560718);
|
||||
}
|
||||
if (is_array($value) && empty($value)) {
|
||||
$this->addError($this->translateErrorMessage($this->emptyMessage), 1347992400);
|
||||
}
|
||||
if ($value instanceof \Countable && $value->count() === 0) {
|
||||
$this->addError($this->translateErrorMessage($this->emptyMessage), 1347992453);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Validator for general numbers
|
||||
*/
|
||||
final class NumberRangeValidator extends AbstractValidator
|
||||
{
|
||||
protected string $notValidMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.numberrange.notvalid';
|
||||
protected string $notInRangeMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.numberrange.range';
|
||||
|
||||
protected array $translationOptions = ['notValidMessage', 'notInRangeMessage'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
'minimum' => [0, 'The minimum value to accept', 'integer'],
|
||||
'maximum' => [PHP_INT_MAX, 'The maximum value to accept', 'integer'],
|
||||
'notValidMessage' => [null, 'Translation key or message for non valid value', 'string'],
|
||||
'notInRangeMessage' => [null, 'Translation key or message for value not in range', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* The given value is valid if it is a number in the specified range.
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if (!is_numeric($value)) {
|
||||
$this->addError($this->translateErrorMessage($this->notValidMessage), 1221563685);
|
||||
return;
|
||||
}
|
||||
|
||||
$minimum = $this->options['minimum'];
|
||||
$maximum = $this->options['maximum'];
|
||||
|
||||
if ($minimum > $maximum) {
|
||||
$x = $minimum;
|
||||
$minimum = $maximum;
|
||||
$maximum = $x;
|
||||
}
|
||||
if ($value < $minimum || $value > $maximum) {
|
||||
$this->addError($this->translateErrorMessage(
|
||||
$this->notInRangeMessage,
|
||||
'',
|
||||
[
|
||||
$minimum,
|
||||
$maximum,
|
||||
]
|
||||
), 1221561046, [$minimum, $maximum]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Validator for general numbers.
|
||||
*/
|
||||
final class NumberValidator extends AbstractValidator
|
||||
{
|
||||
protected string $message = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.number.notvalid';
|
||||
|
||||
protected $supportedOptions = [
|
||||
'message' => [null, 'Translation key or message for invalid value', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks if the given value is a valid number.
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if (!is_numeric($value)) {
|
||||
$this->addError($this->translateErrorMessage($this->message), 1221563685);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Contract for a validator
|
||||
*/
|
||||
interface ObjectValidatorInterface extends ValidatorInterface
|
||||
{
|
||||
/**
|
||||
* Allows to set a container to keep track of validated instances.
|
||||
*
|
||||
* @param \SplObjectStorage $validatedInstancesContainer A container to keep track of validated instances
|
||||
*/
|
||||
public function setValidatedInstancesContainer(\SplObjectStorage $validatedInstancesContainer): void;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException;
|
||||
|
||||
/**
|
||||
* Validator based on regular expressions.
|
||||
*/
|
||||
final class RegularExpressionValidator extends AbstractValidator
|
||||
{
|
||||
protected string $message = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.regularexpression.nomatch';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
'regularExpression' => ['', 'The regular expression to use for validation, used as given', 'string', true],
|
||||
'message' => [null, 'Translation key or message when regular expression results in a no match', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks if the given value matches the specified regular expression.
|
||||
*
|
||||
* @throws InvalidValidationOptionsException
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
$result = preg_match($this->options['regularExpression'], $value);
|
||||
if ($result === 0) {
|
||||
$this->addError(
|
||||
$this->translateErrorMessage($this->message),
|
||||
1221565130
|
||||
);
|
||||
}
|
||||
if ($result === false) {
|
||||
throw new InvalidValidationOptionsException('regularExpression "' . $this->options['regularExpression'] . '" in RegularExpressionValidator contained an error.', 1298273089);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Extbase\Validation\Exception\InvalidValidationOptionsException;
|
||||
|
||||
/**
|
||||
* Validator for string length.
|
||||
*/
|
||||
final class StringLengthValidator extends AbstractValidator
|
||||
{
|
||||
protected string $betweenMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.stringlength.between';
|
||||
protected string $lessMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.stringlength.less';
|
||||
protected string $exceedMessage = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.stringlength.exceed';
|
||||
|
||||
protected array $translationOptions = ['betweenMessage', 'lessMessage', 'exceedMessage'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $supportedOptions = [
|
||||
'minimum' => [0, 'Minimum length for a valid string', 'integer'],
|
||||
'maximum' => [PHP_INT_MAX, 'Maximum length for a valid string', 'integer'],
|
||||
'betweenMessage' => [null, 'Translation key or message for value not between minimum and maximum', 'string'],
|
||||
'lessMessage' => [null, 'Translation key or message for value less than minimum', 'string'],
|
||||
'exceedMessage' => [null, 'Translation key or message for value exceeds maximum', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks if the given value is a valid string (or can be cast to a string
|
||||
* if an object is given) and its length is between minimum and maximum
|
||||
* specified in the validation options.
|
||||
*
|
||||
* @throws InvalidValidationOptionsException
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if ($this->options['maximum'] < $this->options['minimum']) {
|
||||
throw new InvalidValidationOptionsException('The \'maximum\' is shorter than the \'minimum\' in the StringLengthValidator.', 1238107096);
|
||||
}
|
||||
|
||||
if (is_object($value)) {
|
||||
if (!method_exists($value, '__toString')) {
|
||||
$this->addError('The given object could not be converted to a string.', 1238110957);
|
||||
return;
|
||||
}
|
||||
} elseif (!is_string($value)) {
|
||||
$this->addError('The given value was not a valid string.', 1269883975);
|
||||
return;
|
||||
}
|
||||
|
||||
$value = (string)$value;
|
||||
$stringLength = mb_strlen($value, 'utf-8');
|
||||
$isValid = true;
|
||||
if ($stringLength < $this->options['minimum']) {
|
||||
$isValid = false;
|
||||
}
|
||||
if ($stringLength > $this->options['maximum']) {
|
||||
$isValid = false;
|
||||
}
|
||||
|
||||
if ($isValid === false) {
|
||||
if ($this->options['minimum'] > 0 && $this->options['maximum'] < PHP_INT_MAX) {
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
$this->betweenMessage,
|
||||
'',
|
||||
[
|
||||
$this->options['minimum'],
|
||||
$this->options['maximum'],
|
||||
]
|
||||
),
|
||||
1428504122,
|
||||
[$this->options['minimum'], $this->options['maximum']]
|
||||
);
|
||||
} elseif ($this->options['minimum'] > 0) {
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
$this->lessMessage,
|
||||
'',
|
||||
[
|
||||
$this->options['minimum'],
|
||||
]
|
||||
),
|
||||
1238108068,
|
||||
[$this->options['minimum']]
|
||||
);
|
||||
} else {
|
||||
$this->addError(
|
||||
$this->translateErrorMessage(
|
||||
$this->exceedMessage,
|
||||
'',
|
||||
[
|
||||
$this->options['maximum'],
|
||||
]
|
||||
),
|
||||
1238108069,
|
||||
[$this->options['maximum']]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Validator for strings.
|
||||
*/
|
||||
final class StringValidator extends AbstractValidator
|
||||
{
|
||||
protected string $message = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.string.notvalid';
|
||||
|
||||
protected $supportedOptions = [
|
||||
'message' => [null, 'Translation key or message for invalid value', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks if the given value is a string.
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if (!is_string($value)) {
|
||||
$this->addError($this->translateErrorMessage($this->message), 1238108067);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Validator for "plain" text.
|
||||
*/
|
||||
final class TextValidator extends AbstractValidator
|
||||
{
|
||||
protected string $message = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.text.notvalid';
|
||||
|
||||
protected $supportedOptions = [
|
||||
'message' => [null, 'Translation key or message for invalid value', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks if the given value is a valid text (contains no XML tags).
|
||||
*
|
||||
* Be aware that the value of this check entirely depends on the output context.
|
||||
* The validated text is not expected to be secure in every circumstance, if you
|
||||
* want to be sure of that, use a customized regular expression or filter on output.
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if ($value !== strip_tags((string)$value)) {
|
||||
$this->addError($this->translateErrorMessage($this->message), 1221565786);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Validator for url.
|
||||
*/
|
||||
final class UrlValidator extends AbstractValidator
|
||||
{
|
||||
protected string $message = 'LLL:EXT:extbase/Resources/Private/Language/locallang.xlf:validator.url.notvalid';
|
||||
|
||||
protected $supportedOptions = [
|
||||
'message' => [null, 'Translation key or message for invalid value', 'string'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks if the given value is a valid url.
|
||||
*/
|
||||
public function isValid(mixed $value): void
|
||||
{
|
||||
if (!is_string($value) || !GeneralUtility::isValidUrl($value)) {
|
||||
$this->addError($this->translateErrorMessage($this->message), 1238108078);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?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\Extbase\Validation\Validator;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Extbase\Error\Result;
|
||||
|
||||
/**
|
||||
* Contract for a validator
|
||||
*/
|
||||
interface ValidatorInterface
|
||||
{
|
||||
/**
|
||||
* Checks if the given value is valid according to the validator, and returns
|
||||
* the Error Messages object which occurred.
|
||||
*
|
||||
* @param mixed $value The value that should be validated
|
||||
*/
|
||||
public function validate(mixed $value): Result;
|
||||
|
||||
/**
|
||||
* Receive validator options from framework.
|
||||
*/
|
||||
public function setOptions(array $options): void;
|
||||
|
||||
/**
|
||||
* Returns the options of this validator which can be specified by setOptions().
|
||||
*/
|
||||
public function getOptions(): array;
|
||||
|
||||
/**
|
||||
* Sets the request object to the validator.
|
||||
*/
|
||||
public function setRequest(?ServerRequestInterface $request): void;
|
||||
|
||||
/**
|
||||
* Returns the request object of the validator.
|
||||
*/
|
||||
public function getRequest(): ?ServerRequestInterface;
|
||||
}
|
||||
Reference in New Issue
Block a user