Skip to content

Commit 4e7e06f

Browse files
committed
Prevent TextHelper::truncate() from breaking HTML
Fixes #2397
1 parent a68cb4f commit 4e7e06f

File tree

2 files changed

+62
-11
lines changed

2 files changed

+62
-11
lines changed

lib/Cake/Test/Case/View/Helper/TextHelperTest.php

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public function testTruncate() {
6060
$text5 = '0<b>1<i>2<span class="myclass">3</span>4<u>5</u>6</i>7</b>8<b>9</b>0';
6161
$text6 = '<p><strong>Extra dates have been announced for this year\'s tour.</strong></p><p>Tickets for the new shows in</p>';
6262
$text7 = 'El moño está en el lugar correcto. Eso fue lo que dijo la niña, ¿habrá dicho la verdad?';
63-
$text8 = 'Vive la R'.chr(195).chr(169).'publique de France';
63+
$text8 = 'Vive la R' . chr(195) . chr(169) . 'publique de France';
6464
$text9 = 'НОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
6565

6666
$this->assertSame($this->Text->truncate($text1, 15), 'The quick br...');
@@ -86,6 +86,51 @@ public function testTruncate() {
8686
$this->assertSame($this->Text->truncate($text7, 15), 'El moño está...');
8787
$this->assertSame($this->Text->truncate($text8, 15), 'Vive la R'.chr(195).chr(169).'pu...');
8888
$this->assertSame($this->Text->truncate($text9, 10), 'НОПРСТУ...');
89+
90+
$text = '<p><span style="font-size: medium;"><a>Iamatestwithnospacesandhtml</a></span></p>';
91+
$result = $this->Text->truncate($text, 10, array(
92+
'ending' => '...',
93+
'exact' => false,
94+
'html' => true
95+
));
96+
$expected = '<p><span style="font-size: medium;"><a>...</a></span></p>';
97+
$this->assertEquals($expected, $result);
98+
99+
$text = '<p><span style="font-size: medium;">El biógrafo de Steve Jobs, Walter
100+
Isaacson, explica porqué Jobs le pidió que le hiciera su biografía en
101+
este artículo de El País.</span></p>
102+
<p><span style="font-size: medium;"><span style="font-size:
103+
large;">Por qué Steve era distinto.</span></span></p>
104+
<p><span style="font-size: medium;"><a href="http://www.elpais.com/
105+
articulo/primer/plano/Steve/era/distinto/elpepueconeg/
106+
20111009elpneglse_4/Tes">http://www.elpais.com/articulo/primer/plano/
107+
Steve/era/distinto/elpepueconeg/20111009elpneglse_4/Tes</a></span></p>
108+
<p><span style="font-size: medium;">Ya se ha publicado la biografía de
109+
Steve Jobs escrita por Walter Isaacson "<strong>Steve Jobs by Walter
110+
Isaacson</strong>", aquí os dejamos la dirección de amazon donde
111+
podeís adquirirla.</span></p>
112+
<p><span style="font-size: medium;"><a>http://www.amazon.com/Steve-
113+
Jobs-Walter-Isaacson/dp/1451648537</a></span></p>';
114+
$result = $this->Text->truncate($text, 500, array(
115+
'ending' => '... ',
116+
'exact' => false,
117+
'html' => true
118+
));
119+
$expected = '<p><span style="font-size: medium;">El biógrafo de Steve Jobs, Walter
120+
Isaacson, explica porqué Jobs le pidió que le hiciera su biografía en
121+
este artículo de El País.</span></p>
122+
<p><span style="font-size: medium;"><span style="font-size:
123+
large;">Por qué Steve era distinto.</span></span></p>
124+
<p><span style="font-size: medium;"><a href="http://www.elpais.com/
125+
articulo/primer/plano/Steve/era/distinto/elpepueconeg/
126+
20111009elpneglse_4/Tes">http://www.elpais.com/articulo/primer/plano/
127+
Steve/era/distinto/elpepueconeg/20111009elpneglse_4/Tes</a></span></p>
128+
<p><span style="font-size: medium;">Ya se ha publicado la biografía de
129+
Steve Jobs escrita por Walter Isaacson "<strong>Steve Jobs by Walter
130+
Isaacson</strong>", aquí os dejamos la dirección de amazon donde
131+
podeís adquirirla.</span></p>
132+
<p><span style="font-size: medium;"><a>... </p></span></a>';
133+
$this->assertEquals($expected, $result);
89134
}
90135

91136
/**

lib/Cake/View/Helper/TextHelper.php

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -275,20 +275,26 @@ class_exists('Multibyte');
275275
}
276276
if (!$exact) {
277277
$spacepos = mb_strrpos($truncate, ' ');
278-
if (isset($spacepos)) {
279-
if ($html) {
280-
$bits = mb_substr($truncate, $spacepos);
281-
preg_match_all('/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER);
282-
if (!empty($droppedTags)) {
283-
foreach ($droppedTags as $closingTag) {
284-
if (!in_array($closingTag[1], $openTags)) {
285-
array_unshift($openTags, $closingTag[1]);
286-
}
278+
if ($html) {
279+
$truncateCheck = mb_substr($truncate, 0, $spacepos);
280+
$lastOpenTag = mb_strrpos($truncateCheck, '<');
281+
$lastCloseTag = mb_strrpos($truncateCheck, '>');
282+
if ($lastOpenTag > $lastCloseTag) {
283+
preg_match_all('/<[\w]+[^>]*>/s', $truncate, $lastTagMatches);
284+
$lastTag = array_pop($lastTagMatches[0]);
285+
$spacepos = mb_strrpos($truncate, $lastTag) + mb_strlen($lastTag);
286+
}
287+
$bits = mb_substr($truncate, $spacepos);
288+
preg_match_all('/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER);
289+
if (!empty($droppedTags)) {
290+
foreach ($droppedTags as $closingTag) {
291+
if (!in_array($closingTag[1], $openTags)) {
292+
array_unshift($openTags, $closingTag[1]);
287293
}
288294
}
289295
}
290-
$truncate = mb_substr($truncate, 0, $spacepos);
291296
}
297+
$truncate = mb_substr($truncate, 0, $spacepos);
292298
}
293299
$truncate .= $ending;
294300

0 commit comments

Comments
 (0)