Initial Drupal 11 with DDEV setup
This commit is contained in:
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\file\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
/**
|
||||
* A constraint for UploadedFile objects.
|
||||
*/
|
||||
class UploadedFileConstraint extends Constraint {
|
||||
|
||||
/**
|
||||
* The upload max size. Defaults to checking the environment.
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
public ?int $maxSize;
|
||||
|
||||
/**
|
||||
* The upload ini size error message.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $uploadIniSizeErrorMessage = 'The file %file could not be saved because it exceeds %maxsize, the maximum allowed size for uploads.';
|
||||
|
||||
/**
|
||||
* The upload form size error message.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $uploadFormSizeErrorMessage = 'The file %file could not be saved because it exceeds %maxsize, the maximum allowed size for uploads.';
|
||||
|
||||
/**
|
||||
* The upload partial error message.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $uploadPartialErrorMessage = 'The file %file could not be saved because the upload did not complete.';
|
||||
|
||||
/**
|
||||
* The upload no file error message.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $uploadNoFileErrorMessage = 'The file %file could not be saved because the upload did not complete.';
|
||||
|
||||
/**
|
||||
* The generic file upload error message.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $uploadErrorMessage = 'The file %file could not be saved. An unknown error has occurred.';
|
||||
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\file\Validation\Constraint;
|
||||
|
||||
use Drupal\Component\Utility\Environment;
|
||||
use Drupal\Core\StringTranslation\ByteSizeMarkup;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||
|
||||
/**
|
||||
* Constraint validator for uploaded files.
|
||||
*
|
||||
* Use FileValidatorInterface for validating file entities.
|
||||
*
|
||||
* @see \Drupal\Core\Validation\FileValidatorInterface
|
||||
*/
|
||||
class UploadedFileConstraintValidator extends ConstraintValidator {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate(mixed $value, Constraint $constraint): void {
|
||||
if (!$constraint instanceof UploadedFileConstraint) {
|
||||
throw new UnexpectedTypeException($constraint, UploadedFileConstraint::class);
|
||||
}
|
||||
if (!$value instanceof UploadedFile) {
|
||||
throw new UnexpectedTypeException($value, UploadedFile::class);
|
||||
}
|
||||
if ($value->isValid()) {
|
||||
return;
|
||||
}
|
||||
$maxSize = $constraint->maxSize ?? Environment::getUploadMaxSize();
|
||||
|
||||
match ($value->getError()) {
|
||||
\UPLOAD_ERR_INI_SIZE => $this->context->buildViolation($constraint->uploadIniSizeErrorMessage, [
|
||||
'%file' => $value->getClientOriginalName(),
|
||||
'%maxsize' => ByteSizeMarkup::create($maxSize),
|
||||
])->setCode((string) \UPLOAD_ERR_INI_SIZE)
|
||||
->addViolation(),
|
||||
|
||||
\UPLOAD_ERR_FORM_SIZE => $this->context->buildViolation($constraint->uploadFormSizeErrorMessage, [
|
||||
'%file' => $value->getClientOriginalName(),
|
||||
'%maxsize' => ByteSizeMarkup::create($maxSize),
|
||||
])->setCode((string) \UPLOAD_ERR_FORM_SIZE)
|
||||
->addViolation(),
|
||||
|
||||
\UPLOAD_ERR_PARTIAL => $this->context->buildViolation($constraint->uploadPartialErrorMessage, [
|
||||
'%file' => $value->getClientOriginalName(),
|
||||
])->setCode((string) \UPLOAD_ERR_PARTIAL)
|
||||
->addViolation(),
|
||||
|
||||
\UPLOAD_ERR_NO_FILE => $this->context->buildViolation($constraint->uploadNoFileErrorMessage, [
|
||||
'%file' => $value->getClientOriginalName(),
|
||||
])->setCode((string) \UPLOAD_ERR_NO_FILE)
|
||||
->addViolation(),
|
||||
|
||||
default => $this->context->buildViolation($constraint->uploadErrorMessage, [
|
||||
'%file' => $value->getClientOriginalName(),
|
||||
])->setCode((string) $value->getError())
|
||||
->addViolation()
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
27
web/core/modules/file/src/Validation/FileValidationEvent.php
Normal file
27
web/core/modules/file/src/Validation/FileValidationEvent.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\file\Validation;
|
||||
|
||||
use Drupal\file\FileInterface;
|
||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||
use Symfony\Contracts\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Event for file validations.
|
||||
*/
|
||||
class FileValidationEvent extends Event {
|
||||
|
||||
/**
|
||||
* Creates a new FileValidationEvent.
|
||||
*
|
||||
* @param \Drupal\file\FileInterface $file
|
||||
* The file.
|
||||
* @param \Symfony\Component\Validator\ConstraintViolationListInterface $violations
|
||||
* The violations.
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly FileInterface $file,
|
||||
public readonly ConstraintViolationListInterface $violations,
|
||||
) {}
|
||||
|
||||
}
|
||||
63
web/core/modules/file/src/Validation/FileValidator.php
Normal file
63
web/core/modules/file/src/Validation/FileValidator.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\file\Validation;
|
||||
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Validation\ConstraintManager;
|
||||
use Drupal\file\FileInterface;
|
||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* Provides a class for file validation.
|
||||
*/
|
||||
class FileValidator implements FileValidatorInterface {
|
||||
|
||||
/**
|
||||
* Creates a new FileValidator.
|
||||
*
|
||||
* @param \Symfony\Component\Validator\Validator\ValidatorInterface $validator
|
||||
* The validator.
|
||||
* @param \Drupal\Core\Validation\ConstraintManager $constraintManager
|
||||
* The constraint factory.
|
||||
* @param \Symfony\Contracts\EventDispatcher\EventDispatcherInterface $eventDispatcher
|
||||
* The event dispatcher.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
|
||||
* The module handler.
|
||||
*/
|
||||
public function __construct(
|
||||
protected ValidatorInterface $validator,
|
||||
protected ConstraintManager $constraintManager,
|
||||
protected EventDispatcherInterface $eventDispatcher,
|
||||
protected ModuleHandlerInterface $moduleHandler,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate(FileInterface $file, array $validators): ConstraintViolationListInterface {
|
||||
$constraints = [];
|
||||
foreach ($validators as $validator => $options) {
|
||||
// Create the constraint.
|
||||
// Options are an associative array of constraint properties and values.
|
||||
$constraints[] = $this->constraintManager->create($validator, $options);
|
||||
}
|
||||
|
||||
// Get the typed data.
|
||||
$fileTypedData = $file->getTypedData();
|
||||
|
||||
$violations = $this->validator->validate($fileTypedData, $constraints);
|
||||
|
||||
$this->eventDispatcher->dispatch(new FileValidationEvent($file, $violations));
|
||||
|
||||
// Always check the insecure upload constraint.
|
||||
if (count($violations) === 0) {
|
||||
$insecureUploadConstraint = $this->constraintManager->create('FileExtensionSecure', []);
|
||||
$violations = $this->validator->validate($fileTypedData, $insecureUploadConstraint);
|
||||
}
|
||||
|
||||
return $violations;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\file\Validation;
|
||||
|
||||
use Drupal\file\FileInterface;
|
||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||
|
||||
/**
|
||||
* Provides a file validator that supports a list of validations.
|
||||
*/
|
||||
interface FileValidatorInterface {
|
||||
|
||||
/**
|
||||
* Validates a File with a list of validators.
|
||||
*
|
||||
* @param \Drupal\file\FileInterface $file
|
||||
* The file to validate.
|
||||
* @param array $validators
|
||||
* An associative array of validators with:
|
||||
* - key: the plugin ID of the file validation constraint.
|
||||
* - value: an associative array of options to pass to the constraint.
|
||||
*
|
||||
* @return \Symfony\Component\Validator\ConstraintViolationListInterface
|
||||
* The violations list.
|
||||
*/
|
||||
public function validate(FileInterface $file, array $validators): ConstraintViolationListInterface;
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\file\Validation;
|
||||
|
||||
use Drupal\Component\Utility\Bytes;
|
||||
use Drupal\Component\Utility\Environment;
|
||||
|
||||
/**
|
||||
* Provides a trait to create validators from settings.
|
||||
*/
|
||||
trait FileValidatorSettingsTrait {
|
||||
|
||||
/**
|
||||
* Gets the upload validators for the specified settings.
|
||||
*
|
||||
* @param array $settings
|
||||
* An associative array of settings. The following keys are supported:
|
||||
* - max_filesize: The maximum file size in bytes. Defaults to the PHP max
|
||||
* upload size.
|
||||
* - file_extensions: A space-separated list of allowed file extensions.
|
||||
*
|
||||
* @return array
|
||||
* An array suitable for passing to file_save_upload() or the file field
|
||||
* element's '#upload_validators' property.
|
||||
*/
|
||||
public function getFileUploadValidators(array $settings): array {
|
||||
$validators = [
|
||||
// Add in our check of the file name length.
|
||||
'FileNameLength' => [],
|
||||
];
|
||||
|
||||
// Cap the upload size according to the PHP limit.
|
||||
$maxFilesize = Bytes::toNumber(Environment::getUploadMaxSize());
|
||||
if (!empty($settings['max_filesize'])) {
|
||||
$maxFilesize = min($maxFilesize, Bytes::toNumber($settings['max_filesize']));
|
||||
}
|
||||
|
||||
// There is always a file size limit due to the PHP server limit.
|
||||
$validators['FileSizeLimit'] = ['fileLimit' => $maxFilesize];
|
||||
|
||||
// Add the extension check if necessary.
|
||||
if (!empty($settings['file_extensions'])) {
|
||||
$validators['FileExtension'] = [
|
||||
'extensions' => $settings['file_extensions'],
|
||||
];
|
||||
}
|
||||
|
||||
return $validators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\file\Validation;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ClassResolverInterface;
|
||||
use Drupal\Core\TypedData\TypedDataManagerInterface;
|
||||
use Drupal\Core\Validation\ExecutionContextFactory;
|
||||
use Drupal\Core\TypedData\Validation\RecursiveValidator;
|
||||
use Drupal\Core\Validation\ConstraintValidatorFactory;
|
||||
use Drupal\Core\Validation\DrupalTranslator;
|
||||
|
||||
/**
|
||||
* Factory for creating a new RecursiveValidator.
|
||||
*/
|
||||
class RecursiveValidatorFactory {
|
||||
|
||||
/**
|
||||
* Constructs a new RecursiveValidatorFactory.
|
||||
*
|
||||
* @param \Drupal\Core\DependencyInjection\ClassResolverInterface $classResolver
|
||||
* The class resolver.
|
||||
* @param \Drupal\Core\TypedData\TypedDataManagerInterface $typedDataManager
|
||||
* The typed data manager.
|
||||
*/
|
||||
public function __construct(
|
||||
protected ClassResolverInterface $classResolver,
|
||||
protected TypedDataManagerInterface $typedDataManager,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates a new RecursiveValidator.
|
||||
*
|
||||
* @return \Drupal\Core\TypedData\Validation\RecursiveValidator
|
||||
* The validator.
|
||||
*/
|
||||
public function createValidator(): RecursiveValidator {
|
||||
return new RecursiveValidator(
|
||||
new ExecutionContextFactory(new DrupalTranslator()),
|
||||
new ConstraintValidatorFactory($this->classResolver),
|
||||
$this->typedDataManager,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user