Project

General

Profile

Feature #103594 ยป StorageExtensionBlocker.php

BeforeFileAddedEvent PHP file example - Marcelo Vetter, 2024-04-10 21:37

 
<?php
declare(strict_types=1);

namespace ExampleVendor\ExampleVendorNamespace\EventListener;

use Psr\Log\InvalidArgumentException;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Exception;
use TYPO3\CMS\Core\Messaging\AbstractMessage;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Messaging\FlashMessageService;
use \TYPO3\CMS\Core\Resource\Event\BeforeFileAddedEvent;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class StorageExtensionBlocker
{
/**
* @param BeforeFileAddedEvent $event
* @throws Exception
* @throws InvalidArgumentException
* @throws \InvalidArgumentException
*/
public function __invoke(BeforeFileAddedEvent $event): void
{
$storageId = $event->getStorage()->getUid();
$pageTsConfig = BackendUtility::getPagesTSconfig(1);
$userTsConfig = $GLOBALS['BE_USER']->getTSConfig();
$permissions = $pageTsConfig['permissions.']['file.']['storage.'][$storageId.'.']['allowedExtensions'] ?? null;
$permissions = $userTsConfig['permissions.']['file.']['storage.'][$storageId.'.']['allowedExtensions'] ?? $permissions;

$fileName = $event->getFileName();

if ($permissions === null) {
return;
}

if ($this->isValid($fileName, $permissions)) {
return;
}

$this->addFlashMessageAndThrowError($event, $pageTsConfig, $storageId, $permissions, $fileName);
}

/**
* Verifies the input filename against the 'allowedExtensions'
* Page TSconfig permissions.file.storage.[storageUid].allowedExtensions
*
* Filenames are not allowed to contain control characters. Therefore, we
* always filter on [[:cntrl:]].
*
* @param string $fileName File path to evaluate
* @return bool Returns TRUE if the file name is OK.
*/
public function isValid(string $fileName, string $fileAllowPattern): bool
{
$pattern = '/[[:cntrl:]]/';
if ($fileName !== '' && $fileAllowPattern !== '') {
$pattern = '/(?:[[:cntrl:]]|\\.(' . $fileAllowPattern . ')(\\..*)?$)/iu';
}
return preg_match($pattern, $fileName) === 1;
}

/**
* @param BeforeFileAddedEvent $event
* @param array|null $pageTsConfig
* @param int $storageId
* @param mixed $permissions
* @param string $fileName
* @return void
* @throws Exception
* @throws \InvalidArgumentException
*/
private function addFlashMessageAndThrowError(BeforeFileAddedEvent $event, ?array $pageTsConfig, int $storageId, mixed $permissions, string $fileName): void
{
$label = '%s
Extension of file %s is not allowed!
Allowed types for this drive: %s.';
$flashMessage = GeneralUtility::makeInstance(
FlashMessage::class,
vsprintf($label, [
$pageTsConfig['permissions.']['file.']['storage.'][$storageId.'.']['allowedExtensionsMsg'] ?? null,
$event->getFileName(),
str_replace('|', ', ', $permissions),
]),
'File extension not allowed',
AbstractMessage::ERROR,
true
);
$this->addFlashMessage($flashMessage);

$targetFolder = $event->getTargetFolder();
$basePath = $event->getStorage()->getConfiguration()['basePath'];
$fullTargetLocation = $basePath.$targetFolder->getIdentifier();

throw new \InvalidArgumentException('File extension not permitted: '.$fullTargetLocation.$fileName, 1325777289);
}

/**
* Add flash message to message queue
*
* @param FlashMessage $flashMessage
* @throws \InvalidArgumentException
* @throws Exception
*/
protected function addFlashMessage(FlashMessage $flashMessage): void
{
$flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
$defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
$defaultFlashMessageQueue->enqueue($flashMessage);
}
}
    (1-1/1)