Skip to content

[3.0] Keep Stringable arguments instead of dropping them - #9409

Open
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:3.0/formatter-stringable-args
Open

[3.0] Keep Stringable arguments instead of dropping them#9409
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:3.0/formatter-stringable-args

Conversation

@albertlast

Copy link
Copy Markdown
Collaborator

Description

Admin → Members prints the literal text {member_ip} in the IP column, inside a link to ?action=trackip;searchip={member_ip}.

Localization\MessageFormatter::formatMessage() hands its arguments to intl like this:

$fmt = self::$message_formatters[…][$message]->format(array_filter($args, 'is_scalar'));

array_filter($args, 'is_scalar') throws away every object. That is the right call for an array or a plain object — intl fatals on stdClass with "could not be converted to string" — but a Stringable converts perfectly well. Dropping it means the argument never arrives, and ICU leaves the placeholder in the output rather than substituting anything.

Actions/Admin/Members.php::list_getMembers() puts an SMF\IP object in the row:

$row['member_ip'] = new IP($row['member_ip']);

and SMF\IP implements \Stringable. So the column's format_text never got its value.

Stringables are now converted to strings just before the MessageFormat escaping that already runs over string arguments, so one containing {, } or ' is protected the same as any other string, and the non-intl fallback path further down gets the same value.

Checked

On the running forum, Admin → Members:

before   <a href="…?action=trackip;searchip={member_ip}">{member_ip}</a>
after    <a href="…?action=trackip;searchip=172.19.0.1">172.19.0.1</a>

Ten pages re-rendered afterwards — board index, message index, stats, member list, recent, admin home, member list, error log, moderation centre, profile — no fatals and no other change.

The alternative

Members.php could instead declare the column as 'member_ip' => true, which makes ItemList do htmlspecialchars((string) $value) before formatting. That fixes this one column and leaves the trap in place for the next Stringable someone passes, so I fixed the formatter. Happy to do it the other way if you would rather keep formatMessage() strict.

Found by sweeping every rendered page of a stock forum for unsubstituted {placeholders}, alongside #9407 and #9408.

Issues References (Fixes|Related|Closes)

Related to #7933

formatMessage() hands its arguments to intl as

	->format(array_filter($args, 'is_scalar'))

which throws away objects. That is right for an array or a plain object,
which intl cannot use, but a Stringable converts perfectly well, and dropping
it means the argument never arrives and ICU leaves the placeholder sitting in
the output.

The member list is where this shows: Admin -> Members lists an SMF\IP object
for member_ip, so the IP column rendered the literal text {member_ip}, inside
a link to ?action=trackip;searchip={member_ip}. It now reads 172.19.0.1 and
links to that address.

Stringables are converted before the MessageFormat escaping just above, so
one containing a brace or an apostrophe is protected the same as any other
string, and the non-intl fallback path gets the same value.

Signed-off-by: Mathias Papenbrock <mathiaspapealbert@hotmail.com>
Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
@albertlast albertlast mentioned this pull request Aug 8, 2026
@jdarwood007 jdarwood007 added the Localization Language & internationalization label Aug 8, 2026
@jdarwood007 jdarwood007 added this to the 3.0 Alpha 5 milestone Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Localization Language & internationalization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants