From 3ad522ba19b708f611c2ee9d397025ed0a13c262 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 3 Jul 2026 12:11:51 +0100 Subject: [PATCH 1/3] ext/soap: add tests for option parsing to SoapServer constructor --- .../SoapServer_constructor_errors.phpt | 85 +++++++++++++++++++ .../invalid-encoding-option-type.phpt | 30 +++++++ .../invalid-soap_version-option-type.phpt | 29 +++++++ 3 files changed, 144 insertions(+) create mode 100644 ext/soap/tests/SoapServer/SoapServer_constructor_errors.phpt create mode 100644 ext/soap/tests/SoapServer/invalid-encoding-option-type.phpt create mode 100644 ext/soap/tests/SoapServer/invalid-soap_version-option-type.phpt diff --git a/ext/soap/tests/SoapServer/SoapServer_constructor_errors.phpt b/ext/soap/tests/SoapServer/SoapServer_constructor_errors.phpt new file mode 100644 index 000000000000..c9895e22171a --- /dev/null +++ b/ext/soap/tests/SoapServer/SoapServer_constructor_errors.phpt @@ -0,0 +1,85 @@ +--TEST-- +SoapServer constructor invalid type errors +--EXTENSIONS-- +soap +--FILE-- + 25, +]; +try { + $server = new SoapServer($wsdl, $options); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +$options = [ + 'actor' => 25, +]; +try { + $server = new SoapServer($wsdl, $options); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +$options = [ + 'classmap' => 25, +]; +try { + $server = new SoapServer($wsdl, $options); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +$options = [ + 'typemap' => 25, +]; +try { + $server = new SoapServer($wsdl, $options); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +$options = [ + 'features' => 'not an int', +]; +try { + $server = new SoapServer($wsdl, $options); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +$options = [ + 'cache_wsdl' => 'not an int', +]; +try { + $server = new SoapServer($wsdl, $options); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +$options = [ + 'send_errors' => 'not an int or bool', +]; +try { + $server = new SoapServer($wsdl, $options); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +$options = [ + 'trace' => 'not an int or bool', +]; +try { + $server = new SoapServer($wsdl, $options); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +?> +--EXPECT-- + +WSDLSOAP-ERROR: Parsing WSDL: Couldn't load from 'irrelevant' : failed to load external entity "irrelevant" + diff --git a/ext/soap/tests/SoapServer/invalid-encoding-option-type.phpt b/ext/soap/tests/SoapServer/invalid-encoding-option-type.phpt new file mode 100644 index 000000000000..f5c35bbb351a --- /dev/null +++ b/ext/soap/tests/SoapServer/invalid-encoding-option-type.phpt @@ -0,0 +1,30 @@ +--TEST-- +SoapServer constructor with an invalid encoding option +--EXTENSIONS-- +soap +--FILE-- + 25, +]; +try { + $client = new SoapServer($wsdl, $options); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +try { + $client = new ExtendedSoapServer($wsdl, $options); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + + +?> +--EXPECT-- + +WSDLSOAP-ERROR: Parsing WSDL: Couldn't load from 'irrelevant' : failed to load external entity "irrelevant" + diff --git a/ext/soap/tests/SoapServer/invalid-soap_version-option-type.phpt b/ext/soap/tests/SoapServer/invalid-soap_version-option-type.phpt new file mode 100644 index 000000000000..ed3da956c702 --- /dev/null +++ b/ext/soap/tests/SoapServer/invalid-soap_version-option-type.phpt @@ -0,0 +1,29 @@ +--TEST-- +SoapServer constructor with an invalid encoding option +--EXTENSIONS-- +soap +--FILE-- + "I am not an integer", +]; +try { + $client = new SoapServer($wsdl, $options); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +try { + $client = new ExtendedSoapServer($wsdl, $options); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + + +?> +--EXPECT-- + +SOAP-ENV:ServerSoapServer::__construct(): 'soap_version' option must be SOAP_1_1 or SOAP_1_2 From be0e9f01bc51e9a8c0dc68ddb6d9b59afdc0521c Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 3 Jul 2026 12:42:31 +0100 Subject: [PATCH 2/3] ext/soap: use {Type|Value}Errors for programming erros in SoapServer constructor --- ext/soap/soap.c | 176 ++++++++++++------ .../SoapServer_constructor_errors.phpt | 11 +- .../tests/{bugs => SoapServer}/gh19784.phpt | 8 +- .../invalid-encoding-option-type.phpt | 5 +- .../SoapServer/invalid-encoding-option.phpt | 4 +- .../invalid-soap_version-option-type.phpt | 4 +- .../invalid-soap_version-option.phpt | 4 +- .../missing-options-non-wsdl-mode.phpt | 8 +- ext/soap/tests/bugs/gh16256.phpt | 3 +- 9 files changed, 145 insertions(+), 78 deletions(-) rename ext/soap/tests/{bugs => SoapServer}/gh19784.phpt (59%) diff --git a/ext/soap/soap.c b/ext/soap/soap.c index d8f72e0191aa..e70198e6f6c5 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -933,103 +933,157 @@ static HashTable* soap_create_typemap(sdlPtr sdl, HashTable *ht) /* {{{ */ /* {{{ SoapServer constructor */ PHP_METHOD(SoapServer, __construct) { - soapServicePtr service; - zval *options = NULL; + HashTable *options = NULL; zend_string *wsdl; int version = SOAP_1_1; zend_long cache_wsdl; HashTable *typemap_ht = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S!|a", &wsdl, &options) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S!|h", &wsdl, &options) == FAILURE) { RETURN_THROWS(); } - SOAP_SERVER_BEGIN_CODE(); - - service = emalloc(sizeof(soapService)); + soapServicePtr service = emalloc(sizeof(soapService)); memset(service, 0, sizeof(soapService)); - service->send_errors = 1; + service->send_errors = true; cache_wsdl = SOAP_GLOBAL(cache_enabled) ? SOAP_GLOBAL(cache_mode) : 0; if (options != NULL) { - HashTable *ht = Z_ARRVAL_P(options); - zval *tmp; - - if ((tmp = zend_hash_str_find(ht, "soap_version", sizeof("soap_version")-1)) != NULL) { - if (Z_TYPE_P(tmp) == IS_LONG && - (Z_LVAL_P(tmp) == SOAP_1_1 || Z_LVAL_P(tmp) == SOAP_1_2)) { - version = Z_LVAL_P(tmp); - } else { - php_error_docref(NULL, E_ERROR, "'soap_version' option must be SOAP_1_1 or SOAP_1_2"); + const zval *soap_version_zv = zend_hash_str_find(options, ZEND_STRL("soap_version")); + if (soap_version_zv) { + if (UNEXPECTED(Z_TYPE_P(soap_version_zv) != IS_LONG)) { + zend_argument_type_error(2, "\"soap_version\" option must be of type int, %s given", zend_zval_type_name(soap_version_zv)); + goto cleanup; } + zend_long soap_version = Z_LVAL_P(soap_version_zv); + if (UNEXPECTED(soap_version != SOAP_1_1 && soap_version != SOAP_1_2)) { + zend_argument_value_error(2, "\"soap_version\" option must be SOAP_1_1 or SOAP_1_2"); + goto cleanup; + } + version = soap_version; } - if ((tmp = zend_hash_str_find(ht, "uri", sizeof("uri")-1)) != NULL && - Z_TYPE_P(tmp) == IS_STRING) { - service->uri = estrndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); + const zval *uri_zv = zend_hash_str_find(options, ZEND_STRL("uri")); + if (uri_zv) { + if (UNEXPECTED(Z_TYPE_P(uri_zv) != IS_STRING)) { + zend_argument_type_error(2, "\"uri\" option must be of type string, %s given", zend_zval_type_name(uri_zv)); + goto cleanup; + } + service->uri = estrndup(Z_STRVAL_P(uri_zv), Z_STRLEN_P(uri_zv)); } else if (!wsdl) { - php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode"); + zend_argument_type_error(2, "\"uri\" option is required when argument #1 ($wsdl) is null"); + goto cleanup; } - if ((tmp = zend_hash_str_find(ht, "actor", sizeof("actor")-1)) != NULL && - Z_TYPE_P(tmp) == IS_STRING) { - service->actor = estrndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); + const zval *actor_zv = zend_hash_str_find(options, ZEND_STRL("actor")); + if (actor_zv) { + if (UNEXPECTED(Z_TYPE_P(actor_zv) != IS_STRING)) { + zend_argument_type_error(2, "\"actor\" option must be of type string, %s given", zend_zval_type_name(actor_zv)); + goto cleanup; + } + service->actor = estrndup(Z_STRVAL_P(actor_zv), Z_STRLEN_P(actor_zv)); } - if ((tmp = zend_hash_str_find(ht, "encoding", sizeof("encoding")-1)) != NULL && - Z_TYPE_P(tmp) == IS_STRING) { - xmlCharEncodingHandlerPtr encoding; + const zval *encoding_zv = zend_hash_str_find(options, ZEND_STRL("encoding")); + if (encoding_zv) { + if (UNEXPECTED(Z_TYPE_P(encoding_zv) != IS_STRING)) { + zend_argument_type_error(2, "\"encoding\" option must be of type string, %s given", zend_zval_type_name(encoding_zv)); + goto cleanup; + } - encoding = xmlFindCharEncodingHandler(Z_STRVAL_P(tmp)); - if (encoding == NULL) { - php_error_docref(NULL, E_ERROR, "Invalid 'encoding' option - '%s'", Z_STRVAL_P(tmp)); - } else { - service->encoding = encoding; + // TODO Check for null bytes? + xmlCharEncodingHandlerPtr encoding = xmlFindCharEncodingHandler(Z_STRVAL_P(encoding_zv)); + if (UNEXPECTED(encoding == NULL)) { + zend_argument_value_error(2, "\"encoding\" option must be a valid encoding, \"%s\" given", Z_STRVAL_P(encoding_zv)); + goto cleanup; } + service->encoding = encoding; } - if ((tmp = zend_hash_str_find(ht, "classmap", sizeof("classmap")-1)) != NULL && - Z_TYPE_P(tmp) == IS_ARRAY) { - if (HT_IS_PACKED(Z_ARRVAL_P(tmp))) { - php_error_docref(NULL, E_ERROR, "'classmap' option must be an associative array"); + const zval *class_map_zv = zend_hash_str_find(options, ZEND_STRL("classmap")); + if (class_map_zv) { + if (UNEXPECTED(Z_TYPE_P(class_map_zv) != IS_ARRAY)) { + zend_argument_type_error(2, "\"classmap\" option must be of type array, %s given", zend_zval_type_name(class_map_zv)); + goto cleanup; } - service->class_map = zend_array_dup(Z_ARRVAL_P(tmp)); + // TODO: this still accepts mixed keys arrays and not all numerically indexed arrays are packed + if (HT_IS_PACKED(Z_ARRVAL_P(class_map_zv))) { + zend_argument_value_error(2, "\"classmap\" option must be an associative array"); + goto cleanup; + } + service->class_map = zend_array_dup(Z_ARR_P(class_map_zv)); } - if ((tmp = zend_hash_str_find(ht, "typemap", sizeof("typemap")-1)) != NULL && - Z_TYPE_P(tmp) == IS_ARRAY && - zend_hash_num_elements(Z_ARRVAL_P(tmp)) > 0) { - typemap_ht = Z_ARRVAL_P(tmp); + const zval *type_map_zv = zend_hash_str_find(options, ZEND_STRL("typemap")); + if (type_map_zv) { + if (UNEXPECTED(Z_TYPE_P(type_map_zv) != IS_ARRAY)) { + zend_argument_type_error(2, "\"typemap\" option must be of type array, %s given", zend_zval_type_name(type_map_zv)); + goto cleanup; + } + if (zend_hash_num_elements(Z_ARR_P(type_map_zv)) > 0) { + typemap_ht = Z_ARRVAL_P(type_map_zv); + } } - if ((tmp = zend_hash_str_find(ht, "features", sizeof("features")-1)) != NULL && - Z_TYPE_P(tmp) == IS_LONG) { - service->features = Z_LVAL_P(tmp); + const zval *features_zv = zend_hash_str_find(options, ZEND_STRL("features")); + if (features_zv) { + if (UNEXPECTED(Z_TYPE_P(features_zv) != IS_LONG)) { + zend_argument_type_error(2, "\"features\" option must be of type int, %s given", zend_zval_type_name(features_zv)); + goto cleanup; + } + service->features = Z_LVAL_P(features_zv); } - if ((tmp = zend_hash_str_find(ht, "cache_wsdl", sizeof("cache_wsdl")-1)) != NULL && - Z_TYPE_P(tmp) == IS_LONG) { - cache_wsdl = Z_LVAL_P(tmp); + const zval *cache_wsdl_zv = zend_hash_str_find(options, ZEND_STRL("cache_wsdl")); + if (cache_wsdl_zv) { + if (UNEXPECTED(Z_TYPE_P(cache_wsdl_zv) != IS_LONG)) { + zend_argument_type_error(2, "\"cache_wsdl\" option must be of type int, %s given", zend_zval_type_name(cache_wsdl_zv)); + goto cleanup; + } + cache_wsdl = Z_LVAL_P(cache_wsdl_zv); } - if ((tmp = zend_hash_str_find(ht, "send_errors", sizeof("send_errors")-1)) != NULL) { - if (Z_TYPE_P(tmp) == IS_FALSE) { - service->send_errors = 0; - } else if (Z_TYPE_P(tmp) == IS_TRUE) { - service->send_errors = 1; - } else if (Z_TYPE_P(tmp) == IS_LONG) { - service->send_errors = Z_LVAL_P(tmp); + const zval *send_errors_zv = zend_hash_str_find(options, ZEND_STRL("send_errors")); + if (send_errors_zv) { + if (UNEXPECTED(Z_TYPE_P(send_errors_zv) != IS_FALSE && Z_TYPE_P(send_errors_zv) != IS_TRUE && Z_TYPE_P(send_errors_zv) != IS_LONG)) { + zend_argument_type_error(2, "\"send_errors\" option must be of type bool, %s given", zend_zval_type_name(send_errors_zv)); + goto cleanup; + } + switch (Z_TYPE_P(send_errors_zv)) { + case IS_FALSE: + service->send_errors = false; + break; + case IS_TRUE: + service->send_errors = true; + break; + case IS_LONG: + service->send_errors = Z_LVAL_P(send_errors_zv); + break; } } - if ((tmp = zend_hash_find(ht, ZSTR_KNOWN(ZEND_STR_TRACE))) != NULL && - (Z_TYPE_P(tmp) == IS_TRUE || - (Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 1))) { - service->trace = true; + const zval *trace_zv = zend_hash_find(options, ZSTR_KNOWN(ZEND_STR_TRACE)); + if (trace_zv) { + if (UNEXPECTED(Z_TYPE_P(trace_zv) != IS_FALSE && Z_TYPE_P(trace_zv) != IS_TRUE && Z_TYPE_P(trace_zv) != IS_LONG)) { + zend_argument_type_error(2, "\"trace\" option must be of type bool, %s given", zend_zval_type_name(trace_zv)); + goto cleanup; + } + switch (Z_TYPE_P(trace_zv)) { + case IS_FALSE: + service->trace = false; + break; + case IS_TRUE: + service->trace = true; + break; + case IS_LONG: + service->trace = Z_LVAL_P(trace_zv); + break; + } } } else if (!wsdl) { - php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode"); + zend_argument_type_error(2, "\"uri\" option is required when argument #1 ($wsdl) is null"); + goto cleanup; } service->version = version; @@ -1037,6 +1091,7 @@ PHP_METHOD(SoapServer, __construct) service->soap_functions.functions_all = FALSE; service->soap_functions.ft = zend_new_array(0); + SOAP_SERVER_BEGIN_CODE(); if (wsdl) { zend_try { service->sdl = get_sdl(ZEND_THIS, ZSTR_VAL(wsdl), cache_wsdl); @@ -1063,6 +1118,11 @@ PHP_METHOD(SoapServer, __construct) server_obj->service = service; SOAP_SERVER_END_CODE(); + return; + +cleanup: + delete_service(service); + RETURN_THROWS(); } /* }}} */ diff --git a/ext/soap/tests/SoapServer/SoapServer_constructor_errors.phpt b/ext/soap/tests/SoapServer/SoapServer_constructor_errors.phpt index c9895e22171a..c143be174af5 100644 --- a/ext/soap/tests/SoapServer/SoapServer_constructor_errors.phpt +++ b/ext/soap/tests/SoapServer/SoapServer_constructor_errors.phpt @@ -80,6 +80,11 @@ try { } ?> --EXPECT-- - -WSDLSOAP-ERROR: Parsing WSDL: Couldn't load from 'irrelevant' : failed to load external entity "irrelevant" - +TypeError: SoapServer::__construct(): Argument #2 ($options) "uri" option must be of type string, int given +TypeError: SoapServer::__construct(): Argument #2 ($options) "actor" option must be of type string, int given +TypeError: SoapServer::__construct(): Argument #2 ($options) "classmap" option must be of type array, int given +TypeError: SoapServer::__construct(): Argument #2 ($options) "typemap" option must be of type array, int given +TypeError: SoapServer::__construct(): Argument #2 ($options) "features" option must be of type int, string given +TypeError: SoapServer::__construct(): Argument #2 ($options) "cache_wsdl" option must be of type int, string given +TypeError: SoapServer::__construct(): Argument #2 ($options) "send_errors" option must be of type bool, string given +TypeError: SoapServer::__construct(): Argument #2 ($options) "trace" option must be of type bool, string given diff --git a/ext/soap/tests/bugs/gh19784.phpt b/ext/soap/tests/SoapServer/gh19784.phpt similarity index 59% rename from ext/soap/tests/bugs/gh19784.phpt rename to ext/soap/tests/SoapServer/gh19784.phpt index 1f718e74c459..d855bc47909a 100644 --- a/ext/soap/tests/bugs/gh19784.phpt +++ b/ext/soap/tests/SoapServer/gh19784.phpt @@ -4,10 +4,10 @@ GH-19784 (SoapServer memory leak) soap --FILE-- $v_5257); -new SoapServer('foobarbaz',$v_5238,); + +$options = ['encoding' => 'UTF-8']; +$server = new SoapServer('foobarbaz', $options); + ?> --EXPECTF-- diff --git a/ext/soap/tests/SoapServer/invalid-encoding-option-type.phpt b/ext/soap/tests/SoapServer/invalid-encoding-option-type.phpt index f5c35bbb351a..c67e86c322c0 100644 --- a/ext/soap/tests/SoapServer/invalid-encoding-option-type.phpt +++ b/ext/soap/tests/SoapServer/invalid-encoding-option-type.phpt @@ -25,6 +25,5 @@ try { ?> --EXPECT-- - -WSDLSOAP-ERROR: Parsing WSDL: Couldn't load from 'irrelevant' : failed to load external entity "irrelevant" - +TypeError: SoapServer::__construct(): Argument #2 ($options) "encoding" option must be of type string, int given +TypeError: SoapServer::__construct(): Argument #2 ($options) "encoding" option must be of type string, int given diff --git a/ext/soap/tests/SoapServer/invalid-encoding-option.phpt b/ext/soap/tests/SoapServer/invalid-encoding-option.phpt index f594d57dd8a4..08b27c43a673 100644 --- a/ext/soap/tests/SoapServer/invalid-encoding-option.phpt +++ b/ext/soap/tests/SoapServer/invalid-encoding-option.phpt @@ -25,5 +25,5 @@ try { ?> --EXPECT-- - -SOAP-ENV:ServerSoapServer::__construct(): Invalid 'encoding' option - 'non-sense' +ValueError: SoapServer::__construct(): Argument #2 ($options) "encoding" option must be a valid encoding, "non-sense" given +ValueError: SoapServer::__construct(): Argument #2 ($options) "encoding" option must be a valid encoding, "non-sense" given diff --git a/ext/soap/tests/SoapServer/invalid-soap_version-option-type.phpt b/ext/soap/tests/SoapServer/invalid-soap_version-option-type.phpt index ed3da956c702..a63b5dfe06a8 100644 --- a/ext/soap/tests/SoapServer/invalid-soap_version-option-type.phpt +++ b/ext/soap/tests/SoapServer/invalid-soap_version-option-type.phpt @@ -25,5 +25,5 @@ try { ?> --EXPECT-- - -SOAP-ENV:ServerSoapServer::__construct(): 'soap_version' option must be SOAP_1_1 or SOAP_1_2 +TypeError: SoapServer::__construct(): Argument #2 ($options) "soap_version" option must be of type int, string given +TypeError: SoapServer::__construct(): Argument #2 ($options) "soap_version" option must be of type int, string given diff --git a/ext/soap/tests/SoapServer/invalid-soap_version-option.phpt b/ext/soap/tests/SoapServer/invalid-soap_version-option.phpt index 17e45f2dac1b..c3f655699288 100644 --- a/ext/soap/tests/SoapServer/invalid-soap_version-option.phpt +++ b/ext/soap/tests/SoapServer/invalid-soap_version-option.phpt @@ -25,5 +25,5 @@ try { ?> --EXPECT-- - -SOAP-ENV:ServerSoapServer::__construct(): 'soap_version' option must be SOAP_1_1 or SOAP_1_2 +ValueError: SoapServer::__construct(): Argument #2 ($options) "soap_version" option must be SOAP_1_1 or SOAP_1_2 +ValueError: SoapServer::__construct(): Argument #2 ($options) "soap_version" option must be SOAP_1_1 or SOAP_1_2 diff --git a/ext/soap/tests/SoapServer/missing-options-non-wsdl-mode.phpt b/ext/soap/tests/SoapServer/missing-options-non-wsdl-mode.phpt index 54e6493879e1..0b15d39d1915 100644 --- a/ext/soap/tests/SoapServer/missing-options-non-wsdl-mode.phpt +++ b/ext/soap/tests/SoapServer/missing-options-non-wsdl-mode.phpt @@ -48,5 +48,9 @@ try { ?> --EXPECT-- $options not provided - -SOAP-ENV:ServerSoapServer::__construct(): 'uri' option is required in nonWSDL mode +TypeError: SoapServer::__construct(): Argument #2 ($options) "uri" option is required when argument #1 ($wsdl) is null +TypeError: SoapServer::__construct(): Argument #2 ($options) "uri" option is required when argument #1 ($wsdl) is null +Empty $options array +TypeError: SoapServer::__construct(): Argument #2 ($options) "uri" option is required when argument #1 ($wsdl) is null +TypeError: SoapServer::__construct(): Argument #2 ($options) "uri" option is required when argument #1 ($wsdl) is null +$options array only sets "uri" option diff --git a/ext/soap/tests/bugs/gh16256.phpt b/ext/soap/tests/bugs/gh16256.phpt index ca8c00af5bbf..ce2ba1314069 100644 --- a/ext/soap/tests/bugs/gh16256.phpt +++ b/ext/soap/tests/bugs/gh16256.phpt @@ -21,5 +21,4 @@ try { ?> --EXPECT-- SoapClient::__construct(): 'classmap' option must be an associative array - -SOAP-ENV:ServerSoapServer::__construct(): 'classmap' option must be an associative array +SoapServer::__construct(): Argument #2 ($options) "classmap" option must be an associative array From 4491fc0e5c0a72c2e4086465d070a6be375d4365 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 3 Jul 2026 22:02:19 +0100 Subject: [PATCH 3/3] Review comments --- ext/soap/soap.c | 4 ++-- .../tests/SoapServer/SoapServer_constructor_errors.phpt | 1 + .../SoapServer/invalid-soap_version-option-type.phpt | 2 +- .../tests/SoapServer/invalid-soap_version-option.phpt | 2 +- .../tests/SoapServer/missing-options-non-wsdl-mode.phpt | 8 ++++---- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ext/soap/soap.c b/ext/soap/soap.c index e70198e6f6c5..d4845873e689 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -972,7 +972,7 @@ PHP_METHOD(SoapServer, __construct) } service->uri = estrndup(Z_STRVAL_P(uri_zv), Z_STRLEN_P(uri_zv)); } else if (!wsdl) { - zend_argument_type_error(2, "\"uri\" option is required when argument #1 ($wsdl) is null"); + zend_argument_value_error(2, "\"uri\" option is required when argument #1 ($wsdl) is null"); goto cleanup; } @@ -1082,7 +1082,7 @@ PHP_METHOD(SoapServer, __construct) } } } else if (!wsdl) { - zend_argument_type_error(2, "\"uri\" option is required when argument #1 ($wsdl) is null"); + zend_argument_value_error(2, "\"uri\" option is required when argument #1 ($wsdl) is null"); goto cleanup; } diff --git a/ext/soap/tests/SoapServer/SoapServer_constructor_errors.phpt b/ext/soap/tests/SoapServer/SoapServer_constructor_errors.phpt index c143be174af5..61b0a352b339 100644 --- a/ext/soap/tests/SoapServer/SoapServer_constructor_errors.phpt +++ b/ext/soap/tests/SoapServer/SoapServer_constructor_errors.phpt @@ -78,6 +78,7 @@ try { } catch (Throwable $e) { echo $e::class, ': ', $e->getMessage(), PHP_EOL; } + ?> --EXPECT-- TypeError: SoapServer::__construct(): Argument #2 ($options) "uri" option must be of type string, int given diff --git a/ext/soap/tests/SoapServer/invalid-soap_version-option-type.phpt b/ext/soap/tests/SoapServer/invalid-soap_version-option-type.phpt index a63b5dfe06a8..690a35159a7c 100644 --- a/ext/soap/tests/SoapServer/invalid-soap_version-option-type.phpt +++ b/ext/soap/tests/SoapServer/invalid-soap_version-option-type.phpt @@ -1,5 +1,5 @@ --TEST-- -SoapServer constructor with an invalid encoding option +SoapServer constructor with an invalid soap_version option --EXTENSIONS-- soap --FILE-- diff --git a/ext/soap/tests/SoapServer/invalid-soap_version-option.phpt b/ext/soap/tests/SoapServer/invalid-soap_version-option.phpt index c3f655699288..6b8b25e44e12 100644 --- a/ext/soap/tests/SoapServer/invalid-soap_version-option.phpt +++ b/ext/soap/tests/SoapServer/invalid-soap_version-option.phpt @@ -1,5 +1,5 @@ --TEST-- -SoapServer constructor with an invalid encoding option +SoapServer constructor with an invalid soap_version option --EXTENSIONS-- soap --FILE-- diff --git a/ext/soap/tests/SoapServer/missing-options-non-wsdl-mode.phpt b/ext/soap/tests/SoapServer/missing-options-non-wsdl-mode.phpt index 0b15d39d1915..4f1fc89195ed 100644 --- a/ext/soap/tests/SoapServer/missing-options-non-wsdl-mode.phpt +++ b/ext/soap/tests/SoapServer/missing-options-non-wsdl-mode.phpt @@ -48,9 +48,9 @@ try { ?> --EXPECT-- $options not provided -TypeError: SoapServer::__construct(): Argument #2 ($options) "uri" option is required when argument #1 ($wsdl) is null -TypeError: SoapServer::__construct(): Argument #2 ($options) "uri" option is required when argument #1 ($wsdl) is null +ValueError: SoapServer::__construct(): Argument #2 ($options) "uri" option is required when argument #1 ($wsdl) is null +ValueError: SoapServer::__construct(): Argument #2 ($options) "uri" option is required when argument #1 ($wsdl) is null Empty $options array -TypeError: SoapServer::__construct(): Argument #2 ($options) "uri" option is required when argument #1 ($wsdl) is null -TypeError: SoapServer::__construct(): Argument #2 ($options) "uri" option is required when argument #1 ($wsdl) is null +ValueError: SoapServer::__construct(): Argument #2 ($options) "uri" option is required when argument #1 ($wsdl) is null +ValueError: SoapServer::__construct(): Argument #2 ($options) "uri" option is required when argument #1 ($wsdl) is null $options array only sets "uri" option