From 7dc9be77fc5532c3e8fe9ee04954efff09787b94 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov <dmitry@php.net> Date: Thu, 2 Feb 2006 11:41:45 +0000 Subject: [PATCH] Bug #36226 Inconsistent handling when passing potential arrays --- NEWS | 2 + ext/soap/php_encoding.c | 8 ++ ext/soap/php_soap.h | 4 + ext/soap/soap.c | 32 ++++++- ext/soap/tests/bugs/bug36226.phpt | 139 ++++++++++++++++++++++++++++++ 5 files changed, 182 insertions(+), 3 deletions(-) create mode 100755 ext/soap/tests/bugs/bug36226.phpt diff --git a/NEWS b/NEWS index 1e3e8a4d79..4bfc8ababe 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,8 @@ PHP NEWS - Fixed bug #36242 (Possible memory corruption in stream_select()). (Tony) - Fixed bug #36235 (ocicolumnname returns false before a succesfull fetch). (Tony) +- Fixed bug #36226 (Inconsistent handling when passing potential arrays). + (Dmitry) - Fixed bug #36224 (date(DATE_ATOM) gives wrong results). (Derick, Hannes Magnusson) - Fixed bug #36222 (errorInfo in PDOException is always NULL). (Ilia) diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index b9c663298d..6c7a4478d6 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -1157,6 +1157,14 @@ static void model_to_zval_object(zval *ret, sdlContentModelPtr model, xmlNodePtr add_next_index_zval(array, val); } while ((node = get_node(node->next, model->u.element->name)) != NULL); val = array; + } else if ((SOAP_GLOBAL(features) & SOAP_SINGLE_ELEMENT_ARRAYS) && + (model->max_occurs == -1 || model->max_occurs > 1)) { + zval *array; + + MAKE_STD_ZVAL(array); + array_init(array); + add_next_index_zval(array, val); + val = array; } set_zval_property(ret, model->u.element->name, val TSRMLS_CC); } diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h index e6dac36a35..7d2faac1c0 100644 --- a/ext/soap/php_soap.h +++ b/ext/soap/php_soap.h @@ -119,6 +119,7 @@ struct _soapService { char *uri; xmlCharEncodingHandlerPtr encoding; HashTable *class_map; + int features; }; #define SOAP_CLASS 1 @@ -151,6 +152,8 @@ struct _soapService { #define SOAP_AUTHENTICATION_BASIC 0 #define SOAP_AUTHENTICATION_DIGEST 1 +#define SOAP_SINGLE_ELEMENT_ARRAYS (1<<0) + ZEND_BEGIN_MODULE_GLOBALS(soap) HashTable defEncNs; /* mapping of default namespaces to prefixes */ HashTable defEnc; @@ -167,6 +170,7 @@ ZEND_BEGIN_MODULE_GLOBALS(soap) long cache_ttl; xmlCharEncodingHandlerPtr encoding; HashTable *class_map; + int features; ZEND_END_MODULE_GLOBALS(soap) #ifdef PHP_WIN32 diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 099228deb7..d539a51810 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -479,6 +479,7 @@ PHP_RINIT_FUNCTION(soap) SOAP_GLOBAL(soap_version) = SOAP_1_1; SOAP_GLOBAL(encoding) = NULL; SOAP_GLOBAL(class_map) = NULL; + SOAP_GLOBAL(features) = 0; return SUCCESS; } @@ -633,6 +634,8 @@ PHP_MINIT_FUNCTION(soap) REGISTER_STRING_CONSTANT("XSD_NAMESPACE", XSD_NAMESPACE, CONST_CS | CONST_PERSISTENT); REGISTER_STRING_CONSTANT("XSD_1999_NAMESPACE", XSD_1999_NAMESPACE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SOAP_SINGLE_ELEMENT_ARRAYS", SOAP_SINGLE_ELEMENT_ARRAYS, CONST_CS | CONST_PERSISTENT); + old_error_handler = zend_error_cb; zend_error_cb = soap_error_handler; @@ -957,6 +960,11 @@ PHP_METHOD(SoapServer, SoapServer) zend_hash_copy(service->class_map, (*tmp)->value.ht, (copy_ctor_func_t) zval_add_ref, (void *) &ztmp, sizeof(zval *)); } + if (zend_hash_find(ht, "features", sizeof("features"), (void**)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_LONG) { + service->features = Z_LVAL_PP(tmp); + } + } else if (wsdl == NULL) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid arguments. 'uri' option is required in nonWSDL mode."); } @@ -1358,6 +1366,7 @@ PHP_METHOD(SoapServer, handle) int arg_len; xmlCharEncodingHandlerPtr old_encoding; HashTable *old_class_map; + int old_features; SOAP_SERVER_BEGIN_CODE(); @@ -1503,6 +1512,8 @@ PHP_METHOD(SoapServer, handle) SOAP_GLOBAL(encoding) = service->encoding; old_class_map = SOAP_GLOBAL(class_map); SOAP_GLOBAL(class_map) = service->class_map; + old_features = SOAP_GLOBAL(features); + SOAP_GLOBAL(features) = service->features; old_soap_version = SOAP_GLOBAL(soap_version); function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, ¶ms, &soap_version, &soap_headers TSRMLS_CC); xmlFreeDoc(doc_request); @@ -1773,6 +1784,7 @@ fail: SOAP_GLOBAL(encoding) = old_encoding; SOAP_GLOBAL(sdl) = old_sdl; SOAP_GLOBAL(class_map) = old_class_map; + SOAP_GLOBAL(features) = old_features; /* Free soap headers */ zval_dtor(&retval); @@ -2189,6 +2201,11 @@ PHP_METHOD(SoapClient, SoapClient) add_property_zval(this_ptr, "_classmap", class_map); } + if (zend_hash_find(ht, "features", sizeof("features"), (void**)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_ARRAY) { + add_property_long(this_ptr, "_features", Z_LVAL_PP(tmp)); + } + if (zend_hash_find(ht, "connection_timeout", sizeof("connection_timeout"), (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_LONG && Z_LVAL_PP(tmp) > 0) { add_property_long(this_ptr, "_connection_timeout", Z_LVAL_PP(tmp)); @@ -2313,6 +2330,7 @@ static void do_soap_call(zval* this_ptr, zval response; xmlCharEncodingHandlerPtr old_encoding; HashTable *old_class_map; + int old_features; SOAP_CLIENT_BEGIN_CODE(); @@ -2358,6 +2376,13 @@ static void do_soap_call(zval* this_ptr, } else { SOAP_GLOBAL(class_map) = NULL; } + old_features = SOAP_GLOBAL(features); + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_features", sizeof("_features"), (void **) &tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_LONG) { + SOAP_GLOBAL(features) = Z_LVAL_PP(tmp); + } else { + SOAP_GLOBAL(features) = 0; + } if (sdl != NULL) { fn = get_function(sdl, function); @@ -2458,10 +2483,11 @@ static void do_soap_call(zval* this_ptr, zend_throw_exception_object(exception TSRMLS_CC); } #endif - if (SOAP_GLOBAL(encoding) != NULL) { + if (SOAP_GLOBAL(encoding) != NULL) { xmlCharEncCloseFunc(SOAP_GLOBAL(encoding)); - } - SOAP_GLOBAL(class_map) = old_class_map; + } + SOAP_GLOBAL(features) = old_features; + SOAP_GLOBAL(class_map) = old_class_map; SOAP_GLOBAL(encoding) = old_encoding; SOAP_GLOBAL(sdl) = old_sdl; SOAP_CLIENT_END_CODE(); diff --git a/ext/soap/tests/bugs/bug36226.phpt b/ext/soap/tests/bugs/bug36226.phpt new file mode 100755 index 0000000000..572a380b02 --- /dev/null +++ b/ext/soap/tests/bugs/bug36226.phpt @@ -0,0 +1,139 @@ +--TEST-- +Bug #36226 SOAP Inconsistent handling when passing potential arrays. +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +<?php +ini_set("soap.wsdl_cache_enabled",0); +$timestamp = "2005-11-08T11:22:07+03:00"; +$wsdl = dirname(__FILE__)."/bug35142.wsdl"; + +function PostEvents($x) { + var_dump($x); + exit(); + return $x; +} + +class TestSoapClient extends SoapClient { + + function __construct($wsdl, $options) { + parent::__construct($wsdl, $options); + $this->server = new SoapServer($wsdl, $options); + $this->server->addFunction('PostEvents'); + } + + function __doRequest($request, $location, $action, $version) { + echo "$request\n"; + $this->server->handle($request); + return $response; + } + +} + +$soapClient = new TestSoapClient($wsdl, + array('trace' => 1, 'exceptions' => 0, + 'classmap' => array('logOnEvent' => 'LogOnEvent', + 'logOffEvent' => 'LogOffEvent', + 'events' => 'IVREvents'), + 'features' => SOAP_SINGLE_ELEMENT_ARRAYS)); + +$logOnEvent = new LogOnEvent(34567, $timestamp); +$logOffEvents[] = new LogOffEvent(34567, $timestamp, "Smoked"); +$logOffEvents[] = new LogOffEvent(34568, $timestamp, "SmokeFree"); +$ivrEvents = new IVREvents("1.0", 101, 12345, 'IVR', $logOnEvent, $logOffEvents); + +$result = $soapClient->PostEvents($ivrEvents); + +class LogOffEvent { + public $audienceMemberId; + public $timestamp; + public $smokeStatus; + public $callInititator; + + function __construct($audienceMemberId, $timestamp, $smokeStatus) { + $this->audienceMemberId = $audienceMemberId; + $this->timestamp = $timestamp; + $this->smokeStatus = $smokeStatus; + $this->callInitiator = "IVR"; + } +} + +class LogOnEvent { + public $audienceMemberId; + public $timestamp; + + function __construct($audienceMemberId, $timestamp) { + $this->audienceMemberId = $audienceMemberId; + $this->timestamp = $timestamp; + } +} + +class IVREvents { + public $version; + public $activityId; + public $messageId; + public $source; + public $logOnEvent; + public $logOffEvent; + + function __construct($version, $activityId, $messageId, $source, $logOnEvent=NULL, $logOffEvent=NULL) { + $this->version = $version; + $this->activityId = $activityId; + $this->messageId = $messageId; + $this->source = $source; + $this->logOnEvent = $logOnEvent; + $this->logOffEvent = $logOffEvent; + } +} +?> +--EXPECTF-- +<?xml version="1.0" encoding="UTF-8"?> +<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://testurl/Message"><SOAP-ENV:Body><ns1:ivrEvents version="1.0" activityId="101" messageId="12345" source="IVR"><ns1:logOffEvent audienceMemberId="34567" timestamp="2005-11-08T11:22:07+03:00" smokeStatus="Smoked" callInitiator="IVR"/><ns1:logOffEvent audienceMemberId="34568" timestamp="2005-11-08T11:22:07+03:00" smokeStatus="SmokeFree" callInitiator="IVR"/><ns1:logOnEvent audienceMemberId="34567" timestamp="2005-11-08T11:22:07+03:00"/></ns1:ivrEvents></SOAP-ENV:Body></SOAP-ENV:Envelope> + +object(IVREvents)#%d (6) { + ["version"]=> + string(3) "1.0" + ["activityId"]=> + int(101) + ["messageId"]=> + int(12345) + ["logOffEvent"]=> + array(2) { + [0]=> + object(LogOffEvent)#%d (4) { + ["audienceMemberId"]=> + int(34567) + ["timestamp"]=> + string(25) "2005-11-08T11:22:07+03:00" + ["smokeStatus"]=> + string(6) "Smoked" + ["callInitiator"]=> + string(3) "IVR" + } + [1]=> + object(LogOffEvent)#%d (4) { + ["audienceMemberId"]=> + int(34568) + ["timestamp"]=> + string(25) "2005-11-08T11:22:07+03:00" + ["smokeStatus"]=> + string(9) "SmokeFree" + ["callInitiator"]=> + string(3) "IVR" + } + } + ["logOnEvent"]=> + array(1) { + [0]=> + object(LogOnEvent)#10 (2) { + ["audienceMemberId"]=> + int(34567) + ["timestamp"]=> + string(25) "2005-11-08T11:22:07+03:00" + } + } + ["source"]=> + string(3) "IVR" +} -- 2.40.0