Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ PHP NEWS
the Uri\WhatWg\Url parser. (timwolla)
. Reject out-of-range ports when using the Uri\Rfc3986\Uri parser.
(timwolla)
. Return null instead of 0 for Uri\Rfc3986\Uri::getPort() when the
URI contains an empty port. (timwolla)
. Clean up naming of internal API. (timwolla)

28 Aug 2025, PHP 8.5.0beta2
Expand Down
31 changes: 31 additions & 0 deletions ext/uri/tests/059.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
Test empty ports become null
--EXTENSIONS--
uri
--FILE--
<?php

$uri = new \Uri\Rfc3986\Uri('https://example.com:');
var_dump($uri, $uri->getPort());

?>
--EXPECTF--
object(Uri\Rfc3986\Uri)#%d (8) {
["scheme"]=>
string(5) "https"
["username"]=>
NULL
["password"]=>
NULL
["host"]=>
string(11) "example.com"
["port"]=>
NULL
["path"]=>
string(0) ""
["query"]=>
NULL
["fragment"]=>
NULL
}
NULL
17 changes: 8 additions & 9 deletions ext/uri/uri_parser_rfc3986.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_port_read(const
{
const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode);

if (has_text_range(&uriparser_uri->portText)) {
if (has_text_range(&uriparser_uri->portText) && get_text_range_length(&uriparser_uri->portText) > 0) {
ZVAL_LONG(retval, port_str_to_zend_long_checked(uriparser_uri->portText.first, get_text_range_length(&uriparser_uri->portText)));
} else {
ZVAL_NULL(retval);
Expand Down Expand Up @@ -326,15 +326,14 @@ php_uri_parser_rfc3986_uris *php_uri_parser_rfc3986_parse_ex(const char *uri_str
/* Make the resulting URI independent of the 'uri_str'. */
uriMakeOwnerMmA(&uri, mm);

if (
has_text_range(&uri.portText)
&& port_str_to_zend_long_checked(uri.portText.first, get_text_range_length(&uri.portText)) == -1
) {
if (!silent) {
zend_throw_exception(uri_invalid_uri_exception_ce, "The port is out of range", 0);
}
if (has_text_range(&uri.portText) && get_text_range_length(&uri.portText) > 0) {
if (port_str_to_zend_long_checked(uri.portText.first, get_text_range_length(&uri.portText)) == -1) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: why is the separate if? It seems a bit off

Copy link
Member Author

Choose a reason for hiding this comment

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

The outer if is “checking if we have a port” and the inner if is “checking if the port is valid”. Two separate concerns, thus two separate if()s.

Copy link
Member

Choose a reason for hiding this comment

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

I find it strange because we are not interested in the former concern, only the latter is needed. But I don't mind the extra indentation too much to bother with this formatting nuance :)

if (!silent) {
zend_throw_exception(uri_invalid_uri_exception_ce, "The port is out of range", 0);
}

goto fail;
goto fail;
}
}

php_uri_parser_rfc3986_uris *uriparser_uris = uriparser_create_uris();
Expand Down