DOMDocument 在解析包含未转义 </ 序列的 <script> 内容时会提前截断,因其将 </ 误识别为标签闭合;解决方法是预处理 JavaScript 中的 </ 为 </,并确保输入为结构完整的 HTML5 文档。
DOMDocument 在解析包含未转义 `` 序列的 `` 内容时会提前截断,因其将 `` 误识别为标签闭合;解决方法是预处理 JavaScript 中的 `` 为 ``,并确保输入为结构完整的 HTML5 文档。
PHP 的 DOMDocument 是基于 XML 解析器构建的,对 HTML 的容错性有限——尤其当输入为不完整 HTML 片段或 <script> 标签内存在未转义的 </(如 </script> 字符串被拼接生成)时,解析器会在首次遇到 </ 时错误地认为 <script> 已结束,导致后续内容被丢弃或转义,正如示例中 </scr'+'ipt> 消失。
要可靠解析此类内容,需满足两个前提:
<html>、<head>、<body>),避免 DOMDocument 启用“修复模式”引发不可控修正;<script> 内部所有 </ 序列进行 JavaScript 层面的转义(即替换为 </),使其在不改变运行逻辑的前提下避开 HTML 解析器的标签识别机制。以下为推荐的健壮处理方案(含正则安全提取与转义):
$html1 = "<script>document.write('<scr'+'ipt>alert(123);</scr'+'ipt>')</script>";// 构建最小合法 HTML5 文档结构$html = <<<HTML<!DOCTYPE html><html lang="en"><head>$html1</head><body></body></html>HTML;// 安全转义 script 标签内所有 '</' 为 '</'$html = preg_replace_callback('/(<script(?:s[^>]*)?>)(.*?)(</script>)/isU',function ($matches) {$content = preg_replace('|</|', '</', $matches[2][0]);return $matches[1][0] . $content . $matches[3][0];},$html);$dom = new DOMDocument();$dom->recover = false; // 禁用自动修复,提升可预测性$dom->strictErrorChecking = false;$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);$html2 = $dom->saveHTML();echo $html2;
输出将保留原始脚本逻辑:
<script>document.write('<scr'+'ipt>alert(123);</scr'+'ipt>')</script>
注意事项:
<script> 内容,该模式易引入 XSS 风险;若必须处理,应结合 CSP、输出编码与内容策略严格校验;LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD 标志可防止 DOMDocument 自动注入 <html>/<body> 等隐式节点,提升结果可控性;textContent 或 data-* 属性传递字符串,由客户端 JS 动态构造,而非依赖服务端 HTML 解析。总之,DOMDocument 并非 HTML 模板引擎——它适用于结构化文档操作,而非执行 JavaScript 逻辑。正确预处理 + 结构补全,是绕过其解析局限的核心实践。