我想使用DOMDocument解析来自Rich-Text-Editor的sting,正是我需要的:
1)仅允许(div,p,span,b,ul,ol,li,blockquotem br)标签,删除其他标签及其内容
修改 我正在使用strip_tags()来实现这个
2)只允许这些样式:
3)删除允许的标签中的所有属性,例如class,id ...等,只有align attribute
任何想法?
答案 0 :(得分:1)
出于安全原因,我建议不要尝试使用DOMDocument过滤HTML输入,特别是由于cross-site scripting的风险。您可以使用HTML Purifier等过滤器库轻松地在1和3中处理您的要求。由于斯普德利提到的原因,2号更难一点。我首先将HTML Purifier中的样式属性列入白名单,然后使用一些逻辑在过滤后扫描它们,在该元素中添加适当的标记。
以下是使用HTML Purifier的示例(取自basic.php)。我唯一改变的是HTML.AllowedAttributes和HTML.AllowedElements设置。
<?php
// replace this with the path to the HTML Purifier library
require_once 'library/HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
// configuration goes here:
$config->set('Core.Encoding', 'UTF-8'); // replace with your encoding
$config->set('HTML.Doctype', 'XHTML 1.0 Transitional'); // replace with your doctype
$config->set('HTML.AllowedAttributes', '*.style, align');
$config->set('HTML.AllowedElements', 'div, p, span, b, ul, ol, li, blockquote, br');
$config->set('CSS.AllowedProperties', 'font-weight, font-style, text-decoration');
$purifier = new HTMLPurifier($config);
$html = '<div align="center" style="font-style:italic; color: red" title="removeme">Allowed</div> <img src="not_allowed.jpg" /> <script>not allowed</script>';
$filteredHtml = $purifier->purify($html);
echo '<pre>' . htmlspecialchars($filteredHtml) . '</pre>';
哪个输出:
<div align="center" style="font-style:italic;">Allowed</div>,
答案 1 :(得分:0)
由于您只想允许少量HTML元素,因此在将其提供给DOMDocument类之前,可以考虑使用PHP strip_tags()
function清理HTML代码。
这肯定比自己解析DOM更容易找到需要剥离的元素。
这应该涉及你问题的第一部分。
它不会涉及第2或第3部分,但它是一个良好的开端。
答案 2 :(得分:0)
我有一个完全相同的代码,但它没有记录,并使用了一些我不拥有但在公共领域的代码。它非常易于使用,它确保所有标签都关闭,因此它们不会影响您的代码,请使用fix_html函数。它还可以限制使用标签和属性strip_tags_attributes,也可以使用strip_javascript删除任何类型的javascript功能。我广泛使用它,但说实话,我不知道这个是否来自生产。对于您的第二个答案,我认为最好一起删除样式,以便他们可以根据需要使用<i>
或<b>
。请不要让任何人使用下划线。
function findNodeValue($parent, $node) {
$nodes=array();
if(!is_a($parent, "DOMElement")) return NULL;
foreach($parent->childNodes as $child)
if($child->nodeName==$node) $nodes[]=$child;
if(count($nodes)==0) return NULL;
if(count($nodes)==1) return $nodes[0]->nodeValue;
else {
$ret=array();
foreach($nodes as $node)
$ret[]=$node->nodeValue;
return $ret;
}
}
function strip_javascript($filter){
// realign javascript href to onclick
$filter = preg_replace("/href=(['\"]).*?javascript:(.*)?\\1/i", "onclick=' $2 '", $filter);
//remove javascript from tags
while( preg_match("/<(.*)?javascript.*?\(.*?((?>[^()]+)|(?R)).*?\)?\)(.*)?>/i", $filter))
$filter = preg_replace("/<(.*)?javascript.*?\(.*?((?>[^()]+)|(?R)).*?\)?\)(.*)?>/i", "<$1$3$4$5>", $filter);
// dump expressions from contibuted content
$filter = preg_replace("/:expression\(.*?((?>[^(.*?)]+)|(?R)).*?\)\)/i", "", $filter);
$filter = preg_replace("/<iframe.*?>/", "", $filter);
$filter = preg_replace("/<\/iframe>/", "", $filter);
while( preg_match("/<(.*)?:expr.*?\(.*?((?>[^()]+)|(?R)).*?\)?\)(.*)?>/i", $filter))
$filter = preg_replace("/<(.*)?:expr.*?\(.*?((?>[^()]+)|(?R)).*?\)?\)(.*)?>/i", "<$1$3$4$5>", $filter);
// remove all on* events
while( preg_match("/<(.*)?\s?on[^>\s]+?=\s?.+?(['\"]).*?\\2\s?(.*)?>/i", $filter, $match) ) {
$filter = preg_replace("/<(.*)?\s?on[^>\s]+?=\s?.+?(['\"]).*?\\2\s?(.*)?>/i", "<$1$3>", $filter);
}
return $filter;
}
function html2a ( $html ) {
ini_set('pcre.backtrack_limit', 10000);
ini_set('pcre.recursion_limit', 10000);
if ( !preg_match_all( '@\<\s*?(\w+)((?:\b(?:\'[^\']*\'|"[^"]*"|[^\>])*)?)\>((?:(?>[^\<]*)|(?R))*)\<\/\s*?\\1(?:\b[^\>]*)?\>|\<\s*(\w+)(\b(?:\'[^\']*\'|"[^"]*"|[^\>])*)?\/?\>@uxis', $html = trim($html), $m, PREG_OFFSET_CAPTURE | PREG_SET_ORDER) )
return $html;
$i = 0;
$ret = array();
foreach ($m as $set) {
if ( strlen( $val = trim( substr($html, $i, $set[0][1] - $i) ) ) )
$ret[] = $val;
$val = $set[1][1] < 0
? array( 'tag' => strtolower($set[4][0]) )
: array( 'tag' => strtolower($set[1][0]), 'val' => html2a($set[3][0]) );
if ( preg_match_all( '/(\w+)\s*(?:=\s*(?:"([^"]*)"|\'([^\']*)\'|(\w+)))?/usix', isset($set[5]) && $set[2][1] < 0 ? $set[5][0] : $set[2][0],$attrs, PREG_SET_ORDER ) ) {
foreach ($attrs as $a) {
$val['attr'][$a[1]]=$a[count($a)-1];
}
}
$ret[] = $val;
$i = $set[0][1]+strlen( $set[0][0] );
}
$l = strlen($html);
if ( $i < $l )
if ( strlen( $val = trim( substr( $html, $i, $l - $i ) ) ) )
$ret[] = $val;
return $ret;
}
function a2html ( $a, $in = "" ) {
if ( is_array($a) ) {
$s = "";
foreach ($a as $t)
if ( is_array($t) ) {
$attrs="";
if ( isset($t['attr']) )
foreach( $t['attr'] as $k => $v )
$attrs.=" ${k}=".( strpos( $v, '"' )!==false ? "'$v'" : "\"$v\"" );
$s.= $in."<".$t['tag'].$attrs.( isset( $t['val'] ) ? ">\n".a2html( $t['val'], $in).$in."</".$t['tag'] : "/" ).">";
} else
$s.= $in.$t."";
} else {
$s = empty($a) ? "" : $in.$a."";
}
return $s;
}
function remove_unclosed(&$a, $allowunclosed) {
if(!is_array($a)) return;
foreach($a as $k=>$tag) {
if(is_array($tag)) {
if(!isset($tag["val"]) && !in_array($tag["tag"],$allowunclosed)) {
//var_dump($tag["tag"]);
unset($a[$k]);
} elseif(is_array(@$tag["val"]))
remove_unclosed($a[$k]["val"], $allowunclosed);
}
}
}
function fix_html($html, $allowunclosed=array("br")) {
$a = html2a($html);
remove_unclosed($a, $allowunclosed);
return a2html($a);
}
function strip_tags_ex($str,$allowtags) {
$strs=explode('<',$str);
$res=$strs[0];
for($i=1;$i<count($strs);$i++)
{
if(!strpos($strs[$i],'>'))
$res = $res.'<'.$strs[$i];
else
$res = $res.'<'.$strs[$i];
}
return strip_tags($res,$allowtags);
}
function strip_tags_attributes($string,$allowtags=allowedtags,$allowattributes=allowedattributes){
$string=strip_javascript($string);
$string = strip_tags_ex($string,$allowtags);
if (!is_null($allowattributes)) {
if(!is_array($allowattributes))
$allowattributes = explode(",",$allowattributes);
if(is_array($allowattributes))
$allowattributes = implode(")(?<!",$allowattributes);
if (strlen($allowattributes) > 0)
$allowattributes = "(?<!".$allowattributes.")";
$string = preg_replace_callback("/<[^>]*>/i",create_function(
'$matches',
'return preg_replace("/ [^ =]*'.$allowattributes.'=(\"[^\"]*\"|\'[^\']*\')/i", "", $matches[0]);'
),$string);
}
return $string;
}
我找到了strip_javascript http://www.php.net/manual/en/function.strip-tags.php#89453的来源我不知道为什么代码中没有它。可能是因为没有名字,没有电子邮件没有身份可以参考。
答案 3 :(得分:0)
$allowedTags = array( 'div' => true, 'p' => true, 'span' => true, 'b' => true,
'ul' => true, 'ol' => true, 'li' => true, 'blockquot' => true, 'em' => true, 'br' => true );
$allowedStyles = array( 'font-weight: bold' => true, 'font-style: italic' => true, 'text-decoration: underline' => true );
$allowedAttribs = array( 'align' => true );
$doc = new DOMDocument();
$doc->loadXML( '<doc><p style="font-weight: bold">test</p> <b align="left">asdfasd faksd</b><script>asdfasd</script></doc>' );
sanitizeNodeChildren( $doc->documentElement );
echo htmlentities( $doc->saveXml() );
function sanitizeNodeChildren( $parentNode ) {
$node = $parentNode->firstChild;
while( $node ) {
if( !sanitizeNode( $node ) ) {
$nodeToDelete = $node;
$node = $node->nextSibling;
$parentNode->removeChild( $nodeToDelete );
} else {
sanitizeNodeChildren( $node );
$node = $node->nextSibling;
}
}
}
function sanitizeNode( $node ) {
global $allowedTags, $allowedStyles, $allowedAttribs;
if( $node->nodeType == XML_ELEMENT_NODE ) {
if( !isset( $allowedTags[ $node->tagName ] ) ) return false;
foreach( $node->attributes as $name => $attrNode ) {
if( $name == 'style' ) {
if( isset( $allowedStyles[ $attrNode->nodeValue ] ) ) continue;
}
if( isset( $allowedAttribs[ $name ] ) ) continue;
$node->removeAttribute( $name );
}
}
return true;
}