<?php
echo '<pre>';
$html = "
</p>consectetur <b>adipisc<i>in</i>g </b>elit. Maecenas sit amet molestie enim. Nulla gravida mi sed ipsum </p>
<p>pellentesque<br>ut pulvinar orci consequat. Donec tempus rutrum urna at iaculis. Ut sagittis, tellus eu venenatis imperdiet,</p>
<ol>
<li>
<ol>
<li><b></b></li>
<li>sdaf</li>
</ol>
sem dolor mattis leo,
</li>
<li>in consequat elit lorem ut ligula.</li>
</ol>
Praessadf";
echo htmlspecialchars($html)."<br>";
var_dump(check_html($html));
function check_html($html) {
$tags = array();
preg_match_all('#<(/?[a-zA-Z]+)\b.*?>#im', $html, $tags);
$tags = array_map('strtolower', $tags[1]);
$lists = array('ul', 'ol');
$single_tags = array('br');
$tags_stack = new SplStack();
$lists_stack = new SplStack();
foreach ($tags as $tag) {
if ($tag[0] != '/') { // start tag
if (in_array($tag, $single_tags)) { // if single tag, just continue
continue;
} elseif (in_array($tag, $lists)) {
$lists_stack->push($tag); // new list starts
}
$tags_stack->push($tag);
} else { // end tag
if (!$tags_stack->count()) {
return false; // there aren't opened tags
}
$end_tag = trim($tag, '/');
// handle lists
if (in_array($end_tag, $lists)) {
if (!$lists_stack->count() || $lists_stack->pop() != $end_tag) {
return false; // there are no opened lists or unclosed list tag
}
} elseif ($end_tag == 'li') {
if (!$lists_stack->count()) {
return false; // there are no opened lists
}
}
if ($tags_stack->pop() != $end_tag) {
return false; // unclosed tag
}
}
}
return !$tags_stack->count(); // true if stack is empty
}