diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h index a78734aa7f17..d98235b68b73 100644 --- a/ext/soap/php_soap.h +++ b/ext/soap/php_soap.h @@ -223,35 +223,34 @@ static zend_always_inline zval *php_soap_deref(zval *zv) { #define Z_CLIENT_TRACE_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 4)) #define Z_CLIENT_COMPRESSION_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 5)) #define Z_CLIENT_SDL_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 6)) -#define Z_CLIENT_TYPEMAP_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 7)) -#define Z_CLIENT_HTTPSOCKET_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 8)) -#define Z_CLIENT_HTTPURL_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 9)) -#define Z_CLIENT_LOGIN_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 10)) -#define Z_CLIENT_PASSWORD_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 11)) -#define Z_CLIENT_USE_DIGEST_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 12)) -#define Z_CLIENT_DIGEST_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 13)) -#define Z_CLIENT_PROXY_HOST_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 14)) -#define Z_CLIENT_PROXY_PORT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 15)) -#define Z_CLIENT_PROXY_LOGIN_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 16)) -#define Z_CLIENT_PROXY_PASSWORD_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 17)) -#define Z_CLIENT_EXCEPTIONS_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 18)) -#define Z_CLIENT_ENCODING_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 19)) -#define Z_CLIENT_CLASSMAP_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 20)) -#define Z_CLIENT_FEATURES_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 21)) -#define Z_CLIENT_CONNECTION_TIMEOUT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 22)) -#define Z_CLIENT_STREAM_CONTEXT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 23)) -#define Z_CLIENT_USER_AGENT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 24)) -#define Z_CLIENT_KEEP_ALIVE_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 25)) -#define Z_CLIENT_SSL_METHOD_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 26)) -#define Z_CLIENT_SOAP_VERSION_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 27)) -#define Z_CLIENT_USE_PROXY_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 28)) -#define Z_CLIENT_COOKIES_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 29)) -#define Z_CLIENT_DEFAULT_HEADERS_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 30)) -#define Z_CLIENT_SOAP_FAULT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 31)) -#define Z_CLIENT_LAST_REQUEST_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 32)) -#define Z_CLIENT_LAST_RESPONSE_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 33)) -#define Z_CLIENT_LAST_REQUEST_HEADERS_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 34)) -#define Z_CLIENT_LAST_RESPONSE_HEADERS_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 35)) +#define Z_CLIENT_HTTPSOCKET_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 7)) +#define Z_CLIENT_HTTPURL_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 8)) +#define Z_CLIENT_LOGIN_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 9)) +#define Z_CLIENT_PASSWORD_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 10)) +#define Z_CLIENT_USE_DIGEST_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 11)) +#define Z_CLIENT_DIGEST_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 12)) +#define Z_CLIENT_PROXY_HOST_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 13)) +#define Z_CLIENT_PROXY_PORT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 14)) +#define Z_CLIENT_PROXY_LOGIN_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 15)) +#define Z_CLIENT_PROXY_PASSWORD_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 16)) +#define Z_CLIENT_EXCEPTIONS_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 17)) +#define Z_CLIENT_ENCODING_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 18)) +#define Z_CLIENT_CLASSMAP_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 19)) +#define Z_CLIENT_FEATURES_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 20)) +#define Z_CLIENT_CONNECTION_TIMEOUT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 21)) +#define Z_CLIENT_STREAM_CONTEXT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 22)) +#define Z_CLIENT_USER_AGENT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 23)) +#define Z_CLIENT_KEEP_ALIVE_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 24)) +#define Z_CLIENT_SSL_METHOD_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 25)) +#define Z_CLIENT_SOAP_VERSION_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 26)) +#define Z_CLIENT_USE_PROXY_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 27)) +#define Z_CLIENT_COOKIES_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 28)) +#define Z_CLIENT_DEFAULT_HEADERS_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 29)) +#define Z_CLIENT_SOAP_FAULT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 30)) +#define Z_CLIENT_LAST_REQUEST_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 31)) +#define Z_CLIENT_LAST_RESPONSE_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 32)) +#define Z_CLIENT_LAST_REQUEST_HEADERS_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 33)) +#define Z_CLIENT_LAST_RESPONSE_HEADERS_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 34)) typedef struct soap_url_object { php_url *url; diff --git a/ext/soap/soap.c b/ext/soap/soap.c index ac14dee76cf0..fd3a0b3c0440 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -185,6 +185,7 @@ zend_class_entry* soap_var_class_entry; zend_class_entry *soap_url_class_entry; zend_class_entry *soap_sdl_class_entry; +static zend_object_handlers soap_client_object_handlers; static zend_object_handlers soap_server_object_handlers; static zend_object_handlers soap_url_object_handlers; static zend_object_handlers soap_sdl_object_handlers; @@ -194,10 +195,36 @@ typedef struct { zend_object std; } soap_server_object; +typedef struct { + HashTable *typemap; + zend_object std; +} soap_client_object; + +static inline soap_client_object *soap_client_object_fetch(zend_object *obj) { + return (soap_client_object *) ((char *) obj - XtOffsetOf(soap_client_object, std)); +} + static inline soap_server_object *soap_server_object_fetch(zend_object *obj) { return (soap_server_object *) ((char *) obj - XtOffsetOf(soap_server_object, std)); } +static zend_object *soap_client_object_create(zend_class_entry *ce) +{ + soap_client_object *obj = zend_object_alloc(sizeof(soap_client_object), ce); + zend_object_std_init(&obj->std, ce); + object_properties_init(&obj->std, ce); + return &obj->std; +} + +static void soap_client_object_free(zend_object *obj) { + soap_client_object *client_obj = soap_client_object_fetch(obj); + if (client_obj->typemap) { + zend_hash_destroy(client_obj->typemap); + FREE_HASHTABLE(client_obj->typemap); + } + zend_object_std_dtor(obj); +} + static zend_object *soap_server_object_create(zend_class_entry *ce) { soap_server_object *obj = zend_object_alloc(sizeof(soap_server_object), ce); @@ -496,6 +523,13 @@ PHP_MINIT_FUNCTION(soap) /* Register SoapClient class */ soap_class_entry = register_class_SoapClient(); + soap_class_entry->create_object = soap_client_object_create; + soap_class_entry->default_object_handlers = &soap_client_object_handlers; + + memcpy(&soap_client_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + soap_client_object_handlers.offset = XtOffsetOf(soap_client_object, std); + soap_client_object_handlers.free_obj = soap_client_object_free; + soap_client_object_handlers.clone_obj = NULL; /* Register SoapVar class */ soap_var_class_entry = register_class_SoapVar(); @@ -1978,6 +2012,7 @@ PHP_FUNCTION(is_soap_fault) /* SoapClient functions */ /* {{{ SoapClient constructor */ +/* FIXME: double construct call will break this class */ PHP_METHOD(SoapClient, __construct) { @@ -2201,10 +2236,7 @@ PHP_METHOD(SoapClient, __construct) } if (typemap_ht) { - HashTable *typemap = soap_create_typemap(sdl, typemap_ht); - if (typemap) { - ZVAL_ARR(Z_CLIENT_TYPEMAP_P(this_ptr), typemap); - } + soap_client_object_fetch(Z_OBJ_P(this_ptr))->typemap = soap_create_typemap(sdl, typemap_ht); } SOAP_CLIENT_END_CODE(); } @@ -2333,10 +2365,7 @@ static void do_soap_call(zend_execute_data *execute_data, sdl = Z_SOAP_SDL_P(tmp)->sdl; } - tmp = Z_CLIENT_TYPEMAP_P(this_ptr); - if (Z_TYPE_P(tmp) == IS_ARRAY) { - typemap = Z_ARR_P(tmp); - } + typemap = soap_client_object_fetch(Z_OBJ_P(this_ptr))->typemap; clear_soap_fault(this_ptr); diff --git a/ext/soap/soap.stub.php b/ext/soap/soap.stub.php index 82f884e24b30..b70a050bfe3a 100644 --- a/ext/soap/soap.stub.php +++ b/ext/soap/soap.stub.php @@ -540,7 +540,6 @@ class SoapClient private bool $trace = false; private ?int $compression = null; private ?Soap\Sdl $sdl = null; - private ?array $typemap = null; /** @var resource|null */ private $httpsocket = null; private ?Soap\Url $httpurl = null; diff --git a/ext/soap/soap_arginfo.h b/ext/soap/soap_arginfo.h index ca0d2d9644e8..6311aa2b4203 100644 --- a/ext/soap/soap_arginfo.h +++ b/ext/soap/soap_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 7712aba90b16090fbe7c124c1e3f26b2cc3e2ab2 */ + * Stub hash: b3b0e1ba5c8516493a0e323231d203659131338f */ 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") @@ -562,12 +562,6 @@ static zend_class_entry *register_class_SoapClient(void) zend_declare_typed_property(class_entry, property_sdl_name, &property_sdl_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_sdl_class_Soap_Sdl, 0, MAY_BE_NULL)); zend_string_release(property_sdl_name); - zval property_typemap_default_value; - ZVAL_NULL(&property_typemap_default_value); - zend_string *property_typemap_name = zend_string_init("typemap", sizeof("typemap") - 1, 1); - zend_declare_typed_property(class_entry, property_typemap_name, &property_typemap_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY|MAY_BE_NULL)); - zend_string_release(property_typemap_name); - zval property_httpsocket_default_value; ZVAL_NULL(&property_httpsocket_default_value); zend_string *property_httpsocket_name = zend_string_init("httpsocket", sizeof("httpsocket") - 1, 1); diff --git a/ext/soap/tests/bugs/gh21421.phpt b/ext/soap/tests/bugs/gh21421.phpt new file mode 100644 index 000000000000..1b8bb3be716f --- /dev/null +++ b/ext/soap/tests/bugs/gh21421.phpt @@ -0,0 +1,90 @@ +--TEST-- +GH-21421 (SoapClient typemap property breaks engine assumptions) +--EXTENSIONS-- +soap +--FILE-- + 'http://schemas.nothing.com', +'location' => 'test://', +'typemap' => array(array("type_ns" => "http://schemas.nothing.com", +"type_name" => "book", +"from_xml" => "book_from_xml")) +); +$client = new SoapClient(NULL, $options); +var_dump($client); +?> +--EXPECTF-- +object(SoapClient)#%d (35) { + ["uri":"SoapClient":private]=> + string(26) "http://schemas.nothing.com" + ["style":"SoapClient":private]=> + NULL + ["use":"SoapClient":private]=> + NULL + ["location":"SoapClient":private]=> + string(7) "test://" + ["trace":"SoapClient":private]=> + bool(false) + ["compression":"SoapClient":private]=> + NULL + ["sdl":"SoapClient":private]=> + NULL + ["httpsocket":"SoapClient":private]=> + NULL + ["httpurl":"SoapClient":private]=> + NULL + ["_login":"SoapClient":private]=> + NULL + ["_password":"SoapClient":private]=> + NULL + ["_use_digest":"SoapClient":private]=> + bool(false) + ["_digest":"SoapClient":private]=> + NULL + ["_proxy_host":"SoapClient":private]=> + NULL + ["_proxy_port":"SoapClient":private]=> + NULL + ["_proxy_login":"SoapClient":private]=> + NULL + ["_proxy_password":"SoapClient":private]=> + NULL + ["_exceptions":"SoapClient":private]=> + bool(true) + ["_encoding":"SoapClient":private]=> + NULL + ["_classmap":"SoapClient":private]=> + NULL + ["_features":"SoapClient":private]=> + NULL + ["_connection_timeout":"SoapClient":private]=> + int(0) + ["_stream_context":"SoapClient":private]=> + resource(%d) of type (stream-context) + ["_user_agent":"SoapClient":private]=> + NULL + ["_keep_alive":"SoapClient":private]=> + bool(true) + ["_ssl_method":"SoapClient":private]=> + NULL + ["_soap_version":"SoapClient":private]=> + int(1) + ["_use_proxy":"SoapClient":private]=> + NULL + ["_cookies":"SoapClient":private]=> + array(0) { + } + ["__default_headers":"SoapClient":private]=> + NULL + ["__soap_fault":"SoapClient":private]=> + NULL + ["__last_request":"SoapClient":private]=> + NULL + ["__last_response":"SoapClient":private]=> + NULL + ["__last_request_headers":"SoapClient":private]=> + NULL + ["__last_response_headers":"SoapClient":private]=> + NULL +}