Mijn versie

<?php
function htmltagsonly($sString)
{
    # Alle tags die zich in xhtml mogen bevinden.
    $aElements = array('body', 'head', 'html', 'title', 'abbr', 'acronym', 'address', 'blockquote', 'br', 'cite', 'code', 'dfn', 'div', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'kbd', 'p', 'pre', 'q', 'samp', 'span', 'strong', 'var', 'a', 'dl', 'dt', 'dd', 'ol', 'ul', 'li', 'object', 'param', 'b', 'big', 'hr', 'i', 'small', 'sub', 'sup', 'tt', 'del', 'ins', 'bdo', 'button', 'fieldset', 'form', 'input', 'label', 'legend', 'select', 'optgroup', 'option', 'textarea', 'caption', 'col', 'colgroup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'img', 'area', 'map', 'meta', 'noscript', 'script', 'style', 'link', 'base');
    
    # De nieuwe string.
    $sNew = '';
    
    # De tekst dat zich nog voor de tag bevindt.
    $sOther = '';
    
    while(strlen($sString) > 0)
    {
        $iOpen = strpos($sString, '<');
        $iClose = strpos($sString, '>');
        
        # Er is geen tag gevonden, het is dus tekst.
        if($iClose === false || $iOpen === false)
        {
            $sNew .= htmlentities($sString, ENT_QUOTES);
            
            break;
        }
        else
        {
            # Is het echt wel een tag, zoals <tag> en niet zomaar twee haakjes als ><.
            while($iOpen > $iClose)
            {
                $iClose = strpos($sString, '>', $iClose + 1);
                
                # Het was geen echte tag, dus het is tekst.
                if($iClose === false)
                {
                    $sNew .= htmlentities($sString, ENT_QUOTES);
                }
            }
            
            # Zit er niet nog een < voor de tag.
            $iTemp = strpos($sString, '<', $iOpen + 1);
            while($iOpen < $iTemp && $iTemp < $iClose)
            {
                $iOpen = $iTemp;
                $iTemp = strpos($sString, '<', $iOpen + 1);
            }
            
            # Er is een tag gevonden.
            if($iOpen < $iClose)
            {
                $sTag = substr($sString, $iOpen, $iClose - $iOpen + 1);
                
                # Heeft de tag wel een waarde en is het niet gewoon <>.
                $sTagValue = substr($sTag, 1, -1);
                if(empty($sTagValue) === true)
                {
                    $iOpen = $iClose + 1;
                }
                
                # De tekst voor de tag ophalen.
                $sTemp = substr($sString, 0, $iOpen);
                if(empty($sTemp) === false)
                {
                    $sOther .= $sTemp;
                }
                
                # Stond er nog tekst voor de tag?
                if(empty($sOther) === false)
                {
                    $sNew .= htmlentities($sOther, ENT_QUOTES);
                    
                    $sOther = '';
                }
                
                # Is de tag niet leeg?
                if(empty($sTagValue) === false)
                {
                    # Kijken of het een open of gesloten is.
                    if($sTag{1} == '/') # Sluit tag.
                    {
                        # Haalt de tag naam uit de tag.
                        if(($iEndPos = strpos($sTag, ' ')) !== false || ($iEndPos = strpos($sTag, '>')) !== false)
                        {
                            $sTagName = substr($sTag, 2, $iEndPos - 2);
                        }
                    }
                    else # Open tag.
                    {
                        # Haalt de tag naam uit de tag.
                        if(($iEndPos = strpos($sTag, ' ')) !== false || ($iEndPos = strpos($sTag, '/')) !== false || ($iEndPos = strpos($sTag, '>')) !== false)
                        {
                            $sTagName = substr($sTag, 1, $iEndPos - 1);
                        }
                    }
                    
                    if(in_array($sTagName, $aElements) === false)
                    {
                        $sNew .= htmlentities($sTag, ENT_QUOTES);
                    }
                    else
                    {
                        $sNew .= $sTag;
                    }
                }
                
                # Hakt het al geparsde deel van de tekst af.
                $sString = substr($sString, $iClose + 1);
            }
        }
    }
    
    return $sNew;
}
?>

Ikkedikke's versie

<?php
function htmltagsonly($sString)
{
    $sString = htmlentities($sString);
    
    $sElements = 'blockquote|optgroup|noscript|colgroup|textarea|fieldset|acronym|caption|address|legend|script|strong|option|button|select|object|style|tfoot|thead|table|title|tbody|label|param|input|small|cite|abbr|head|samp|span|font|code|html|body|base|link|form|meta|area|big|pre|sup|sub|map|bdo|del|ins|var|div|img|dfn|kbd|col|dl|dt|h6|h2|h4|dd|h1|tt|h3|em|td|li|th|h5|ol|hr|tr|ul|br|p|i|q|a|b';
    
    $sString = preg_replace("~(&lt;/?(".$sElements.")(.*?)&gt;)~ie", "html_entity_decode('\\1',ENT_QUOTES)", $sString);
    
    return $sString;
}
?>