diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index a25aff396b2..ec27db3d907 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -864,6 +864,45 @@ static xmlNodePtr to_xml_null(encodeTypePtr type, zval *data, int style, xmlNode return ret; } +static void set_zval_property(zval* object, char* name, zval* val TSRMLS_DC) +{ + zend_class_entry *old_scope; + + old_scope = EG(scope); + EG(scope) = Z_OBJCE_P(object); +#ifdef ZEND_ENGINE_2 + val->refcount--; +#endif + add_property_zval(object, name, val); + EG(scope) = old_scope; +} + +static zval* get_zval_property(zval* object, char* name TSRMLS_DC) +{ + if (Z_TYPE_P(object) == IS_OBJECT) { + zval member; + zval *data; + zend_class_entry *old_scope; + + ZVAL_STRING(&member, name, 0); + old_scope = EG(scope); + EG(scope) = Z_OBJCE_P(object); + data = Z_OBJ_HT_P(object)->read_property(object, &member, BP_VAR_IS TSRMLS_CC); + EG(scope) = old_scope; + if (data == EG(uninitialized_zval_ptr)) { + return NULL; + } + return data; + } else if (Z_TYPE_P(object) == IS_ARRAY) { + zval **data_ptr; + + if (zend_hash_find(Z_ARRVAL_P(object), name, strlen(name)+1, (void**)&data_ptr) == SUCCESS) { + return *data_ptr; + } + } + return NULL; +} + static void model_to_zval_object(zval *ret, sdlContentModelPtr model, xmlNodePtr data, sdlPtr sdl TSRMLS_DC) { switch (model->kind) { @@ -920,10 +959,7 @@ static void model_to_zval_object(zval *ret, sdlContentModelPtr model, xmlNodePtr } while ((node = get_node(node->next, model->u.element->name)) != NULL); val = array; } -#ifdef ZEND_ENGINE_2 - val->refcount--; -#endif - add_property_zval(ret, model->u.element->name, val); + set_zval_property(ret, model->u.element->name, val TSRMLS_CC); } } break; @@ -965,7 +1001,7 @@ static zval *to_zval_object(encodeTypePtr type, xmlNodePtr data) if (zend_hash_find(SOAP_GLOBAL(class_map), type->type_str, strlen(type->type_str)+1, (void**)&classname) == SUCCESS && Z_TYPE_PP(classname) == IS_STRING && (tmp = zend_fetch_class(Z_STRVAL_PP(classname), Z_STRLEN_PP(classname), ZEND_FETCH_CLASS_AUTO TSRMLS_CC)) != NULL) { - ce = tmp; + ce = tmp; } } sdl = SOAP_GLOBAL(sdl); @@ -988,10 +1024,7 @@ static zval *to_zval_object(encodeTypePtr type, xmlNodePtr data) object_init_ex(ret, ce); base = master_to_zval_int(enc, data); -#ifdef ZEND_ENGINE_2 - base->refcount--; -#endif - add_property_zval(ret, "_", base); + set_zval_property(ret, "_", base TSRMLS_CC); } else { MAKE_STD_ZVAL(ret); FIND_XML_NULL(data, ret); @@ -1013,10 +1046,7 @@ static zval *to_zval_object(encodeTypePtr type, xmlNodePtr data) object_init_ex(ret, ce); base = master_to_zval_int(sdlType->encode, data); -#ifdef ZEND_ENGINE_2 - base->refcount--; -#endif - add_property_zval(ret, "_", base); + set_zval_property(ret, "_", base TSRMLS_CC); } } else { MAKE_STD_ZVAL(ret); @@ -1054,10 +1084,7 @@ static zval *to_zval_object(encodeTypePtr type, xmlNodePtr data) xmlNodeSetContent(dummy, str_val); data = master_to_zval((*attr)->encode, dummy); xmlFreeNode(dummy); -#ifdef ZEND_ENGINE_2 - data->refcount--; -#endif - add_property_zval(ret, (*attr)->name, data); + set_zval_property(ret, (*attr)->name, data TSRMLS_CC); } } zend_hash_move_forward_ex(sdlType->attributes, &pos); @@ -1074,30 +1101,28 @@ static zval *to_zval_object(encodeTypePtr type, xmlNodePtr data) while (trav != NULL) { if (trav->type == XML_ELEMENT_NODE) { zval *tmpVal; - zval **prop; - int key_len; + zval *prop; tmpVal = master_to_zval(NULL, trav); - key_len = strlen(trav->name) + 1; - if (zend_hash_find(Z_OBJPROP_P(ret), (char*)trav->name, key_len, (void **) &prop) == FAILURE) { -#ifdef ZEND_ENGINE_2 - tmpVal->refcount--; -#endif - add_property_zval_ex(ret, (char*)trav->name, key_len, tmpVal TSRMLS_CC); + prop = get_zval_property(ret, (char*)trav->name TSRMLS_CC); + if (!prop) { + set_zval_property(ret, (char*)trav->name, tmpVal TSRMLS_CC); } else { /* Property already exist - make array */ - if (Z_TYPE_PP(prop) != IS_ARRAY) { + if (Z_TYPE_P(prop) != IS_ARRAY) { /* Convert into array */ zval *arr; MAKE_STD_ZVAL(arr); array_init(arr); - add_next_index_zval(arr, *prop); - *prop = arr; + prop->refcount++; + add_next_index_zval(arr, prop); + set_zval_property(ret, (char*)trav->name, arr TSRMLS_CC); + prop = arr; } /* Add array element */ - add_next_index_zval(*prop, tmpVal); + add_next_index_zval(prop, tmpVal); } } trav = trav->next; @@ -1106,18 +1131,19 @@ static zval *to_zval_object(encodeTypePtr type, xmlNodePtr data) return ret; } -static int model_to_xml_object(xmlNodePtr node, sdlContentModelPtr model, HashTable *prop, int style, int strict) +static int model_to_xml_object(xmlNodePtr node, sdlContentModelPtr model, zval *object, int style, int strict TSRMLS_DC) { switch (model->kind) { case XSD_CONTENT_ELEMENT: { - zval **data; + zval *data; xmlNodePtr property; encodePtr enc; - if (zend_hash_find(prop, model->u.element->name, strlen(model->u.element->name)+1, (void**)&data) == SUCCESS) { + data = get_zval_property(object, model->u.element->name TSRMLS_CC); + if (data) { enc = model->u.element->encode; - if ((model->max_occurs == -1 || model->max_occurs > 1) && Z_TYPE_PP(data) == IS_ARRAY) { - HashTable *ht = Z_ARRVAL_PP(data); + if ((model->max_occurs == -1 || model->max_occurs > 1) && Z_TYPE_P(data) == IS_ARRAY) { + HashTable *ht = Z_ARRVAL_P(data); zval **val; zend_hash_internal_pointer_reset(ht); @@ -1146,7 +1172,7 @@ static int model_to_xml_object(xmlNodePtr node, sdlContentModelPtr model, HashTa zend_hash_move_forward(ht); } } else { - if (Z_TYPE_PP(data) == IS_NULL && model->u.element->nillable) { + if (Z_TYPE_P(data) == IS_NULL && model->u.element->nillable) { property = xmlNewNode(NULL,"BOGUS"); xmlAddChild(node, property); if (style == SOAP_ENCODED) { @@ -1156,7 +1182,7 @@ static int model_to_xml_object(xmlNodePtr node, sdlContentModelPtr model, HashTa xmlSetNsProp(property, xsi, "nil", "1"); } } else { - property = master_to_xml(enc, *data, style, node); + property = master_to_xml(enc, data, style, node); if (property->children && property->children->content && model->u.element->fixed && strcmp(model->u.element->fixed,property->children->content) != 0) { soap_error3(E_ERROR, "Encoding: Element '%s' has fixed value '%s' (value '%s' is not allowed)", model->u.element->name, model->u.element->fixed, property->children->content); @@ -1186,7 +1212,7 @@ static int model_to_xml_object(xmlNodePtr node, sdlContentModelPtr model, HashTa zend_hash_internal_pointer_reset_ex(model->u.content, &pos); while (zend_hash_get_current_data_ex(model->u.content, (void**)&tmp, &pos) == SUCCESS) { - if (!model_to_xml_object(node, *tmp, prop, style, model->min_occurs > 0)) { + if (!model_to_xml_object(node, *tmp, object, style, model->min_occurs > 0 TSRMLS_CC)) { return 0; } zend_hash_move_forward_ex(model->u.content, &pos); @@ -1200,7 +1226,7 @@ static int model_to_xml_object(xmlNodePtr node, sdlContentModelPtr model, HashTa zend_hash_internal_pointer_reset_ex(model->u.content, &pos); while (zend_hash_get_current_data_ex(model->u.content, (void**)&tmp, &pos) == SUCCESS) { - int tmp_ret = model_to_xml_object(node, *tmp, prop, style, 0); + int tmp_ret = model_to_xml_object(node, *tmp, object, style, 0 TSRMLS_CC); if (tmp_ret == 1) { return 1; } else if (tmp_ret != 0) { @@ -1211,7 +1237,7 @@ static int model_to_xml_object(xmlNodePtr node, sdlContentModelPtr model, HashTa return ret; } case XSD_CONTENT_GROUP: { - return model_to_xml_object(node, model->u.group->model, prop, style, model->min_occurs > 0); + return model_to_xml_object(node, model->u.group->model, object, style, model->min_occurs > 0 TSRMLS_CC); } default: break; @@ -1287,9 +1313,9 @@ static xmlNodePtr to_xml_object(encodeTypePtr type, zval *data, int style, xmlNo enc = enc->details.sdl_type->encode; } if (enc) { - zval **tmp; - if (prop && zend_hash_find(prop, "_", sizeof("_"), (void**)&tmp) == SUCCESS) { - xmlParam = master_to_xml(enc, *tmp, style, parent); + zval *tmp = get_zval_property(data, "_" TSRMLS_CC); + if (tmp) { + xmlParam = master_to_xml(enc, tmp, style, parent); } else if (prop == NULL) { xmlParam = master_to_xml(enc, data, style, parent); } else { @@ -1308,10 +1334,10 @@ static xmlNodePtr to_xml_object(encodeTypePtr type, zval *data, int style, xmlNo sdlType->encode->details.sdl_type->kind != XSD_TYPEKIND_UNION) { xmlParam = master_to_xml(sdlType->encode, data, style, parent); } else { - zval **tmp; + zval *tmp = get_zval_property(data, "_" TSRMLS_CC); - if (prop && zend_hash_find(prop, "_", sizeof("_"), (void**)&tmp) == SUCCESS) { - xmlParam = master_to_xml(sdlType->encode, *tmp, style, parent); + if (tmp) { + xmlParam = master_to_xml(sdlType->encode, tmp, style, parent); } else if (prop == NULL) { xmlParam = master_to_xml(sdlType->encode, data, style, parent); } else { @@ -1358,25 +1384,26 @@ static xmlNodePtr to_xml_object(encodeTypePtr type, zval *data, int style, xmlNo zend_hash_move_forward(prop); } } else if (sdlType->model) { - model_to_xml_object(xmlParam, sdlType->model, prop, style, 1); + model_to_xml_object(xmlParam, sdlType->model, data, style, 1 TSRMLS_CC); } if (sdlType->attributes) { sdlAttributePtr *attr; - zval **data; + zval *zattr; HashPosition pos; zend_hash_internal_pointer_reset_ex(sdlType->attributes, &pos); while (zend_hash_get_current_data_ex(sdlType->attributes, (void**)&attr, &pos) == SUCCESS) { if ((*attr)->name) { - if (zend_hash_find(prop, (*attr)->name, strlen((*attr)->name)+1, (void**)&data) == SUCCESS) { + zattr = get_zval_property(data, (*attr)->name TSRMLS_CC); + if (zattr) { xmlNodePtr dummy; - dummy = master_to_xml((*attr)->encode, *data, SOAP_LITERAL, xmlParam); + dummy = master_to_xml((*attr)->encode, zattr, SOAP_LITERAL, xmlParam); if (dummy->children && dummy->children->content) { if ((*attr)->fixed && strcmp((*attr)->fixed,dummy->children->content) != 0) { soap_error3(E_ERROR, "Encoding: Attribute '%s' has fixed value '%s' (value '%s' is not allowed)", (*attr)->name, (*attr)->fixed, dummy->children->content); } - if ((*attr)->namens && + if ((*attr)->namens && (type->ns == NULL || strcmp((*attr)->namens, type->ns))) { xmlNsPtr nsp = encode_add_ns(xmlParam, (*attr)->namens); diff --git a/ext/soap/tests/bugs/bug30928.phpt b/ext/soap/tests/bugs/bug30928.phpt new file mode 100644 index 00000000000..c7b497c0ed3 --- /dev/null +++ b/ext/soap/tests/bugs/bug30928.phpt @@ -0,0 +1,63 @@ +--TEST-- +Bug #30928 When Using WSDL, SoapServer doesn't handle private or protected properties +--SKIPIF-- + +--FILE-- +server = new SoapServer($wsdl, $options); + $this->server->addFunction('test'); + } + + function __doRequest($request, $location, $action, $version) { + ob_start(); + $this->server->handle($request); + $response = ob_get_contents(); + ob_end_clean(); + return $response; + } +} + +$x = new LocalSoapClient(dirname(__FILE__)."/bug30928.wsdl", + array()); +var_dump($x->test(new foo())); + +$x = new LocalSoapClient(dirname(__FILE__)."/bug30928.wsdl", + array("classmap" => array('testType'=>'foo'))); +var_dump($x->test(new foo())); + +echo "ok\n"; +?> +--EXPECTF-- +object(stdClass)#%d (3) { + ["a"]=> + string(1) "a" + ["b"]=> + string(1) "b" + ["c"]=> + string(1) "c" +} +object(foo)#%d (3) { + ["a"]=> + string(1) "a" + ["b:private"]=> + string(1) "b" + ["c:protected"]=> + string(1) "c" +} +ok diff --git a/ext/soap/tests/bugs/bug30928.wsdl b/ext/soap/tests/bugs/bug30928.wsdl new file mode 100644 index 00000000000..9814883ed5f --- /dev/null +++ b/ext/soap/tests/bugs/bug30928.wsdl @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +