Skip to content

Commit fdedd3b

Browse files
committed
feature symfony#54346 [Serializer] Fix: Report Xml warning/error instead of silently returning a wrong xml (VincentLanglet)
This PR was squashed before being merged into the 7.1 branch. Discussion ---------- [Serializer] Fix: Report Xml warning/error instead of silently returning a wrong xml | Q | A | ------------- | --- | Branch? | 7.1 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | Fix #... <!-- prefix each issue number with "Fix #", no need to create an issue if none exists, explain below instead --> | License | MIT When `DomDocument::saveXML` encounter an error/warning, for example ``` DOMDocument::saveXML(): xmlEscapeEntities : char out of range ``` the method will return false or an empty/incomplete XML. In case of `false`, since symfony doesn't use strict type, it will be cast into `string` (for 6.4+ version with native typehint) so the `encode` method will return an empty string. In case of empty/incomplete XML, symfony returns it as if, without any notice about the error/warning. I think Symfony should not silently ignore such XML error when decoding. Or should it be an option ? Commits ------- 70e74dd [Serializer] Fix: Report Xml warning/error instead of silently returning a wrong xml
2 parents 9ece00c + 70e74dd commit fdedd3b

File tree

2 files changed

+27
-2
lines changed

2 files changed

+27
-2
lines changed

src/Symfony/Component/Serializer/Encoder/XmlEncoder.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public function encode(mixed $data, string $format, array $context = []): string
8282
$encoderIgnoredNodeTypes = $context[self::ENCODER_IGNORED_NODE_TYPES] ?? $this->defaultContext[self::ENCODER_IGNORED_NODE_TYPES];
8383
$ignorePiNode = \in_array(\XML_PI_NODE, $encoderIgnoredNodeTypes, true);
8484
if ($data instanceof \DOMDocument) {
85-
return $data->saveXML($ignorePiNode ? $data->documentElement : null);
85+
return $this->saveXml($data, $ignorePiNode ? $data->documentElement : null);
8686
}
8787

8888
$xmlRootNodeName = $context[self::ROOT_NODE_NAME] ?? $this->defaultContext[self::ROOT_NODE_NAME];
@@ -97,7 +97,7 @@ public function encode(mixed $data, string $format, array $context = []): string
9797
$this->appendNode($dom, $data, $format, $context, $xmlRootNodeName);
9898
}
9999

100-
return $dom->saveXML($ignorePiNode ? $dom->documentElement : null, $context[self::SAVE_OPTIONS] ?? $this->defaultContext[self::SAVE_OPTIONS]);
100+
return $this->saveXml($dom, $ignorePiNode ? $dom->documentElement : null, $context[self::SAVE_OPTIONS] ?? $this->defaultContext[self::SAVE_OPTIONS]);
101101
}
102102

103103
public function decode(string $data, string $format, array $context = []): mixed
@@ -498,4 +498,23 @@ private function createDomDocument(array $context): \DOMDocument
498498

499499
return $document;
500500
}
501+
502+
/**
503+
* @throws NotEncodableValueException
504+
*/
505+
private function saveXml(\DOMDocument $document, ?\DOMNode $node = null, ?int $options = null): string
506+
{
507+
$prevErrorHandler = set_error_handler(static function ($type, $message, $file, $line, $context = []) use (&$prevErrorHandler) {
508+
if (\E_ERROR === $type || \E_WARNING === $type) {
509+
throw new NotEncodableValueException($message);
510+
}
511+
512+
return $prevErrorHandler ? $prevErrorHandler($type, $message, $file, $line, $context) : false;
513+
});
514+
try {
515+
return $document->saveXML($node, $options);
516+
} finally {
517+
restore_error_handler();
518+
}
519+
}
501520
}

src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,12 @@ public function testEncodeTraversableWhenNormalizable()
433433
$this->assertEquals($expected, $serializer->serialize(new NormalizableTraversableDummy(), 'xml'));
434434
}
435435

436+
public function testEncodeException()
437+
{
438+
$this->expectException(NotEncodableValueException::class);
439+
$this->encoder->encode('Invalid character: '.\chr(7), 'xml');
440+
}
441+
436442
public function testDecode()
437443
{
438444
$source = $this->getXmlSource();

0 commit comments

Comments
 (0)