|
@@ -63,7 +63,7 @@ class XmlDeserializationVisitor extends AbstractVisitor
|
|
|
$dom->loadXML($data);
|
|
|
foreach ($dom->childNodes as $child) {
|
|
|
if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
|
|
|
- $internalSubset = str_replace(array("\n", "\r"), '', $child->internalSubset);
|
|
|
+ $internalSubset = $this->getDomDocumentTypeEntitySubset($child, $data);
|
|
|
if (!in_array($internalSubset, $this->doctypeWhitelist, true)) {
|
|
|
throw new InvalidArgumentException(sprintf(
|
|
|
'The document type "%s" is not allowed. If it is safe, you may add it to the whitelist configuration.',
|
|
@@ -346,4 +346,43 @@ class XmlDeserializationVisitor extends AbstractVisitor
|
|
|
{
|
|
|
return $this->doctypeWhitelist;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Retrieves internalSubset even in bugfixed php versions
|
|
|
+ * @param \DOMDocumentType $child
|
|
|
+ * @param $data
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ private function getDomDocumentTypeEntitySubset(\DOMDocumentType $child, $data)
|
|
|
+ {
|
|
|
+ if(!$this->isBugFixedPhpVersion()){
|
|
|
+ return str_replace(array("\n", "\r"), '', $child->internalSubset);
|
|
|
+ }
|
|
|
+ $startPos = $endPos = stripos($data, '<!doctype');
|
|
|
+ $braces = 0;
|
|
|
+ do {
|
|
|
+ $char = $data[$endPos++];
|
|
|
+ if($char === '<'){
|
|
|
+ ++$braces;
|
|
|
+ }
|
|
|
+ if($char === '>'){
|
|
|
+ --$braces;
|
|
|
+ }
|
|
|
+ } while ($braces > 0);
|
|
|
+ $internalSubset = substr($data, $startPos, $endPos-$startPos);
|
|
|
+ $internalSubset = str_replace(array("\n", "\r"), '', $internalSubset);
|
|
|
+ $internalSubset = preg_replace('/\s{2,}/', ' ', $internalSubset);
|
|
|
+ $internalSubset = str_replace(array("[ <!", "> ]>"), array('[<!', '>]>'), $internalSubset);
|
|
|
+ return $internalSubset;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Whether or not PHP internalSubset bug is fixed in current version
|
|
|
+ * @return boolean
|
|
|
+ * @link https://bugs.php.net/bug.php?id=67081
|
|
|
+ **/
|
|
|
+ private function isBugFixedPhpVersion()
|
|
|
+ {
|
|
|
+ return (PHP_VERSION_ID >= 50513) || (PHP_VERSION_ID >= 50429 && PHP_VERSION_ID < 50500);
|
|
|
+ }
|
|
|
}
|