代码分享之合法校验过滤编辑器提交的HTML内容技术
分享一段代码,用最简单的函数实现前端编辑器提交过来的内容的合法性校验,允许一般的安全性 HTML 标签,对属性做了安全校验,属性只允许出现在部分 HTML 标签中,如 a、img、span、font。除了非常安全的属性外,还允许了 style 属性,style 属性其实也有一定的风险,容易造成页面样式错乱,但是大部分编辑器生成的 HTML 还是包含 style 属性的。对 style 属性里面的 CSS 没有再做分析,以后有时间再补充。
代码中使用了 Closure,因此需要 PHP 5.3 以上的版本才能跑。另外里面用到了函数 array_get,这个不是 PHP 内置函数,使用的时候需要注意修改。
function HtmlFilter(
$html,
$allow_tags = array(
'a', 'img', 'span', 'font',
'div', 'em', 'br', 'strong',
'td', 'tr', 'table',
'b', 'p', 'q', 'u', 'i',
'ul', 'li', 'ol', 'dt', 'dd', 'dl',
'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'hr', 'label', 'pre', 'small', 'tt'
),
$allow_attr = array(
'href', 'target', 'src', 'style', 'color', 'title', 'alt', 'width', 'height'
)
)
{
$tags = [];
preg_replace_callback('/<([^>\s]*).*?\/?>/i', function($matches) use (&$tags) {
if (isset($matches[1])) {
$tag_name = trim($matches[1], "<>/ \t\n\r\0\x0B");
$tags[$tag_name] = 1;
}
}, $html);
$tags = array_keys($tags);
$illegal_tags = array_diff($tags, $allow_tags);
foreach ($illegal_tags as $k => $v) {
$v = preg_replace(['/([\[\]\(\)\.\\\\])/'], ['\\\\${1}'], $v);
$html = preg_replace('/<'.$v.'[\s\S]+?<\/'.$v.'>/i', '', $html);
$html = preg_replace('/<'.$v.'\/?>/i', '', $html);
}
$other_tags = array_diff($tags, $illegal_tags);
foreach ($other_tags as $k => $v) {
$html = preg_replace_callback('/<'.$v.'\s([^>]*)*?\/?>/i', function($matches) use ($v, $allow_attr) {
if (isset($matches[1])) {
$tag_attr = trim($matches[1]);
if (!$tag_attr) {
return '<' . $v . '>';
}
preg_match_all('/([\w]+)\s*=\s*"([^"]*)"/i', $tag_attr, $matches_attr);
if (isset($matches_attr[1]) && isset($matches_attr[2])
&& in_array($v, ['a', 'img', 'span', 'font'])
) {
$str = '<' . $v;
foreach ($matches_attr[1] as $x => $y){
if (in_array($y, $allow_attr)) {
$str .= ' ' . $y . '="' . array_get($matches_attr[2], $x) . '"';
}
}
$str .= '>';
return $str;
} else {
return '<' . $v . '>';
}
}else{
return array_get($matches, 0);
}
}, $html);
}
return $html;
}
暂无