Loading core/modules/file/file.module +8 −1 Original line number Diff line number Diff line Loading @@ -339,7 +339,14 @@ function file_validate_extensions(FileInterface $file, $extensions) { $errors = []; $regex = '/\.(' . preg_replace('/ +/', '|', preg_quote($extensions)) . ')$/i'; if (!preg_match($regex, $file->getFilename())) { // Filename may differ from the basename, for instance in case files migrated // from D7 file entities. Because of that new files are saved temporarily with // a generated file name, without the original extension, we will use the // generated filename property for extension validation only in case of // temporary files; and use the file system file name in case of permanent // files. $subject = $file->isTemporary() ? $file->getFilename() : $file->getFileUri(); if (!preg_match($regex, $subject)) { $errors[] = t('Only files with the following extensions are allowed: %files-allowed.', ['%files-allowed' => $extensions]); } return $errors; Loading core/modules/file/tests/src/Kernel/ValidatorTest.php +83 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,89 @@ public function testFileValidateExtensions() { $this->assertCount(1, $errors, 'Invalid extension blocked.'); } /** * Tests the file_validate_extensions() function. * * @param array $file_properties * The properties of the file being validated. * @param string[] $extensions * An array of the allowed file extensions. * @param string[] $expected_errors * The expected error messages as string. * * @dataProvider providerTestFileValidateExtensionsOnUri */ public function testFileValidateExtensionsOnUri(array $file_properties, array $extensions, array $expected_errors) { $file = File::create($file_properties); $actual_errors = file_validate_extensions($file, implode(' ', $extensions)); $actual_errors_as_string = array_map(function ($error_message) { return (string) $error_message; }, $actual_errors); $this->assertEquals($expected_errors, $actual_errors_as_string); } /** * Data provider for ::testFileValidateExtensionsOnUri. * * @return array[][] * The test cases. */ public function providerTestFileValidateExtensionsOnUri(): array { $temporary_txt_file_properties = [ 'filename' => 'asdf.txt', 'uri' => 'temporary://asdf', 'status' => 0, ]; $permanent_txt_file_properties = [ 'filename' => 'asdf.txt', 'uri' => 'public://asdf_0.txt', 'status' => 1, ]; $permanent_png_file_properties = [ 'filename' => 'The Druplicon', 'uri' => 'public://druplicon.png', 'status' => 1, ]; return [ 'Temporary txt validated with "asdf", "txt", "pork"' => [ 'File properties' => $temporary_txt_file_properties, 'Allowed_extensions' => ['asdf', 'txt', 'pork'], 'Expected errors' => [], ], 'Temporary txt validated with "exe" and "png"' => [ 'File properties' => $temporary_txt_file_properties, 'Allowed_extensions' => ['exe', 'png'], 'Expected errors' => [ 'Only files with the following extensions are allowed: <em class="placeholder">exe png</em>.', ], ], 'Permanent txt validated with "asdf", "txt", "pork"' => [ 'File properties' => $permanent_txt_file_properties, 'Allowed_extensions' => ['asdf', 'txt', 'pork'], 'Expected errors' => [], ], 'Permanent txt validated with "exe" and "png"' => [ 'File properties' => $permanent_txt_file_properties, 'Allowed_extensions' => ['exe', 'png'], 'Expected errors' => [ 'Only files with the following extensions are allowed: <em class="placeholder">exe png</em>.', ], ], 'Permanent png validated with "png", "gif", "jpg", "jpeg"' => [ 'File properties' => $permanent_png_file_properties, 'Allowed_extensions' => ['png', 'gif', 'jpg', 'jpeg'], 'Expected errors' => [], ], 'Permanent png validated with "exe" and "txt"' => [ 'File properties' => $permanent_png_file_properties, 'Allowed_extensions' => ['exe', 'txt'], 'Expected errors' => [ 'Only files with the following extensions are allowed: <em class="placeholder">exe txt</em>.', ], ], ]; } /** * This ensures a specific file is actually an image. */ Loading Loading
core/modules/file/file.module +8 −1 Original line number Diff line number Diff line Loading @@ -339,7 +339,14 @@ function file_validate_extensions(FileInterface $file, $extensions) { $errors = []; $regex = '/\.(' . preg_replace('/ +/', '|', preg_quote($extensions)) . ')$/i'; if (!preg_match($regex, $file->getFilename())) { // Filename may differ from the basename, for instance in case files migrated // from D7 file entities. Because of that new files are saved temporarily with // a generated file name, without the original extension, we will use the // generated filename property for extension validation only in case of // temporary files; and use the file system file name in case of permanent // files. $subject = $file->isTemporary() ? $file->getFilename() : $file->getFileUri(); if (!preg_match($regex, $subject)) { $errors[] = t('Only files with the following extensions are allowed: %files-allowed.', ['%files-allowed' => $extensions]); } return $errors; Loading
core/modules/file/tests/src/Kernel/ValidatorTest.php +83 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,89 @@ public function testFileValidateExtensions() { $this->assertCount(1, $errors, 'Invalid extension blocked.'); } /** * Tests the file_validate_extensions() function. * * @param array $file_properties * The properties of the file being validated. * @param string[] $extensions * An array of the allowed file extensions. * @param string[] $expected_errors * The expected error messages as string. * * @dataProvider providerTestFileValidateExtensionsOnUri */ public function testFileValidateExtensionsOnUri(array $file_properties, array $extensions, array $expected_errors) { $file = File::create($file_properties); $actual_errors = file_validate_extensions($file, implode(' ', $extensions)); $actual_errors_as_string = array_map(function ($error_message) { return (string) $error_message; }, $actual_errors); $this->assertEquals($expected_errors, $actual_errors_as_string); } /** * Data provider for ::testFileValidateExtensionsOnUri. * * @return array[][] * The test cases. */ public function providerTestFileValidateExtensionsOnUri(): array { $temporary_txt_file_properties = [ 'filename' => 'asdf.txt', 'uri' => 'temporary://asdf', 'status' => 0, ]; $permanent_txt_file_properties = [ 'filename' => 'asdf.txt', 'uri' => 'public://asdf_0.txt', 'status' => 1, ]; $permanent_png_file_properties = [ 'filename' => 'The Druplicon', 'uri' => 'public://druplicon.png', 'status' => 1, ]; return [ 'Temporary txt validated with "asdf", "txt", "pork"' => [ 'File properties' => $temporary_txt_file_properties, 'Allowed_extensions' => ['asdf', 'txt', 'pork'], 'Expected errors' => [], ], 'Temporary txt validated with "exe" and "png"' => [ 'File properties' => $temporary_txt_file_properties, 'Allowed_extensions' => ['exe', 'png'], 'Expected errors' => [ 'Only files with the following extensions are allowed: <em class="placeholder">exe png</em>.', ], ], 'Permanent txt validated with "asdf", "txt", "pork"' => [ 'File properties' => $permanent_txt_file_properties, 'Allowed_extensions' => ['asdf', 'txt', 'pork'], 'Expected errors' => [], ], 'Permanent txt validated with "exe" and "png"' => [ 'File properties' => $permanent_txt_file_properties, 'Allowed_extensions' => ['exe', 'png'], 'Expected errors' => [ 'Only files with the following extensions are allowed: <em class="placeholder">exe png</em>.', ], ], 'Permanent png validated with "png", "gif", "jpg", "jpeg"' => [ 'File properties' => $permanent_png_file_properties, 'Allowed_extensions' => ['png', 'gif', 'jpg', 'jpeg'], 'Expected errors' => [], ], 'Permanent png validated with "exe" and "txt"' => [ 'File properties' => $permanent_png_file_properties, 'Allowed_extensions' => ['exe', 'txt'], 'Expected errors' => [ 'Only files with the following extensions are allowed: <em class="placeholder">exe txt</em>.', ], ], ]; } /** * This ensures a specific file is actually an image. */ Loading