protected static function truncateHtml($string, $count, $suffix, $encoding = false)
{
$config = \HTMLPurifier_Config::create(null);
$config->set('Cache.SerializerPath', \Yii::$app->getRuntimePath());
$lexer = \HTMLPurifier_Lexer::create($config);
$tokens = $lexer->tokenizeHTML($string, $config, null);
$openTokens = [];
$totalCount = 0;
$truncated = [];
foreach ($tokens as $token) {
if ($token instanceof \HTMLPurifier_Token_Start) {
//Tag begins
if ($totalCount < $count) {
$openTokens[$token->name] = isset($openTokens[$token->name]) ? $openTokens[$token->name] + 1 : 1;
$truncated[] = $token;
}
} elseif ($token instanceof \HTMLPurifier_Token_Text && $totalCount <= $count) {
//Text
if (false === $encoding) {
preg_match('/^(\\s*)/um', $token->data, $prefixSpace) ?: ($prefixSpace = ['', '']);
$token->data = $prefixSpace[1] . self::truncateWords(ltrim($token->data), $count - $totalCount, '');
$currentCount = self::countWords($token->data);
} else {
$token->data = self::truncate($token->data, $count - $totalCount, '', $encoding);
$currentCount = mb_strlen($token->data, $encoding);
}
$totalCount += $currentCount;
$truncated[] = $token;
} elseif ($token instanceof \HTMLPurifier_Token_End) {
//Tag ends
if (!empty($openTokens[$token->name])) {
$openTokens[$token->name]--;
$truncated[] = $token;
}
} elseif ($token instanceof \HTMLPurifier_Token_Empty) {
//Self contained tags, i.e. <img/> etc.
$truncated[] = $token;
}
if (0 === $openTokens && $totalCount >= $count) {
break;
}
}
$context = new \HTMLPurifier_Context();
$generator = new \HTMLPurifier_Generator($config, $context);
return $generator->generateFromTokens($truncated) . ($totalCount >= $count ? $suffix : '');
}