Never been to CodeSnippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world (or not, you can keep them private!)

Close dangling HTML tags (See related posts)

Close open HTML tags, e.g. if you allow HTML in your comments. Not quite as robust as running it through tidy, but tidy is not always available.

function close_dangling_tags($html){
  #put all opened tags into an array
  preg_match_all("#<([a-z]+)( .*)?(?!/)>#iU",$html,$result);
  $openedtags=$result[1];

  #put all closed tags into an array
  preg_match_all("#</([a-z]+)>#iU",$html,$result);
  $closedtags=$result[1];
  $len_opened = count($openedtags);
  # all tags are closed
  if(count($closedtags) == $len_opened){
    return $html;
  }

  $openedtags = array_reverse($openedtags);
  # close tags
  for($i=0;$i < $len_opened;$i++) {
    if (!in_array($openedtags[$i],$closedtags)){
      $html .= '</'.$openedtags[$i].'>';
    } else {
      unset($closedtags[array_search($openedtags[$i],$closedtags)]);
    }
  }
  return $html;
}

Comments on this post

DynV posts on Apr 04, 2009 at 03:02
Here's my version of the 3rd line:
preg_match_all("#<([a-z]+)(?<!br)( [^/]*)?(?!/)>#iU",$html,$result); // ( .*) modified to ( [^/]*) so that it take (?!/) into consideration ; Zero-width negative lookbehind (?<!text) added after name to rule out empty elements that the editor will not have the closing />

As the comment mention, the editor that I need to close some tags that it fails to close also don't use the XHTML version of empty elements ; it figures it can't even do valid HTML, you expect XHTML ? :D In my case, only
was relevant but it could've been other so I would've changed (?<!br) for (?<!br|hr|area|base|basefont|br|col|frame|hr|img|input|isindex|link|meta|param) HOWEVER negative lookbehind, if implemented, have different requirements but all known to date require known lenghts so inserting *. or x{#,} is out of the question and for good reasons too !
DynV posts on Apr 04, 2009 at 03:03
... In my case, only &lt;br&gt; was relevant ...
DynV posts on Apr 04, 2009 at 03:04
webmaster please fix the original to include br tag like in the last comment than delete my others
berto posts on Mar 19, 2010 at 20:56
ALMOST perfect.

But for me, applying DynV's idea didn't work (or I didn't apply it correctly).

Here's a version of the PHP code that works like a charm, (and thanks to you both for giving me the ideas):


function closetags($html) {
	preg_match_all('#<(?!meta|img|br|hr|input\b)\b([a-z]+)(?: .*)?(?<![/|/ ])>#iU', $html, $result);
	$openedtags = $result[1];
	preg_match_all('#</([a-z]+)>#iU', $html, $result);
	$closedtags = $result[1];
	$len_opened = count($openedtags);
	if (count($closedtags) == $len_opened) {
		return $html;
	}
	$openedtags = array_reverse($openedtags);
	for ($i=0; $i < $len_opened; $i++) {
		if (!in_array($openedtags[$i], $closedtags)) {
			$html .= '</'.$openedtags[$i].'>';
		} else {
			unset($closedtags[array_search($openedtags[$i], $closedtags)]);
		}
	}
	return $html;
} 



You can see that single tags such as br, img, input, and so on are excluded. You could easily add more to the list by adding more, (separating them within the expression with a vertical slash).

You need to create an account or log in to post comments to this site.