diff --git a/composer.json b/composer.json index e6354846fb2f..136aa0234a81 100644 --- a/composer.json +++ b/composer.json @@ -84,7 +84,7 @@ "symfony/options-resolver": "^5.4", "symfony/polyfill-intl-icu": "^1.23.0", "symfony/polyfill-intl-idn": "^1.23.0", - "symfony/polyfill-intl-normalizer": "^1.23.0", + "symfony/polyfill-intl-normalizer": "^1.27", "symfony/polyfill-mbstring": "^1.23.1", "symfony/polyfill-php80": "^1.23.1", "symfony/polyfill-php81": "^1.23", diff --git a/composer.lock b/composer.lock index 2301a2e548af..b387024be089 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e26d1d688b8734df7eb2937e976d0aaf", + "content-hash": "c0f01b7b0dfa88545a0a6bde5676b612", "packages": [ { "name": "bacon/bacon-qr-code", diff --git a/typo3/sysext/core/Classes/Http/UploadedFile.php b/typo3/sysext/core/Classes/Http/UploadedFile.php index e99ddcfb2bac..3e05d9972293 100644 --- a/typo3/sysext/core/Classes/Http/UploadedFile.php +++ b/typo3/sysext/core/Classes/Http/UploadedFile.php @@ -104,7 +104,10 @@ public function __construct($input, $size, $errorStatus, $clientFilename = null, if ($clientFilename !== null && !is_string($clientFilename)) { throw new \InvalidArgumentException('Invalid client filename provided for an uploaded file.', 1436717304); } - $this->clientFilename = $clientFilename; + if (is_string($clientFilename)) { + $clientFilename = \Normalizer::normalize($clientFilename); + } + $this->clientFilename = is_string($clientFilename) ? $clientFilename : null; if ($clientMediaType !== null && !is_string($clientMediaType)) { throw new \InvalidArgumentException('Invalid client media type provided for an uploaded file.', 1436717305); diff --git a/typo3/sysext/core/Classes/Resource/ResourceStorage.php b/typo3/sysext/core/Classes/Resource/ResourceStorage.php index 16477462ae98..5cb075869f8b 100644 --- a/typo3/sysext/core/Classes/Resource/ResourceStorage.php +++ b/typo3/sysext/core/Classes/Resource/ResourceStorage.php @@ -2149,7 +2149,7 @@ public function addUploadedFile(array $uploadedFileData, Folder $targetFolder = $targetFolder = $this->getDefaultFolder(); } if ($targetFileName === null) { - $targetFileName = $uploadedFileData['name']; + $targetFileName = \Normalizer::normalize($uploadedFileData['name']); } $targetFileName = $this->driver->sanitizeFileName($targetFileName); diff --git a/typo3/sysext/core/Classes/Utility/File/ExtendedFileUtility.php b/typo3/sysext/core/Classes/Utility/File/ExtendedFileUtility.php index 9190164dc7c1..806c1917a1b3 100644 --- a/typo3/sysext/core/Classes/Utility/File/ExtendedFileUtility.php +++ b/typo3/sysext/core/Classes/Utility/File/ExtendedFileUtility.php @@ -1086,6 +1086,10 @@ public function func_upload($cmds) 'size' => [$uploadedFileData['size']], ]; } + $uploadedFileData['name'] = array_map( + static fn (string $name) => \Normalizer::normalize($name), + $uploadedFileData['name'] + ); $resultObjects = []; $numberOfUploadedFilesForPosition = count($uploadedFileData['name']); // Loop through all uploaded files diff --git a/typo3/sysext/core/Tests/Unit/Http/UploadedFileTest.php b/typo3/sysext/core/Tests/Unit/Http/UploadedFileTest.php index ee5e15b13931..874d5834a508 100644 --- a/typo3/sysext/core/Tests/Unit/Http/UploadedFileTest.php +++ b/typo3/sysext/core/Tests/Unit/Http/UploadedFileTest.php @@ -286,4 +286,15 @@ public function getGetStreamRaisesExceptionAfterMove(): void $this->expectExceptionCode(1436717306); $upload->getStream(); } + + /** + * see https://en.wikipedia.org/wiki/Unicode_equivalence#Normalization, "NFD" + * @test + */ + public function nfdFileNameIsNormalized(): void + { + $clientFileName = hex2bin('6fcc88') . '.png'; + $subject = new UploadedFile(fopen('php://temp', 'wb+'), 0, 0, $clientFileName); + self::assertSame(hex2bin('c3b6') . '.png', $subject->getClientFilename()); + } } diff --git a/typo3/sysext/core/composer.json b/typo3/sysext/core/composer.json index 59a5079d899a..f6d5d3d426a3 100644 --- a/typo3/sysext/core/composer.json +++ b/typo3/sysext/core/composer.json @@ -63,7 +63,7 @@ "symfony/options-resolver": "^5.4", "symfony/polyfill-intl-icu": "^1.23.0", "symfony/polyfill-intl-idn": "^1.23.0", - "symfony/polyfill-intl-normalizer": "^1.23.0", + "symfony/polyfill-intl-normalizer": "^1.27", "symfony/polyfill-mbstring": "^1.23.1", "symfony/polyfill-php80": "^1.23.1", "symfony/polyfill-php81": "^1.23",