-
Notifications
You must be signed in to change notification settings - Fork 8k
Open
Description
Description
I ran into a C14N issue with Dom\XMLDocument while upgrading php-soap/xml to veewee/xml v4.
When a document is built via the DOM API (createElementNS + appendChild), non-exclusive C14N() strips all namespace declarations while keeping the prefixed element names, producing invalid XML.
Reproducer: https://3v4l.org/PGDSl#v8.5.3
<?php
echo "PHP " . PHP_VERSION . PHP_EOL . PHP_EOL;
// 1. DOM-built document: C14N drops namespace declarations
$doc = Dom\XMLDocument::createEmpty();
$root = $doc->createElementNS("urn:envelope", "env:Root");
$doc->appendChild($root);
$child = $doc->createElementNS("urn:child", "x:Child");
$root->appendChild($child);
echo "DOM-built Dom\XMLDocument" . PHP_EOL;
echo " saveXML: " . trim($doc->saveXML()) . PHP_EOL;
echo " C14N: " . $doc->C14N() . PHP_EOL;
// Expected: <env:Root xmlns:env="urn:envelope"><x:Child xmlns:x="urn:child"></x:Child></env:Root>
// Actual: <env:Root><x:Child></x:Child></env:Root>
// ^ namespace declarations are missing, this is not valid XML
echo PHP_EOL;
// 2. Same structure parsed from string: C14N works correctly
$doc2 = Dom\XMLDocument::createFromString(
'<env:Root xmlns:env="urn:envelope"><x:Child xmlns:x="urn:child"/></env:Root>'
);
echo "Parsed Dom\XMLDocument" . PHP_EOL;
echo " C14N: " . $doc2->C14N() . PHP_EOL;
// Correct: <env:Root xmlns:env="urn:envelope"><x:Child xmlns:x="urn:child"></x:Child></env:Root>
echo PHP_EOL;
// 3. Legacy DOMDocument DOM-built: C14N works correctly
$doc3 = new DOMDocument();
$root3 = $doc3->createElementNS("urn:envelope", "env:Root");
$doc3->appendChild($root3);
$child3 = $doc3->createElementNS("urn:child", "x:Child");
$root3->appendChild($child3);
echo "DOM-built DOMDocument (legacy)" . PHP_EOL;
echo " C14N: " . $doc3->C14N() . PHP_EOL;
// Correct: <env:Root xmlns:env="urn:envelope"><x:Child xmlns:x="urn:child"></x:Child></env:Root>
echo PHP_EOL;
// 4. Exclusive C14N on DOM-built document: works correctly
echo "DOM-built Dom\XMLDocument (exclusive C14N)" . PHP_EOL;
echo " C14N: " . $doc->C14N(exclusive: true) . PHP_EOL;
// Correct: <env:Root xmlns:env="urn:envelope"><x:Child xmlns:x="urn:child"></x:Child></env:Root>Output:
DOM-built Dom\XMLDocument
saveXML: <?xml version="1.0" encoding="UTF-8"?>
<env:Root xmlns:env="urn:envelope"><x:Child xmlns:x="urn:child"/></env:Root>
C14N: <env:Root><x:Child></x:Child></env:Root>
Parsed Dom\XMLDocument
C14N: <env:Root xmlns:env="urn:envelope"><x:Child xmlns:x="urn:child"></x:Child></env:Root>
DOM-built DOMDocument (legacy)
C14N: <env:Root xmlns:env="urn:envelope"><x:Child xmlns:x="urn:child"></x:Child></env:Root>
DOM-built Dom\XMLDocument (exclusive C14N)
C14N: <env:Root xmlns:env="urn:envelope"><x:Child xmlns:x="urn:child"></x:Child></env:Root>
As you can see, the first C14N output is invalid XML.
The key observations:
- DOM-built Dom\XMLDocument: C14N() outputs env:Root<x:Child></x:Child></env:Root> (missing xmlns:env and xmlns:x)
- Same structure parsed via createFromString: works correctly
- Legacy DOMDocument DOM-built: works correctly
- Exclusive C14N(exclusive: true) on DOM-built: also works correctly
So the issue is specific to non-exclusive C14N on programmatically built Dom\XMLDocument documents.
Related:
Dom\XMLDocument::C14N()seems broken compared toDOMDocument::C14N()#20444 (same root cause, closed)- 40c291c (fix for the above, but doesn't cover the DOM-built case)
The issue persists on 8.4.19 and 8.5.3.
Cheers,
Toon
/cc @ndossche
PHP Version
Any 8.4 and 8.5
Operating System
any
Reactions are currently unavailable