1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Add internal URI handling API (#19073)

Part of https://github.com/php/php-src/pull/14461. Related to https://wiki.php.net/rfc/url_parsing_api.
This commit is contained in:
Máté Kocsis
2025-08-19 18:35:09 +02:00
committed by GitHub
parent 504a633780
commit 1cff1815d0
94 changed files with 1239 additions and 317 deletions

13
NEWS
View File

@@ -12,6 +12,14 @@ PHP NEWS
error in PHP 9. (alexandre-daubois)
. Fixed OSS-Fuzz #439125710 (Pipe cannot be used in write context).
(nielsdos)
. Added support for configuring the URI parser for the FTP/FTPS as well as
the SSL/TLS stream wrappers as described in
https://wiki.php.net/rfc/url_parsing_api#plugability. (kocsismate)
- Filter:
. Added support for configuring the URI parser for FILTER_VALIDATE_URL
as described in https://wiki.php.net/rfc/url_parsing_api#plugability.
(kocsismate)
- ODBC:
. Remove ODBCVER and assume ODBC 3.5. (Calvin Buckley)
@@ -26,6 +34,11 @@ PHP NEWS
- Session:
. Added support for partitioned cookies. (nielsdos)
- SOAP:
. Added support for configuring the URI parser for SoapClient::_doRequest()
as described in https://wiki.php.net/rfc/url_parsing_api#plugability.
(kocsismate)
- SPL:
. Deprecate ArrayObject and ArrayIterator with objects. (Girgias)

View File

@@ -85,6 +85,9 @@ PHP 8.5 INTERNALS UPGRADE NOTES
. ext/standard/php_smart_string.h and ext/standard/php_smart_string_public.h
were removed. Use the corresponding headers in Zend/ instead.
- URI
. Internal API for URI handling was added via the php_uri_*() functions.
========================
2. Build system changes
========================

View File

@@ -16,10 +16,11 @@
+----------------------------------------------------------------------+
*/
#include "zend_exceptions.h"
#include "php_filter.h"
#include "filter_private.h"
#include "ext/standard/url.h"
#include "ext/pcre/php_pcre.h"
#include "ext/uri/php_uri.h"
#include "zend_multiply.h"
@@ -89,6 +90,8 @@
#define FORMAT_IPV4 4
#define FORMAT_IPV6 6
#define URL_OPTION_URI_PARSER_CLASS "uri_parser_class"
static bool _php_filter_validate_ipv6(const char *str, size_t str_len, int ip[8]);
static bool php_filter_parse_int(const char *str, size_t str_len, zend_long *ret) { /* {{{ */
@@ -591,7 +594,6 @@ static bool php_filter_is_valid_ipv6_hostname(const zend_string *s)
void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
{
php_url *url;
size_t old_len = Z_STRLEN_P(value);
php_filter_url(value, flags, option_array, charset);
@@ -600,52 +602,66 @@ void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
RETURN_VALIDATION_FAILED
}
/* Use parse_url - if it returns false, we return NULL */
url = php_url_parse_ex(Z_STRVAL_P(value), Z_STRLEN_P(value));
/* Parse options */
zval *option_val;
zend_string *parser_name;
int parser_name_set;
FETCH_STR_OPTION(parser_name, URL_OPTION_URI_PARSER_CLASS);
if (url == NULL) {
uri_handler_t *uri_handler = php_uri_get_handler(parser_name_set ? parser_name : NULL);
if (uri_handler == NULL) {
zend_value_error("%s(): \"uri_parser_class\" option has invalid value", get_active_function_name());
RETURN_VALIDATION_FAILED
}
if (url->scheme != NULL &&
(zend_string_equals_literal_ci(url->scheme, "http") || zend_string_equals_literal_ci(url->scheme, "https"))) {
/* Parse the URI - if it fails, we return NULL */
php_uri *uri = php_uri_parse_to_struct(uri_handler, Z_STRVAL_P(value), Z_STRLEN_P(value), URI_COMPONENT_READ_RAW, true);
if (uri == NULL) {
RETURN_VALIDATION_FAILED
}
if (url->host == NULL) {
goto bad_url;
if (uri->scheme != NULL &&
(zend_string_equals_literal_ci(uri->scheme, "http") || zend_string_equals_literal_ci(uri->scheme, "https"))) {
if (uri->host == NULL) {
php_uri_struct_free(uri);
RETURN_VALIDATION_FAILED
}
if (
/* Skipping these checks is possible because the new URI implementations perform comprehensive validations. */
strcmp(uri_handler->name, URI_PARSER_PHP) == 0 &&
/* An IPv6 enclosed by square brackets is a valid hostname.*/
!php_filter_is_valid_ipv6_hostname(url->host) &&
!php_filter_is_valid_ipv6_hostname(uri->host) &&
/* Validate domain.
* This includes a loose check for an IPv4 address. */
!php_filter_validate_domain_ex(url->host, FILTER_FLAG_HOSTNAME)
!php_filter_validate_domain_ex(uri->host, FILTER_FLAG_HOSTNAME)
) {
php_url_free(url);
php_uri_struct_free(uri);
RETURN_VALIDATION_FAILED
}
}
if (
url->scheme == NULL ||
/* some schemas allow the host to be empty */
(url->host == NULL && (!zend_string_equals_literal(url->scheme, "mailto") && !zend_string_equals_literal(url->scheme, "news") && !zend_string_equals_literal(url->scheme, "file"))) ||
((flags & FILTER_FLAG_PATH_REQUIRED) && url->path == NULL) || ((flags & FILTER_FLAG_QUERY_REQUIRED) && url->query == NULL)
if (uri->scheme == NULL ||
/* some schemes allow the host to be empty */
(uri->host == NULL && (!zend_string_equals_literal(uri->scheme, "mailto") && !zend_string_equals_literal(uri->scheme, "news") && !zend_string_equals_literal(uri->scheme, "file"))) ||
((flags & FILTER_FLAG_PATH_REQUIRED) && uri->path == NULL) || ((flags & FILTER_FLAG_QUERY_REQUIRED) && uri->query == NULL)
) {
bad_url:
php_url_free(url);
php_uri_struct_free(uri);
RETURN_VALIDATION_FAILED
}
if ((url->user != NULL && !is_userinfo_valid(url->user))
|| (url->pass != NULL && !is_userinfo_valid(url->pass))
if (strcmp(uri_handler->name, URI_PARSER_PHP) == 0 &&
(
(uri->user != NULL && !is_userinfo_valid(uri->user)) ||
(uri->password != NULL && !is_userinfo_valid(uri->password))
)
) {
php_url_free(url);
php_uri_struct_free(uri);
RETURN_VALIDATION_FAILED
}
php_url_free(url);
php_uri_struct_free(uri);
}
/* }}} */

184
ext/filter/tests/062.phpt Normal file
View File

@@ -0,0 +1,184 @@
--TEST--
filter_var() and FILTER_VALIDATE_URL with different URI parsers
--EXTENSIONS--
filter
--FILE--
<?php
function validateUrls(string $parserName)
{
$values = [
'http://example.com/index.html',
'http://www.example.com/index.php',
'http://www.example/img/test.png',
'http://www.example/img/dir/',
'http://www.example/img/dir',
'http://www.thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com/',
'http://toolongtoolongtoolongtoolongtoolongtoolongtoolongtoolongtoolongtoolong.com',
'http://eauBcFReEmjLcoZwI0RuONNnwU4H9r151juCaqTI5VeIP5jcYIqhx1lh5vV00l2rTs6y7hOp7rYw42QZiq6VIzjcYrRm8gFRMk9U9Wi1grL8Mr5kLVloYLthHgyA94QK3SaXCATklxgo6XvcbXIqAGG7U0KxTr8hJJU1p2ZQ2mXHmp4DhYP8N9SRuEKzaCPcSIcW7uj21jZqBigsLsNAXEzU8SPXZjmVQVtwQATPWeWyGW4GuJhjP4Q8o0.com',
'http://kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.CQ1oT5Uq3jJt6Uhy3VH9u3Gi5YhfZCvZVKgLlaXNFhVKB1zJxvunR7SJa.com.',
'http://kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58R.example.com',
'http://[2001:0db8:0000:85a3:0000:0000:ac1f:8001]',
'http://[2001:db8:0:85a3:0:0:ac1f:8001]:123/me.html',
'http://[2001:db8:0:85a3::ac1f:8001]/',
'http://[::1]',
'http://cont-ains.h-yph-en-s.com',
'http://..com',
'http://a.-bc.com',
'http://ab.cd-.com',
'http://-.abc.com',
'http://abc.-.abc.com',
'http://underscore_.example.com',
'http//www.example/wrong/url/',
'http:/www.example',
'file:///tmp/test.c',
'ftp://ftp.example.com/tmp/',
'/tmp/test.c',
'/',
'http://',
'http:/',
'http:',
'http',
'',
-1,
[],
'mailto:foo@bar.com',
'news:news.php.net',
'file://foo/bar',
"http://\r\n/bar",
"http://example.com:qq",
"http://example.com:-2",
"http://example.com:65536",
"http://example.com:65537",
];
foreach ($values as $value) {
var_dump(filter_var($value, FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName]));
}
var_dump(filter_var("qwe", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName]));
var_dump(filter_var("http://qwe", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName]));
var_dump(filter_var("http://", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName]));
var_dump(filter_var("/tmp/test", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName]));
var_dump(filter_var("http://www.example.com", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName]));
var_dump(filter_var("http://www.example.com", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName, "flags" => FILTER_FLAG_PATH_REQUIRED]));
var_dump(filter_var("http://www.example.com/path/at/the/server/", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName, "flags" => FILTER_FLAG_PATH_REQUIRED]));
var_dump(filter_var("http://www.example.com/index.html", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName, "flags" => FILTER_FLAG_QUERY_REQUIRED]));
var_dump(filter_var("http://www.example.com/index.php?a=b&c=d", FILTER_VALIDATE_URL, ["uri_parser_class" => $parserName, "flags" => FILTER_FLAG_QUERY_REQUIRED]));
}
echo "RFC3986:\n";
validateUrls(Uri\Rfc3986Uri::class);
echo "\nWHATWG:\n";
validateUrls(Uri\WhatWgUri::class);
echo "Done\n";
?>
--EXPECT--
RFC3986:
string(29) "http://example.com/index.html"
string(32) "http://www.example.com/index.php"
string(31) "http://www.example/img/test.png"
string(27) "http://www.example/img/dir/"
string(26) "http://www.example/img/dir"
string(79) "http://www.thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com/"
bool(false)
bool(false)
string(261) "http://kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.CQ1oT5Uq3jJt6Uhy3VH9u3Gi5YhfZCvZVKgLlaXNFhVKB1zJxvunR7SJa.com."
bool(false)
string(48) "http://[2001:0db8:0000:85a3:0000:0000:ac1f:8001]"
string(50) "http://[2001:db8:0:85a3:0:0:ac1f:8001]:123/me.html"
string(36) "http://[2001:db8:0:85a3::ac1f:8001]/"
string(12) "http://[::1]"
string(31) "http://cont-ains.h-yph-en-s.com"
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
string(18) "file:///tmp/test.c"
string(26) "ftp://ftp.example.com/tmp/"
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
string(18) "mailto:foo@bar.com"
string(17) "news:news.php.net"
string(14) "file://foo/bar"
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
string(10) "http://qwe"
bool(false)
bool(false)
string(22) "http://www.example.com"
bool(false)
string(42) "http://www.example.com/path/at/the/server/"
bool(false)
string(40) "http://www.example.com/index.php?a=b&c=d"
WHATWG:
string(29) "http://example.com/index.html"
string(32) "http://www.example.com/index.php"
string(31) "http://www.example/img/test.png"
string(27) "http://www.example/img/dir/"
string(26) "http://www.example/img/dir"
string(79) "http://www.thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com/"
bool(false)
bool(false)
string(261) "http://kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.kDTvHt1PPDgX5EiP2MwiXjcoWNOhhTuOVAUWJ3TmpBYCC9QoJV114LMYrV3Zl58.CQ1oT5Uq3jJt6Uhy3VH9u3Gi5YhfZCvZVKgLlaXNFhVKB1zJxvunR7SJa.com."
bool(false)
string(48) "http://[2001:0db8:0000:85a3:0000:0000:ac1f:8001]"
string(50) "http://[2001:db8:0:85a3:0:0:ac1f:8001]:123/me.html"
string(36) "http://[2001:db8:0:85a3::ac1f:8001]/"
string(12) "http://[::1]"
string(31) "http://cont-ains.h-yph-en-s.com"
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
string(18) "file:///tmp/test.c"
string(26) "ftp://ftp.example.com/tmp/"
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
string(18) "mailto:foo@bar.com"
string(17) "news:news.php.net"
string(14) "file://foo/bar"
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
string(10) "http://qwe"
bool(false)
bool(false)
string(22) "http://www.example.com"
bool(false)
string(42) "http://www.example.com/path/at/the/server/"
bool(false)
string(40) "http://www.example.com/index.php?a=b&c=d"
Done

View File

@@ -23,9 +23,10 @@
#include "php.h"
#include "ext/standard/file.h"
#include "ext/standard/url.h"
#include "ext/uri/php_uri.h"
#include "streams/php_streams_int.h"
#include "zend_smart_str.h"
#include "zend_exceptions.h"
#include "php_openssl.h"
#include "php_openssl_backend.h"
#include "php_network.h"
@@ -2627,23 +2628,29 @@ static zend_long php_openssl_get_crypto_method(
/* }}} */
static char *php_openssl_get_url_name(const char *resourcename,
size_t resourcenamelen, int is_persistent) /* {{{ */
size_t resourcenamelen, int is_persistent, php_stream_context *context) /* {{{ */
{
php_url *url;
if (!resourcename) {
return NULL;
}
url = php_url_parse_ex(resourcename, resourcenamelen);
if (!url) {
uri_handler_t *uri_handler = php_stream_context_get_uri_handler("ssl", context);
if (uri_handler == NULL) {
zend_value_error("%s(): Provided stream context has invalid value for the \"uri_parser_class\" option", get_active_function_name());
return NULL;
}
if (url->host) {
const char * host = ZSTR_VAL(url->host);
char * url_name = NULL;
size_t len = ZSTR_LEN(url->host);
uri_internal_t *internal_uri = php_uri_parse(uri_handler, resourcename, resourcenamelen, true);
if (internal_uri == NULL) {
return NULL;
}
char * url_name = NULL;
zval host_zv;
zend_result result = php_uri_get_host(internal_uri, URI_COMPONENT_READ_RAW, &host_zv);
if (result == SUCCESS && Z_TYPE(host_zv) == IS_STRING) {
const char * host = Z_STRVAL(host_zv);
size_t len = Z_STRLEN(host_zv);
/* skip trailing dots */
while (len && host[len-1] == '.') {
@@ -2653,13 +2660,12 @@ static char *php_openssl_get_url_name(const char *resourcename,
if (len) {
url_name = pestrndup(host, len, is_persistent);
}
php_url_free(url);
return url_name;
}
php_url_free(url);
return NULL;
php_uri_free(internal_uri);
zval_ptr_dtor(&host_zv);
return url_name;
}
/* }}} */
@@ -2757,7 +2763,7 @@ php_stream *php_openssl_ssl_socket_factory(const char *proto, size_t protolen,
#endif
}
sslsock->url_name = php_openssl_get_url_name(resourcename, resourcenamelen, !!persistent_id);
sslsock->url_name = php_openssl_get_url_name(resourcename, resourcenamelen, !!persistent_id, context);
return stream;
}

View File

@@ -8,7 +8,9 @@ $standard = new ReflectionExtension('standard');
var_dump($standard->getDependencies());
?>
--EXPECTF--
array(1) {
array(%d) {
["uri"]=>
%s(8) "Required"
["session"]=>
%s(8) "Optional"
}

View File

@@ -18,6 +18,7 @@
#include "php_soap.h"
#include "ext/hash/php_hash.h" /* For php_hash_bin2hex() */
#include "ext/uri/php_uri.h"
static char *get_http_header_value_nodup(char *headers, char *type, size_t *len);
static char *get_http_header_value(char *headers, char *type);
@@ -162,7 +163,7 @@ void http_context_headers(php_stream_context* context,
}
}
static php_stream* http_connect(zval* this_ptr, php_url *phpurl, int use_ssl, php_stream_context *context, int *use_proxy)
static php_stream* http_connect(zval* this_ptr, php_uri *uri, int use_ssl, php_stream_context *context, int *use_proxy)
{
php_stream *stream;
zval *tmp, ssl_proxy_peer_name;
@@ -182,8 +183,8 @@ static php_stream* http_connect(zval* this_ptr, php_url *phpurl, int use_ssl, ph
port = Z_LVAL_P(proxy_port);
*use_proxy = 1;
} else {
host = ZSTR_VAL(phpurl->host);
port = phpurl->port;
host = ZSTR_VAL(uri->host);
port = uri->port;
}
tmp = Z_CLIENT_CONNECTION_TIMEOUT_P(this_ptr);
@@ -247,21 +248,21 @@ static php_stream* http_connect(zval* this_ptr, php_url *phpurl, int use_ssl, ph
/* Set peer_name or name verification will try to use the proxy server name */
if (!context || (tmp = php_stream_context_get_option(context, "ssl", "peer_name")) == NULL) {
ZVAL_STR_COPY(&ssl_proxy_peer_name, phpurl->host);
ZVAL_STR_COPY(&ssl_proxy_peer_name, uri->host);
php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_name", &ssl_proxy_peer_name);
zval_ptr_dtor(&ssl_proxy_peer_name);
}
smart_str_append_const(&soap_headers, "CONNECT ");
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->host));
smart_str_appends(&soap_headers, ZSTR_VAL(uri->host));
smart_str_appendc(&soap_headers, ':');
smart_str_append_unsigned(&soap_headers, phpurl->port);
smart_str_append_unsigned(&soap_headers, uri->port);
smart_str_append_const(&soap_headers, " HTTP/1.1\r\n");
smart_str_append_const(&soap_headers, "Host: ");
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->host));
if (phpurl->port != 80) {
smart_str_appends(&soap_headers, ZSTR_VAL(uri->host));
if (uri->port != 80) {
smart_str_appendc(&soap_headers, ':');
smart_str_append_unsigned(&soap_headers, phpurl->port);
smart_str_append_unsigned(&soap_headers, uri->port);
}
smart_str_append_const(&soap_headers, "\r\n");
proxy_authentication(this_ptr, &soap_headers);
@@ -335,18 +336,15 @@ static bool in_domain(const zend_string *host, const zend_string *domain)
}
}
int make_http_soap_request(zval *this_ptr,
zend_string *buf,
char *location,
char *soapaction,
int soap_version,
zval *return_value)
{
int make_http_soap_request(
zval *this_ptr, zend_string *buf, zend_string *location, char *soapaction,
int soap_version, const zend_string *uri_parser_class, zval *return_value
) {
zend_string *request;
smart_str soap_headers = {0};
smart_str soap_headers_z = {0};
size_t err;
php_url *phpurl = NULL;
php_uri *uri = NULL;
php_stream *stream;
zval *tmp;
int use_proxy = 0;
@@ -432,8 +430,13 @@ int make_http_soap_request(zval *this_ptr,
stream = NULL;
}
if (location != NULL && location[0] != '\000') {
phpurl = php_url_parse(location);
if (location != NULL && ZSTR_VAL(location)[0] != '\000') {
uri_handler_t *uri_handler = php_uri_get_handler(uri_parser_class);
if (uri_handler == NULL) {
zend_argument_value_error(6, "must be a valid URI parser name");
return FALSE;
}
uri = php_uri_parse_to_struct(uri_handler, ZSTR_VAL(location), ZSTR_LEN(location), URI_COMPONENT_READ_RAW, true);
}
tmp = Z_CLIENT_STREAM_CONTEXT_P(this_ptr);
@@ -450,8 +453,10 @@ int make_http_soap_request(zval *this_ptr,
}
try_again:
if (phpurl == NULL || phpurl->host == NULL) {
if (phpurl != NULL) {php_url_free(phpurl);}
if (uri == NULL || uri->host == NULL) {
if (uri != NULL) {
php_uri_struct_free(uri);
}
if (request != buf) {
zend_string_release_ex(request, 0);
}
@@ -462,10 +467,10 @@ try_again:
}
use_ssl = 0;
if (phpurl->scheme != NULL && zend_string_equals_literal(phpurl->scheme, "https")) {
if (uri->scheme != NULL && zend_string_equals_literal(uri->scheme, "https")) {
use_ssl = 1;
} else if (phpurl->scheme == NULL || !zend_string_equals_literal(phpurl->scheme, "http")) {
php_url_free(phpurl);
} else if (uri->scheme == NULL || !zend_string_equals_literal(uri->scheme, "http")) {
php_uri_struct_free(uri);
if (request != buf) {
zend_string_release_ex(request, 0);
}
@@ -478,7 +483,7 @@ try_again:
old_allow_url_fopen = PG(allow_url_fopen);
PG(allow_url_fopen) = 1;
if (use_ssl && php_stream_locate_url_wrapper("https://", NULL, STREAM_LOCATE_WRAPPERS_ONLY) == NULL) {
php_url_free(phpurl);
php_uri_struct_free(uri);
if (request != buf) {
zend_string_release_ex(request, 0);
}
@@ -489,22 +494,22 @@ try_again:
return FALSE;
}
if (phpurl->port == 0) {
phpurl->port = use_ssl ? 443 : 80;
if (uri->port == 0) {
uri->port = use_ssl ? 443 : 80;
}
/* Check if request to the same host */
if (stream != NULL) {
php_url *orig;
php_uri *orig;
tmp = Z_CLIENT_HTTPURL_P(this_ptr);
if (Z_TYPE_P(tmp) == IS_OBJECT && instanceof_function(Z_OBJCE_P(tmp), soap_url_class_entry) &&
(orig = Z_SOAP_URL_P(tmp)->url) != NULL &&
(orig = Z_SOAP_URL_P(tmp)->uri) != NULL &&
((use_proxy && !use_ssl) ||
(((use_ssl && orig->scheme != NULL && zend_string_equals_literal(orig->scheme, "https")) ||
(!use_ssl && orig->scheme == NULL) ||
(!use_ssl && !zend_string_equals_literal(orig->scheme, "https"))) &&
zend_string_equals(orig->host, phpurl->host) &&
orig->port == phpurl->port))) {
zend_string_equals(orig->host, uri->host) &&
orig->port == uri->port))) {
} else {
ZVAL_NULL(Z_CLIENT_HTTPSOCKET_P(this_ptr));
php_stream_close(stream);
@@ -526,12 +531,12 @@ try_again:
}
if (!stream) {
stream = http_connect(this_ptr, phpurl, use_ssl, context, &use_proxy);
stream = http_connect(this_ptr, uri, use_ssl, context, &use_proxy);
if (stream) {
php_stream_to_zval(stream, Z_CLIENT_HTTPSOCKET_P(this_ptr));
ZVAL_LONG(Z_CLIENT_USE_PROXY_P(this_ptr), use_proxy);
} else {
php_url_free(phpurl);
php_uri_struct_free(uri);
if (request != buf) {
zend_string_release_ex(request, 0);
}
@@ -556,7 +561,7 @@ try_again:
object_init_ex(url_zval, soap_url_class_entry);
soap_url_object *url_obj = Z_SOAP_URL_P(url_zval);
url_obj->url = phpurl;
url_obj->uri = uri;
if (context &&
(tmp = php_stream_context_get_option(context, "http", "protocol_version")) != NULL &&
@@ -569,24 +574,24 @@ try_again:
smart_str_append_const(&soap_headers, "POST ");
if (use_proxy && !use_ssl) {
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->scheme));
smart_str_appends(&soap_headers, ZSTR_VAL(uri->scheme));
smart_str_append_const(&soap_headers, "://");
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->host));
smart_str_appends(&soap_headers, ZSTR_VAL(uri->host));
smart_str_appendc(&soap_headers, ':');
smart_str_append_unsigned(&soap_headers, phpurl->port);
smart_str_append_unsigned(&soap_headers, uri->port);
}
if (phpurl->path) {
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->path));
if (uri->path) {
smart_str_appends(&soap_headers, ZSTR_VAL(uri->path));
} else {
smart_str_appendc(&soap_headers, '/');
}
if (phpurl->query) {
if (uri->query) {
smart_str_appendc(&soap_headers, '?');
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->query));
smart_str_appends(&soap_headers, ZSTR_VAL(uri->query));
}
if (phpurl->fragment) {
if (uri->fragment) {
smart_str_appendc(&soap_headers, '#');
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->fragment));
smart_str_appends(&soap_headers, ZSTR_VAL(uri->fragment));
}
if (http_1_1) {
smart_str_append_const(&soap_headers, " HTTP/1.1\r\n");
@@ -594,10 +599,10 @@ try_again:
smart_str_append_const(&soap_headers, " HTTP/1.0\r\n");
}
smart_str_append_const(&soap_headers, "Host: ");
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->host));
if (phpurl->port != (use_ssl?443:80)) {
smart_str_appends(&soap_headers, ZSTR_VAL(uri->host));
if (uri->port != (use_ssl?443:80)) {
smart_str_appendc(&soap_headers, ':');
smart_str_append_unsigned(&soap_headers, phpurl->port);
smart_str_append_unsigned(&soap_headers, uri->port);
}
if (!http_1_1 || Z_TYPE_P(Z_CLIENT_KEEP_ALIVE_P(this_ptr)) == IS_FALSE) {
smart_str_append_const(&soap_headers, "\r\n"
@@ -739,14 +744,14 @@ try_again:
PHP_MD5Init(&md5ctx);
PHP_MD5Update(&md5ctx, (unsigned char*)"POST:", sizeof("POST:")-1);
if (phpurl->path) {
PHP_MD5Update(&md5ctx, (unsigned char*)ZSTR_VAL(phpurl->path), ZSTR_LEN(phpurl->path));
if (uri->path) {
PHP_MD5Update(&md5ctx, (unsigned char*)ZSTR_VAL(uri->path), ZSTR_LEN(uri->path));
} else {
PHP_MD5Update(&md5ctx, (unsigned char*)"/", 1);
}
if (phpurl->query) {
if (uri->query) {
PHP_MD5Update(&md5ctx, (unsigned char*)"?", 1);
PHP_MD5Update(&md5ctx, (unsigned char*)ZSTR_VAL(phpurl->query), ZSTR_LEN(phpurl->query));
PHP_MD5Update(&md5ctx, (unsigned char*)ZSTR_VAL(uri->query), ZSTR_LEN(uri->query));
}
PHP_MD5Final(hash, &md5ctx);
@@ -787,18 +792,18 @@ try_again:
smart_str_appendl(&soap_headers, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
}
smart_str_append_const(&soap_headers, "\", uri=\"");
if (phpurl->path) {
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->path));
if (uri->path) {
smart_str_appends(&soap_headers, ZSTR_VAL(uri->path));
} else {
smart_str_appendc(&soap_headers, '/');
}
if (phpurl->query) {
if (uri->query) {
smart_str_appendc(&soap_headers, '?');
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->query));
smart_str_appends(&soap_headers, ZSTR_VAL(uri->query));
}
if (phpurl->fragment) {
if (uri->fragment) {
smart_str_appendc(&soap_headers, '#');
smart_str_appends(&soap_headers, ZSTR_VAL(phpurl->fragment));
smart_str_appends(&soap_headers, ZSTR_VAL(uri->fragment));
}
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "qop", sizeof("qop")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
@@ -865,10 +870,10 @@ try_again:
zval *tmp;
if (((tmp = zend_hash_index_find(Z_ARRVAL_P(data), 1)) == NULL ||
Z_TYPE_P(tmp) != IS_STRING ||
strncmp(phpurl->path?ZSTR_VAL(phpurl->path):"/",Z_STRVAL_P(tmp),Z_STRLEN_P(tmp)) == 0) &&
strncmp(uri->path?ZSTR_VAL(uri->path):"/",Z_STRVAL_P(tmp),Z_STRLEN_P(tmp)) == 0) &&
((tmp = zend_hash_index_find(Z_ARRVAL_P(data), 2)) == NULL ||
Z_TYPE_P(tmp) != IS_STRING ||
in_domain(phpurl->host, Z_STR_P(tmp))) &&
in_domain(uri->host, Z_STR_P(tmp))) &&
(use_ssl || (tmp = zend_hash_index_find(Z_ARRVAL_P(data), 3)) == NULL)) {
if (!first_cookie) {
smart_str_appends(&soap_headers, "; ");
@@ -1047,15 +1052,15 @@ try_again:
}
}
if (!zend_hash_index_exists(Z_ARRVAL(zcookie), 1)) {
char *t = phpurl->path?ZSTR_VAL(phpurl->path):"/";
char *t = uri->path?ZSTR_VAL(uri->path):"/";
char *c = strrchr(t, '/');
if (c) {
add_index_stringl(&zcookie, 1, t, c-t);
}
}
if (!zend_hash_index_exists(Z_ARRVAL(zcookie), 2)) {
add_index_str(&zcookie, 2, phpurl->host);
GC_ADDREF(phpurl->host);
add_index_str(&zcookie, 2, uri->host);
GC_ADDREF(uri->host);
}
zend_symtable_update(Z_ARRVAL_P(cookies), name.s, &zcookie);
@@ -1143,39 +1148,46 @@ try_again:
char *loc;
if ((loc = get_http_header_value(ZSTR_VAL(http_headers), "Location:")) != NULL) {
php_url *new_url = php_url_parse(loc);
uri_handler_t *uri_handler = php_uri_get_handler(uri_parser_class);
if (uri_handler == NULL) {
efree(loc);
zend_argument_value_error(6, "must be a valid URI parser name");
return FALSE;
}
php_uri *new_uri = php_uri_parse_to_struct(uri_handler, loc, strlen(loc), URI_COMPONENT_READ_RAW, true);
efree(loc);
if (new_url != NULL) {
if (new_uri != NULL) {
zend_string_release_ex(http_headers, 0);
zend_string_release_ex(http_body, 0);
if (new_url->scheme == NULL && new_url->path != NULL) {
new_url->scheme = phpurl->scheme ? zend_string_copy(phpurl->scheme) : NULL;
new_url->host = phpurl->host ? zend_string_copy(phpurl->host) : NULL;
new_url->port = phpurl->port;
if (new_url->path && ZSTR_VAL(new_url->path)[0] != '/') {
if (phpurl->path) {
char *t = ZSTR_VAL(phpurl->path);
if (new_uri->scheme == NULL && new_uri->path != NULL) {
new_uri->scheme = new_uri->scheme ? zend_string_copy(new_uri->scheme) : NULL;
new_uri->host = new_uri->host ? zend_string_copy(new_uri->host) : NULL;
new_uri->port = new_uri->port;
if (new_uri->path && ZSTR_VAL(new_uri->path)[0] != '/') {
if (new_uri->path) {
char *t = ZSTR_VAL(new_uri->path);
char *p = strrchr(t, '/');
if (p) {
zend_string *s = zend_string_alloc((p - t) + ZSTR_LEN(new_url->path) + 2, 0);
zend_string *s = zend_string_alloc((p - t) + ZSTR_LEN(new_uri->path) + 2, 0);
strncpy(ZSTR_VAL(s), t, (p - t) + 1);
ZSTR_VAL(s)[(p - t) + 1] = 0;
strcat(ZSTR_VAL(s), ZSTR_VAL(new_url->path));
zend_string_release_ex(new_url->path, 0);
new_url->path = s;
strcat(ZSTR_VAL(s), ZSTR_VAL(new_uri->path));
zend_string_release_ex(new_uri->path, 0);
new_uri->path = s;
}
} else {
zend_string *s = zend_string_alloc(ZSTR_LEN(new_url->path) + 2, 0);
zend_string *s = zend_string_alloc(ZSTR_LEN(new_uri->path) + 2, 0);
ZSTR_VAL(s)[0] = '/';
ZSTR_VAL(s)[1] = 0;
strcat(ZSTR_VAL(s), ZSTR_VAL(new_url->path));
zend_string_release_ex(new_url->path, 0);
new_url->path = s;
strcat(ZSTR_VAL(s), ZSTR_VAL(new_uri->path));
zend_string_release_ex(new_uri->path, 0);
new_uri->path = s;
}
}
}
phpurl = new_url;
uri = new_uri;
if (--redirect_max < 1) {
add_soap_fault(this_ptr, "HTTP", "Redirection limit reached, aborting", NULL, NULL, SOAP_GLOBAL(lang_en));
@@ -1235,20 +1247,20 @@ try_again:
}
if (Z_TYPE(digest) != IS_UNDEF) {
php_url *new_url = emalloc(sizeof(php_url));
php_uri *new_uri = emalloc(sizeof(php_uri));
zval_ptr_dtor(Z_CLIENT_DIGEST_P(this_ptr));
ZVAL_COPY_VALUE(Z_CLIENT_DIGEST_P(this_ptr), &digest);
*new_url = *phpurl;
if (phpurl->scheme) phpurl->scheme = zend_string_copy(phpurl->scheme);
if (phpurl->user) phpurl->user = zend_string_copy(phpurl->user);
if (phpurl->pass) phpurl->pass = zend_string_copy(phpurl->pass);
if (phpurl->host) phpurl->host = zend_string_copy(phpurl->host);
if (phpurl->path) phpurl->path = zend_string_copy(phpurl->path);
if (phpurl->query) phpurl->query = zend_string_copy(phpurl->query);
if (phpurl->fragment) phpurl->fragment = zend_string_copy(phpurl->fragment);
phpurl = new_url;
*new_uri = *uri;
if (uri->scheme) uri->scheme = zend_string_copy(uri->scheme);
if (uri->user) uri->user = zend_string_copy(uri->user);
if (uri->password) uri->password = zend_string_copy(uri->password);
if (uri->host) uri->host = zend_string_copy(uri->host);
if (uri->path) uri->path = zend_string_copy(uri->path);
if (uri->query) uri->query = zend_string_copy(uri->query);
if (uri->fragment) uri->fragment = zend_string_copy(uri->fragment);
uri = new_uri;
efree(auth);
zend_string_release_ex(http_headers, 0);

View File

@@ -19,12 +19,10 @@
#ifndef PHP_HTTP_H
#define PHP_HTTP_H
int make_http_soap_request(zval *this_ptr,
zend_string *request,
char *location,
char *soapaction,
int soap_version,
zval *response);
int make_http_soap_request(
zval *this_ptr, zend_string *buf, zend_string *location, char *soapaction,
int soap_version, const zend_string *uri_parser_class, zval *return_value
);
int proxy_authentication(zval* this_ptr, smart_str* soap_headers);
int basic_authentication(zval* this_ptr, smart_str* soap_headers);

View File

@@ -27,6 +27,7 @@
#include "zend_smart_str.h"
#include "php_ini.h"
#include "SAPI.h"
#include "ext/uri/php_uri.h"
#include <libxml/parser.h>
#include <libxml/xpath.h>
@@ -255,7 +256,7 @@ static zend_always_inline zval *php_soap_deref(zval *zv) {
#define Z_CLIENT_LAST_RESPONSE_HEADERS_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 35)
typedef struct soap_url_object {
php_url *url;
php_uri *uri;
zend_object std;
} soap_url_object;

View File

@@ -233,9 +233,9 @@ static void soap_url_object_free(zend_object *obj)
{
soap_url_object *url_obj = soap_url_object_fetch(obj);
if (url_obj->url) {
php_url_free(url_obj->url);
url_obj->url = NULL;
if (url_obj->uri) {
php_uri_struct_free(url_obj->uri);
url_obj->uri = NULL;
}
zend_object_std_dtor(&url_obj->std);
@@ -2784,28 +2784,28 @@ PHP_METHOD(SoapClient, __getLastResponseHeaders)
/* {{{ SoapClient::__doRequest() */
PHP_METHOD(SoapClient, __doRequest)
{
zend_string *buf;
char *location, *action;
size_t location_size, action_size;
zend_string *buf, *location, *uri_parser_class = NULL;
char *action;
size_t action_size;
zend_long version;
bool one_way = 0;
zval *this_ptr = ZEND_THIS;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sssl|b",
if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSsl|bS!",
&buf,
&location, &location_size,
&location,
&action, &action_size,
&version, &one_way) == FAILURE) {
&version, &one_way, &uri_parser_class) == FAILURE) {
RETURN_THROWS();
}
if (SOAP_GLOBAL(features) & SOAP_WAIT_ONE_WAY_CALLS) {
one_way = 0;
}
if (one_way) {
if (make_http_soap_request(this_ptr, buf, location, action, version, NULL)) {
if (make_http_soap_request(this_ptr, buf, location, action, version, uri_parser_class, NULL)) {
RETURN_EMPTY_STRING();
}
} else if (make_http_soap_request(this_ptr, buf, location, action, version,
} else if (make_http_soap_request(this_ptr, buf, location, action, version, uri_parser_class,
return_value)) {
return;
}

View File

@@ -605,7 +605,7 @@ namespace {
public function __getLastResponseHeaders(): ?string {}
/** @tentative-return-type */
public function __doRequest(string $request, string $location, string $action, int $version, bool $oneWay = false): ?string {}
public function __doRequest(string $request, string $location, string $action, int $version, bool $oneWay = false, ?string $uriParserClass = null): ?string {}
/** @tentative-return-type */
public function __setCookie(string $name, ?string $value = null): void {}

View File

@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 4277993645a3f560c7a9971466fabf2d451bc92d */
* Stub hash: 24e266bf0933d5622f2a341db5b694ecb1740f13 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_use_soap_error_handler, 0, 0, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enable, _IS_BOOL, 0, "true")
@@ -124,6 +124,7 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SoapClient___doR
ZEND_ARG_TYPE_INFO(0, action, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, version, IS_LONG, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, oneWay, _IS_BOOL, 0, "false")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, uriParserClass, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SoapClient___setCookie, 0, 1, IS_VOID, 0)

View File

@@ -18,7 +18,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction("f");
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -33,7 +33,7 @@ class TestSoapClient extends SoapClient {
$this->server->addFunction('echoAnyElement');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -18,7 +18,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction('test');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -12,7 +12,7 @@ class LocalSoapClient extends SoapClient {
parent::__construct($wsdl, $options);
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"

View File

@@ -20,7 +20,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction('EchoString');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -22,7 +22,7 @@ class LocalSoapClient extends SoapClient {
$this->server->setClass('hello_world');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -21,7 +21,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction('foo');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
$xml = simplexml_load_string($request);
echo $xml->children("http://schemas.xmlsoap.org/soap/envelope/")->Body->children("http://test-uri")->children()->param1->asXML(),"\n";
unset($xml);

View File

@@ -21,7 +21,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction("getContinentList");
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo $request;
ob_start();
$this->server->handle($request);

View File

@@ -9,7 +9,7 @@ soap.wsdl_cache_enabled=0
class LocalSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope

View File

@@ -25,7 +25,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction('test');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -19,7 +19,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction("Test");
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo "$location\n";
ob_start();
$this->server->handle($request);

View File

@@ -5,7 +5,7 @@ soap
--FILE--
<?php
class MySoapClient extends SoapClient {
public function __doRequest($request, $location, $action, $version, $one_way = 0): string {
public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo $request, "\n";
return '';
}

View File

@@ -23,7 +23,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction('test');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -5,7 +5,7 @@ soap
--FILE--
<?php
class TestSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope

View File

@@ -5,7 +5,7 @@ soap
--FILE--
<?php
class TestSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0): never {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): never {
echo "$request\n";
exit;
}

View File

@@ -20,7 +20,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction('EchoString');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -23,7 +23,7 @@ class LocalSoapClient extends SoapClient {
$this->server->setClass('fp');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -25,7 +25,7 @@ class TestSoapClient extends SoapClient {
$this->server->addFunction('PostEvents');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo "$request\n";
ob_start();
$this->server->handle($request);

View File

@@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0
--FILE--
<?php
class TestSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0): never {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): never {
echo $request;
exit;
}

View File

@@ -24,7 +24,7 @@ class TestSoapClient extends SoapClient {
$this->server->addFunction('PostEvents');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo "$request\n";
$this->server->handle($request);
return $response;

View File

@@ -25,7 +25,7 @@ class TestSoapClient extends SoapClient {
$this->server->addFunction('PostEvents');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo "$request\n";
ob_start();
$this->server->handle($request);

View File

@@ -20,7 +20,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction('echoLong');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -7,7 +7,7 @@ soap.wsdl_cache=3
--FILE--
<?php
class TestSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

View File

@@ -21,7 +21,7 @@ class TestSoapClient extends SoapClient {
$this->server->addFunction('Test');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -19,7 +19,7 @@ class TestSoapClient extends SoapClient {
$this->server->addFunction('Test');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -22,7 +22,7 @@ class TestSoapClient extends SoapClient {
$this->server->addFunction('Test');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -21,7 +21,7 @@ class TestSoapClient extends SoapClient {
$this->server->addFunction('Test');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = 0, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0
--FILE--
<?php
class LocalSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope

View File

@@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0
--FILE--
<?php
class LocalSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

View File

@@ -23,7 +23,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction('test');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -19,7 +19,7 @@ class TestSoap extends SoapClient {
$this->server->addFunction("checkAuth");
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -16,7 +16,7 @@ class TestSoapClient extends SoapClient {
$this->server = new SoapServer($wsdl, $options);
$this->server->addFunction('test');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -8,7 +8,7 @@ soap.wsdl_cache_enabled=0
<?php
class TestSoapClient extends SoapClient
{
public function __doRequest($req, $loc, $act, $ver, $one_way = 0): string
public function __doRequest($req, $loc, $act, $ver, $one_way = 0, ?string $uriParserClass = null): string
{
return <<<XML
<?xml version="1.0" encoding="UTF-8"?>

View File

@@ -17,7 +17,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction('bar');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -57,9 +57,9 @@ $options = [
class BugSoapClient extends SoapClient
{
public function __doRequest($request, $location, $action, $version, $one_way = null): string
public function __doRequest($request, $location, $action, $version, $one_way = null, ?string $uriParserClass = null): string
{
$response = parent::__doRequest($request, $location, $action, $version, $one_way);
$response = parent::__doRequest($request, $location, $action, $version, $one_way, $uriParserClass);
var_dump(strlen($response));

View File

@@ -6,7 +6,7 @@ soap
<?php
class TestSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope

View File

@@ -23,7 +23,7 @@ class LocalSoapClient extends SoapClient {
$this->server->setObject(new testSoap());
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -5,7 +5,7 @@ soap
--FILE--
<?php
class XSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way=false): never {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): never {
echo self::$crash;
}
}

View File

@@ -14,7 +14,7 @@ class TestSoapClient extends SoapClient {
parent::__construct($wsdl, $options);
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://test.com/soap/v3/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>

View File

@@ -15,7 +15,7 @@ function soap_string_from_xml($str)
}
class TestSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0): ?string {
function __doRequest($request, $location, $action, $version, $one_way = 0, ?string $uriParserClass = null): ?string {
$res='<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>

View File

@@ -9,7 +9,7 @@ soap.wsdl_cache_enabled=0
#[AllowDynamicProperties]
class MySoapClient extends SoapClient {
public function __doRequest($request, $location, $action, $version, $one_way = 0): string {
public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo $request, "\n";
return '';
}

View File

@@ -5,7 +5,7 @@ soap
--FILE--
<?php
class MySoapClient extends SoapClient {
public function __doRequest($request, $location, $action, $version, $one_way = 0): string {
public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo $request, PHP_EOL;
return '';
}

View File

@@ -7,7 +7,7 @@ soap
#[AllowDynamicProperties]
class MySoapClient extends SoapClient {
public function __doRequest($request, $location, $action, $version, $one_way = 0): string {
public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo $request, "\n";
return '';
}

View File

@@ -9,7 +9,7 @@ soap.wsdl_cache_enabled=0
class bug70875 extends SOAPClient
{
public function __doRequest($request, $location, $action, $version, $one_way = 0): never
public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): never
{
die("no SIGSEGV");
}

View File

@@ -6,7 +6,7 @@ soap
<?php
$client = new class(null, [ 'location' => '', 'uri' => 'http://example.org']) extends SoapClient {
public function __doRequest($request, $location, $action, $version, $one_way = 0): string {
public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo $request;
return '';
}

View File

@@ -6,7 +6,7 @@ soap
<?php
$client = new class(null, ['location' => '', 'uri' => 'http://example.org']) extends SoapClient {
public function __doRequest($request, $location, $action, $version, $one_way = 0): string {
public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo $request, "\n";
return '';
}

View File

@@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0
--FILE--
<?php
class LocalSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:test.example.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sf="urn:object.test.example.org"><soapenv:Body><queryResponse><result xsi:type="QueryResult"><done>true</done><queryLocator xsi:nil="true"/><records xsi:type="sf:genericObject"><sf:type>CampaignMember</sf:type><sf:Id>00vi0000011VMgeAAG</sf:Id><sf:Id>00vi0000011VMgeAAG</sf:Id><sf:CampaignId>701i0000001lreeAAA</sf:CampaignId><sf:Status>Sent</sf:Status><sf:ContactId xsi:nil="true"/><sf:LeadId>00Qi000001UrbYFEAZ</sf:LeadId><sf:Contact xsi:nil="true"/><sf:Lead xsi:type="sf:genericObject"><sf:type>Lead</sf:type><sf:Id xsi:nil="true"/><sf:Email>angela.lansbury@cbs.com</sf:Email></sf:Lead></records><size>1</size></result></queryResponse></soapenv:Body></soapenv:Envelope>
EOF;

View File

@@ -5,7 +5,7 @@ soap
--FILE--
<?php
class MySoapClient extends SoapClient {
public function __doRequest($request, $location, $action, $version, $one_way = 0): string {
public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo $request, "\n";
return '';
}

View File

@@ -9,7 +9,7 @@ $client = new class(__DIR__ . '/bug77410.wsdl', [
'cache_wsdl' => WSDL_CACHE_NONE,
'trace' => 1,
]) extends SoapClient {
public function __doRequest($request, $location, $action, $version, $one_way = 0): string {
public function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo $request, "\n";
return '';
}

View File

@@ -9,7 +9,7 @@ YuanchengJiang
$wsdl = __DIR__."/bug35142.wsdl";
class TestSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0): ?string {
function __doRequest($request, $location, $action, $version, $one_way = 0, ?string $uriParserClass = null): ?string {
var_dump($request);
return '';
}

View File

@@ -7,7 +7,7 @@ soap
--FILE--
<?php
class TestSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = false): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>

View File

@@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0
--FILE--
<?php
class TestSoapClient extends SoapClient{
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>

View File

@@ -34,7 +34,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction("f");
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -42,7 +42,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction("f");
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0
--FILE--
<?php
class TestSoapClient extends SoapClient{
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>

View File

@@ -39,7 +39,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction("f");
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -39,7 +39,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction("f");
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -28,7 +28,7 @@ enum NonBackedEnum
}
class TestSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0): ?string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): ?string {
echo $request;
}
}

View File

@@ -15,7 +15,7 @@ $test2["a"] = "a";
$test2[] =& $test2;
class TestSoapClient extends SoapClient {
public function __doRequest(string $request, string $location, string $action, int $version, bool $oneWay = false): ?string
public function __doRequest(string $request, string $location, string $action, int $version, bool $oneWay = false, ?string $uriParserClass = null): ?string
{
die($request);
}

View File

@@ -18,6 +18,7 @@ class TestSoapClient extends SoapClient {
$action,
$version,
$one_way = false,
?string $uriParserClass = null,
): ?string {
die($request);
}

View File

@@ -17,7 +17,7 @@ class LocalSoapClient extends SoapClient {
$this->server->addFunction('Add');
}
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();

View File

@@ -8,7 +8,7 @@ soap.wsdl_cache_enabled=0
--FILE--
<?php
class TestSoapClient extends SoapClient{
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>

View File

@@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0
--FILE--
<?php
class TestSoapClient extends SoapClient{
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
echo $request;
exit;
}

View File

@@ -8,7 +8,7 @@ soap.wsdl_cache_enabled=0
--FILE--
<?php
class TestSoapClient extends SoapClient{
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>

View File

@@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0
--FILE--
<?php
class TestSoapClient extends SoapClient{
function __doRequest($request, $location, $action, $version, $one_way = 0): never {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): never {
echo $request;
exit;
}

View File

@@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0
--FILE--
<?php
class TestSoapClient extends SoapClient{
function __doRequest($request, $location, $action, $version, $one_way = 0): string {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): string {
return <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.nothing.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body>

View File

@@ -7,7 +7,7 @@ soap.wsdl_cache_enabled=0
--FILE--
<?php
class TestSoapClient extends SoapClient{
function __doRequest($request, $location, $action, $version, $one_way = 0): never {
function __doRequest($request, $location, $action, $version, $one_way = false, ?string $uriParserClass = null): never {
echo $request;
exit;
}

View File

@@ -141,6 +141,7 @@ static void user_shutdown_function_dtor(zval *zv);
static void user_tick_function_dtor(user_tick_function_entry *tick_function_entry);
static const zend_module_dep standard_deps[] = { /* {{{ */
ZEND_MOD_REQUIRED("uri")
ZEND_MOD_OPTIONAL("session")
ZEND_MOD_END
};
@@ -304,6 +305,7 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */
BASIC_MINIT_SUBMODULE(user_filters)
BASIC_MINIT_SUBMODULE(password)
BASIC_MINIT_SUBMODULE(image)
BASIC_MINIT_SUBMODULE(url)
#ifdef ZTS
BASIC_MINIT_SUBMODULE(localeconv)

View File

@@ -21,6 +21,7 @@
#include "php_globals.h"
#include "php_network.h"
#include "php_ini.h"
#include "zend_exceptions.h"
#include <stdio.h>
#include <stdlib.h>
@@ -38,6 +39,7 @@
#endif
#include "php_standard.h"
#include "ext/uri/php_uri.h"
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
@@ -124,16 +126,22 @@ static int php_stream_ftp_stream_close(php_stream_wrapper *wrapper, php_stream *
/* {{{ php_ftp_fopen_connect */
static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char *path, const char *mode, int options,
zend_string **opened_path, php_stream_context *context, php_stream **preuseid,
php_url **presource, int *puse_ssl, int *puse_ssl_on_data)
php_uri **presource, int *puse_ssl, int *puse_ssl_on_data)
{
php_stream *stream = NULL, *reuseid = NULL;
php_url *resource = NULL;
php_uri *resource = NULL;
int result, use_ssl, use_ssl_on_data = 0;
char tmp_line[512];
char *transport;
int transport_len;
resource = php_url_parse(path);
uri_handler_t *uri_handler = php_stream_context_get_uri_handler("ftp", context);
if (uri_handler == NULL) {
zend_value_error("%s(): Provided stream context has invalid value for the \"uri_parser_class\" option", get_active_function_name());
return NULL;
}
resource = php_uri_parse_to_struct(uri_handler, path, strlen(path), URI_COMPONENT_READ_RAW, true);
if (resource == NULL || resource->path == NULL) {
if (resource && presource) {
*presource = resource;
@@ -254,12 +262,12 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char
if (result >= 300 && result <= 399) {
php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, tmp_line, 0);
if (resource->pass != NULL) {
ZSTR_LEN(resource->pass) = php_raw_url_decode(ZSTR_VAL(resource->pass), ZSTR_LEN(resource->pass));
if (resource->password != NULL) {
ZSTR_LEN(resource->password) = php_raw_url_decode(ZSTR_VAL(resource->password), ZSTR_LEN(resource->password));
PHP_FTP_CNTRL_CHK(ZSTR_VAL(resource->pass), ZSTR_LEN(resource->pass), "Invalid password %s")
PHP_FTP_CNTRL_CHK(ZSTR_VAL(resource->password), ZSTR_LEN(resource->password), "Invalid password %s")
php_stream_printf(stream, "PASS %s\r\n", ZSTR_VAL(resource->pass));
php_stream_printf(stream, "PASS %s\r\n", ZSTR_VAL(resource->password));
} else {
/* if the user has configured who they are,
send that as the password */
@@ -299,7 +307,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char
return stream;
connect_errexit:
php_url_free(resource);
php_uri_struct_free(resource);
if (stream) {
php_stream_close(stream);
@@ -404,7 +412,7 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa
int options, zend_string **opened_path, php_stream_context *context STREAMS_DC)
{
php_stream *stream = NULL, *datastream = NULL;
php_url *resource = NULL;
php_uri *resource = NULL;
char tmp_line[512];
char ip[sizeof("123.123.123.123")];
unsigned short portno;
@@ -579,12 +587,12 @@ php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *pa
/* remember control stream */
datastream->wrapperthis = stream;
php_url_free(resource);
php_uri_struct_free(resource);
return datastream;
errexit:
if (resource) {
php_url_free(resource);
php_uri_struct_free(resource);
}
if (stream) {
php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result);
@@ -683,7 +691,7 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch
{
php_stream *stream, *reuseid, *datastream = NULL;
php_ftp_dirstream_data *dirsdata;
php_url *resource = NULL;
php_uri *resource = NULL;
int result = 0, use_ssl, use_ssl_on_data = 0;
char *hoststart = NULL, tmp_line[512];
char ip[sizeof("123.123.123.123")];
@@ -745,7 +753,7 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch
goto opendir_errexit;
}
php_url_free(resource);
php_uri_struct_free(resource);
dirsdata = emalloc(sizeof *dirsdata);
dirsdata->datastream = datastream;
@@ -756,7 +764,7 @@ static php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const ch
opendir_errexit:
if (resource) {
php_url_free(resource);
php_uri_struct_free(resource);
}
if (stream) {
php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result);
@@ -773,7 +781,7 @@ opendir_errexit:
static int php_stream_ftp_url_stat(php_stream_wrapper *wrapper, const char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context)
{
php_stream *stream = NULL;
php_url *resource = NULL;
php_uri *resource = NULL;
int result;
char tmp_line[512];
@@ -877,12 +885,12 @@ mdtm_error:
#endif
#endif
php_stream_close(stream);
php_url_free(resource);
php_uri_struct_free(resource);
return 0;
stat_errexit:
if (resource) {
php_url_free(resource);
php_uri_struct_free(resource);
}
if (stream) {
php_stream_close(stream);
@@ -895,7 +903,7 @@ stat_errexit:
static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context)
{
php_stream *stream = NULL;
php_url *resource = NULL;
php_uri *resource = NULL;
int result;
char tmp_line[512];
@@ -925,13 +933,13 @@ static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, i
goto unlink_errexit;
}
php_url_free(resource);
php_uri_struct_free(resource);
php_stream_close(stream);
return 1;
unlink_errexit:
if (resource) {
php_url_free(resource);
php_uri_struct_free(resource);
}
if (stream) {
php_stream_close(stream);
@@ -944,18 +952,30 @@ unlink_errexit:
static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_from, const char *url_to, int options, php_stream_context *context)
{
php_stream *stream = NULL;
php_url *resource_from = NULL, *resource_to = NULL;
php_uri *resource_from = NULL, *resource_to = NULL;
int result;
char tmp_line[512];
resource_from = php_url_parse(url_from);
resource_to = php_url_parse(url_to);
uri_handler_t *uri_handler = php_stream_context_get_uri_handler("ftp", context);
if (uri_handler == NULL) {
zend_value_error("%s(): Provided stream context has invalid value for the \"uri_parser_class\" option", get_active_function_name());
return 0;
}
resource_from = php_uri_parse_to_struct(uri_handler, url_from, strlen(url_from), URI_COMPONENT_READ_RAW, true);
if (!resource_from) {
return 0;
}
resource_to = php_uri_parse_to_struct(uri_handler, url_to, strlen(url_to), URI_COMPONENT_READ_RAW, true);
if (!resource_to) {
goto rename_errexit;
}
/* Must be same scheme (ftp/ftp or ftps/ftps), same host, and same port
(or a 21/0 0/21 combination which is also "same")
Also require paths to/from */
if (!resource_from ||
!resource_to ||
!resource_from->scheme ||
if (!resource_from->scheme ||
!resource_to->scheme ||
!zend_string_equals(resource_from->scheme, resource_to->scheme) ||
!resource_from->host ||
@@ -999,17 +1019,15 @@ static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_fr
goto rename_errexit;
}
php_url_free(resource_from);
php_url_free(resource_to);
php_uri_struct_free(resource_from);
php_uri_struct_free(resource_to);
php_stream_close(stream);
return 1;
rename_errexit:
if (resource_from) {
php_url_free(resource_from);
}
php_uri_struct_free(resource_from);
if (resource_to) {
php_url_free(resource_to);
php_uri_struct_free(resource_to);
}
if (stream) {
php_stream_close(stream);
@@ -1022,7 +1040,7 @@ rename_errexit:
static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, int mode, int options, php_stream_context *context)
{
php_stream *stream = NULL;
php_url *resource = NULL;
php_uri *resource = NULL;
int result, recursive = options & PHP_STREAM_MKDIR_RECURSIVE;
char tmp_line[512];
@@ -1089,7 +1107,7 @@ static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, in
efree(buf);
}
php_url_free(resource);
php_uri_struct_free(resource);
php_stream_close(stream);
if (result < 200 || result > 299) {
@@ -1101,7 +1119,7 @@ static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, in
mkdir_errexit:
if (resource) {
php_url_free(resource);
php_uri_struct_free(resource);
}
if (stream) {
php_stream_close(stream);
@@ -1114,7 +1132,7 @@ mkdir_errexit:
static int php_stream_ftp_rmdir(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context)
{
php_stream *stream = NULL;
php_url *resource = NULL;
php_uri *resource = NULL;
int result;
char tmp_line[512];
@@ -1143,14 +1161,14 @@ static int php_stream_ftp_rmdir(php_stream_wrapper *wrapper, const char *url, in
goto rmdir_errexit;
}
php_url_free(resource);
php_uri_struct_free(resource);
php_stream_close(stream);
return 1;
rmdir_errexit:
if (resource) {
php_url_free(resource);
php_uri_struct_free(resource);
}
if (stream) {
php_stream_close(stream);

View File

@@ -20,11 +20,13 @@
#include "php.h"
#include "php_globals.h"
#include "ext/uri/php_uri.h"
#include "php_streams.h"
#include "php_network.h"
#include "php_ini.h"
#include "ext/standard/basic_functions.h"
#include "zend_smart_str.h"
#include "zend_exceptions.h"
#include <stdio.h>
#include <stdlib.h>
@@ -358,7 +360,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
zval *response_header STREAMS_DC) /* {{{ */
{
php_stream *stream = NULL;
php_url *resource = NULL;
php_uri *resource = NULL;
int use_ssl;
int use_proxy = 0;
zend_string *tmp = NULL;
@@ -391,7 +393,12 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
return NULL;
}
resource = php_url_parse(path);
uri_handler_t *uri_handler = php_stream_context_get_uri_handler("http", context);
if (uri_handler == NULL) {
zend_value_error("%s(): Provided stream context has invalid value for the \"uri_parser_class\" option", get_active_function_name());
return NULL;
}
resource = php_uri_parse_to_struct(uri_handler, path, strlen(path), URI_COMPONENT_READ_RAW, true);
if (resource == NULL) {
return NULL;
}
@@ -403,7 +410,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
(tmpzval = php_stream_context_get_option(context, wrapper->wops->label, "proxy")) == NULL ||
Z_TYPE_P(tmpzval) != IS_STRING ||
Z_STRLEN_P(tmpzval) == 0) {
php_url_free(resource);
php_uri_struct_free(resource);
return php_stream_open_wrapper_ex(path, mode, REPORT_ERRORS, NULL, context);
}
/* Called from a non-http wrapper with http proxying requested (i.e. ftp) */
@@ -416,7 +423,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
if (strpbrk(mode, "awx+")) {
php_stream_wrapper_log_error(wrapper, options, "HTTP wrapper does not support writeable connections");
php_url_free(resource);
php_uri_struct_free(resource);
return NULL;
}
@@ -445,7 +452,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
if (request_fulluri && (strchr(path, '\n') != NULL || strchr(path, '\r') != NULL)) {
php_stream_wrapper_log_error(wrapper, options, "HTTP wrapper full URI path does not allow CR or LF characters");
php_url_free(resource);
php_uri_struct_free(resource);
zend_string_release(transport_string);
return NULL;
}
@@ -461,7 +468,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
if (d > timeoutmax) {
php_stream_wrapper_log_error(wrapper, options, "timeout must be lower than " ZEND_ULONG_FMT, (zend_ulong)timeoutmax);
zend_string_release(transport_string);
php_url_free(resource);
php_uri_struct_free(resource);
return NULL;
}
#ifndef PHP_WIN32
@@ -742,33 +749,31 @@ finish:
/* auth header if it was specified */
if (((have_header & HTTP_HEADER_AUTH) == 0) && resource->user) {
/* make scratch large enough to hold the whole URL (over-estimate) */
size_t scratch_len = strlen(path) + 1;
char *scratch = emalloc(scratch_len);
zend_string *stmp;
smart_str scratch = {0};
/* decode the strings first */
php_url_decode(ZSTR_VAL(resource->user), ZSTR_LEN(resource->user));
strcpy(scratch, ZSTR_VAL(resource->user));
strcat(scratch, ":");
smart_str_append(&scratch, resource->user);
smart_str_appendc(&scratch, ':');
/* Note: password is optional! */
if (resource->pass) {
php_url_decode(ZSTR_VAL(resource->pass), ZSTR_LEN(resource->pass));
strcat(scratch, ZSTR_VAL(resource->pass));
if (resource->password) {
php_url_decode(ZSTR_VAL(resource->password), ZSTR_LEN(resource->password));
smart_str_append(&scratch, resource->password);
}
stmp = php_base64_encode((unsigned char*)scratch, strlen(scratch));
zend_string *scratch_str = smart_str_extract(&scratch);
zend_string *stmp = php_base64_encode((unsigned char*)ZSTR_VAL(scratch_str), ZSTR_LEN(scratch_str));
smart_str_appends(&req_buf, "Authorization: Basic ");
smart_str_appends(&req_buf, ZSTR_VAL(stmp));
smart_str_append(&req_buf, stmp);
smart_str_appends(&req_buf, "\r\n");
php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, NULL, 0);
zend_string_efree(scratch_str);
zend_string_free(stmp);
efree(scratch);
}
/* if the user has configured who they are, send a From: line */
@@ -1090,9 +1095,9 @@ finish:
header_info.location = NULL;
}
php_url_free(resource);
php_uri_struct_free(resource);
/* check for invalid redirection URLs */
if ((resource = php_url_parse(new_path)) == NULL) {
if ((resource = php_uri_parse_to_struct(uri_handler, new_path, strlen(new_path), URI_COMPONENT_READ_RAW, true)) == NULL) {
php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path);
efree(new_path);
goto out;
@@ -1116,7 +1121,7 @@ finish:
/* check for control characters in login, password & path */
if (strncasecmp(new_path, "http://", sizeof("http://") - 1) || strncasecmp(new_path, "https://", sizeof("https://") - 1)) {
CHECK_FOR_CNTRL_CHARS(resource->user);
CHECK_FOR_CNTRL_CHARS(resource->pass);
CHECK_FOR_CNTRL_CHARS(resource->password);
CHECK_FOR_CNTRL_CHARS(resource->path);
}
int new_flags = HTTP_WRAPPER_REDIRECTED;
@@ -1147,7 +1152,7 @@ out:
}
if (resource) {
php_url_free(resource);
php_uri_struct_free(resource);
}
if (stream) {

View File

@@ -0,0 +1,49 @@
--TEST--
Test file_get_contents() function when a custom URI parser is configured
--FILE--
<?php
try {
$context = stream_context_create([
"http" => [
"uri_parser_class" => "not-exists",
],
]);
var_dump(file_get_contents("https://example.com", context: $context));
} catch (Error $e) {
echo $e->getMessage() . "\n";
}
$context = stream_context_create([
"http" => [
"uri_parser_class" => null,
],
]);
var_dump(file_get_contents("https:///example.com", context: $context)); // invalid for parse_url only, valid for the other handlers
$context = stream_context_create([
"http" => [
"uri_parser_class" => \Uri\Rfc3986\Uri::class,
],
]);
var_dump(file_get_contents("https://éxamplé.com", context: $context)); // invalid for RFC 3986 only, valid for the other handlers
$context = stream_context_create([
"http" => [
"uri_parser_class" => \Uri\WhatWg\Url::class,
],
]);
var_dump(file_get_contents("https://exa%23mple.org", context: $context)); // invalid for WHATWG only, valid for the other handlers
?>
--EXPECTF--
file_get_contents(): Provided stream context has invalid value for the "uri_parser_class" option
Warning: file_get_contents(https:///example.com): Failed to open stream: operation failed in %s on line %d
bool(false)
Warning: file_get_contents(https://éxamplé.com): Failed to open stream: operation failed in %s on line %d
bool(false)
Warning: file_get_contents(https://exa%23mple.org): Failed to open stream: operation failed in %s on line %d
bool(false)

View File

@@ -25,6 +25,8 @@
#include "file.h"
#include "zend_simd.h"
#include "Zend/zend_smart_str.h"
#include "Zend/zend_exceptions.h"
#include "ext/uri/php_uri.h"
/* {{{ free_url */
PHPAPI void php_url_free(php_url *theurl)
@@ -47,6 +49,13 @@ PHPAPI void php_url_free(php_url *theurl)
}
/* }}} */
static void parse_url_free_uri(void *uri)
{
php_url *parse_url_uri = (php_url *) uri;
php_url_free(parse_url_uri);
}
static void php_replace_controlchars(char *str, size_t len)
{
unsigned char *s = (unsigned char *)str;
@@ -311,7 +320,166 @@ parse_host:
return ret;
}
/* }}} */
static void parse_url_decode_component(zval *zv, uri_component_read_mode_t read_mode)
{
if (Z_TYPE_P(zv) != IS_STRING) {
return;
}
if (read_mode == URI_COMPONENT_READ_RAW) {
return;
}
php_raw_url_decode(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
}
static zend_result parse_url_read_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
php_url *parse_url_uri = internal_uri->uri;
if (parse_url_uri->scheme) {
ZVAL_STR_COPY(retval, parse_url_uri->scheme);
parse_url_decode_component(retval, read_mode);
} else {
ZVAL_NULL(retval);
}
return SUCCESS;
}
static zend_result parse_url_read_username(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
php_url *parse_url_uri = internal_uri->uri;
if (parse_url_uri->user) {
ZVAL_STR_COPY(retval, parse_url_uri->user);
parse_url_decode_component(retval, read_mode);
} else {
ZVAL_NULL(retval);
}
return SUCCESS;
}
static zend_result parse_url_read_password(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
php_url *parse_url_uri = internal_uri->uri;
if (parse_url_uri->pass) {
ZVAL_STR_COPY(retval, parse_url_uri->pass);
parse_url_decode_component(retval, read_mode);
} else {
ZVAL_NULL(retval);
}
return SUCCESS;
}
static zend_result parse_url_read_host(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
php_url *parse_url_uri = internal_uri->uri;
if (parse_url_uri->host) {
ZVAL_STR_COPY(retval, parse_url_uri->host);
parse_url_decode_component(retval, read_mode);
} else {
ZVAL_NULL(retval);
}
return SUCCESS;
}
static zend_result parse_url_read_port(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
php_url *parse_url_uri = internal_uri->uri;
if (parse_url_uri->port) {
ZVAL_LONG(retval, parse_url_uri->port);
parse_url_decode_component(retval, read_mode);
} else {
ZVAL_NULL(retval);
}
return SUCCESS;
}
static zend_result parse_url_read_path(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
php_url *parse_url_uri = internal_uri->uri;
if (parse_url_uri->path) {
ZVAL_STR_COPY(retval, parse_url_uri->path);
parse_url_decode_component(retval, read_mode);
} else {
ZVAL_NULL(retval);
}
return SUCCESS;
}
static zend_result parse_url_read_query(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
php_url *parse_url_uri = internal_uri->uri;
if (parse_url_uri->query) {
ZVAL_STR_COPY(retval, parse_url_uri->query);
parse_url_decode_component(retval, read_mode);
} else {
ZVAL_NULL(retval);
}
return SUCCESS;
}
static zend_result parse_url_read_fragment(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval)
{
php_url *parse_url_uri = internal_uri->uri;
if (parse_url_uri->fragment) {
ZVAL_STR_COPY(retval, parse_url_uri->fragment);
parse_url_decode_component(retval, read_mode);
} else {
ZVAL_NULL(retval);
}
return SUCCESS;
}
static void throw_invalid_uri_exception(void)
{
zend_throw_exception(uri_invalid_uri_exception_ce, "The specified URI is malformed", 0);
}
static void *parse_url_parse_uri(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent)
{
bool has_port;
php_url *url = php_url_parse_ex2(uri_str, uri_str_len, &has_port);
if (url == NULL && !silent) {
throw_invalid_uri_exception();
}
return url;
}
const uri_handler_t parse_url_uri_handler = {
.name = URI_PARSER_PHP,
.parse_uri = parse_url_parse_uri,
.clone_uri = NULL,
.uri_to_string = NULL,
.free_uri = parse_url_free_uri,
{
.scheme = {.read_func = parse_url_read_scheme, .write_func = NULL},
.username = {.read_func = parse_url_read_username, .write_func = NULL},
.password = {.read_func = parse_url_read_password, .write_func = NULL},
.host = {.read_func = parse_url_read_host, .write_func = NULL},
.port = {.read_func = parse_url_read_port, .write_func = NULL},
.path = {.read_func = parse_url_read_path, .write_func = NULL},
.query = {.read_func = parse_url_read_query, .write_func = NULL},
.fragment = {.read_func = parse_url_read_fragment, .write_func = NULL},
}
};
/* {{{ Parse a URL and return its components */
PHP_FUNCTION(parse_url)
@@ -753,3 +921,8 @@ no_name_header:
php_stream_close(stream);
}
/* }}} */
PHP_MINIT_FUNCTION(url)
{
return php_uri_handler_register(&parse_url_uri_handler);
}

View File

@@ -17,6 +17,8 @@
#ifndef URL_H
#define URL_H
PHP_MINIT_FUNCTION(url);
typedef struct php_url {
zend_string *scheme;
zend_string *user;

View File

@@ -562,11 +562,11 @@ void lexbor_request_shutdown(void)
lexbor_urls = 0;
}
lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexbor_base_url, zval *errors, bool silent)
lxb_url_t *lexbor_parse_uri_ex(const char *uri_str, size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, bool silent)
{
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 *) uri_str, uri_str_len);
const char *reason = fill_errors(errors);
if (url == NULL && !silent) {
@@ -577,9 +577,9 @@ lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexb
return url;
}
static void *lexbor_parse_uri(const zend_string *uri_str, const void *base_url, zval *errors, bool silent)
static void *lexbor_parse_uri(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent)
{
return lexbor_parse_uri_ex(uri_str, base_url, errors, silent);
return lexbor_parse_uri_ex(uri_str, uri_str_len, base_url, errors, silent);
}
static void *lexbor_clone_uri(void *uri)

View File

@@ -22,7 +22,7 @@
extern const uri_handler_t lexbor_uri_handler;
lxb_url_t *lexbor_parse_uri_ex(const zend_string *uri_str, const lxb_url_t *lexbor_base_url, zval *errors, bool silent);
lxb_url_t *lexbor_parse_uri_ex(const char *uri_str, size_t uri_str_len, const lxb_url_t *lexbor_base_url, zval *errors, bool silent);
zend_result lexbor_request_init(void);
void lexbor_request_shutdown(void);

View File

@@ -25,7 +25,7 @@
#include "Zend/zend_enum.h"
#include "ext/standard/info.h"
#include "php_uri_common.h"
#include "php_uri.h"
#include "php_lexbor.h"
#include "php_uriparser.h"
#include "php_uri_arginfo.h"
@@ -106,6 +106,205 @@ static HashTable *uri_get_debug_properties(zend_object *object)
return result;
}
PHPAPI uri_handler_t *php_uri_get_handler(const zend_string *uri_handler_name)
{
if (uri_handler_name == NULL) {
return uri_handler_by_name(URI_PARSER_PHP, sizeof(URI_PARSER_PHP) - 1);
}
return uri_handler_by_name(ZSTR_VAL(uri_handler_name), ZSTR_LEN(uri_handler_name));
}
ZEND_ATTRIBUTE_NONNULL PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, const char *uri_str, size_t uri_str_len, bool silent)
{
uri_internal_t *internal_uri = emalloc(sizeof(*internal_uri));
internal_uri->handler = uri_handler;
internal_uri->uri = uri_handler->parse_uri(uri_str, uri_str_len, NULL, NULL, silent);
if (UNEXPECTED(internal_uri->uri == NULL)) {
efree(internal_uri);
return NULL;
}
return internal_uri;
}
ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_get_property(const uri_internal_t *internal_uri, uri_property_name_t property_name, uri_component_read_mode_t read_mode, zval *zv)
{
const uri_property_handler_t *property_handler = uri_property_handler_from_internal_uri(internal_uri, property_name);
if (property_handler == NULL) {
return FAILURE;
}
zend_result result = property_handler->read_func(internal_uri, read_mode, zv);
ZEND_ASSERT(result == FAILURE || (Z_TYPE_P(zv) == IS_STRING && GC_REFCOUNT(Z_STR_P(zv)) == 2) || Z_TYPE_P(zv) == IS_NULL || Z_TYPE_P(zv) == IS_LONG);
return result;
}
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_SCHEME, read_mode, zv);
}
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_username(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_USERNAME, read_mode, zv);
}
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_password(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_PASSWORD, read_mode, zv);
}
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_host(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_HOST, read_mode, zv);
}
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_port(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_PORT, read_mode, zv);
}
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_path(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_PATH, read_mode, zv);
}
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_query(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_QUERY, read_mode, zv);
}
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_fragment(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv)
{
return php_uri_get_property(internal_uri, URI_PROPERTY_NAME_FRAGMENT, read_mode, zv);
}
ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_free(uri_internal_t *internal_uri)
{
internal_uri->handler->free_uri(internal_uri->uri);
internal_uri->uri = NULL;
internal_uri->handler = NULL;
efree(internal_uri);
}
ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct(
const uri_handler_t *uri_handler, const char *uri_str, size_t uri_str_len, uri_component_read_mode_t read_mode, bool silent
) {
uri_internal_t *uri_internal = php_uri_parse(uri_handler, uri_str, uri_str_len, silent);
if (uri_internal == NULL) {
return NULL;
}
php_uri *uri = ecalloc(1, sizeof(*uri));
zval tmp;
zend_result result;
result = php_uri_get_scheme(uri_internal, read_mode, &tmp);
if (result == FAILURE) {
goto error;
}
if (Z_TYPE(tmp) == IS_STRING) {
uri->scheme = Z_STR(tmp);
}
result = php_uri_get_username(uri_internal, read_mode, &tmp);
if (result == FAILURE) {
goto error;
}
if (Z_TYPE(tmp) == IS_STRING) {
uri->user = Z_STR(tmp);
}
result = php_uri_get_password(uri_internal, read_mode, &tmp);
if (result == FAILURE) {
goto error;
}
if (Z_TYPE(tmp) == IS_STRING) {
uri->password = Z_STR(tmp);
}
result = php_uri_get_host(uri_internal, read_mode, &tmp);
if (result == FAILURE) {
goto error;
}
if (Z_TYPE(tmp) == IS_STRING) {
uri->host = Z_STR(tmp);
}
result = php_uri_get_port(uri_internal, read_mode, &tmp);
if (result == FAILURE) {
goto error;
}
if (Z_TYPE(tmp) == IS_LONG) {
uri->port = Z_LVAL(tmp);
}
result = php_uri_get_path(uri_internal, read_mode, &tmp);
if (result == FAILURE) {
goto error;
}
if (Z_TYPE(tmp) == IS_STRING) {
uri->path = Z_STR(tmp);
}
result = php_uri_get_query(uri_internal, read_mode, &tmp);
if (result == FAILURE) {
goto error;
}
if (Z_TYPE(tmp) == IS_STRING) {
uri->query = Z_STR(tmp);
}
result = php_uri_get_fragment(uri_internal, read_mode, &tmp);
if (result == FAILURE) {
goto error;
}
if (Z_TYPE(tmp) == IS_STRING) {
uri->fragment = Z_STR(tmp);
}
php_uri_free(uri_internal);
return uri;
error:
php_uri_free(uri_internal);
php_uri_struct_free(uri);
return NULL;
}
ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_struct_free(php_uri *uri)
{
if (uri->scheme) {
zend_string_release(uri->scheme);
}
if (uri->user) {
zend_string_release(uri->user);
}
if (uri->password) {
zend_string_release(uri->password);
}
if (uri->host) {
zend_string_release(uri->host);
}
if (uri->path) {
zend_string_release(uri->path);
}
if (uri->query) {
zend_string_release(uri->query);
}
if (uri->fragment) {
zend_string_release(uri->fragment);
}
efree(uri);
}
/**
* Pass the errors parameter by ref to errors_zv for userland, and frees it if
* it is not not needed anymore.
@@ -136,7 +335,7 @@ static zend_result pass_errors_by_ref_and_free(zval *errors_zv, zval *errors)
return SUCCESS;
}
PHPAPI void php_uri_instantiate_uri(
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) PHPAPI void php_uri_instantiate_uri(
INTERNAL_FUNCTION_PARAMETERS, const uri_handler_t *handler, const zend_string *uri_str, const zend_object *base_url_object,
bool should_throw, bool should_update_this_object, zval *errors_zv
) {
@@ -150,7 +349,7 @@ PHPAPI void php_uri_instantiate_uri(
base_url = internal_base_url->uri;
}
void *uri = handler->parse_uri(uri_str, base_url, should_throw || errors_zv != NULL ? &errors : NULL, !should_throw);
void *uri = handler->parse_uri(ZSTR_VAL(uri_str), ZSTR_LEN(uri_str), base_url, should_throw || errors_zv != NULL ? &errors : NULL, !should_throw);
if (UNEXPECTED(uri == NULL)) {
if (should_throw) {
zval_ptr_dtor(&errors);
@@ -573,7 +772,7 @@ static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS, const char *handler_na
if (internal_uri->uri != NULL) {
internal_uri->handler->free_uri(internal_uri->uri);
}
internal_uri->uri = internal_uri->handler->parse_uri(Z_STR_P(uri_zv), NULL, NULL, true);
internal_uri->uri = internal_uri->handler->parse_uri(Z_STRVAL_P(uri_zv), Z_STRLEN_P(uri_zv), NULL, NULL, true);
if (internal_uri->uri == NULL) {
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(object->ce->name));
RETURN_THROWS();
@@ -762,7 +961,7 @@ PHP_METHOD(Uri_WhatWg_Url, __debugInfo)
static zend_object *uri_create_object_handler(zend_class_entry *class_type)
{
uri_object_t *uri_object = zend_object_alloc(sizeof(uri_object_t), class_type);
uri_object_t *uri_object = zend_object_alloc(sizeof(*uri_object), class_type);
zend_object_std_init(&uri_object->std, class_type);
object_properties_init(&uri_object->std, class_type);
@@ -806,7 +1005,7 @@ zend_object *uri_clone_obj_handler(zend_object *object)
return &new_uri_object->std;
}
PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers)
ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers)
{
ce->create_object = uri_create_object_handler;
ce->default_object_handlers = object_handlers;
@@ -816,14 +1015,14 @@ PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zen
object_handlers->clone_obj = uri_clone_obj_handler;
}
zend_result uri_handler_register(const uri_handler_t *uri_handler)
PHPAPI zend_result php_uri_handler_register(const uri_handler_t *uri_handler)
{
zend_string *key = zend_string_init_interned(uri_handler->name, strlen(uri_handler->name), 1);
zend_string *key = zend_string_init_interned(uri_handler->name, strlen(uri_handler->name), true);
ZEND_ASSERT(uri_handler->name != NULL);
ZEND_ASSERT(uri_handler->parse_uri != NULL);
ZEND_ASSERT(uri_handler->clone_uri != NULL);
ZEND_ASSERT(uri_handler->uri_to_string != NULL);
ZEND_ASSERT(uri_handler->clone_uri != NULL || strcmp(uri_handler->name, URI_PARSER_PHP) == 0);
ZEND_ASSERT(uri_handler->uri_to_string != NULL || strcmp(uri_handler->name, URI_PARSER_PHP) == 0);
ZEND_ASSERT(uri_handler->free_uri != NULL);
zend_result result = zend_hash_add_ptr(&uri_handlers, key, (void *) uri_handler) != NULL ? SUCCESS : FAILURE;
@@ -850,11 +1049,11 @@ static PHP_MINIT_FUNCTION(uri)
zend_hash_init(&uri_handlers, 4, NULL, NULL, true);
if (PHP_MINIT(uri_uriparser)(INIT_FUNC_ARGS_PASSTHRU) == FAILURE) {
if (php_uri_handler_register(&uriparser_uri_handler) == FAILURE) {
return FAILURE;
}
if (uri_handler_register(&lexbor_uri_handler) == FAILURE) {
if (php_uri_handler_register(&lexbor_uri_handler) == FAILURE) {
return FAILURE;
}

View File

@@ -22,6 +22,193 @@
extern zend_module_entry uri_module_entry;
#define phpext_uri_ptr &uri_module_entry
PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers);
typedef struct php_uri {
zend_string *scheme;
zend_string *user;
zend_string *password;
zend_string *host;
unsigned short port;
zend_string *path;
zend_string *query;
zend_string *fragment;
} php_uri;
/**
* Registers a URI handler. The handler must have a unique name.
*
* @param uri_handler The URI handler
* @return SUCCESS in case of success, FAILURE otherwise
*/
PHPAPI zend_result php_uri_handler_register(const uri_handler_t *uri_handler);
/**
* Returns the registered URI handler based on uri_handler_name.
*
* @param uri_handler_name The URI handler name
* @return The URI handler
*/
PHPAPI uri_handler_t *php_uri_get_handler(const zend_string *uri_handler_name);
ZEND_ATTRIBUTE_NONNULL PHPAPI uri_internal_t *php_uri_parse(const uri_handler_t *uri_handler, const char *uri_str, size_t uri_str_len, bool silent);
/**
* Retrieves the scheme component based on the read_mode and passes it to the zv ZVAL in case of success.
*
* Read_mode can be one of the following:
* - URI_COMPONENT_READ_RAW: Retrieves the raw, non-normalized variant of the URI component
* - URI_COMPONENT_READ_NORMALIZED_ASCII: Retrieves the normalized variant of the requested URI component that must only contain ASCII characters
* - URI_COMPONENT_READ_NORMALIZED_UNICODE: Retrieves the normalized variant of the requested URI component that may contain Unicode codepoints
*
* @param internal_uri The internal URI whose uri member is used to retrieve the component
* @param read_mode The read mode
* @param zv The output parameter containing the retrieved component as a ZVAL (either IS_STRING or IS_NULL).
* @return SUCCESS in case of success, FAILURE otherwise.
*/
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_scheme(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv);
/**
* Retrieves the username component based on the read_mode and passes it to the zv ZVAL in case of success.
*
* Read_mode can be one of the following:
* - URI_COMPONENT_READ_RAW: Retrieves the raw, non-normalized variant of the URI component
* - URI_COMPONENT_READ_NORMALIZED_ASCII: Retrieves the normalized variant of the requested URI component that must only contain ASCII characters
* - URI_COMPONENT_READ_NORMALIZED_UNICODE: Retrieves the normalized variant of the requested URI component that may contain Unicode codepoints
*
* @param internal_uri The internal URI whose uri member is used to retrieve the component
* @param read_mode The read mode
* @param zv The output parameter containing the retrieved component as a ZVAL (either IS_STRING or IS_NULL).
* @return SUCCESS in case of success, FAILURE otherwise.
*/
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_username(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv);
/**
* Retrieves the password component based on the read_mode and passes it to the zv ZVAL in case of success.
*
* Read_mode can be one of the following:
* - URI_COMPONENT_READ_RAW: Retrieves the raw, non-normalized variant of the URI component
* - URI_COMPONENT_READ_NORMALIZED_ASCII: Retrieves the normalized variant of the requested URI component that must only contain ASCII characters
* - URI_COMPONENT_READ_NORMALIZED_UNICODE: Retrieves the normalized variant of the requested URI component that may contain Unicode codepoints
*
* @param internal_uri The internal URI whose uri member is used to retrieve the component
* @param read_mode The read mode
* @param zv The output parameter containing the retrieved component as a ZVAL (either IS_STRING or IS_NULL).
* @return SUCCESS in case of success, FAILURE otherwise.
*/
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_password(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv);
/**
* Retrieves the host component based on the read_mode and passes it to the zv ZVAL in case of success.
*
* Read_mode can be one of the following:
* - URI_COMPONENT_READ_RAW: Retrieves the raw, non-normalized variant of the URI component
* - URI_COMPONENT_READ_NORMALIZED_ASCII: Retrieves the normalized variant of the requested URI component that must only contain ASCII characters
* - URI_COMPONENT_READ_NORMALIZED_UNICODE: Retrieves the normalized variant of the requested URI component that may contain Unicode codepoints
*
* @param internal_uri The internal URI whose uri member is used to retrieve the component
* @param read_mode The read mode
* @param zv The output parameter containing the retrieved component as a ZVAL (either IS_STRING or IS_NULL).
* @return SUCCESS in case of success, FAILURE otherwise.
*/
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_host(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv);
/**
* Retrieves the port component based on the read_mode and passes it to the zv ZVAL in case of success.
*
* Read_mode can be one of the following:
* - URI_COMPONENT_READ_RAW: Retrieves the raw, non-normalized variant of the URI component
* - URI_COMPONENT_READ_NORMALIZED_ASCII: Retrieves the normalized variant of the requested URI component that must only contain ASCII characters
* - URI_COMPONENT_READ_NORMALIZED_UNICODE: Retrieves the normalized variant of the requested URI component that may contain Unicode codepoints
*
* @param internal_uri The internal URI whose uri member is used to retrieve the component
* @param read_mode The read mode
* @param zv The output parameter containing the retrieved component as a ZVAL (either IS_LONG or IS_NULL).
* @return SUCCESS in case of success, FAILURE otherwise.
*/
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_port(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv);
/**
* Retrieves the path component based on the read_mode and passes it to the zv ZVAL in case of success.
*
* Read_mode can be one of the following:
* - URI_COMPONENT_READ_RAW: Retrieves the raw, non-normalized variant of the URI component
* - URI_COMPONENT_READ_NORMALIZED_ASCII: Retrieves the normalized variant of the requested URI component that must only contain ASCII characters
* - URI_COMPONENT_READ_NORMALIZED_UNICODE: Retrieves the normalized variant of the requested URI component that may contain Unicode codepoints
*
* @param internal_uri The internal URI whose uri member is used to retrieve the component
* @param read_mode The read mode
* @param zv The output parameter containing the retrieved component as a ZVAL (either IS_STRING or IS_NULL).
* @return SUCCESS in case of success, FAILURE otherwise.
*/
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_path(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv);
/**
* Retrieves the query component based on the read_mode and passes it to the zv ZVAL in case of success.
*
* Read_mode can be one of the following:
* - URI_COMPONENT_READ_RAW: Retrieves the raw, non-normalized variant of the URI component
* - URI_COMPONENT_READ_NORMALIZED_ASCII: Retrieves the normalized variant of the requested URI component that must only contain ASCII characters
* - URI_COMPONENT_READ_NORMALIZED_UNICODE: Retrieves the normalized variant of the requested URI component that may contain Unicode codepoints
*
* @param internal_uri The internal URI whose uri member is used to retrieve the component
* @param read_mode The read mode
* @param zv The output parameter containing the retrieved component as a ZVAL (either IS_STRING or IS_NULL).
* @return SUCCESS in case of success, FAILURE otherwise.
*/
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_query(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv);
/**
* Retrieves the fragment component based on the read_mode and passes it to the zv ZVAL in case of success.
*
* Read_mode can be one of the following:
* - URI_COMPONENT_READ_RAW: Retrieves the raw, non-normalized variant of the URI component
* - URI_COMPONENT_READ_NORMALIZED_ASCII: Retrieves the normalized variant of the requested URI component that must only contain ASCII characters
* - URI_COMPONENT_READ_NORMALIZED_UNICODE: Retrieves the normalized variant of the requested URI component that may contain Unicode codepoints
*
* @param internal_uri The internal URI whose uri member is used to retrieve the component
* @param read_mode The read mode
* @param zv The output parameter containing the retrieved component as a ZVAL (either IS_STRING or IS_NULL).
* @return SUCCESS in case of success, FAILURE otherwise.
*/
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_fragment(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *zv);
/**
* Frees the uri member within the provided internal URI.
*
* @param internal_uri The internal URI
*/
ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_free(uri_internal_t *internal_uri);
/**
* Creates a new php_uri struct containing all the URI components. The components are retrieved based on the read_mode parameter.
*
* Read_mode can be one of the following:
* - URI_COMPONENT_READ_RAW: Retrieves the raw, non-normalized variant of the URI component
* - URI_COMPONENT_READ_NORMALIZED_ASCII: Retrieves the normalized variant of the requested URI component that must only contain ASCII characters
* - URI_COMPONENT_READ_NORMALIZED_UNICODE: Retrieves the normalized variant of the requested URI component that may contain Unicode codepoints
*
* @param uri_handler The URI handler whose parse_uri() handler is called
* @param uri_str The input string that is going to be parsed
* @param uri_str_len Length of the input string
* @param read_mode The read mode based on which components are retrieved
* @param silent Whether to throw a Uri\InvalidUriException in case of failure
* @return The created php_uri struct in case of success, NULL otherwise
*/
ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct(
const uri_handler_t *uri_handler, const char *uri_str, size_t uri_str_len, uri_component_read_mode_t read_mode, bool silent
);
/**
* Frees the provided php_uri struct.
*
* @param uri The php_uri struct to free
*/
ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_struct_free(php_uri *uri);
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) PHPAPI void php_uri_instantiate_uri(
INTERNAL_FUNCTION_PARAMETERS, const uri_handler_t *handler, const zend_string *uri_str, const zend_object *base_url_object,
bool should_throw, bool should_update_this_object, zval *errors_zv
);
ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_implementation_set_object_handlers(zend_class_entry *ce, zend_object_handlers *object_handlers);
#endif

View File

@@ -76,10 +76,13 @@ typedef struct uri_property_handlers_t {
} uri_property_handlers_t;
typedef struct uri_handler_t {
/**
* Name (the FQCN) of the URI handler. The "" name is reserved for the handler of the legacy parse_url().
*/
const char *name;
/**
* Parse a URI string into a URI.
* Parses a URI string into a URI.
*
* If the URI string is valid, a URI is returned. In case of failure, NULL is
* returned.
@@ -93,10 +96,46 @@ typedef struct uri_handler_t {
*
* If the silent parameter is true, a Uri\InvalidUriException instance must be thrown.
* If the parameter is false, the possible errors should be handled by the caller.
*
* @param uri_str The input string that is going to be parsed
* @param uri_str_len Length of the input string
* @param base_url The base URI if reference resolution should be performed, otherwise NULL
* @param errors An out parameter that stores additional error information
* @param silent Whether to throw a Uri\InvalidUriException in case of failure
*/
void *(*parse_uri)(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent);
/**
* Clones a URI to a new URI.
*
* A deep-clone must be performed that copies all pointer members to a new memory address.
* @param uri The input URI
* @return The cloned URI
*/
void *(*parse_uri)(const zend_string *uri_str, const void *base_url, zval *errors, bool silent);
void *(*clone_uri)(void *uri);
/**
* Recomposes a URI as a string according to the recomposition_mode and exclude_fragment parameters.
* The returned zend_string must not be persistent.
*
* Recomposition_mode can be one of the following:
* - URI_RECOMPOSITION_RAW_ASCII: Recomposes the raw, non-normalized variant of the URI as a string that must only contain ASCII characters
* - URI_RECOMPOSITION_RAW_UNICODE: Recomposes the raw, non-normalized variant of the URI as a string that may contain Unicode codepoints
* - URI_RECOMPOSITION_NORMALIZED_ASCII: Recomposes the normalized variant of the URI as a string that must only contain ASCII characters
* - URI_RECOMPOSITION_NORMALIZED_UNICODE: Recomposes the normalized variant of the URI as a string that may contain Unicode codepoints
*
* @param uri The input URI
* @param recomposition_mode The type of recomposition
* @param exclude_fragment Whether the fragment component should be part of the recomposed URI
* @return The recomposed URI as a non-persistent zend_string
*/
zend_string *(*uri_to_string)(void *uri, uri_recomposition_mode_t recomposition_mode, bool exclude_fragment);
/**
* Frees the provided URI.
*
* @param uri The input URI
*/
void (*free_uri)(void *uri);
const uri_property_handlers_t property_handlers;
@@ -125,9 +164,9 @@ static inline uri_internal_t *uri_internal_from_obj(const zend_object *object) {
#define URI_PARSER_RFC3986 "Uri\\Rfc3986\\Uri"
#define URI_PARSER_WHATWG "Uri\\WhatWg\\Url"
#define URI_PARSER_PHP "parse_url"
#define URI_SERIALIZED_PROPERTY_NAME "uri"
zend_result uri_handler_register(const uri_handler_t *uri_handler);
const uri_property_handler_t *uri_property_handler_from_internal_uri(const uri_internal_t *internal_uri, uri_property_name_t property_name);
void uri_read_component(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name, uri_component_read_mode_t component_read_mode);
void uri_write_component_str(INTERNAL_FUNCTION_PARAMETERS, uri_property_name_t property_name);

View File

@@ -275,15 +275,6 @@ ZEND_ATTRIBUTE_NONNULL static zend_result uriparser_read_fragment(const uri_inte
return SUCCESS;
}
PHP_MINIT_FUNCTION(uri_uriparser)
{
if (uri_handler_register(&uriparser_uri_handler) == FAILURE) {
return FAILURE;
}
return SUCCESS;
}
static uriparser_uris_t *uriparser_create_uris(void)
{
uriparser_uris_t *uriparser_uris = ecalloc(1, sizeof(*uriparser_uris));
@@ -292,12 +283,12 @@ static uriparser_uris_t *uriparser_create_uris(void)
return uriparser_uris;
}
void *uriparser_parse_uri_ex(const zend_string *uri_str, const uriparser_uris_t *uriparser_base_urls, bool silent)
void *uriparser_parse_uri_ex(const char *uri_str, size_t uri_str_len, const uriparser_uris_t *uriparser_base_urls, bool silent)
{
UriUriA uri = {0};
/* Parse the URI. */
if (uriParseSingleUriExMmA(&uri, ZSTR_VAL(uri_str), ZSTR_VAL(uri_str) + ZSTR_LEN(uri_str), NULL, mm) != URI_SUCCESS) {
if (uriParseSingleUriExMmA(&uri, uri_str, uri_str + uri_str_len, NULL, mm) != URI_SUCCESS) {
if (!silent) {
zend_throw_exception(uri_invalid_uri_exception_ce, "The specified URI is malformed", 0);
}
@@ -347,13 +338,12 @@ void *uriparser_parse_uri_ex(const zend_string *uri_str, const uriparser_uris_t
return NULL;
}
void *uriparser_parse_uri(const zend_string *uri_str, const void *base_url, zval *errors, bool silent)
void *uriparser_parse_uri(const char *uri_str, size_t uri_str_len, const void *base_url, zval *errors, bool silent)
{
return uriparser_parse_uri_ex(uri_str, base_url, silent);
return uriparser_parse_uri_ex(uri_str, uri_str_len, base_url, silent);
}
/* TODO make the clone handler accept a flag to distinguish between clone() calls and withers.
* When calling a wither successfully, the normalized URI is surely invalidated, therefore
/* When calling a wither successfully, the normalized URI is surely invalidated, therefore
* it doesn't make sense to copy it. In case of failure, an exception is thrown, and the URI object
* is discarded altogether. */
ZEND_ATTRIBUTE_NONNULL static void *uriparser_clone_uri(void *uri)

View File

@@ -28,10 +28,8 @@ typedef struct uriparser_uris_t {
bool normalized_uri_initialized;
} uriparser_uris_t;
PHP_MINIT_FUNCTION(uri_uriparser);
zend_result uriparser_read_userinfo(const uri_internal_t *internal_uri, uri_component_read_mode_t read_mode, zval *retval);
void *uriparser_parse_uri_ex(const zend_string *uri_str, const uriparser_uris_t *uriparser_base_url, bool silent);
void *uriparser_parse_uri_ex(const char *uri_str, size_t uri_str_len, const uriparser_uris_t *uriparser_base_url, bool silent);
#endif

View File

@@ -65,6 +65,10 @@ PHPAPI void php_stream_context_set_option(php_stream_context *context,
const char *wrappername, const char *optionname, zval *optionvalue);
void php_stream_context_unset_option(php_stream_context *context,
const char *wrappername, const char *optionname);
struct uri_handler_t;
PHPAPI struct uri_handler_t *php_stream_context_get_uri_handler(const char *wrappername, php_stream_context *context);
PHPAPI php_stream_notifier *php_stream_notification_alloc(void);
PHPAPI void php_stream_notification_free(php_stream_notifier *notifier);
END_EXTERN_C()

View File

@@ -28,6 +28,7 @@
#include "ext/standard/file.h"
#include "ext/standard/basic_functions.h" /* for BG(CurrentStatFile) */
#include "ext/standard/php_string.h" /* for php_memnstr, used by php_stream_get_record() */
#include "ext/uri/php_uri.h"
#include <stddef.h>
#include <fcntl.h>
#include "php_streams_int.h"
@@ -2457,6 +2458,24 @@ void php_stream_context_unset_option(php_stream_context *context,
}
/* }}} */
PHPAPI struct uri_handler_t *php_stream_context_get_uri_handler(const char *wrappername, php_stream_context *context)
{
if (context == NULL) {
return php_uri_get_handler(NULL);
}
zval *uri_handler_name = php_stream_context_get_option(context, wrappername, "uri_parser_class");
if (uri_handler_name == NULL || Z_TYPE_P(uri_handler_name) == IS_NULL) {
return php_uri_get_handler(NULL);
}
if (Z_TYPE_P(uri_handler_name) != IS_STRING) {
return NULL;
}
return php_uri_get_handler(Z_STR_P(uri_handler_name));
}
/* {{{ php_stream_dirent_alphasort */
PHPAPI int php_stream_dirent_alphasort(const zend_string **a, const zend_string **b)
{