每当我们通过数据库或类似来源的某些编辑来获取一些用户输入的内容时,我们可能会检索仅包含开始标记但没有关闭的部分.
这可能会妨碍网站的当前布局.
是否有客户端或服务器端的方法来解决这个问题?
找到了一个很好的答案:
使用PHP 5并使用DOMDocument对象的loadHTML()方法.这自动解析格式错误的HTML,随后调用saveXML()将输出有效的HTML.DOM函数可以在这里找到:
http://www.php.net/dom
用法:
$doc = new DOMDocument(); $doc->loadHTML($yourText); $yourText = $doc->saveHTML();
你可以使用Tidy:
Tidy是Tidy HTML清理和修复实用程序的绑定,它不仅允许您清理和操作HTML文档,还可以遍历文档树.
或HTMLPurifier
HTML Purifier是一个用PHP编写的符合标准的HTML过滤器库.HTML Purifier不仅会删除所有恶意代码(更好地称为XSS),并且具有经过全面审核,安全且允许的白名单,还可以确保您的文档符合标准,只有通过全面了解W3C的规范才能实现.
我有解决方案的PHP
#iU", $html, $result ); $openedtags = $result[1]; #put all closed tags into an array preg_match_all ( "#([a-z]+)>#iU", $html, $result ); $closedtags = $result[1]; $len_opened = count ( $openedtags ); # all tags are closed if( count ( $closedtags ) == $len_opened ) { return $html; } $openedtags = array_reverse ( $openedtags ); # close tags for( $i = 0; $i < $len_opened; $i++ ) { if ( !in_array ( $openedtags[$i], $closedtags ) ) { $html .= "" . $openedtags[$i] . ">"; } else { unset ( $closedtags[array_search ( $openedtags[$i], $closedtags)] ); } } return $html; } // close opened html tags ?>
你可以使用这个功能
test test"); ?>
对于HTML片段,并且根据KJS的答案,当片段有一个根元素时,我已成功完成以下操作:
$dom = new DOMDocument(); $dom->loadHTML($string); $body = $dom->documentElement->firstChild->firstChild; $string = $dom->saveHTML($body);
如果没有根元素,这是可能的(但似乎只包含p标签中的第一个文本子节点 paratext
):
$dom = new DOMDocument(); $dom->loadHTML($string); $bodyChildNodes = $dom->documentElement->firstChild->childNodes; $string = ''; foreach ($bodyChildNodes as $node){ $string .= $dom->saveHTML($node); }
或者更好,从PHP> = 5.4和libxml> = 2.7.8(2.7.7 for LIBXML_HTML_NOIMPLIED
):
$dom = new DOMDocument(); // Load with no html/body tags and do not add a default dtd $dom->loadHTML($string, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); $string = $dom->saveHTML();
除了像Tidy这样的服务器端工具,您还可以使用用户的浏览器为您进行一些清理.其中一个非常棒的事情innerHTML
是,它将对动态内容应用与HTML页面相同的即时修复.这段代码工作得很好(有两个警告),实际上没有任何内容写入页面:
var divTemp = document.createElement('div'); divTemp.innerHTML = 'these tags aren\'t closed'; console.log(divTemp.innerHTML);
警告:
不同的浏览器将返回不同的字符串.这不是很糟糕,除了在IE的情况下,它将返回大写标签并将从标签属性中删除引号,这将不会通过验证.这里的解决方案是在服务器端进行一些简单的清理.但至少文档将是正确结构化的XML.
我怀疑你可能不得不在读取innerHTML之前延迟 - 给浏览器一个消化字符串的机会 - 或者你冒险回到确切的内容.我只是尝试了IE8,它看起来像字符串立即解析,但我对IE6不太确定.最好在延迟后读取innerHTML(或将其抛入setTimeout()以强制它到队列的末尾).
我建议你接受@ Gordon的建议并使用Tidy,如果你有权访问它(它实现的工作量较少)并且失败了,请使用innerHTML并在PHP中编写自己的整洁函数.
虽然这不是你的问题的一部分,因为这是一个CMS,考虑使用YUI 2富文本编辑器这样的东西.它实现起来相当容易,有些容易定制,大多数用户都非常熟悉这个界面,并且它会发出完全有效的代码.还有其他几个现成的富文本编辑器,但YUI拥有最好的许可证,是我见过的最强大的.