uri: Do not create new UrlValidationErrorType objects (#19009)

`zend_enum_new()` is not intended to be used “at runtime”, since it will create
a new object, breaking the singleton property. Instead
`zend_enum_get_case_cstr()` must be used.
This commit is contained in:
Tim Düsterhus 2025-07-02 13:57:50 +02:00 committed by GitHub
parent f906fad985
commit ec8b016d08
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 59 additions and 39 deletions

4
NEWS
View file

@ -2,6 +2,10 @@ PHP NEWS
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.5.0alpha2 ?? ??? ????, PHP 8.5.0alpha2
- URI:
. Return the singleton UrlValidationErrorType instances from Uri\WhatWg\Url
instead of creating new objects that are different from the singleton.
(timwolla)
03 Jul 2025, PHP 8.5.0alpha1 03 Jul 2025, PHP 8.5.0alpha1

View file

@ -73,7 +73,7 @@ static void lexbor_cleanup_parser(void)
* When errors is NULL, the caller is not interested in the additional error information, * When errors is NULL, the caller is not interested in the additional error information,
* so the function does nothing. * so the function does nothing.
*/ */
static zend_string *fill_errors(zval *errors) static const char *fill_errors(zval *errors)
{ {
if (errors == NULL) { if (errors == NULL) {
return NULL; return NULL;
@ -87,140 +87,138 @@ static zend_string *fill_errors(zval *errors)
return NULL; return NULL;
} }
zend_string *result = NULL; const char *result = NULL;
lexbor_plog_entry_t *lxb_error; lexbor_plog_entry_t *lxb_error;
while ((lxb_error = lexbor_array_obj_pop(&lexbor_parser.log->list)) != NULL) { while ((lxb_error = lexbor_array_obj_pop(&lexbor_parser.log->list)) != NULL) {
zval error; zval error;
object_init_ex(&error, uri_whatwg_url_validation_error_ce); object_init_ex(&error, uri_whatwg_url_validation_error_ce);
zend_update_property_string(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZEND_STRL("context"), (const char *) lxb_error->data); zend_update_property_string(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZEND_STRL("context"), (const char *) lxb_error->data);
zend_string *error_str; const char *error_str;
zval failure; zval failure;
switch (lxb_error->id) { switch (lxb_error->id) {
case LXB_URL_ERROR_TYPE_DOMAIN_TO_ASCII: case LXB_URL_ERROR_TYPE_DOMAIN_TO_ASCII:
error_str = ZSTR_INIT_LITERAL("DomainToAscii", false); error_str = "DomainToAscii";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_DOMAIN_TO_UNICODE: case LXB_URL_ERROR_TYPE_DOMAIN_TO_UNICODE:
error_str = ZSTR_INIT_LITERAL("DomainToUnicode", false); error_str = "DomainToUnicode";
ZVAL_FALSE(&failure); ZVAL_FALSE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_DOMAIN_INVALID_CODE_POINT: case LXB_URL_ERROR_TYPE_DOMAIN_INVALID_CODE_POINT:
error_str = ZSTR_INIT_LITERAL("DomainInvalidCodePoint", false); error_str = "DomainInvalidCodePoint";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_HOST_INVALID_CODE_POINT: case LXB_URL_ERROR_TYPE_HOST_INVALID_CODE_POINT:
error_str = ZSTR_INIT_LITERAL("HostInvalidCodePoint", false); error_str = "HostInvalidCodePoint";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV4_EMPTY_PART: case LXB_URL_ERROR_TYPE_IPV4_EMPTY_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4EmptyPart", false); error_str = "Ipv4EmptyPart";
ZVAL_FALSE(&failure); ZVAL_FALSE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV4_TOO_MANY_PARTS: case LXB_URL_ERROR_TYPE_IPV4_TOO_MANY_PARTS:
error_str = ZSTR_INIT_LITERAL("Ipv4TooManyParts", false); error_str = "Ipv4TooManyParts";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV4_NON_NUMERIC_PART: case LXB_URL_ERROR_TYPE_IPV4_NON_NUMERIC_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4NonNumericPart", false); error_str = "Ipv4NonNumericPart";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV4_NON_DECIMAL_PART: case LXB_URL_ERROR_TYPE_IPV4_NON_DECIMAL_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4NonDecimalPart", false); error_str = "Ipv4NonDecimalPart";
ZVAL_FALSE(&failure); ZVAL_FALSE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV4_OUT_OF_RANGE_PART: case LXB_URL_ERROR_TYPE_IPV4_OUT_OF_RANGE_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4OutOfRangePart", false); error_str = "Ipv4OutOfRangePart";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV6_UNCLOSED: case LXB_URL_ERROR_TYPE_IPV6_UNCLOSED:
error_str = ZSTR_INIT_LITERAL("Ipv6Unclosed", false); error_str = "Ipv6Unclosed";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV6_INVALID_COMPRESSION: case LXB_URL_ERROR_TYPE_IPV6_INVALID_COMPRESSION:
error_str = ZSTR_INIT_LITERAL("Ipv6InvalidCompression", false); error_str = "Ipv6InvalidCompression";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV6_TOO_MANY_PIECES: case LXB_URL_ERROR_TYPE_IPV6_TOO_MANY_PIECES:
error_str = ZSTR_INIT_LITERAL("Ipv6TooManyPieces", false); error_str = "Ipv6TooManyPieces";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV6_MULTIPLE_COMPRESSION: case LXB_URL_ERROR_TYPE_IPV6_MULTIPLE_COMPRESSION:
error_str = ZSTR_INIT_LITERAL("Ipv6MultipleCompression", false); error_str = "Ipv6MultipleCompression";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV6_INVALID_CODE_POINT: case LXB_URL_ERROR_TYPE_IPV6_INVALID_CODE_POINT:
error_str = ZSTR_INIT_LITERAL("Ipv6InvalidCodePoint", false); error_str = "Ipv6InvalidCodePoint";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV6_TOO_FEW_PIECES: case LXB_URL_ERROR_TYPE_IPV6_TOO_FEW_PIECES:
error_str = ZSTR_INIT_LITERAL("Ipv6TooFewPieces", false); error_str = "Ipv6TooFewPieces";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_MANY_PIECES: case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_MANY_PIECES:
error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6TooManyPieces", false); error_str = "Ipv4InIpv6TooManyPieces";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_INVALID_CODE_POINT: case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_INVALID_CODE_POINT:
error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6InvalidCodePoint", false); error_str = "Ipv4InIpv6InvalidCodePoint";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_OUT_OF_RANGE_PART: case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_OUT_OF_RANGE_PART:
error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6OutOfRangePart", false); error_str = "Ipv4InIpv6OutOfRangePart";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_FEW_PARTS: case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_FEW_PARTS:
error_str = ZSTR_INIT_LITERAL("Ipv4InIpv6TooFewParts", false); error_str = "Ipv4InIpv6TooFewParts";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_INVALID_URL_UNIT: case LXB_URL_ERROR_TYPE_INVALID_URL_UNIT:
error_str = ZSTR_INIT_LITERAL("InvalidUrlUnit", false); error_str = "InvalidUrlUnit";
ZVAL_FALSE(&failure); ZVAL_FALSE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_SPECIAL_SCHEME_MISSING_FOLLOWING_SOLIDUS: case LXB_URL_ERROR_TYPE_SPECIAL_SCHEME_MISSING_FOLLOWING_SOLIDUS:
error_str = ZSTR_INIT_LITERAL("SpecialSchemeMissingFollowingSolidus", false); error_str = "SpecialSchemeMissingFollowingSolidus";
ZVAL_FALSE(&failure); ZVAL_FALSE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_MISSING_SCHEME_NON_RELATIVE_URL: case LXB_URL_ERROR_TYPE_MISSING_SCHEME_NON_RELATIVE_URL:
error_str = ZSTR_INIT_LITERAL("MissingSchemeNonRelativeUrl", false); error_str = "MissingSchemeNonRelativeUrl";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_INVALID_REVERSE_SOLIDUS: case LXB_URL_ERROR_TYPE_INVALID_REVERSE_SOLIDUS:
error_str = ZSTR_INIT_LITERAL("InvalidReverseSoldius", false); error_str = "InvalidReverseSoldius";
ZVAL_FALSE(&failure); ZVAL_FALSE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_INVALID_CREDENTIALS: case LXB_URL_ERROR_TYPE_INVALID_CREDENTIALS:
error_str = ZSTR_INIT_LITERAL("InvalidCredentials", false); error_str = "InvalidCredentials";
ZVAL_FALSE(&failure); ZVAL_FALSE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_HOST_MISSING: case LXB_URL_ERROR_TYPE_HOST_MISSING:
error_str = ZSTR_INIT_LITERAL("HostMissing", false); error_str = "HostMissing";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_PORT_OUT_OF_RANGE: case LXB_URL_ERROR_TYPE_PORT_OUT_OF_RANGE:
error_str = ZSTR_INIT_LITERAL("PortOutOfRange", false); error_str = "PortOutOfRange";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_PORT_INVALID: case LXB_URL_ERROR_TYPE_PORT_INVALID:
error_str = ZSTR_INIT_LITERAL("PortInvalid", false); error_str = "PortInvalid";
ZVAL_TRUE(&failure); ZVAL_TRUE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER: case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER:
error_str = ZSTR_INIT_LITERAL("FileInvalidWindowsDriveLetter", false); error_str = "FileInvalidWindowsDriveLetter";
ZVAL_FALSE(&failure); ZVAL_FALSE(&failure);
break; break;
case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST: case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST:
error_str = ZSTR_INIT_LITERAL("FileInvalidWindowsDriveLetterHost", false); error_str = "FileInvalidWindowsDriveLetterHost";
ZVAL_FALSE(&failure); ZVAL_FALSE(&failure);
break; break;
EMPTY_SWITCH_DEFAULT_CASE() EMPTY_SWITCH_DEFAULT_CASE()
} }
zval error_type; zval error_type;
zend_enum_new(&error_type, uri_whatwg_url_validation_error_type_ce, error_str, NULL); ZVAL_OBJ(&error_type, zend_enum_get_case_cstr(uri_whatwg_url_validation_error_type_ce, error_str));
zend_update_property_ex(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZSTR_KNOWN(ZEND_STR_TYPE), &error_type); zend_update_property_ex(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZSTR_KNOWN(ZEND_STR_TYPE), &error_type);
zend_string_release_ex(error_str, false);
zval_ptr_dtor(&error_type);
zend_update_property(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZEND_STRL("failure"), &failure); zend_update_property(uri_whatwg_url_validation_error_ce, Z_OBJ(error), ZEND_STRL("failure"), &failure);
@ -236,14 +234,14 @@ static zend_string *fill_errors(zval *errors)
static void throw_invalid_url_exception_during_write(zval *errors, const char *component) static void throw_invalid_url_exception_during_write(zval *errors, const char *component)
{ {
zend_string *reason = fill_errors(errors); const char *reason = fill_errors(errors);
zend_object *exception = zend_throw_exception_ex( zend_object *exception = zend_throw_exception_ex(
uri_whatwg_invalid_url_exception_ce, uri_whatwg_invalid_url_exception_ce,
0, 0,
"The specified %s is malformed%s%s%s", "The specified %s is malformed%s%s%s",
component, component,
reason ? " (" : "", reason ? " (" : "",
reason ? ZSTR_VAL(reason) : "", reason ? reason : "",
reason ? ")" : "" reason ? ")" : ""
); );
zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors); zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors);
@ -567,10 +565,10 @@ lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexb
lexbor_cleanup_parser(); lexbor_cleanup_parser();
lxb_url_t *url = lxb_url_parse(&lexbor_parser, lexbor_base_url, (unsigned char *) ZSTR_VAL(uri_str), ZSTR_LEN(uri_str)); lxb_url_t *url = lxb_url_parse(&lexbor_parser, lexbor_base_url, (unsigned char *) ZSTR_VAL(uri_str), ZSTR_LEN(uri_str));
zend_string *reason = fill_errors(errors); const char *reason = fill_errors(errors);
if (url == NULL && !silent) { if (url == NULL && !silent) {
zend_object *exception = zend_throw_exception_ex(uri_whatwg_invalid_url_exception_ce, 0, "The specified URI is malformed%s%s%s", reason ? " (" : "", reason ? ZSTR_VAL(reason) : "", reason ? ")" : ""); zend_object *exception = zend_throw_exception_ex(uri_whatwg_invalid_url_exception_ce, 0, "The specified URI is malformed%s%s%s", reason ? " (" : "", reason ? reason : "", reason ? ")" : "");
zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors); zend_update_property(exception->ce, exception, ZEND_STRL("errors"), errors);
} }

18
ext/uri/tests/054.phpt Normal file
View file

@ -0,0 +1,18 @@
--TEST--
Test UrlValidationErrorType singleton
--EXTENSIONS--
uri
--FILE--
<?php
try {
new \Uri\WhatWg\Url('http://localhost:99999');
} catch (Uri\WhatWg\InvalidUrlException $e) {
echo $e->getMessage() . "\n";
var_dump($e->errors[0]->type === \Uri\WhatWg\UrlValidationErrorType::PortOutOfRange);
}
?>
--EXPECT--
The specified URI is malformed (PortOutOfRange)
bool(true)