LMLPHP后院

代码分享之合法校验过滤编辑器提交的HTML内容技术

maybe yes 发表于 2016-06-25 18:07

分享一段代码,用最简单的函数实现前端编辑器提交过来的内容的合法性校验,允许一般的安全性 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;
}
2024-04-20 15:03:24 1713596604 0.027858