Skip to content

Commit 459a56c

Browse files
committed
ext/uri: Fix InvalidReverseSolidus enum case typo
1 parent 425cd3d commit 459a56c

6 files changed

Lines changed: 117 additions & 9 deletions

File tree

ext/uri/php_uri.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "Zend/zend_exceptions.h"
2222
#include "Zend/zend_attributes.h"
2323
#include "Zend/zend_enum.h"
24+
#include "Zend/zend_ast.h"
2425
#include "ext/standard/info.h"
2526

2627
#include "php_uri.h"
@@ -1111,6 +1112,69 @@ PHPAPI zend_result php_uri_parser_register(const php_uri_parser *uri_parser)
11111112
return result;
11121113
}
11131114

1115+
/* Registers the deprecated, misspelled "InvalidReverseSoldius" class constant as
1116+
* an alias of the correctly spelled UrlValidationErrorType::InvalidReverseSolidus
1117+
* enum case. The typo was shipped in PHP 8.5, so the alias is kept for backwards
1118+
* compatibility.
1119+
*
1120+
* The value is stored as a lazy "self::InvalidReverseSolidus" constant AST instead
1121+
* of an eager enum case object: enum case objects are materialized lazily (the case
1122+
* constants are still IS_CONSTANT_AST during module startup), so resolving the case
1123+
* eagerly here would crash. The AST is allocated persistently and flagged immutable,
1124+
* mirroring how the engine stores internal enum case constants. */
1125+
static void php_uri_register_invalid_reverse_solidus_alias(zend_class_entry *ce)
1126+
{
1127+
zend_string *self_name = ZSTR_KNOWN(ZEND_STR_SELF);
1128+
zend_string *case_name = zend_string_init_interned("InvalidReverseSolidus", sizeof("InvalidReverseSolidus") - 1, true);
1129+
1130+
/* Build a persistent AST equivalent to "self::InvalidReverseSolidus":
1131+
* ZEND_AST_CLASS_CONST(child[0] = "self", child[1] = "InvalidReverseSolidus"). */
1132+
const uint32_t num_children = 2;
1133+
size_t size = sizeof(zend_ast_ref) + zend_ast_size(num_children)
1134+
+ num_children * sizeof(zend_ast_zval);
1135+
char *p = pemalloc(size, 1);
1136+
1137+
zend_ast_ref *ref = (zend_ast_ref *) p;
1138+
p += sizeof(zend_ast_ref);
1139+
GC_SET_REFCOUNT(ref, 1);
1140+
GC_TYPE_INFO(ref) = GC_CONSTANT_AST | GC_PERSISTENT | GC_IMMUTABLE;
1141+
1142+
zend_ast *ast = (zend_ast *) p;
1143+
p += zend_ast_size(num_children);
1144+
ast->kind = ZEND_AST_CLASS_CONST;
1145+
ast->attr = ZEND_FETCH_CLASS_EXCEPTION;
1146+
ast->lineno = 0;
1147+
1148+
ast->child[0] = (zend_ast *) p;
1149+
p += sizeof(zend_ast_zval);
1150+
ast->child[0]->kind = ZEND_AST_ZVAL;
1151+
ast->child[0]->attr = 0;
1152+
ZVAL_STR(zend_ast_get_zval(ast->child[0]), self_name);
1153+
Z_LINENO_P(zend_ast_get_zval(ast->child[0])) = 0;
1154+
1155+
ast->child[1] = (zend_ast *) p;
1156+
ast->child[1]->kind = ZEND_AST_ZVAL;
1157+
ast->child[1]->attr = 0;
1158+
ZVAL_STR(zend_ast_get_zval(ast->child[1]), case_name);
1159+
Z_LINENO_P(zend_ast_get_zval(ast->child[1])) = 0;
1160+
1161+
zval alias_value;
1162+
Z_TYPE_INFO(alias_value) = IS_CONSTANT_AST;
1163+
Z_AST(alias_value) = ref;
1164+
1165+
zend_string *alias_name = zend_string_init_interned("InvalidReverseSoldius", sizeof("InvalidReverseSoldius") - 1, true);
1166+
zend_class_constant *alias = zend_declare_class_constant_ex(
1167+
ce, alias_name, &alias_value, ZEND_ACC_PUBLIC | ZEND_ACC_DEPRECATED, NULL);
1168+
1169+
/* Attach #[\Deprecated(since: "8.6", message: "...")] so the deprecation notice
1170+
* directs users to the correctly spelled enum case. */
1171+
zend_attribute *attr = zend_add_class_constant_attribute(ce, alias, ZSTR_KNOWN(ZEND_STR_DEPRECATED_CAPITALIZED), 2);
1172+
ZVAL_STR(&attr->args[0].value, zend_string_init("8.6", strlen("8.6"), 1));
1173+
attr->args[0].name = ZSTR_KNOWN(ZEND_STR_SINCE);
1174+
ZVAL_STR(&attr->args[1].value, zend_string_init("use Uri\\WhatWg\\UrlValidationErrorType::InvalidReverseSolidus instead", strlen("use Uri\\WhatWg\\UrlValidationErrorType::InvalidReverseSolidus instead"), 1));
1175+
attr->args[1].name = ZSTR_KNOWN(ZEND_STR_MESSAGE);
1176+
}
1177+
11141178
static PHP_MINIT_FUNCTION(uri)
11151179
{
11161180
php_uri_ce_rfc3986_uri = register_class_Uri_Rfc3986_Uri();
@@ -1140,6 +1204,7 @@ static PHP_MINIT_FUNCTION(uri)
11401204
php_uri_ce_whatwg_url_host_type = register_class_Uri_WhatWg_UrlHostType();
11411205
php_uri_ce_whatwg_url_validation_error = register_class_Uri_WhatWg_UrlValidationError();
11421206
php_uri_ce_whatwg_url_validation_error_type = register_class_Uri_WhatWg_UrlValidationErrorType();
1207+
php_uri_register_invalid_reverse_solidus_alias(php_uri_ce_whatwg_url_validation_error_type);
11431208

11441209
zend_hash_init(&uri_parsers, 4, NULL, NULL, true);
11451210

ext/uri/php_uri.stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ enum UrlValidationErrorType
153153
case InvalidUrlUnit;
154154
case SpecialSchemeMissingFollowingSolidus;
155155
case MissingSchemeNonRelativeUrl;
156-
case InvalidReverseSoldius;
156+
case InvalidReverseSolidus;
157157
case InvalidCredentials;
158158
case HostMissing;
159159
case PortOutOfRange;

ext/uri/php_uri_arginfo.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/uri/php_uri_decl.h

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
Uri\WhatWg\UrlValidationErrorType keeps a deprecated alias for the InvalidReverseSoldius typo
3+
--EXTENSIONS--
4+
uri
5+
--FILE--
6+
<?php
7+
$caseNames = array_map(
8+
static fn($case) => $case->name,
9+
Uri\WhatWg\UrlValidationErrorType::cases(),
10+
);
11+
12+
// The correctly spelled case exists; the misspelled alias is not a case.
13+
var_dump(in_array('InvalidReverseSolidus', $caseNames, true));
14+
var_dump(in_array('InvalidReverseSoldius', $caseNames, true));
15+
16+
$type = Uri\WhatWg\UrlValidationErrorType::InvalidReverseSolidus;
17+
18+
// The deprecated alias resolves to the same case and emits a deprecation notice.
19+
$alias = Uri\WhatWg\UrlValidationErrorType::InvalidReverseSoldius;
20+
var_dump($alias === $type);
21+
22+
// Serialization uses the correct spelling and round-trips.
23+
$serialized = serialize($type);
24+
var_dump($serialized);
25+
var_dump(unserialize($serialized) === $type);
26+
27+
$errors = [];
28+
Uri\WhatWg\Url::parse("https:\\\\example.com", null, $errors);
29+
var_dump(in_array(
30+
Uri\WhatWg\UrlValidationErrorType::InvalidReverseSolidus,
31+
array_map(static fn($error) => $error->type, $errors),
32+
true,
33+
));
34+
?>
35+
--EXPECTF--
36+
bool(true)
37+
bool(false)
38+
39+
Deprecated: Constant Uri\WhatWg\UrlValidationErrorType::InvalidReverseSoldius is deprecated since 8.6, use Uri\WhatWg\UrlValidationErrorType::InvalidReverseSolidus instead in %s on line %d
40+
bool(true)
41+
string(63) "E:55:"Uri\WhatWg\UrlValidationErrorType:InvalidReverseSolidus";"
42+
bool(true)
43+
bool(true)

ext/uri/uri_parser_whatwg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ static const char *fill_errors(zval *errors)
167167
ZVAL_TRUE(&failure);
168168
break;
169169
case LXB_URL_ERROR_TYPE_INVALID_REVERSE_SOLIDUS:
170-
error_str = "InvalidReverseSoldius";
170+
error_str = "InvalidReverseSolidus";
171171
ZVAL_FALSE(&failure);
172172
break;
173173
case LXB_URL_ERROR_TYPE_INVALID_CREDENTIALS:

0 commit comments

Comments
 (0)