Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6db84b6

Browse files
committed
bug #39068 [DependencyInjection][Translator] Silent deprecation triggered by libxml_disable_entity_loader (jderusse)
This PR was squashed before being merged into the 4.4 branch. Discussion ---------- [DependencyInjection][Translator] Silent deprecation triggered by libxml_disable_entity_loader | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | Fix #39040 | License | MIT | Doc PR | - The XML entity loader is disabled by default since libxml 2.9 But, since PHP 8.0, calling the method `libxml_disable_entity_loader` triggers a deprecation which has been solved in symfony by calling `libxml_disable_entity_loader` only for libxml < 2.9 The issue is, some dependencies, enable the entity loader and does not restore the initial state afterward, leading to exceptions triggered by Symfony iteself. In previous versions symfony was resilient by disabling the flag before working, which is not the case anymore to avoid the deprecation. This PR restore the resiliency of Symfony for PHP < 8.0, which is not yet deprecated. But we have no way to check the status of the entity loader without triggering a deprecation with Symfony 8. Commits ------- 114b7a5 [DependencyInjection][Translator] Silent deprecation triggered by libxml_disable_entity_loader
2 parents 66e76d1 + 114b7a5 commit 6db84b6

File tree

5 files changed

+112
-13
lines changed

5 files changed

+112
-13
lines changed

src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,21 +634,50 @@ public function validateSchema(\DOMDocument $dom)
634634
EOF
635635
;
636636

637-
if (\LIBXML_VERSION < 20900) {
637+
if ($this->shouldEnableEntityLoader()) {
638638
$disableEntities = libxml_disable_entity_loader(false);
639639
$valid = @$dom->schemaValidateSource($source);
640640
libxml_disable_entity_loader($disableEntities);
641641
} else {
642642
$valid = @$dom->schemaValidateSource($source);
643643
}
644-
645644
foreach ($tmpfiles as $tmpfile) {
646645
@unlink($tmpfile);
647646
}
648647

649648
return $valid;
650649
}
651650

651+
private function shouldEnableEntityLoader(): bool
652+
{
653+
// Version prior to 8.0 can be enabled without deprecation
654+
if (\PHP_VERSION_ID < 80000) {
655+
return true;
656+
}
657+
658+
static $dom, $schema;
659+
if (null === $dom) {
660+
$dom = new \DOMDocument();
661+
$dom->loadXML('<?xml version="1.0"?><test/>');
662+
663+
$tmpfile = tempnam(sys_get_temp_dir(), 'symfony');
664+
register_shutdown_function(static function () use ($tmpfile) {
665+
@unlink($tmpfile);
666+
});
667+
$schema = '<?xml version="1.0" encoding="utf-8"?>
668+
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
669+
<xsd:include schemaLocation="file:///'.str_replace('\\', '/', $tmpfile).'" />
670+
</xsd:schema>';
671+
file_put_contents($tmpfile, '<?xml version="1.0" encoding="utf-8"?>
672+
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
673+
<xsd:element name="test" type="testType" />
674+
<xsd:complexType name="testType"/>
675+
</xsd:schema>');
676+
}
677+
678+
return !@$dom->schemaValidateSource($schema);
679+
}
680+
652681
private function validateAlias(\DOMElement $alias, string $file)
653682
{
654683
foreach ($alias->attributes as $name => $node) {

src/Symfony/Component/Form/Tests/Resources/TranslationFilesTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,21 @@ public function testTranslationFileIsValid($filePath)
2929
$this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message'))));
3030
}
3131

32+
/**
33+
* @dataProvider provideTranslationFiles
34+
* @group Legacy
35+
*/
36+
public function testTranslationFileIsValidWithoutEntityLoader($filePath)
37+
{
38+
$document = new \DOMDocument();
39+
$document->loadXML(file_get_contents($filePath));
40+
libxml_disable_entity_loader(true);
41+
42+
$errors = XliffUtils::validateSchema($document);
43+
44+
$this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message'))));
45+
}
46+
3247
public function provideTranslationFiles()
3348
{
3449
return array_map(

src/Symfony/Component/Security/Core/Tests/Resources/TranslationFilesTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,20 @@ public function testTranslationFileIsValid($filePath)
2929
$this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message'))));
3030
}
3131

32+
/**
33+
* @dataProvider provideTranslationFiles
34+
*/
35+
public function testTranslationFileIsValidWithoutEntityLoader($filePath)
36+
{
37+
$document = new \DOMDocument();
38+
$document->loadXML(file_get_contents($filePath));
39+
libxml_disable_entity_loader(true);
40+
41+
$errors = XliffUtils::validateSchema($document);
42+
43+
$this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message'))));
44+
}
45+
3246
public function provideTranslationFiles()
3347
{
3448
return array_map(

src/Symfony/Component/Translation/Util/XliffUtils.php

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,21 +61,18 @@ public static function validateSchema(\DOMDocument $dom): array
6161
{
6262
$xliffVersion = static::getVersionNumber($dom);
6363
$internalErrors = libxml_use_internal_errors(true);
64-
if (\LIBXML_VERSION < 20900) {
64+
if ($shouldEnable = self::shouldEnableEntityLoader()) {
6565
$disableEntities = libxml_disable_entity_loader(false);
6666
}
67-
68-
$isValid = @$dom->schemaValidateSource(self::getSchema($xliffVersion));
69-
if (!$isValid) {
70-
if (\LIBXML_VERSION < 20900) {
67+
try {
68+
$isValid = @$dom->schemaValidateSource(self::getSchema($xliffVersion));
69+
if (!$isValid) {
70+
return self::getXmlErrors($internalErrors);
71+
}
72+
} finally {
73+
if ($shouldEnable) {
7174
libxml_disable_entity_loader($disableEntities);
7275
}
73-
74-
return self::getXmlErrors($internalErrors);
75-
}
76-
77-
if (\LIBXML_VERSION < 20900) {
78-
libxml_disable_entity_loader($disableEntities);
7976
}
8077

8178
$dom->normalizeDocument();
@@ -86,6 +83,36 @@ public static function validateSchema(\DOMDocument $dom): array
8683
return [];
8784
}
8885

86+
private static function shouldEnableEntityLoader(): bool
87+
{
88+
// Version prior to 8.0 can be enabled without deprecation
89+
if (\PHP_VERSION_ID < 80000) {
90+
return true;
91+
}
92+
93+
static $dom, $schema;
94+
if (null === $dom) {
95+
$dom = new \DOMDocument();
96+
$dom->loadXML('<?xml version="1.0"?><test/>');
97+
98+
$tmpfile = tempnam(sys_get_temp_dir(), 'symfony');
99+
register_shutdown_function(static function () use ($tmpfile) {
100+
@unlink($tmpfile);
101+
});
102+
$schema = '<?xml version="1.0" encoding="utf-8"?>
103+
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
104+
<xsd:include schemaLocation="file:///'.str_replace('\\', '/', $tmpfile).'" />
105+
</xsd:schema>';
106+
file_put_contents($tmpfile, '<?xml version="1.0" encoding="utf-8"?>
107+
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
108+
<xsd:element name="test" type="testType" />
109+
<xsd:complexType name="testType"/>
110+
</xsd:schema>');
111+
}
112+
113+
return !@$dom->schemaValidateSource($schema);
114+
}
115+
89116
public static function getErrorsAsString(array $xmlErrors): string
90117
{
91118
$errorsAsString = '';

src/Symfony/Component/Validator/Tests/Resources/TranslationFilesTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,20 @@ public function testTranslationFileIsValid($filePath)
2929
$this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message'))));
3030
}
3131

32+
/**
33+
* @dataProvider provideTranslationFiles
34+
*/
35+
public function testTranslationFileIsValidWithoutEntityLoader($filePath)
36+
{
37+
$document = new \DOMDocument();
38+
$document->loadXML(file_get_contents($filePath));
39+
libxml_disable_entity_loader(true);
40+
41+
$errors = XliffUtils::validateSchema($document);
42+
43+
$this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message'))));
44+
}
45+
3246
public function provideTranslationFiles()
3347
{
3448
return array_map(

0 commit comments

Comments
 (0)