代码分享之合法校验过滤编辑器提交的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; }
暂无