我有一个案例,我需要检查部分 html 代码中是否存在不匹配和格式错误的标签(主要是,例如 ,这是我的示例中的常见错误),并且各种重型验证器无法使用。所以我最终在 PHP 中制作了自己的自定义验证例程,它粘贴在下面(如果您有不同语言的文本,您可能需要使用 mb_substr 而不是基于索引的字符检索)(注意它不解析CDATA 或脚本/样式标签,但可以轻松扩展):
function check_html( $html )
{
$stack = array();
$autoclosed = array('br', 'hr', 'input', 'embed', 'img', 'meta', 'link', 'param', 'source', 'track', 'area', 'base', 'col', 'wbr');
$l = strlen($html); $i = 0;
$incomment = false; $intag = false; $instring = false;
$closetag = false; $tag = '';
while($i<$l)
{
while($i<$l && preg_match('#\\s#', $c=$html[$i])) $i++;
if ( $i >= $l ) break;
if ( $incomment && ('-->' === substr($html, $i, 3)) )
{
// close comment
$incomment = false;
$i += 3;
continue;
}
$c = $html[$i++];
if ( '<' === $c )
{
if ( $incomment ) continue;
if ( $intag ) return false;
if ( '!--' === substr($html, $i, 3) )
{
// open comment
$incomment = true;
$i += 3;
continue;
}
// open tag
$intag = true;
if ( '/' === $html[$i] )
{
$i++;
$closetag = true;
}
else
{
$closetag = false;
}
$tag = '';
while($i<$l && preg_match('#[a-z0-9\\-]#i', $c=$html[$i]) )
{
$tag .= $c;
$i++;
}
if ( !strlen($tag) ) return false;
$tag = strtolower($tag);
if ( $i<$l && !preg_match('#[\\s/>]#', $html[$i]) ) return false;
if ( $i<$l && $closetag && preg_match('#^\\s*/>#sim', substr($html, $i)) ) return false;
if ( $closetag )
{
if ( in_array($tag, $autoclosed) || (array_pop($stack) !== $tag) )
return false;
}
else if ( !in_array($tag, $autoclosed) )
{
$stack[] = $tag;
}
}
else if ( '>' ===$c )
{
if ( $incomment ) continue;
// close tag
if ( !$intag ) return false;
$intag = false;
}
}
return !$incomment && !$intag && empty($stack);
}