diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 19566e9aa7..2ebdbda090 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -634,14 +634,13 @@ $imports EOF ; - if (\LIBXML_VERSION < 20900) { + if ($this->shouldEnableEntityLoader()) { $disableEntities = libxml_disable_entity_loader(false); $valid = @$dom->schemaValidateSource($source); libxml_disable_entity_loader($disableEntities); } else { $valid = @$dom->schemaValidateSource($source); } - foreach ($tmpfiles as $tmpfile) { @unlink($tmpfile); } @@ -649,6 +648,36 @@ EOF return $valid; } + private function shouldEnableEntityLoader(): bool + { + // Version prior to 8.0 can be enabled without deprecation + if (\PHP_VERSION_ID < 80000) { + return true; + } + + static $dom, $schema; + if (null === $dom) { + $dom = new \DOMDocument(); + $dom->loadXML(''); + + $tmpfile = tempnam(sys_get_temp_dir(), 'symfony'); + register_shutdown_function(static function () use ($tmpfile) { + @unlink($tmpfile); + }); + $schema = ' + + +'; + file_put_contents($tmpfile, ' + + + +'); + } + + return !@$dom->schemaValidateSource($schema); + } + private function validateAlias(\DOMElement $alias, string $file) { foreach ($alias->attributes as $name => $node) { diff --git a/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php index 53b2cee448..5a9669e92b 100644 --- a/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php +++ b/src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php @@ -29,6 +29,21 @@ class TranslationFilesTest extends TestCase $this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); } + /** + * @dataProvider provideTranslationFiles + * @group Legacy + */ + public function testTranslationFileIsValidWithoutEntityLoader($filePath) + { + $document = new \DOMDocument(); + $document->loadXML(file_get_contents($filePath)); + libxml_disable_entity_loader(true); + + $errors = XliffUtils::validateSchema($document); + + $this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); + } + public function provideTranslationFiles() { return array_map( diff --git a/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php index 2402b01998..4255e91d92 100644 --- a/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php @@ -29,6 +29,20 @@ class TranslationFilesTest extends TestCase $this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); } + /** + * @dataProvider provideTranslationFiles + */ + public function testTranslationFileIsValidWithoutEntityLoader($filePath) + { + $document = new \DOMDocument(); + $document->loadXML(file_get_contents($filePath)); + libxml_disable_entity_loader(true); + + $errors = XliffUtils::validateSchema($document); + + $this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); + } + public function provideTranslationFiles() { return array_map( diff --git a/src/Symfony/Component/Translation/Util/XliffUtils.php b/src/Symfony/Component/Translation/Util/XliffUtils.php index a8c05c2244..e4373a7d5b 100644 --- a/src/Symfony/Component/Translation/Util/XliffUtils.php +++ b/src/Symfony/Component/Translation/Util/XliffUtils.php @@ -61,21 +61,18 @@ class XliffUtils { $xliffVersion = static::getVersionNumber($dom); $internalErrors = libxml_use_internal_errors(true); - if (\LIBXML_VERSION < 20900) { + if ($shouldEnable = self::shouldEnableEntityLoader()) { $disableEntities = libxml_disable_entity_loader(false); } - - $isValid = @$dom->schemaValidateSource(self::getSchema($xliffVersion)); - if (!$isValid) { - if (\LIBXML_VERSION < 20900) { + try { + $isValid = @$dom->schemaValidateSource(self::getSchema($xliffVersion)); + if (!$isValid) { + return self::getXmlErrors($internalErrors); + } + } finally { + if ($shouldEnable) { libxml_disable_entity_loader($disableEntities); } - - return self::getXmlErrors($internalErrors); - } - - if (\LIBXML_VERSION < 20900) { - libxml_disable_entity_loader($disableEntities); } $dom->normalizeDocument(); @@ -86,6 +83,36 @@ class XliffUtils return []; } + private static function shouldEnableEntityLoader(): bool + { + // Version prior to 8.0 can be enabled without deprecation + if (\PHP_VERSION_ID < 80000) { + return true; + } + + static $dom, $schema; + if (null === $dom) { + $dom = new \DOMDocument(); + $dom->loadXML(''); + + $tmpfile = tempnam(sys_get_temp_dir(), 'symfony'); + register_shutdown_function(static function () use ($tmpfile) { + @unlink($tmpfile); + }); + $schema = ' + + +'; + file_put_contents($tmpfile, ' + + + +'); + } + + return !@$dom->schemaValidateSource($schema); + } + public static function getErrorsAsString(array $xmlErrors): string { $errorsAsString = ''; diff --git a/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php b/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php index 894ae55f10..6e0620b517 100644 --- a/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php +++ b/src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php @@ -29,6 +29,20 @@ class TranslationFilesTest extends TestCase $this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); } + /** + * @dataProvider provideTranslationFiles + */ + public function testTranslationFileIsValidWithoutEntityLoader($filePath) + { + $document = new \DOMDocument(); + $document->loadXML(file_get_contents($filePath)); + libxml_disable_entity_loader(true); + + $errors = XliffUtils::validateSchema($document); + + $this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); + } + public function provideTranslationFiles() { return array_map(