Skip to content

Commit e30c0ae

Browse files
committed
Redo over-zealous ncr encoding and check char limts better
1 parent f9efabc commit e30c0ae

5 files changed

Lines changed: 83 additions & 12 deletions

File tree

‎entity/rule.php‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -274,15 +274,15 @@ public function set_title($title)
274274
// Enforce a string
275275
$title = (string) $title;
276276

277-
// Replace four-byte UTF-8 characters before storing in utf8mb3 columns.
278-
$title = utf8_encode_ucr($title);
279-
280-
// Limit both the displayed and stored title lengths to the column size.
281-
if (truncate_string($title, 200, 200) !== $title)
277+
// Enforce the public title limit before storage encoding expands characters.
278+
if (truncate_string($title, 200, 2000) !== $title)
282279
{
283280
throw new \phpbb\boardrules\exception\unexpected_value(array('title', 'TOO_LONG'));
284281
}
285282

283+
// MSSQL string literals cannot safely preserve every BMP character.
284+
$title = strpos($this->db->get_sql_layer(), 'mssql') === 0 ? utf8_encode_ncr($title) : utf8_encode_ucr($title);
285+
286286
// Set the title on our data array
287287
$this->data['rule_title'] = $title;
288288

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
/**
3+
*
4+
* Board Rules extension for the phpBB Forum Software package.
5+
*
6+
* @copyright (c) 2026 phpBB Limited <https://www.phpbb.com>
7+
* @license GNU General Public License, version 2 (GPL-2.0)
8+
*
9+
*/
10+
11+
namespace phpbb\boardrules\migrations\v30x;
12+
13+
class m21_expand_rule_title extends \phpbb\db\migration\migration
14+
{
15+
/**
16+
* {@inheritdoc}
17+
*/
18+
public static function depends_on()
19+
{
20+
return array('\phpbb\boardrules\migrations\v30x\m20_unicode_language_trees');
21+
}
22+
23+
/**
24+
* {@inheritdoc}
25+
*/
26+
public function update_schema()
27+
{
28+
return array(
29+
'change_columns' => array(
30+
$this->table_prefix . 'boardrules' => array(
31+
'rule_title' => array('VCHAR_UNI:2000', ''),
32+
),
33+
),
34+
);
35+
}
36+
37+
/**
38+
* Keep the expanded column until the initial schema migration drops the table.
39+
* Reverting it could fail when encoded titles no longer fit the old size.
40+
*
41+
* @return array Array of table schema changes
42+
*/
43+
public function revert_schema()
44+
{
45+
return array();
46+
}
47+
}

‎tests/entity/rule_entity_save_test.php‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,36 @@ public function test_four_byte_title_characters_are_encoded_and_other_unicode_is
8888
$this->db->sql_freeresult($result);
8989

9090
self::assertSame('emoji-title', $row['rule_anchor']);
91-
self::assertSame('Emoji &#128512; 中文 Кириллица title', $row['rule_title']);
91+
self::assertSame(
92+
strpos($this->db->get_sql_layer(), 'mssql') === 0
93+
? 'Emoji &#128512; &#20013;&#25991; &#1050;&#1080;&#1088;&#1080;&#1083;&#1083;&#1080;&#1094;&#1072; title'
94+
: 'Emoji &#128512; 中文 Кириллица title',
95+
$row['rule_title']
96+
);
9297

9398
$entity->load(1);
9499
self::assertSame('emoji-title', $entity->get_anchor());
95100
self::assertSame('Emoji 😀 中文 Кириллица title', $entity->get_title());
96101
}
97102

103+
public function test_maximum_length_unicode_title_is_preserved()
104+
{
105+
$title = str_repeat('К', 200);
106+
$entity = $this->get_rule_entity();
107+
$entity->load(1)->set_title($title)->save()->load(1);
108+
109+
self::assertSame($title, $entity->get_title());
110+
}
111+
112+
public function test_expanded_ncr_storage_is_preserved()
113+
{
114+
$title = str_repeat('😀', 200);
115+
$entity = $this->get_rule_entity();
116+
$entity->load(1)->set_title($title)->save()->load(1);
117+
118+
self::assertSame($title, $entity->get_title());
119+
}
120+
98121
/**
99122
* Test saving to (non-existant) rules from the database
100123
*

‎tests/entity/rule_entity_title_test.php‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ public function title_test_data()
3838
str_repeat('К', 200),
3939
str_repeat('К', 200),
4040
),
41+
array(
42+
str_repeat('a', 194) . '&amp;&amp;',
43+
str_repeat('a', 194) . '&amp;&amp;',
44+
),
4145
);
4246
}
4347

@@ -75,11 +79,6 @@ public function title_fails_test_data()
7579
array(
7680
str_repeat('a', 201),
7781
),
78-
79-
// Escaped request value exceeds the stored column length.
80-
array(
81-
str_repeat('a', 194) . '&amp;&amp;',
82-
),
8382
);
8483
}
8584

‎tests/functional/admin_controller_test.php‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,9 @@ public function test_acp_create_rule($crawler)
167167
$stored_title = $this->db->sql_fetchfield('rule_title', false, $result);
168168
$this->db->sql_freeresult($result);
169169

170-
$expected_title = 'Test &#128512; 中文 Кириллица Rule';
170+
$expected_title = strpos($this->db->get_sql_layer(), 'mssql') === 0
171+
? 'Test &#128512; &#20013;&#25991; &#1050;&#1080;&#1088;&#1080;&#1083;&#1083;&#1080;&#1094;&#1072; Rule'
172+
: 'Test &#128512; 中文 Кириллица Rule';
171173
self::assertSame($expected_title, $stored_title);
172174
self::assertSame($rule_title, utf8_decode_ncr($stored_title));
173175
}

0 commit comments

Comments
 (0)