Skip to content

ext/intl: Guard Spoofchecker restriction-level APIs at ICU 53 (fix build on ICU 50.x)#22248

Open
GrahamCampbell wants to merge 2 commits into
php:PHP-8.4from
GrahamCampbell:intl-spoofchecker-icu53-guard
Open

ext/intl: Guard Spoofchecker restriction-level APIs at ICU 53 (fix build on ICU 50.x)#22248
GrahamCampbell wants to merge 2 commits into
php:PHP-8.4from
GrahamCampbell:intl-spoofchecker-icu53-guard

Conversation

@GrahamCampbell
Copy link
Copy Markdown
Contributor

@GrahamCampbell GrahamCampbell commented Jun 7, 2026

PHP 8.4.22 fails to compile the intl extension when the system ICU is older than 53 — on Amazon Linux 2 (system ICU 50.2) the build breaks with USPOOF_ASCII, the other Spoofchecker restriction-level constants, and URestrictionLevel undeclared. The cause is GH-22055 (fixing #22053), which removed the #if U_ICU_VERSION_MAJOR_NUM >= 58 guards around the Spoofchecker restriction-level constants and the setRestrictionLevel() method, so they are now referenced unconditionally.

This is fine on master and PHP-8.5 (icu-uc >= 57.1) but not on PHP-8.4, which still accepts icu-uc >= 50.1. The symbols have existed since ICU 51 except USPOOF_SINGLE_SCRIPT_RESTRICTIVE (ICU 53, used in the setRestrictionLevel() body); since 50.2 satisfies the 50.1 minimum, configure passes and only the compile fails. ICU 53 is therefore the right floor: guarding at >= 53 builds on every ICU PHP-8.4 supports while still exposing the API on ICU 53+ — which is what GH-22055 wanted, since its >= 58 guard was too strict and hid the API on ICU 57.x.

The fix restores the guard at #if U_ICU_VERSION_MAJOR_NUM >= 53 around the constants and setRestrictionLevel() in spoofchecker.stub.php (regenerating spoofchecker_arginfo.h) and around the setRestrictionLevel() body in spoofchecker_main.c. The unrelated setAllowedChars() message change is kept.

@GrahamCampbell GrahamCampbell force-pushed the intl-spoofchecker-icu53-guard branch from f814198 to 384a146 Compare June 7, 2026 19:50
@devnexen devnexen requested a review from LamentXU123 June 7, 2026 20:11
Copy link
Copy Markdown
Contributor

@LamentXU123 LamentXU123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed correct analysis. I wasn't aware PHP 8.4 has a different minimum ICU version than 8.5 and 8.6. Thank you for this PR!

@LamentXU123
Copy link
Copy Markdown
Contributor

LamentXU123 commented Jun 8, 2026

@GrahamCampbell We may need to add this into the PHP 8.4 NEWS file to notice others that we fix this.
This should only be merged into 8.4 so I will create 2 blank commit on upper branches (i.e. 8.5 and master)
For hardening reasons this can also be merged into upper branches (PHP 8.5 and master) without NEWS just in case if in the future we lower the minimum supported version.

@LamentXU123 LamentXU123 self-assigned this Jun 8, 2026
@GrahamCampbell
Copy link
Copy Markdown
Contributor Author

Added a news entry.

@LamentXU123
Copy link
Copy Markdown
Contributor

@GrahamCampbell Thank you. The PR looks good and we will merge it if @devnexen has no opinions :)

@devnexen
Copy link
Copy Markdown
Member

devnexen commented Jun 8, 2026

none I just wanted to see how you do :)

public const int INVISIBLE = UNKNOWN;
/** @cvalue USPOOF_CHAR_LIMIT */
public const int CHAR_LIMIT = UNKNOWN;
#if U_ICU_VERSION_MAJOR_NUM >= 53
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, we may still want to support ICU 51 since it is technically >50.1, which is our minimum supported version in 8.4. So I'd suggest to only guard USPOOF_SINGLE_SCRIPT_RESTRICTIVE under ICU 53 and guard the rest under ICU 51. This benefit people who are using 51 < ICU version < 53 that they should have access to these const that exists since ICU 51

That is, I suggest to change this guard to >= 51 and specifically list USPOOF_SINGLE_SCRIPT_RESTRICTIVE out and put it in a ICU >= 53 guard.

<?php
$r = new ReflectionClass("SpoofChecker");
if (false === $r->getConstant("SINGLE_SCRIPT_RESTRICTIVE")) {
die("skip Incompatible ICU version");
Copy link
Copy Markdown
Contributor

@LamentXU123 LamentXU123 Jun 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
die("skip Incompatible ICU version");
die("skip for ICU version < 53");

to align with other skip message in the intl extension. Might need to consider to change the version message to 51 if the upper suggestion is agreed.

<?php
$r = new ReflectionClass("Spoofchecker");
if (false === $r->getConstant("SINGLE_SCRIPT_RESTRICTIVE")) {
die("skip Incompatible ICU version");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
die("skip Incompatible ICU version");
die("skip for ICU version < 53");

Ditto.

<?php
if (!class_exists("Spoofchecker")) print 'skip';

if (!method_exists(new Spoofchecker(), 'setRestrictionLevel')) print 'skip ICU version < 53';
Copy link
Copy Markdown
Contributor

@LamentXU123 LamentXU123 Jun 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!method_exists(new Spoofchecker(), 'setRestrictionLevel')) print 'skip ICU version < 53';
if (!method_exists(new Spoofchecker(), 'setRestrictionLevel')) print 'skip for ICU version < 53';

Ditto. However this can always be accepted whether we agree to move the majority of your guard to 51 because the setRestrictionLevel is guarded under 53 anyways.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants