如何在PHP中验证XML的CDATA部分

4

根据用户输入,我创建了一个基于XML的文档。其中一个XML节点包含一个CDATA节。如果在CDATA节中插入的字符是“特殊”的(我认为是控制字符),那么整个XML将变得无效。

例如:

$dom = new DOMDocument('1.0', 'utf-8');
$dom->appendChild($dom->createElement('root'))
    ->appendChild($dom->createCDATASection(
        "This is some text with a SOH char \x01."
    ));

$test = new DOMDocument;
$test->loadXml($dom->saveXML());
echo $test->saveXml();

将会给予

Warning: DOMDocument::loadXML(): CData section not finished
This is some text with a SOH cha in Entity, line: 2 in /newfile.php on line 17

Warning: DOMDocument::loadXML(): PCDATA invalid Char value 1 in Entity, line: 2 in /newfile.php on line 17

Warning: DOMDocument::loadXML(): Sequence ']]>' not allowed in content in Entity, line: 2 in /newfile.php on line 17

Warning: DOMDocument::loadXML(): Sequence ']]>' not allowed in content in Entity, line: 2 in /newfile.php on line 17

Warning: DOMDocument::loadXML(): internal errorExtra content at the end of the document in Entity, line: 2 in /newfile.php on line 17
<?xml version="1.0"?>

有没有一种好的方法在PHP中确保CDATA部分是有效的?

1
一些用户不知何故复制/粘贴了SOH控制字符。 - johnlemon
你可以通过使用白名单或黑名单字符映射来简单地对输入进行清理。我会从 filter_var([], FILTER_SANITIZE_STRING) 开始。 - Gajus
很遗憾的是,DOMDocument没有采取措施来保证XML输出。包含]]>或控制字符的CDATA不会被检查,包含--的注释节点也不会被检查。即使使用DOMDocument,这两种情况都是创建无效XML的简单方法。 - Francis Avila
DOM确实有一些检查来防止无效的XML。不过我很惊讶它不能防止CDATA部分中的控制字符。 - Gordon
4个回答

8

CDATA节允许的字符范围CDATA节,

#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

所以您需要对字符串进行清理,只包含那些字符。


有没有内置函数可以做到这个? - johnlemon
@danip 我不知道有没有这样的功能。你可以尝试使用 preg_match - Gordon

2

因为 "\x01" 不是可打印字符,所以会导致警告。你可以像这样解决这个问题:

$dom = new DOMDocument('1.0', 'utf-8');
$dom->appendChild($dom->createElement('root'))
->appendChild($dom->createCDATASection(
    urlencode("This is some text with a SOH char \x01.")
));

$test = new DOMDocument;
$test->loadXml($dom->saveXML());
echo urldecode($test->saveXml());

2
使用Gordon的答案,我制作了:
 /**
 * Removes invalid characters from an HTML string
 *
 * @param string $content
 *
 * @return string
 */
function sanitize_html($content) {
  if (!$content) return '';
  $invalid_characters = '/[^\x9\xa\x20-\xD7FF\xE000-\xFFFD]/';
  return preg_replace($invalid_characters, '', $content);
}

使用方法:


-1

我理解OP是在询问如何生成XML文件而非读取它。 - Gordon
您可能需要根据您关于filter_var的评论更新您的问题,尽管当OP需要任意Unicode时,filter_var可能无法起作用。 - Gordon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接