Skip to content

[3.0] Compare URL schemes case insensitively - #9325

Open
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:fix/url-is-scheme-case
Open

[3.0] Compare URL schemes case insensitively#9325
albertlast wants to merge 1 commit into
SimpleMachines:release-3.0from
albertlast:fix/url-is-scheme-case

Conversation

@albertlast

@albertlast albertlast commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Note

This change was produced by an LLM. The code, the commit message and this
description were all written by Claude (Anthropic), driven by @albertlast. It has
not yet had human code review.

Everything stated below was verified by actually running it, rather than only
reasoned about. Even so, please review it as untrusted work: the diagnosis may be
right while the fix is not what SMF would prefer stylistically or architecturally.

Description

RFC 3986, section 3.1: "scheme names are case-insensitive". SMF\Url keeps the scheme
exactly as it was written rather than normalizing it, and isScheme() compares the two
with in_array():

return !empty($this->scheme) && \in_array($this->scheme, array_map('strval', (array) $scheme));

So a URL written with an uppercase scheme does not match its own name.

Two callers depend on this. isWebsite() is isScheme(['http', 'https']), so
HTTP://example.com is not recognised as a website. And User uses it to decide
whether an avatar value is an inline image or a remote address:

$member->avatar->url->isScheme('data')

which means a DATA: URI is treated as a remote URL.

This folds both sides before comparing. The comparison is also made strict while it is
there, since in_array() without the third argument was comparing loosely.

How this was verified

PHP 8.4.23. Same script before and after:

URL isScheme('https') isWebsite()
https://example.com true → true true → true
HTTPS://example.com false → true false → true
HtTp://example.com false → false false → true
ftp://example.com false → false false → false
URL isScheme('data')
data:image/png;base64,… true → true
DATA:image/png;base64,… false → true

Lowercase schemes, which is nearly everything in practice, behave exactly as before.

php -l and PHP-CS-Fixer clean.

Relationship to other PRs

Sources/Url.php is not touched by any other open PR.

Found while writing unit tests for the stateless parts of the codebase (#9326), which
carries the regression tests for this fix. This PR is independent of that one and can
be merged on its own.

Issues References (Fixes|Related|Closes)

  1. No existing issue found for this.
  2. Related: [3.0] Add a PHPUnit suite for the parts that need no database #9326

RFC 3986, section 3.1, makes scheme names case insensitive, and this
class keeps the scheme exactly as it was written rather than normalizing
it. isScheme() compared the two with in_array(), so a URL written with an
uppercase scheme did not match its own name.

That reaches two callers. isWebsite() stops recognising HTTP:// and
HTTPS:// as websites, and the avatar handling in User treats a DATA: URI
as though it were a remote address.

Folds both sides before comparing, and makes the comparison strict while
it is there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant