<?php
/**
 * Functie om een string in te korten
 *
 * Deze funtie kort een string in en houd daarbij rekening met html tags.
 * Html tags nemen geen ruimte in in de gereturnde string en ze worden
 * ook niet afgebroken als de maximale lengte bereikt is. De lengte van
 * de ingekorte string en de string waarmee die beëindigt wordt kan zelf
 * worden bepaald. 
 *
 * @author Rik Veenboer
 * @param  string $data      de string die verkort moet worden
 * @param  int    $length    de lengte die de string moet krijgen
 * @param  string $endString de string waarmee de verkorte string beëindigt wordt
 * @return string            een string met de ingekorte $data
**/
function shorten($data, $length = 20, $endString = '...') {
    // De regexes voor de open en close html tags
    $regex = array(
        'open' => '/^\<[ ]*([a-z]+)[ ]*(?:[a-z]*[ ]*\=[ ]*\"[^\"\'<>]*\")*[ ]*(\/?)[ ]*\>$/',
        'close' => '/\<[ ]*\/[ ]*%s+[ ]*\>/s'
    );
    $short = '';
    // De lengte van de nieuwe string is inclusief de puntjes op het einde behalve als de invoer al kort genoeg is
    $isShortString = strlen(strip_tags($data)) <= $length;
    $length -= $isShortString ? 0 : strlen($endString);
    $free = $length;
    // Elk teken afgaan totdat ze op zijn of totdat er geen meer nodig zijn
    for ($i = 0; $i < strlen($data) && $free > 0; $i++) {
        // Controleren of het huidige teken een < is en of er ook nog een > achter staat
        if ($data{$i} == '<' && ($pos = strpos($data, '>', $i + 1)) !== false) {
            // De open tag in een string zetten
            $open = substr($data, $i, ($pos - $i + 1));
            // Controleren of de opentag geldig is
            if (preg_match($regex['open'], $open, $match)) {
                // Tags waarvan geen sluit tag bestaat detecteren
                if (isset($match[2]) && $match[2] == '/') {
                    $short .= $open;
                    // De pointer voorbij deze tag zetten en verder gaan
                    $i += strlen($open) - 1;
                    continue;
                }
                // Sluittag opzoeken
                if (preg_match(sprintf($regex['close'], $match[1]), substr($data, $pos), $match)) {
                    $close = $match[0];
                    // De waarde tussen de open en sluit tag vandaan halen en apart parsen
                    $value = shorten(substr($data, $pos + 1, strpos($data, $close, $pos) - $pos - 1), $free, '');
                    $free -= strlen($value);
                    // Het geheel toevoegen aan de verkorte string
                    $short .= $open . $value . $close;
                    // Pointer voorbij de sluit tag zetten
                    $i += strlen($open . $value . $close) - 1;
                } else {
                    // Als er geen geldige sluit tag is gevonden voegen we open tag beveiligd toe
                    $short .= htmlentities($open, ENT_QUOTES);
                    $i += strlen($open) - 1;
                }
                // Ga verder met het volgende teken
                continue;
            }
        }
        // Het huidige teken beveiligd toevoegen
        $short .= htmlentities($data{$i}, ENT_QUOTES);
        $free--;
    }
    // Alleen puntjes toevoegen als de invoer langer dan de opgegeven lengte is
    return $short . ($isShortString ? '' : $endString);
}
?>