diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md
index c4807313d9..971f451269 100644
--- a/framework/CHANGELOG.md
+++ b/framework/CHANGELOG.md
@@ -4,6 +4,7 @@ Yii Framework 2 Change Log
2.0.12 under development
--------------------------
+- Bug #13657: Fixed `yii\helpers\StringHelper::truncateHtml()` skip extra tags at the end (sam002)
- Bug #7946 Fixed a bug when the `form` attribute was not propagated to the hidden input of the checkbox (Kolyunya)
- Bug #13087: Fixed getting active validators for safe attribute (developeruz)
- Bug #13571: Fix `yii\db\mssql\QueryBuilder::checkIntegrity` for all tables (boboldehampsink)
diff --git a/framework/helpers/BaseStringHelper.php b/framework/helpers/BaseStringHelper.php
index e06da6ed6e..3dca93158a 100644
--- a/framework/helpers/BaseStringHelper.php
+++ b/framework/helpers/BaseStringHelper.php
@@ -160,10 +160,8 @@ class BaseStringHelper
$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;
- }
+ $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 = ['',''];
@@ -178,12 +176,23 @@ class BaseStringHelper
} elseif ($token instanceof \HTMLPurifier_Token_End) { //Tag ends
if (!empty($openTokens[$token->name])) {
$openTokens[$token->name]--;
+ if ($openTokens[$token->name] <= 0) {
+ unset($openTokens[$token->name]);
+ }
$truncated[] = $token;
}
} elseif ($token instanceof \HTMLPurifier_Token_Empty) { //Self contained tags, i.e. etc.
$truncated[] = $token;
}
- if (0 === $openTokens && $totalCount >= $count) {
+ if ($totalCount >= $count) {
+ if (0 < count($openTokens)) {
+ foreach (array_reverse($openTokens) as $name => $countTag) {
+ while ($countTag > 0) {
+ $truncated[] = new \HTMLPurifier_Token_End($name);
+ $countTag--;
+ }
+ }
+ }
break;
}
}
diff --git a/tests/framework/helpers/StringHelperTest.php b/tests/framework/helpers/StringHelperTest.php
index 1e505871b1..27a060d207 100644
--- a/tests/framework/helpers/StringHelperTest.php
+++ b/tests/framework/helpers/StringHelperTest.php
@@ -117,6 +117,8 @@ class StringHelperTest extends TestCase
$this->assertEquals('
This is a test for...', StringHelper::truncate('
This is a test for a sentance', 18, '...', null, true));
$this->assertEquals('
This is a test
This is a test