From 459a56cbd4cac28ee3de24311808c5bd6ca3705c Mon Sep 17 00:00:00 2001 From: Soybean <159681973+OracleNep@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:14:23 +0800 Subject: [PATCH] ext/uri: Fix InvalidReverseSolidus enum case typo --- ext/uri/php_uri.c | 65 +++++++++++++++++++ ext/uri/php_uri.stub.php | 2 +- ext/uri/php_uri_arginfo.h | 4 +- ext/uri/php_uri_decl.h | 10 +-- .../tests/invalid_reverse_solidus_alias.phpt | 43 ++++++++++++ ext/uri/uri_parser_whatwg.c | 2 +- 6 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 ext/uri/tests/invalid_reverse_solidus_alias.phpt diff --git a/ext/uri/php_uri.c b/ext/uri/php_uri.c index 58f34a370151..33abd6ac79b1 100644 --- a/ext/uri/php_uri.c +++ b/ext/uri/php_uri.c @@ -21,6 +21,7 @@ #include "Zend/zend_exceptions.h" #include "Zend/zend_attributes.h" #include "Zend/zend_enum.h" +#include "Zend/zend_ast.h" #include "ext/standard/info.h" #include "php_uri.h" @@ -1111,6 +1112,69 @@ PHPAPI zend_result php_uri_parser_register(const php_uri_parser *uri_parser) return result; } +/* Registers the deprecated, misspelled "InvalidReverseSoldius" class constant as + * an alias of the correctly spelled UrlValidationErrorType::InvalidReverseSolidus + * enum case. The typo was shipped in PHP 8.5, so the alias is kept for backwards + * compatibility. + * + * The value is stored as a lazy "self::InvalidReverseSolidus" constant AST instead + * of an eager enum case object: enum case objects are materialized lazily (the case + * constants are still IS_CONSTANT_AST during module startup), so resolving the case + * eagerly here would crash. The AST is allocated persistently and flagged immutable, + * mirroring how the engine stores internal enum case constants. */ +static void php_uri_register_invalid_reverse_solidus_alias(zend_class_entry *ce) +{ + zend_string *self_name = ZSTR_KNOWN(ZEND_STR_SELF); + zend_string *case_name = zend_string_init_interned("InvalidReverseSolidus", sizeof("InvalidReverseSolidus") - 1, true); + + /* Build a persistent AST equivalent to "self::InvalidReverseSolidus": + * ZEND_AST_CLASS_CONST(child[0] = "self", child[1] = "InvalidReverseSolidus"). */ + const uint32_t num_children = 2; + size_t size = sizeof(zend_ast_ref) + zend_ast_size(num_children) + + num_children * sizeof(zend_ast_zval); + char *p = pemalloc(size, 1); + + zend_ast_ref *ref = (zend_ast_ref *) p; + p += sizeof(zend_ast_ref); + GC_SET_REFCOUNT(ref, 1); + GC_TYPE_INFO(ref) = GC_CONSTANT_AST | GC_PERSISTENT | GC_IMMUTABLE; + + zend_ast *ast = (zend_ast *) p; + p += zend_ast_size(num_children); + ast->kind = ZEND_AST_CLASS_CONST; + ast->attr = ZEND_FETCH_CLASS_EXCEPTION; + ast->lineno = 0; + + ast->child[0] = (zend_ast *) p; + p += sizeof(zend_ast_zval); + ast->child[0]->kind = ZEND_AST_ZVAL; + ast->child[0]->attr = 0; + ZVAL_STR(zend_ast_get_zval(ast->child[0]), self_name); + Z_LINENO_P(zend_ast_get_zval(ast->child[0])) = 0; + + ast->child[1] = (zend_ast *) p; + ast->child[1]->kind = ZEND_AST_ZVAL; + ast->child[1]->attr = 0; + ZVAL_STR(zend_ast_get_zval(ast->child[1]), case_name); + Z_LINENO_P(zend_ast_get_zval(ast->child[1])) = 0; + + zval alias_value; + Z_TYPE_INFO(alias_value) = IS_CONSTANT_AST; + Z_AST(alias_value) = ref; + + zend_string *alias_name = zend_string_init_interned("InvalidReverseSoldius", sizeof("InvalidReverseSoldius") - 1, true); + zend_class_constant *alias = zend_declare_class_constant_ex( + ce, alias_name, &alias_value, ZEND_ACC_PUBLIC | ZEND_ACC_DEPRECATED, NULL); + + /* Attach #[\Deprecated(since: "8.6", message: "...")] so the deprecation notice + * directs users to the correctly spelled enum case. */ + zend_attribute *attr = zend_add_class_constant_attribute(ce, alias, ZSTR_KNOWN(ZEND_STR_DEPRECATED_CAPITALIZED), 2); + ZVAL_STR(&attr->args[0].value, zend_string_init("8.6", strlen("8.6"), 1)); + attr->args[0].name = ZSTR_KNOWN(ZEND_STR_SINCE); + ZVAL_STR(&attr->args[1].value, zend_string_init("use Uri\\WhatWg\\UrlValidationErrorType::InvalidReverseSolidus instead", strlen("use Uri\\WhatWg\\UrlValidationErrorType::InvalidReverseSolidus instead"), 1)); + attr->args[1].name = ZSTR_KNOWN(ZEND_STR_MESSAGE); +} + static PHP_MINIT_FUNCTION(uri) { php_uri_ce_rfc3986_uri = register_class_Uri_Rfc3986_Uri(); @@ -1140,6 +1204,7 @@ static PHP_MINIT_FUNCTION(uri) php_uri_ce_whatwg_url_host_type = register_class_Uri_WhatWg_UrlHostType(); php_uri_ce_whatwg_url_validation_error = register_class_Uri_WhatWg_UrlValidationError(); php_uri_ce_whatwg_url_validation_error_type = register_class_Uri_WhatWg_UrlValidationErrorType(); + php_uri_register_invalid_reverse_solidus_alias(php_uri_ce_whatwg_url_validation_error_type); zend_hash_init(&uri_parsers, 4, NULL, NULL, true); diff --git a/ext/uri/php_uri.stub.php b/ext/uri/php_uri.stub.php index b0b83fcf83ec..447d3a3321da 100644 --- a/ext/uri/php_uri.stub.php +++ b/ext/uri/php_uri.stub.php @@ -153,7 +153,7 @@ enum UrlValidationErrorType case InvalidUrlUnit; case SpecialSchemeMissingFollowingSolidus; case MissingSchemeNonRelativeUrl; - case InvalidReverseSoldius; + case InvalidReverseSolidus; case InvalidCredentials; case HostMissing; case PortOutOfRange; diff --git a/ext/uri/php_uri_arginfo.h b/ext/uri/php_uri_arginfo.h index 0fb464ee74aa..d1bff8f2dbbc 100644 --- a/ext/uri/php_uri_arginfo.h +++ b/ext/uri/php_uri_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit php_uri.stub.php instead. - * Stub hash: a3b4696ac001d537cc34b818715c7eb382c17c5b + * Stub hash: 8bf205edfa9cb281e73daf66285aa6a60f3431c0 * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Uri_Rfc3986_Uri_parse, 0, 1, IS_STATIC, 1) @@ -480,7 +480,7 @@ static zend_class_entry *register_class_Uri_WhatWg_UrlValidationErrorType(void) zend_enum_add_case_cstr(class_entry, "MissingSchemeNonRelativeUrl", NULL); - zend_enum_add_case_cstr(class_entry, "InvalidReverseSoldius", NULL); + zend_enum_add_case_cstr(class_entry, "InvalidReverseSolidus", NULL); zend_enum_add_case_cstr(class_entry, "InvalidCredentials", NULL); diff --git a/ext/uri/php_uri_decl.h b/ext/uri/php_uri_decl.h index d1fd58d04b2c..8b8a980846db 100644 --- a/ext/uri/php_uri_decl.h +++ b/ext/uri/php_uri_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit php_uri.stub.php instead. - * Stub hash: a3b4696ac001d537cc34b818715c7eb382c17c5b */ + * Stub hash: 8bf205edfa9cb281e73daf66285aa6a60f3431c0 */ -#ifndef ZEND_PHP_URI_DECL_a3b4696ac001d537cc34b818715c7eb382c17c5b_H -#define ZEND_PHP_URI_DECL_a3b4696ac001d537cc34b818715c7eb382c17c5b_H +#ifndef ZEND_PHP_URI_DECL_8bf205edfa9cb281e73daf66285aa6a60f3431c0_H +#define ZEND_PHP_URI_DECL_8bf205edfa9cb281e73daf66285aa6a60f3431c0_H typedef enum zend_enum_Uri_UriComparisonMode { ZEND_ENUM_Uri_UriComparisonMode_IncludeFragment = 1, @@ -46,7 +46,7 @@ typedef enum zend_enum_Uri_WhatWg_UrlValidationErrorType { ZEND_ENUM_Uri_WhatWg_UrlValidationErrorType_InvalidUrlUnit = 20, ZEND_ENUM_Uri_WhatWg_UrlValidationErrorType_SpecialSchemeMissingFollowingSolidus = 21, ZEND_ENUM_Uri_WhatWg_UrlValidationErrorType_MissingSchemeNonRelativeUrl = 22, - ZEND_ENUM_Uri_WhatWg_UrlValidationErrorType_InvalidReverseSoldius = 23, + ZEND_ENUM_Uri_WhatWg_UrlValidationErrorType_InvalidReverseSolidus = 23, ZEND_ENUM_Uri_WhatWg_UrlValidationErrorType_InvalidCredentials = 24, ZEND_ENUM_Uri_WhatWg_UrlValidationErrorType_HostMissing = 25, ZEND_ENUM_Uri_WhatWg_UrlValidationErrorType_PortOutOfRange = 26, @@ -63,4 +63,4 @@ typedef enum zend_enum_Uri_WhatWg_UrlHostType { ZEND_ENUM_Uri_WhatWg_UrlHostType_Empty = 5, } zend_enum_Uri_WhatWg_UrlHostType; -#endif /* ZEND_PHP_URI_DECL_a3b4696ac001d537cc34b818715c7eb382c17c5b_H */ +#endif /* ZEND_PHP_URI_DECL_8bf205edfa9cb281e73daf66285aa6a60f3431c0_H */ diff --git a/ext/uri/tests/invalid_reverse_solidus_alias.phpt b/ext/uri/tests/invalid_reverse_solidus_alias.phpt new file mode 100644 index 000000000000..652106b4f14a --- /dev/null +++ b/ext/uri/tests/invalid_reverse_solidus_alias.phpt @@ -0,0 +1,43 @@ +--TEST-- +Uri\WhatWg\UrlValidationErrorType keeps a deprecated alias for the InvalidReverseSoldius typo +--EXTENSIONS-- +uri +--FILE-- + $case->name, + Uri\WhatWg\UrlValidationErrorType::cases(), +); + +// The correctly spelled case exists; the misspelled alias is not a case. +var_dump(in_array('InvalidReverseSolidus', $caseNames, true)); +var_dump(in_array('InvalidReverseSoldius', $caseNames, true)); + +$type = Uri\WhatWg\UrlValidationErrorType::InvalidReverseSolidus; + +// The deprecated alias resolves to the same case and emits a deprecation notice. +$alias = Uri\WhatWg\UrlValidationErrorType::InvalidReverseSoldius; +var_dump($alias === $type); + +// Serialization uses the correct spelling and round-trips. +$serialized = serialize($type); +var_dump($serialized); +var_dump(unserialize($serialized) === $type); + +$errors = []; +Uri\WhatWg\Url::parse("https:\\\\example.com", null, $errors); +var_dump(in_array( + Uri\WhatWg\UrlValidationErrorType::InvalidReverseSolidus, + array_map(static fn($error) => $error->type, $errors), + true, +)); +?> +--EXPECTF-- +bool(true) +bool(false) + +Deprecated: Constant Uri\WhatWg\UrlValidationErrorType::InvalidReverseSoldius is deprecated since 8.6, use Uri\WhatWg\UrlValidationErrorType::InvalidReverseSolidus instead in %s on line %d +bool(true) +string(63) "E:55:"Uri\WhatWg\UrlValidationErrorType:InvalidReverseSolidus";" +bool(true) +bool(true) diff --git a/ext/uri/uri_parser_whatwg.c b/ext/uri/uri_parser_whatwg.c index f4e148704004..241c9f2d2513 100644 --- a/ext/uri/uri_parser_whatwg.c +++ b/ext/uri/uri_parser_whatwg.c @@ -167,7 +167,7 @@ static const char *fill_errors(zval *errors) ZVAL_TRUE(&failure); break; case LXB_URL_ERROR_TYPE_INVALID_REVERSE_SOLIDUS: - error_str = "InvalidReverseSoldius"; + error_str = "InvalidReverseSolidus"; ZVAL_FALSE(&failure); break; case LXB_URL_ERROR_TYPE_INVALID_CREDENTIALS: