xref: /PHP-8.3/ext/soap/soap.c (revision 2dbc6056)
1 /*
2   +----------------------------------------------------------------------+
3   | Copyright (c) The PHP Group                                          |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 3.01 of the PHP license,      |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | https://www.php.net/license/3_01.txt                                 |
9   | If you did not receive a copy of the PHP license and are unable to   |
10   | obtain it through the world-wide-web, please send a note to          |
11   | license@php.net so we can mail you a copy immediately.               |
12   +----------------------------------------------------------------------+
13   | Authors: Brad Lafountain <rodif_bl@yahoo.com>                        |
14   |          Shane Caraveo <shane@caraveo.com>                           |
15   |          Dmitry Stogov <dmitry@php.net>                              |
16   +----------------------------------------------------------------------+
17 */
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 #include "php_soap.h"
23 #if defined(HAVE_PHP_SESSION) && !defined(COMPILE_DL_SESSION)
24 #include "ext/session/php_session.h"
25 #endif
26 #include "soap_arginfo.h"
27 #include "zend_exceptions.h"
28 #include "zend_interfaces.h"
29 
30 
31 static int le_sdl = 0;
32 int le_url = 0;
33 static int le_typemap = 0;
34 
35 typedef struct _soapHeader {
36 	sdlFunctionPtr                    function;
37 	zval                              function_name;
38 	int                               mustUnderstand;
39 	int                               num_params;
40 	zval                             *parameters;
41 	zval                              retval;
42 	sdlSoapBindingFunctionHeaderPtr   hdr;
43 	struct _soapHeader               *next;
44 } soapHeader;
45 
46 /* Local functions */
47 static void function_to_string(sdlFunctionPtr function, smart_str *buf);
48 static void type_to_string(sdlTypePtr type, smart_str *buf, int level);
49 
50 static void clear_soap_fault(zval *obj);
51 static void set_soap_fault(zval *obj, char *fault_code_ns, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail, char *name);
52 static void add_soap_fault_ex(zval *fault, zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail);
53 static ZEND_NORETURN void soap_server_fault(char* code, char* string, char *actor, zval* details, char *name);
54 static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader* hdr);
55 
56 static sdlParamPtr get_param(sdlFunctionPtr function, char *param_name, int index, int);
57 static sdlFunctionPtr get_function(sdlPtr sdl, const char *function_name);
58 static sdlFunctionPtr get_doc_function(sdlPtr sdl, xmlNodePtr node);
59 
60 static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, char* actor, zval *function_name, int *num_params, zval **parameters, int *version, soapHeader **headers);
61 static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function_name,char *uri,zval *ret, soapHeader *headers, int version);
62 static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function, char *function_name, char *uri, zval *arguments, int arg_count, int version, HashTable *soap_headers);
63 static xmlNodePtr serialize_parameter(sdlParamPtr param,zval *param_val,int index,char *name, int style, xmlNodePtr parent);
64 static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName, int style, xmlNodePtr parent);
65 
66 static void delete_service(void *service);
67 static void delete_url(void *handle);
68 static void delete_hashtable(void *hashtable);
69 static void delete_argv(struct _soap_class *class);
70 
71 static void soap_error_handler(int error_num, zend_string *error_filename, const uint32_t error_lineno, zend_string *message);
72 
73 #define SOAP_SERVER_BEGIN_CODE() \
74 	bool _old_handler = SOAP_GLOBAL(use_soap_error_handler);\
75 	char* _old_error_code = SOAP_GLOBAL(error_code);\
76 	zend_object* _old_error_object = Z_OBJ(SOAP_GLOBAL(error_object));\
77 	int _old_soap_version = SOAP_GLOBAL(soap_version);\
78 	SOAP_GLOBAL(use_soap_error_handler) = 1;\
79 	SOAP_GLOBAL(error_code) = "Server";\
80 	Z_OBJ(SOAP_GLOBAL(error_object)) = Z_OBJ_P(ZEND_THIS);
81 
82 #define SOAP_SERVER_END_CODE() \
83 	SOAP_GLOBAL(use_soap_error_handler) = _old_handler;\
84 	SOAP_GLOBAL(error_code) = _old_error_code;\
85 	Z_OBJ(SOAP_GLOBAL(error_object)) = _old_error_object;\
86 	SOAP_GLOBAL(soap_version) = _old_soap_version;
87 
88 #define SOAP_CLIENT_BEGIN_CODE() \
89 	bool _old_handler = SOAP_GLOBAL(use_soap_error_handler);\
90 	char* _old_error_code = SOAP_GLOBAL(error_code);\
91 	zend_object* _old_error_object = Z_OBJ(SOAP_GLOBAL(error_object));\
92 	int _old_soap_version = SOAP_GLOBAL(soap_version);\
93 	bool _old_in_compilation = CG(in_compilation); \
94 	zend_execute_data *_old_current_execute_data = EG(current_execute_data); \
95 	zval *_old_stack_top = EG(vm_stack_top); \
96 	int _bailout = 0;\
97 	SOAP_GLOBAL(use_soap_error_handler) = 1;\
98 	SOAP_GLOBAL(error_code) = "Client";\
99 	Z_OBJ(SOAP_GLOBAL(error_object)) = Z_OBJ_P(ZEND_THIS);\
100 	zend_try {
101 
102 #define SOAP_CLIENT_END_CODE() \
103 	} zend_catch {\
104 		CG(in_compilation) = _old_in_compilation; \
105 		EG(current_execute_data) = _old_current_execute_data; \
106 		if (EG(exception) == NULL || \
107 		    !instanceof_function(EG(exception)->ce, soap_fault_class_entry)) {\
108 			_bailout = 1;\
109 		}\
110 		if (_old_stack_top != EG(vm_stack_top)) { \
111 			while (EG(vm_stack)->prev != NULL && \
112 			       ((char*)_old_stack_top < (char*)EG(vm_stack) || \
113 			        (char*) _old_stack_top > (char*)EG(vm_stack)->end)) { \
114 				zend_vm_stack tmp = EG(vm_stack)->prev; \
115 				efree(EG(vm_stack)); \
116 				EG(vm_stack) = tmp; \
117 				EG(vm_stack_end) = tmp->end; \
118 			} \
119 			EG(vm_stack)->top = _old_stack_top; \
120 		} \
121 	} zend_end_try();\
122 	SOAP_GLOBAL(use_soap_error_handler) = _old_handler;\
123 	SOAP_GLOBAL(error_code) = _old_error_code;\
124 	Z_OBJ(SOAP_GLOBAL(error_object)) = _old_error_object;\
125 	SOAP_GLOBAL(soap_version) = _old_soap_version;\
126 	if (_bailout) {\
127 		zend_bailout();\
128 	}
129 
130 #define FETCH_THIS_SDL(ss) \
131 	{ \
132 		zval *__tmp = Z_CLIENT_SDL_P(ZEND_THIS); \
133 		if (Z_TYPE_P(__tmp) == IS_RESOURCE) { \
134 			FETCH_SDL_RES(ss,__tmp); \
135 		} else { \
136 			ss = NULL; \
137 		} \
138 	}
139 
140 #define FETCH_SDL_RES(ss,tmp) ss = (sdlPtr) zend_fetch_resource_ex(tmp, "sdl", le_sdl)
141 
142 #define FETCH_TYPEMAP_RES(ss,tmp) ss = (HashTable*) zend_fetch_resource_ex(tmp, "typemap", le_typemap)
143 
144 #define Z_PARAM_NAME_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 0))
145 #define Z_PARAM_DATA_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 1))
146 
147 #define Z_HEADER_NAMESPACE_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 0))
148 #define Z_HEADER_NAME_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 1))
149 #define Z_HEADER_DATA_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 2))
150 #define Z_HEADER_MUST_UNDERSTAND_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 3))
151 #define Z_HEADER_ACTOR_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 4))
152 
153 #define Z_SERVER_SOAP_FAULT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), 0))
154 
155 /* SoapFault extends Exception, so take those properties into account. */
156 #define FAULT_PROP_START_OFFSET zend_ce_exception->default_properties_count
157 #define Z_FAULT_STRING_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), FAULT_PROP_START_OFFSET + 0))
158 #define Z_FAULT_CODE_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), FAULT_PROP_START_OFFSET + 1))
159 #define Z_FAULT_CODENS_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), FAULT_PROP_START_OFFSET + 2))
160 #define Z_FAULT_ACTOR_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), FAULT_PROP_START_OFFSET + 3))
161 #define Z_FAULT_DETAIL_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), FAULT_PROP_START_OFFSET + 4))
162 #define Z_FAULT_NAME_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), FAULT_PROP_START_OFFSET + 5))
163 #define Z_FAULT_HEADERFAULT_P(zv) php_soap_deref(OBJ_PROP_NUM(Z_OBJ_P(zv), FAULT_PROP_START_OFFSET + 6))
164 
165 #define FETCH_THIS_SERVICE(ss) \
166 	{ \
167 		ss = soap_server_object_fetch(Z_OBJ_P(ZEND_THIS))->service; \
168 		if (!ss) { \
169 			zend_throw_error(NULL, "Cannot fetch SoapServer object"); \
170 			SOAP_SERVER_END_CODE(); \
171 			RETURN_THROWS(); \
172 		} \
173 	}
174 
175 zend_class_entry* soap_class_entry;
176 static zend_class_entry* soap_server_class_entry;
177 static zend_class_entry* soap_fault_class_entry;
178 static zend_class_entry* soap_header_class_entry;
179 static zend_class_entry* soap_param_class_entry;
180 zend_class_entry* soap_var_class_entry;
181 
182 static zend_object_handlers soap_server_object_handlers;
183 
184 typedef struct {
185 	soapServicePtr service;
186 	zend_object std;
187 } soap_server_object;
188 
soap_server_object_fetch(zend_object * obj)189 static inline soap_server_object *soap_server_object_fetch(zend_object *obj) {
190 	return (soap_server_object *) ((char *) obj - XtOffsetOf(soap_server_object, std));
191 }
192 
soap_server_object_create(zend_class_entry * ce)193 static zend_object *soap_server_object_create(zend_class_entry *ce)
194 {
195 	soap_server_object *obj = zend_object_alloc(sizeof(soap_server_object), ce);
196 	zend_object_std_init(&obj->std, ce);
197 	object_properties_init(&obj->std, ce);
198 	return &obj->std;
199 }
200 
soap_server_object_free(zend_object * obj)201 static void soap_server_object_free(zend_object *obj) {
202 	soap_server_object *server_obj = soap_server_object_fetch(obj);
203 	if (server_obj->service) {
204 		delete_service(server_obj->service);
205 	}
206 	zend_object_std_dtor(obj);
207 }
208 
209 ZEND_DECLARE_MODULE_GLOBALS(soap)
210 
211 static void (*old_error_handler)(int, zend_string *, const uint32_t, zend_string *);
212 
213 PHP_RINIT_FUNCTION(soap);
214 PHP_MINIT_FUNCTION(soap);
215 PHP_MSHUTDOWN_FUNCTION(soap);
216 PHP_MINFO_FUNCTION(soap);
217 
218 zend_module_entry soap_module_entry = {
219 #ifdef STANDARD_MODULE_HEADER
220   STANDARD_MODULE_HEADER,
221 #endif
222   "soap",
223   ext_functions,
224   PHP_MINIT(soap),
225   PHP_MSHUTDOWN(soap),
226   PHP_RINIT(soap),
227   NULL,
228   PHP_MINFO(soap),
229 #ifdef STANDARD_MODULE_HEADER
230   PHP_SOAP_VERSION,
231 #endif
232   STANDARD_MODULE_PROPERTIES,
233 };
234 
235 #ifdef COMPILE_DL_SOAP
236 #ifdef ZTS
237 ZEND_TSRMLS_CACHE_DEFINE()
238 #endif
ZEND_GET_MODULE(soap)239 ZEND_GET_MODULE(soap)
240 #endif
241 
242 ZEND_INI_MH(OnUpdateCacheMode)
243 {
244 	char *p = (char *) ZEND_INI_GET_ADDR();
245 	*p = (char)atoi(ZSTR_VAL(new_value));
246 	return SUCCESS;
247 }
248 
PHP_INI_MH(OnUpdateCacheDir)249 static PHP_INI_MH(OnUpdateCacheDir)
250 {
251 	/* Only do the open_basedir check at runtime */
252 	if (stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) {
253 		char *p;
254 
255 		if (memchr(ZSTR_VAL(new_value), '\0', ZSTR_LEN(new_value)) != NULL) {
256 			return FAILURE;
257 		}
258 
259 		/* we do not use zend_memrchr() since path can contain ; itself */
260 		if ((p = strchr(ZSTR_VAL(new_value), ';'))) {
261 			char *p2;
262 			p++;
263 			if ((p2 = strchr(p, ';'))) {
264 				p = p2 + 1;
265 			}
266 		} else {
267 			p = ZSTR_VAL(new_value);
268 		}
269 
270 		if (PG(open_basedir) && *p && php_check_open_basedir(p)) {
271 			return FAILURE;
272 		}
273 	}
274 
275 	OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
276 	return SUCCESS;
277 }
278 
279 PHP_INI_BEGIN()
280 STD_PHP_INI_BOOLEAN("soap.wsdl_cache_enabled",     "1", PHP_INI_ALL, OnUpdateBool,
281                   cache_enabled, zend_soap_globals, soap_globals)
282 STD_PHP_INI_ENTRY("soap.wsdl_cache_dir",         "/tmp", PHP_INI_ALL, OnUpdateCacheDir,
283                   cache_dir, zend_soap_globals, soap_globals)
284 STD_PHP_INI_ENTRY("soap.wsdl_cache_ttl",         "86400", PHP_INI_ALL, OnUpdateLong,
285                   cache_ttl, zend_soap_globals, soap_globals)
286 STD_PHP_INI_ENTRY("soap.wsdl_cache",             "1", PHP_INI_ALL, OnUpdateCacheMode,
287                   cache_mode, zend_soap_globals, soap_globals)
288 STD_PHP_INI_ENTRY("soap.wsdl_cache_limit",       "5", PHP_INI_ALL, OnUpdateLong,
289                   cache_limit, zend_soap_globals, soap_globals)
290 PHP_INI_END()
291 
292 static HashTable defEnc, defEncIndex, defEncNs;
293 
php_soap_prepare_globals(void)294 static void php_soap_prepare_globals(void)
295 {
296 	int i;
297 	const encode* enc;
298 
299 	zend_hash_init(&defEnc, 0, NULL, NULL, 1);
300 	zend_hash_init(&defEncIndex, 0, NULL, NULL, 1);
301 	zend_hash_init(&defEncNs, 0, NULL, NULL, 1);
302 
303 	i = 0;
304 	do {
305 		enc = &defaultEncoding[i];
306 
307 		/* If has a ns and a str_type then index it */
308 		if (defaultEncoding[i].details.type_str) {
309 			if (defaultEncoding[i].details.ns != NULL) {
310 				char *ns_type;
311 				spprintf(&ns_type, 0, "%s:%s", defaultEncoding[i].details.ns, defaultEncoding[i].details.type_str);
312 				zend_hash_str_add_ptr(&defEnc, ns_type, strlen(ns_type), (void*)enc);
313 				efree(ns_type);
314 			} else {
315 				zend_hash_str_add_ptr(&defEnc, defaultEncoding[i].details.type_str, strlen(defaultEncoding[i].details.type_str), (void*)enc);
316 			}
317 		}
318 		/* Index everything by number */
319 		zend_hash_index_add_ptr(&defEncIndex, defaultEncoding[i].details.type, (void*)enc);
320 		i++;
321 	} while (defaultEncoding[i].details.type != END_KNOWN_TYPES);
322 
323 	/* hash by namespace */
324 	zend_hash_str_add_ptr(&defEncNs, XSD_1999_NAMESPACE, sizeof(XSD_1999_NAMESPACE)-1, XSD_NS_PREFIX);
325 	zend_hash_str_add_ptr(&defEncNs, XSD_NAMESPACE, sizeof(XSD_NAMESPACE)-1, XSD_NS_PREFIX);
326 	zend_hash_str_add_ptr(&defEncNs, XSI_NAMESPACE, sizeof(XSI_NAMESPACE)-1, XSI_NS_PREFIX);
327 	zend_hash_str_add_ptr(&defEncNs, XML_NAMESPACE, sizeof(XML_NAMESPACE)-1, XML_NS_PREFIX);
328 	zend_hash_str_add_ptr(&defEncNs, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)-1, SOAP_1_1_ENC_NS_PREFIX);
329 	zend_hash_str_add_ptr(&defEncNs, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)-1, SOAP_1_2_ENC_NS_PREFIX);
330 }
331 
php_soap_init_globals(zend_soap_globals * soap_globals)332 static void php_soap_init_globals(zend_soap_globals *soap_globals)
333 {
334 #if defined(COMPILE_DL_SOAP) && defined(ZTS)
335 	ZEND_TSRMLS_CACHE_UPDATE();
336 #endif
337 	soap_globals->defEnc = defEnc;
338 	soap_globals->defEncIndex = defEncIndex;
339 	soap_globals->defEncNs = defEncNs;
340 	soap_globals->typemap = NULL;
341 	soap_globals->use_soap_error_handler = 0;
342 	soap_globals->error_code = NULL;
343 	ZVAL_OBJ(&soap_globals->error_object, NULL);
344 	soap_globals->sdl = NULL;
345 	soap_globals->soap_version = SOAP_1_1;
346 	soap_globals->mem_cache = NULL;
347 	soap_globals->ref_map = NULL;
348 }
349 
PHP_MSHUTDOWN_FUNCTION(soap)350 PHP_MSHUTDOWN_FUNCTION(soap)
351 {
352 	zend_error_cb = old_error_handler;
353 	zend_hash_destroy(&SOAP_GLOBAL(defEnc));
354 	zend_hash_destroy(&SOAP_GLOBAL(defEncIndex));
355 	zend_hash_destroy(&SOAP_GLOBAL(defEncNs));
356 	if (SOAP_GLOBAL(mem_cache)) {
357 		zend_hash_destroy(SOAP_GLOBAL(mem_cache));
358 		free(SOAP_GLOBAL(mem_cache));
359 	}
360 	UNREGISTER_INI_ENTRIES();
361 	return SUCCESS;
362 }
363 
PHP_RINIT_FUNCTION(soap)364 PHP_RINIT_FUNCTION(soap)
365 {
366 	SOAP_GLOBAL(typemap) = NULL;
367 	SOAP_GLOBAL(use_soap_error_handler) = 0;
368 	SOAP_GLOBAL(error_code) = NULL;
369 	ZVAL_OBJ(&SOAP_GLOBAL(error_object), NULL);
370 	SOAP_GLOBAL(sdl) = NULL;
371 	SOAP_GLOBAL(soap_version) = SOAP_1_1;
372 	SOAP_GLOBAL(encoding) = NULL;
373 	SOAP_GLOBAL(class_map) = NULL;
374 	SOAP_GLOBAL(features) = 0;
375 	SOAP_GLOBAL(ref_map) = NULL;
376 	return SUCCESS;
377 }
378 
delete_sdl_res(zend_resource * res)379 static void delete_sdl_res(zend_resource *res)
380 {
381 	delete_sdl(res->ptr);
382 }
383 
delete_url_res(zend_resource * res)384 static void delete_url_res(zend_resource *res)
385 {
386 	delete_url(res->ptr);
387 }
388 
delete_hashtable_res(zend_resource * res)389 static void delete_hashtable_res(zend_resource *res)
390 {
391 	delete_hashtable(res->ptr);
392 }
393 
PHP_MINIT_FUNCTION(soap)394 PHP_MINIT_FUNCTION(soap)
395 {
396 	/* TODO: add ini entry for always use soap errors */
397 	php_soap_prepare_globals();
398 	ZEND_INIT_MODULE_GLOBALS(soap, php_soap_init_globals, NULL);
399 	REGISTER_INI_ENTRIES();
400 
401 	/* Register SoapClient class */
402 	soap_class_entry = register_class_SoapClient();
403 
404 	/* Register SoapVar class */
405 	soap_var_class_entry = register_class_SoapVar();
406 
407 	/* Register SoapServer class */
408 	soap_server_class_entry = register_class_SoapServer();
409 	soap_server_class_entry->create_object = soap_server_object_create;
410 	soap_server_class_entry->default_object_handlers = &soap_server_object_handlers;
411 
412 	memcpy(&soap_server_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
413 	soap_server_object_handlers.offset = XtOffsetOf(soap_server_object, std);
414 	soap_server_object_handlers.free_obj = soap_server_object_free;
415 	soap_server_object_handlers.clone_obj = NULL;
416 
417 	/* Register SoapFault class */
418 	soap_fault_class_entry = register_class_SoapFault(zend_ce_exception);
419 
420 	/* Register SoapParam class */
421 	soap_param_class_entry = register_class_SoapParam();
422 
423 	soap_header_class_entry = register_class_SoapHeader();
424 
425 	le_sdl = zend_register_list_destructors_ex(delete_sdl_res, NULL, "SOAP SDL", module_number);
426 	le_url = zend_register_list_destructors_ex(delete_url_res, NULL, "SOAP URL", module_number);
427 	le_typemap = zend_register_list_destructors_ex(delete_hashtable_res, NULL, "SOAP table", module_number);
428 
429 	register_soap_symbols(module_number);
430 
431 	old_error_handler = zend_error_cb;
432 	zend_error_cb = soap_error_handler;
433 
434 	return SUCCESS;
435 }
436 
PHP_MINFO_FUNCTION(soap)437 PHP_MINFO_FUNCTION(soap)
438 {
439 	php_info_print_table_start();
440 	php_info_print_table_row(2, "Soap Client", "enabled");
441 	php_info_print_table_row(2, "Soap Server", "enabled");
442 	php_info_print_table_end();
443 	DISPLAY_INI_ENTRIES();
444 }
445 
446 
447 /* {{{ SoapParam constructor */
PHP_METHOD(SoapParam,__construct)448 PHP_METHOD(SoapParam, __construct)
449 {
450 	zval *data;
451 	zend_string *name;
452 	zval *this_ptr;
453 
454 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zS", &data, &name) == FAILURE) {
455 		RETURN_THROWS();
456 	}
457 
458 	if (ZSTR_LEN(name) == 0) {
459 		zend_argument_value_error(2, "cannot be empty");
460 		RETURN_THROWS();
461 	}
462 
463 	this_ptr = ZEND_THIS;
464 	ZVAL_STR_COPY(Z_PARAM_NAME_P(this_ptr), name);
465 	ZVAL_COPY(Z_PARAM_DATA_P(this_ptr), data);
466 }
467 /* }}} */
468 
469 
470 /* {{{ SoapHeader constructor */
PHP_METHOD(SoapHeader,__construct)471 PHP_METHOD(SoapHeader, __construct)
472 {
473 	zval *data = NULL;
474 	zend_string *ns, *name, *actor_str = NULL;
475 	zend_long actor_long;
476 	bool actor_is_null = 1;
477 	bool must_understand = 0;
478 	zval *this_ptr;
479 
480 	ZEND_PARSE_PARAMETERS_START(2, 5)
481 		Z_PARAM_STR(ns)
482 		Z_PARAM_STR(name)
483 		Z_PARAM_OPTIONAL
484 		Z_PARAM_ZVAL(data)
485 		Z_PARAM_BOOL(must_understand)
486 		Z_PARAM_STR_OR_LONG_OR_NULL(actor_str, actor_long, actor_is_null)
487 	ZEND_PARSE_PARAMETERS_END();
488 
489 	if (ZSTR_LEN(ns) == 0) {
490 		zend_argument_value_error(1, "cannot be empty");
491 		RETURN_THROWS();
492 	}
493 	if (ZSTR_LEN(name) == 0) {
494 		zend_argument_value_error(2, "cannot be empty");
495 		RETURN_THROWS();
496 	}
497 
498 	this_ptr = ZEND_THIS;
499 	ZVAL_STR_COPY(Z_HEADER_NAMESPACE_P(this_ptr), ns);
500 	ZVAL_STR_COPY(Z_HEADER_NAME_P(this_ptr), name);
501 	if (data) {
502 		ZVAL_COPY(Z_HEADER_DATA_P(this_ptr), data);
503 	}
504 	ZVAL_BOOL(Z_HEADER_MUST_UNDERSTAND_P(this_ptr), must_understand);
505 
506 	if (actor_str) {
507 		if (ZSTR_LEN(actor_str) > 2) {
508 			ZVAL_STR_COPY(Z_HEADER_ACTOR_P(this_ptr), actor_str);
509 		} else {
510 			zend_argument_value_error(5, "must be longer than 2 characters");
511 			RETURN_THROWS();
512 		}
513 	} else if (!actor_is_null) {
514 		if ((actor_long == SOAP_ACTOR_NEXT || actor_long == SOAP_ACTOR_NONE || actor_long == SOAP_ACTOR_UNLIMATERECEIVER)) {
515 			ZVAL_LONG(Z_HEADER_ACTOR_P(this_ptr), actor_long);
516 		} else {
517 			zend_argument_value_error(5, "must be one of SOAP_ACTOR_NEXT, SOAP_ACTOR_NONE, or SOAP_ACTOR_UNLIMATERECEIVER");
518 			RETURN_THROWS();
519 		}
520 	}
521 }
522 /* }}} */
523 
soap_fault_dtor_properties(zval * obj)524 static void soap_fault_dtor_properties(zval *obj)
525 {
526 	zval_ptr_dtor(Z_FAULT_STRING_P(obj));
527 	zval_ptr_dtor(Z_FAULT_CODE_P(obj));
528 	zval_ptr_dtor(Z_FAULT_CODENS_P(obj));
529 	zval_ptr_dtor(Z_FAULT_ACTOR_P(obj));
530 	zval_ptr_dtor(Z_FAULT_DETAIL_P(obj));
531 	zval_ptr_dtor(Z_FAULT_NAME_P(obj));
532 	zval_ptr_dtor(Z_FAULT_HEADERFAULT_P(obj));
533 	ZVAL_EMPTY_STRING(Z_FAULT_STRING_P(obj));
534 	ZVAL_NULL(Z_FAULT_CODE_P(obj));
535 	ZVAL_NULL(Z_FAULT_CODENS_P(obj));
536 	ZVAL_NULL(Z_FAULT_ACTOR_P(obj));
537 	ZVAL_NULL(Z_FAULT_DETAIL_P(obj));
538 	ZVAL_NULL(Z_FAULT_NAME_P(obj));
539 	ZVAL_NULL(Z_FAULT_HEADERFAULT_P(obj));
540 }
541 
542 /* {{{ SoapFault constructor */
PHP_METHOD(SoapFault,__construct)543 PHP_METHOD(SoapFault, __construct)
544 {
545 	char *fault_string = NULL, *fault_code = NULL, *fault_actor = NULL, *name = NULL, *fault_code_ns = NULL;
546 	size_t fault_string_len, fault_actor_len = 0, name_len = 0, fault_code_len = 0;
547 	zval *details = NULL, *headerfault = NULL, *this_ptr;
548 	zend_string *code_str;
549 	HashTable *code_ht;
550 
551 	ZEND_PARSE_PARAMETERS_START(2, 6)
552 		Z_PARAM_ARRAY_HT_OR_STR_OR_NULL(code_ht, code_str)
553 		Z_PARAM_STRING(fault_string, fault_string_len)
554 		Z_PARAM_OPTIONAL
555 		Z_PARAM_STRING_OR_NULL(fault_actor, fault_actor_len)
556 		Z_PARAM_ZVAL_OR_NULL(details)
557 		Z_PARAM_STRING_OR_NULL(name, name_len)
558 		Z_PARAM_ZVAL_OR_NULL(headerfault)
559 	ZEND_PARSE_PARAMETERS_END();
560 
561 	if (code_str) {
562 		fault_code = ZSTR_VAL(code_str);
563 		fault_code_len = ZSTR_LEN(code_str);
564 	} else if (code_ht && zend_hash_num_elements(code_ht) == 2) {
565 		zval *t_ns = zend_hash_index_find(code_ht, 0);
566 		zval *t_code = zend_hash_index_find(code_ht, 1);
567 		if (t_ns && t_code && Z_TYPE_P(t_ns) == IS_STRING && Z_TYPE_P(t_code) == IS_STRING) {
568 			fault_code_ns = Z_STRVAL_P(t_ns);
569 			fault_code = Z_STRVAL_P(t_code);
570 			fault_code_len = Z_STRLEN_P(t_code);
571 		}
572 	}
573 
574 	if ((code_str || code_ht) && (fault_code == NULL || fault_code_len == 0)) {
575 		zend_argument_value_error(1, "is not a valid fault code");
576 		RETURN_THROWS();
577 	}
578 
579 	/* Delete previously set properties */
580 	soap_fault_dtor_properties(ZEND_THIS);
581 
582 	if (name != NULL && name_len == 0) {
583 		name = NULL;
584 	}
585 
586 	this_ptr = ZEND_THIS;
587 	set_soap_fault(this_ptr, fault_code_ns, fault_code, fault_string, fault_actor, details, name);
588 	if (headerfault != NULL) {
589 		ZVAL_COPY(Z_FAULT_HEADERFAULT_P(this_ptr), headerfault);
590 	}
591 }
592 /* }}} */
593 
594 /* {{{ SoapFault constructor */
PHP_METHOD(SoapFault,__toString)595 PHP_METHOD(SoapFault, __toString)
596 {
597 	zval *faultcode, *faultstring, *file, *line, trace, rv1, rv2, rv3, rv4;
598 	zend_string *str;
599 	zval *this_ptr;
600 	zend_string *faultcode_val, *faultstring_val, *file_val;
601 	zend_long line_val;
602 
603 	if (zend_parse_parameters_none() == FAILURE) {
604 		RETURN_THROWS();
605 	}
606 
607 	this_ptr = ZEND_THIS;
608 	faultcode = zend_read_property(soap_fault_class_entry, Z_OBJ_P(this_ptr), "faultcode", sizeof("faultcode")-1, 1, &rv1);
609 	faultstring = zend_read_property(soap_fault_class_entry, Z_OBJ_P(this_ptr), "faultstring", sizeof("faultstring")-1, 1, &rv2);
610 	file = zend_read_property_ex(soap_fault_class_entry, Z_OBJ_P(this_ptr), ZSTR_KNOWN(ZEND_STR_FILE), /* silent */ true, &rv3);
611 	line = zend_read_property_ex(soap_fault_class_entry, Z_OBJ_P(this_ptr), ZSTR_KNOWN(ZEND_STR_LINE), /* silent */ true, &rv4);
612 
613 	zend_call_method_with_0_params(
614 		Z_OBJ_P(ZEND_THIS), Z_OBJCE_P(ZEND_THIS), NULL, "gettraceasstring", &trace);
615 
616 	faultcode_val = zval_get_string(faultcode);
617 	faultstring_val = zval_get_string(faultstring);
618 	file_val = zval_get_string(file);
619 	line_val = zval_get_long(line);
620 	convert_to_string(&trace);
621 
622 	str = strpprintf(0, "SoapFault exception: [%s] %s in %s:" ZEND_LONG_FMT "\nStack trace:\n%s",
623 	               ZSTR_VAL(faultcode_val), ZSTR_VAL(faultstring_val), ZSTR_VAL(file_val), line_val,
624 	               Z_STRLEN(trace) ? Z_STRVAL(trace) : "#0 {main}\n");
625 
626 	zend_string_release_ex(file_val, 0);
627 	zend_string_release_ex(faultstring_val, 0);
628 	zend_string_release_ex(faultcode_val, 0);
629 	zval_ptr_dtor(&trace);
630 
631 	RETVAL_STR(str);
632 }
633 /* }}} */
634 
635 /* {{{ SoapVar constructor */
PHP_METHOD(SoapVar,__construct)636 PHP_METHOD(SoapVar, __construct)
637 {
638 	zval *data, *this_ptr;
639 	zend_long type;
640 	bool type_is_null = 1;
641 	zend_string *stype = NULL, *ns = NULL, *name = NULL, *namens = NULL;
642 
643 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z!l!|S!S!S!S!", &data, &type, &type_is_null, &stype, &ns, &name, &namens) == FAILURE) {
644 		RETURN_THROWS();
645 	}
646 
647 	this_ptr = ZEND_THIS;
648 	if (type_is_null) {
649 		ZVAL_LONG(Z_VAR_ENC_TYPE_P(this_ptr), UNKNOWN_TYPE);
650 	} else {
651 		if (zend_hash_index_exists(&SOAP_GLOBAL(defEncIndex), type)) {
652 			ZVAL_LONG(Z_VAR_ENC_TYPE_P(this_ptr), type);
653 		} else {
654 			zend_argument_value_error(2, "is not a valid encoding");
655 			RETURN_THROWS();
656 		}
657 	}
658 
659 	if (data) {
660 		ZVAL_COPY(Z_VAR_ENC_VALUE_P(this_ptr), data);
661 	}
662 
663 	if (stype && ZSTR_LEN(stype) != 0) {
664 		ZVAL_STR_COPY(Z_VAR_ENC_STYPE_P(this_ptr), stype);
665 	}
666 	if (ns && ZSTR_LEN(ns) != 0) {
667 		ZVAL_STR_COPY(Z_VAR_ENC_NS_P(this_ptr), ns);
668 	}
669 	if (name && ZSTR_LEN(name) != 0) {
670 		ZVAL_STR_COPY(Z_VAR_ENC_NAME_P(this_ptr), name);
671 	}
672 	if (namens && ZSTR_LEN(namens) != 0) {
673 		ZVAL_STR_COPY(Z_VAR_ENC_NAMENS_P(this_ptr), namens);
674 	}
675 }
676 /* }}} */
677 
soap_create_typemap(sdlPtr sdl,HashTable * ht)678 static HashTable* soap_create_typemap(sdlPtr sdl, HashTable *ht) /* {{{ */
679 {
680 	zval *tmp;
681 	HashTable *ht2;
682 	HashTable *typemap = NULL;
683 
684 	ZEND_HASH_FOREACH_VAL(ht, tmp) {
685 		char *type_name = NULL;
686 		char *type_ns = NULL;
687 		zval *to_xml = NULL;
688 		zval *to_zval = NULL;
689 		encodePtr enc, new_enc;
690 		zend_string *name;
691 
692 		if (Z_TYPE_P(tmp) != IS_ARRAY) {
693 			zend_type_error("SoapHeader::__construct(): \"typemap\" option must be of type array, %s given", zend_zval_value_name(tmp));
694 			return NULL;
695 		}
696 		ht2 = Z_ARRVAL_P(tmp);
697 
698 		if (!HT_IS_PACKED(ht2)) {
699 			ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(ht2, name, tmp) {
700 				if (name) {
701 					if (zend_string_equals_literal(name, "type_name")) {
702 						if (Z_TYPE_P(tmp) == IS_STRING) {
703 							type_name = Z_STRVAL_P(tmp);
704 						} else if (Z_TYPE_P(tmp) != IS_NULL) {
705 						}
706 					} else if (zend_string_equals_literal(name, "type_ns")) {
707 						if (Z_TYPE_P(tmp) == IS_STRING) {
708 							type_ns = Z_STRVAL_P(tmp);
709 						} else if (Z_TYPE_P(tmp) != IS_NULL) {
710 						}
711 					} else if (zend_string_equals_literal(name, "to_xml")) {
712 						to_xml = tmp;
713 					} else if (zend_string_equals_literal(name, "from_xml")) {
714 						to_zval = tmp;
715 					}
716 				}
717 			} ZEND_HASH_FOREACH_END();
718 		}
719 
720 		if (type_name) {
721 			smart_str nscat = {0};
722 
723 			if (type_ns) {
724 				enc = get_encoder(sdl, type_ns, type_name);
725 			} else {
726 				enc = get_encoder_ex(sdl, type_name, strlen(type_name));
727 			}
728 
729 			new_enc = emalloc(sizeof(encode));
730 			memset(new_enc, 0, sizeof(encode));
731 
732 			if (enc) {
733 				new_enc->details.type = enc->details.type;
734 				new_enc->details.ns = estrdup(enc->details.ns);
735 				new_enc->details.type_str = estrdup(enc->details.type_str);
736 				new_enc->details.sdl_type = enc->details.sdl_type;
737 			} else {
738 				enc = get_conversion(UNKNOWN_TYPE);
739 				new_enc->details.type = enc->details.type;
740 				if (type_ns) {
741 					new_enc->details.ns = estrdup(type_ns);
742 				}
743 				new_enc->details.type_str = estrdup(type_name);
744 			}
745 			new_enc->to_xml = enc->to_xml;
746 			new_enc->to_zval = enc->to_zval;
747 			new_enc->details.map = emalloc(sizeof(soapMapping));
748 			memset(new_enc->details.map, 0, sizeof(soapMapping));
749 			if (to_xml) {
750 				ZVAL_COPY(&new_enc->details.map->to_xml, to_xml);
751 				new_enc->to_xml = to_xml_user;
752 			} else if (enc->details.map && Z_TYPE(enc->details.map->to_xml) != IS_UNDEF) {
753 				ZVAL_COPY(&new_enc->details.map->to_xml, &enc->details.map->to_xml);
754 			}
755 			if (to_zval) {
756 				ZVAL_COPY(&new_enc->details.map->to_zval, to_zval);
757 				new_enc->to_zval = to_zval_user;
758 			} else if (enc->details.map && Z_TYPE(enc->details.map->to_zval) != IS_UNDEF) {
759 				ZVAL_COPY(&new_enc->details.map->to_zval, &enc->details.map->to_zval);
760 			}
761 			if (!typemap) {
762 				typemap = emalloc(sizeof(HashTable));
763 				zend_hash_init(typemap, 0, NULL, delete_encoder, 0);
764 			}
765 
766 			if (type_ns) {
767 				smart_str_appends(&nscat, type_ns);
768 				smart_str_appendc(&nscat, ':');
769 			}
770 			smart_str_appends(&nscat, type_name);
771 			smart_str_0(&nscat);
772 			zend_hash_update_ptr(typemap, nscat.s, new_enc);
773 			smart_str_free(&nscat);
774 		}
775 	} ZEND_HASH_FOREACH_END();
776 	return typemap;
777 }
778 /* }}} */
779 
780 /* {{{ SoapServer constructor */
PHP_METHOD(SoapServer,__construct)781 PHP_METHOD(SoapServer, __construct)
782 {
783 	soapServicePtr service;
784 	zval *options = NULL;
785 	zend_string *wsdl;
786 	int version = SOAP_1_1;
787 	zend_long cache_wsdl;
788 	HashTable *typemap_ht = NULL;
789 
790 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S!|a", &wsdl, &options) == FAILURE) {
791 		RETURN_THROWS();
792 	}
793 
794 	SOAP_SERVER_BEGIN_CODE();
795 
796 	service = emalloc(sizeof(soapService));
797 	memset(service, 0, sizeof(soapService));
798 	service->send_errors = 1;
799 
800 	cache_wsdl = SOAP_GLOBAL(cache_enabled) ? SOAP_GLOBAL(cache_mode) : 0;
801 
802 	if (options != NULL) {
803 		HashTable *ht = Z_ARRVAL_P(options);
804 		zval *tmp;
805 
806 		if ((tmp = zend_hash_str_find(ht, "soap_version", sizeof("soap_version")-1)) != NULL) {
807 			if (Z_TYPE_P(tmp) == IS_LONG &&
808 			    (Z_LVAL_P(tmp) == SOAP_1_1 || Z_LVAL_P(tmp) == SOAP_1_2)) {
809 				version = Z_LVAL_P(tmp);
810 			} else {
811 				php_error_docref(NULL, E_ERROR, "'soap_version' option must be SOAP_1_1 or SOAP_1_2");
812 			}
813 		}
814 
815 		if ((tmp = zend_hash_str_find(ht, "uri", sizeof("uri")-1)) != NULL &&
816 		    Z_TYPE_P(tmp) == IS_STRING) {
817 			service->uri = estrndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
818 		} else if (!wsdl) {
819 			php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
820 		}
821 
822 		if ((tmp = zend_hash_str_find(ht, "actor", sizeof("actor")-1)) != NULL &&
823 		    Z_TYPE_P(tmp) == IS_STRING) {
824 			service->actor = estrndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
825 		}
826 
827 		if ((tmp = zend_hash_str_find(ht, "encoding", sizeof("encoding")-1)) != NULL &&
828 		    Z_TYPE_P(tmp) == IS_STRING) {
829 			xmlCharEncodingHandlerPtr encoding;
830 
831 			encoding = xmlFindCharEncodingHandler(Z_STRVAL_P(tmp));
832 			if (encoding == NULL) {
833 				php_error_docref(NULL, E_ERROR, "Invalid 'encoding' option - '%s'", Z_STRVAL_P(tmp));
834 			} else {
835 			  service->encoding = encoding;
836 			}
837 		}
838 
839 		if ((tmp = zend_hash_str_find(ht, "classmap", sizeof("classmap")-1)) != NULL &&
840 			Z_TYPE_P(tmp) == IS_ARRAY) {
841 			if (HT_IS_PACKED(Z_ARRVAL_P(tmp))) {
842 				php_error_docref(NULL, E_ERROR, "'classmap' option must be an associative array");
843 			}
844 			service->class_map = zend_array_dup(Z_ARRVAL_P(tmp));
845 		}
846 
847 		if ((tmp = zend_hash_str_find(ht, "typemap", sizeof("typemap")-1)) != NULL &&
848 			Z_TYPE_P(tmp) == IS_ARRAY &&
849 			zend_hash_num_elements(Z_ARRVAL_P(tmp)) > 0) {
850 			typemap_ht = Z_ARRVAL_P(tmp);
851 		}
852 
853 		if ((tmp = zend_hash_str_find(ht, "features", sizeof("features")-1)) != NULL &&
854 			Z_TYPE_P(tmp) == IS_LONG) {
855 			service->features = Z_LVAL_P(tmp);
856 		}
857 
858 		if ((tmp = zend_hash_str_find(ht, "cache_wsdl", sizeof("cache_wsdl")-1)) != NULL &&
859 		    Z_TYPE_P(tmp) == IS_LONG) {
860 			cache_wsdl = Z_LVAL_P(tmp);
861 		}
862 
863 		if ((tmp = zend_hash_str_find(ht, "send_errors", sizeof("send_errors")-1)) != NULL) {
864 			if (Z_TYPE_P(tmp) == IS_FALSE) {
865 				service->send_errors = 0;
866 			} else if (Z_TYPE_P(tmp) == IS_TRUE) {
867 				service->send_errors = 1;
868 			} else if (Z_TYPE_P(tmp) == IS_LONG) {
869 				service->send_errors = Z_LVAL_P(tmp);
870 			}
871 		}
872 
873 	} else if (!wsdl) {
874 		php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
875 	}
876 
877 	service->version = version;
878 	service->type = SOAP_FUNCTIONS;
879 	service->soap_functions.functions_all = FALSE;
880 	service->soap_functions.ft = zend_new_array(0);
881 
882 	if (wsdl) {
883 		service->sdl = get_sdl(ZEND_THIS, ZSTR_VAL(wsdl), cache_wsdl);
884 		if (service->uri == NULL) {
885 			if (service->sdl->target_ns) {
886 				service->uri = estrdup(service->sdl->target_ns);
887 			} else {
888 				/*FIXME*/
889 				service->uri = estrdup("http://unknown-uri/");
890 			}
891 		}
892 	}
893 
894 	if (typemap_ht) {
895 		service->typemap = soap_create_typemap(service->sdl, typemap_ht);
896 	}
897 
898 	soap_server_object *server_obj = soap_server_object_fetch(Z_OBJ_P(ZEND_THIS));
899 	server_obj->service = service;
900 
901 	SOAP_SERVER_END_CODE();
902 }
903 /* }}} */
904 
905 
906 /* {{{ Sets persistence mode of SoapServer */
PHP_METHOD(SoapServer,setPersistence)907 PHP_METHOD(SoapServer, setPersistence)
908 {
909 	soapServicePtr service;
910 	zend_long value;
911 
912 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) == FAILURE) {
913 		RETURN_THROWS();
914 	}
915 
916 	SOAP_SERVER_BEGIN_CODE();
917 
918 	FETCH_THIS_SERVICE(service);
919 
920 	if (service->type == SOAP_CLASS) {
921 		if (value == SOAP_PERSISTENCE_SESSION ||
922 			value == SOAP_PERSISTENCE_REQUEST) {
923 			service->soap_class.persistence = value;
924 		} else {
925 			zend_argument_value_error(
926 				1, "must be either SOAP_PERSISTENCE_SESSION or SOAP_PERSISTENCE_REQUEST when the SOAP server is used in class mode"
927 			);
928 		}
929 	} else {
930 		zend_throw_error(NULL, "SoapServer::setPersistence(): Persistence cannot be set when the SOAP server is used in function mode");
931 	}
932 
933 	SOAP_SERVER_END_CODE();
934 }
935 /* }}} */
936 
937 
938 /* {{{ Sets class which will handle SOAP requests */
PHP_METHOD(SoapServer,setClass)939 PHP_METHOD(SoapServer, setClass)
940 {
941 	soapServicePtr service;
942 	zend_class_entry *ce = NULL;
943 	int num_args = 0;
944 	zval *argv = NULL;
945 
946 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "C*", &ce, &argv, &num_args) == FAILURE) {
947 		RETURN_THROWS();
948 	}
949 
950 	SOAP_SERVER_BEGIN_CODE();
951 
952 	FETCH_THIS_SERVICE(service);
953 
954 	service->type = SOAP_CLASS;
955 	service->soap_class.ce = ce;
956 
957 	delete_argv(&service->soap_class);
958 
959 	service->soap_class.persistence = SOAP_PERSISTENCE_REQUEST;
960 	service->soap_class.argc = num_args;
961 	if (service->soap_class.argc > 0) {
962 		int i;
963 		service->soap_class.argv = safe_emalloc(sizeof(zval), service->soap_class.argc, 0);
964 		for (i = 0;i < service->soap_class.argc;i++) {
965 			ZVAL_COPY(&service->soap_class.argv[i], &argv[i]);
966 		}
967 	}
968 
969 	SOAP_SERVER_END_CODE();
970 }
971 /* }}} */
972 
973 
974 /* {{{ Sets object which will handle SOAP requests */
PHP_METHOD(SoapServer,setObject)975 PHP_METHOD(SoapServer, setObject)
976 {
977 	soapServicePtr service;
978 	zval *obj;
979 
980 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &obj) == FAILURE) {
981 		RETURN_THROWS();
982 	}
983 
984 	SOAP_SERVER_BEGIN_CODE();
985 
986 	FETCH_THIS_SERVICE(service);
987 
988 	service->type = SOAP_OBJECT;
989 
990 	zval_ptr_dtor(&service->soap_object);
991 	ZVAL_OBJ_COPY(&service->soap_object, Z_OBJ_P(obj));
992 
993 	SOAP_SERVER_END_CODE();
994 }
995 /* }}} */
996 
997 
998 /* {{{ Returns list of defined functions */
PHP_METHOD(SoapServer,getFunctions)999 PHP_METHOD(SoapServer, getFunctions)
1000 {
1001 	soapServicePtr  service;
1002 	HashTable      *ft = NULL;
1003 
1004 	if (zend_parse_parameters_none() == FAILURE) {
1005 		RETURN_THROWS();
1006 	}
1007 
1008 	SOAP_SERVER_BEGIN_CODE();
1009 
1010 	FETCH_THIS_SERVICE(service);
1011 
1012 	array_init(return_value);
1013 	if (service->type == SOAP_OBJECT) {
1014 		ft = &(Z_OBJCE(service->soap_object)->function_table);
1015 	} else if (service->type == SOAP_CLASS) {
1016 		ft = &service->soap_class.ce->function_table;
1017 	} else if (service->soap_functions.functions_all == TRUE) {
1018 		ft = EG(function_table);
1019 	} else if (service->soap_functions.ft != NULL) {
1020 		zval *name;
1021 
1022 		ZEND_HASH_MAP_FOREACH_VAL(service->soap_functions.ft, name) {
1023 			add_next_index_str(return_value, zend_string_copy(Z_STR_P(name)));
1024 		} ZEND_HASH_FOREACH_END();
1025 	}
1026 	if (ft != NULL) {
1027 		zend_function *f;
1028 
1029 		ZEND_HASH_MAP_FOREACH_PTR(ft, f) {
1030 			if ((service->type != SOAP_OBJECT && service->type != SOAP_CLASS) || (f->common.fn_flags & ZEND_ACC_PUBLIC)) {
1031 				add_next_index_str(return_value, zend_string_copy(f->common.function_name));
1032 			}
1033 		} ZEND_HASH_FOREACH_END();
1034 	}
1035 
1036 	SOAP_SERVER_END_CODE();
1037 }
1038 /* }}} */
1039 
1040 
1041 /* {{{ Adds one or several functions those will handle SOAP requests */
PHP_METHOD(SoapServer,addFunction)1042 PHP_METHOD(SoapServer, addFunction)
1043 {
1044 	soapServicePtr service;
1045 	zval *function_name, function_copy;
1046 
1047 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &function_name) == FAILURE) {
1048 		RETURN_THROWS();
1049 	}
1050 
1051 	SOAP_SERVER_BEGIN_CODE();
1052 
1053 	FETCH_THIS_SERVICE(service);
1054 
1055 	/* TODO: could use zend_is_callable here */
1056 
1057 	if (Z_TYPE_P(function_name) == IS_ARRAY) {
1058 		if (service->type == SOAP_FUNCTIONS) {
1059 			zval *tmp_function;
1060 
1061 			if (service->soap_functions.ft == NULL) {
1062 				service->soap_functions.functions_all = FALSE;
1063 				service->soap_functions.ft = zend_new_array(zend_hash_num_elements(Z_ARRVAL_P(function_name)));
1064 			}
1065 
1066 			ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(function_name), tmp_function) {
1067 				zend_string *key;
1068 				zend_function *f;
1069 
1070 				if (Z_TYPE_P(tmp_function) != IS_STRING) {
1071 					zend_argument_type_error(1, "must contain only strings");
1072 					SOAP_SERVER_END_CODE();
1073 					RETURN_THROWS();
1074 				}
1075 
1076 				key = zend_string_tolower(Z_STR_P(tmp_function));
1077 
1078 				if ((f = zend_hash_find_ptr(EG(function_table), key)) == NULL) {
1079 					zend_string_release_ex(key, false);
1080 					zend_type_error("SoapServer::addFunction(): Function \"%s\" not found", Z_STRVAL_P(tmp_function));
1081 					SOAP_SERVER_END_CODE();
1082 					RETURN_THROWS();
1083 				}
1084 
1085 				ZVAL_STR_COPY(&function_copy, f->common.function_name);
1086 				zend_hash_update(service->soap_functions.ft, key, &function_copy);
1087 
1088 				zend_string_release_ex(key, 0);
1089 			} ZEND_HASH_FOREACH_END();
1090 		}
1091 	} else if (Z_TYPE_P(function_name) == IS_STRING) {
1092 		zend_string *key;
1093 		zend_function *f;
1094 
1095 		key = zend_string_tolower(Z_STR_P(function_name));
1096 
1097 		if ((f = zend_hash_find_ptr(EG(function_table), key)) == NULL) {
1098 			zend_string_release_ex(key, false);
1099 			zend_argument_type_error(1, "must be a valid function name, function \"%s\" not found", Z_STRVAL_P(function_name));
1100 			SOAP_SERVER_END_CODE();
1101 			RETURN_THROWS();
1102 		}
1103 		if (service->soap_functions.ft == NULL) {
1104 			service->soap_functions.functions_all = FALSE;
1105 			service->soap_functions.ft = zend_new_array(0);
1106 		}
1107 
1108 		ZVAL_STR_COPY(&function_copy, f->common.function_name);
1109 		zend_hash_update(service->soap_functions.ft, key, &function_copy);
1110 		zend_string_release_ex(key, 0);
1111 	} else if (Z_TYPE_P(function_name) == IS_LONG) {
1112 		if (Z_LVAL_P(function_name) == SOAP_FUNCTIONS_ALL) {
1113 			if (service->soap_functions.ft != NULL) {
1114 				zend_hash_destroy(service->soap_functions.ft);
1115 				efree(service->soap_functions.ft);
1116 				service->soap_functions.ft = NULL;
1117 			}
1118 			service->soap_functions.functions_all = TRUE;
1119 		} else {
1120 			zend_argument_value_error(1, "must be SOAP_FUNCTIONS_ALL when an integer is passed");
1121 		}
1122 	} else {
1123 		zend_argument_type_error(1, "must be of type array|string|int, %s given", zend_zval_value_name(function_name));
1124 	}
1125 
1126 	SOAP_SERVER_END_CODE();
1127 }
1128 /* }}} */
1129 
_soap_server_exception(soapServicePtr service,sdlFunctionPtr function,zval * this_ptr)1130 static void _soap_server_exception(soapServicePtr service, sdlFunctionPtr function, zval *this_ptr) /* {{{ */
1131 {
1132 	zval exception_object;
1133 
1134 	ZVAL_OBJ(&exception_object, EG(exception));
1135 	if (instanceof_function(Z_OBJCE(exception_object), soap_fault_class_entry)) {
1136 		soap_server_fault_ex(function, &exception_object, NULL);
1137 	} else if (instanceof_function(Z_OBJCE(exception_object), zend_ce_error)) {
1138 		if (service->send_errors) {
1139 			zval rv;
1140 			zend_string *msg = zval_get_string(zend_read_property_ex(zend_ce_error, Z_OBJ(exception_object), ZSTR_KNOWN(ZEND_STR_MESSAGE), /* silent */ false, &rv));
1141 			add_soap_fault_ex(&exception_object, this_ptr, "Server", ZSTR_VAL(msg), NULL, NULL);
1142 			zend_string_release_ex(msg, 0);
1143 		} else {
1144 			add_soap_fault_ex(&exception_object, this_ptr, "Server", "Internal Error", NULL, NULL);
1145 		}
1146 		soap_server_fault_ex(function, &exception_object, NULL);
1147 	}
1148 }
1149 /* }}} */
1150 
1151 /* {{{ Handles a SOAP request */
PHP_METHOD(SoapServer,handle)1152 PHP_METHOD(SoapServer, handle)
1153 {
1154 	int soap_version, old_soap_version;
1155 	sdlPtr old_sdl = NULL;
1156 	soapServicePtr service;
1157 	xmlDocPtr doc_request = NULL, doc_return = NULL;
1158 	zval function_name, *params, *soap_obj, retval;
1159 	char cont_len[30];
1160 	int num_params = 0, size, i, call_status = 0;
1161 	xmlChar *buf;
1162 	HashTable *function_table;
1163 	soapHeader *soap_headers = NULL;
1164 	sdlFunctionPtr function;
1165 	char *arg = NULL;
1166 	size_t arg_len = 0;
1167 	xmlCharEncodingHandlerPtr old_encoding;
1168 	HashTable *old_class_map, *old_typemap;
1169 	int old_features;
1170 	zval tmp_soap;
1171 
1172 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &arg, &arg_len) == FAILURE) {
1173 		RETURN_THROWS();
1174 	}
1175 
1176 	SOAP_SERVER_BEGIN_CODE();
1177 
1178 	FETCH_THIS_SERVICE(service);
1179 	SOAP_GLOBAL(soap_version) = service->version;
1180 
1181 	if (arg && ZEND_SIZE_T_INT_OVFL(arg_len)) {
1182 		soap_server_fault("Server", "Input string is too long", NULL, NULL, NULL);
1183 		SOAP_SERVER_END_CODE();
1184 		return;
1185 	}
1186 
1187 	if (SG(request_info).request_method &&
1188 	    strcmp(SG(request_info).request_method, "GET") == 0 &&
1189 	    SG(request_info).query_string &&
1190 	    stricmp(SG(request_info).query_string, "wsdl") == 0) {
1191 
1192 		if (service->sdl) {
1193 /*
1194 			char *hdr = emalloc(sizeof("Location: ")+strlen(service->sdl->source));
1195 			strcpy(hdr,"Location: ");
1196 			strcat(hdr,service->sdl->source);
1197 			sapi_add_header(hdr, sizeof("Location: ")+strlen(service->sdl->source)-1, 1);
1198 			efree(hdr);
1199 */
1200 			zval readfile, readfile_ret, param;
1201 
1202 			sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
1203 			ZVAL_STRING(&param, service->sdl->source);
1204 			ZVAL_STRING(&readfile, "readfile");
1205 			if (call_user_function(EG(function_table), NULL, &readfile, &readfile_ret, 1, &param ) == FAILURE) {
1206 				soap_server_fault("Server", "Couldn't find WSDL", NULL, NULL, NULL);
1207 			}
1208 
1209 			zval_ptr_dtor(&param);
1210 			zval_ptr_dtor_str(&readfile);
1211 			zval_ptr_dtor(&readfile_ret);
1212 
1213 			SOAP_SERVER_END_CODE();
1214 			return;
1215 		} else {
1216 			soap_server_fault("Server", "WSDL generation is not supported yet", NULL, NULL, NULL);
1217 /*
1218 			sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8"), 1);
1219 			PUTS("<?xml version=\"1.0\" ?>\n<definitions\n");
1220 			PUTS("    xmlns=\"http://schemas.xmlsoap.org/wsdl/\"\n");
1221 			PUTS("    targetNamespace=\"");
1222 			PUTS(service->uri);
1223 			PUTS("\">\n");
1224 			PUTS("</definitions>");
1225 */
1226 			SOAP_SERVER_END_CODE();
1227 			return;
1228 		}
1229 	}
1230 
1231 	ZVAL_NULL(&retval);
1232 
1233 	if (php_output_start_default() != SUCCESS) {
1234 		php_error_docref(NULL, E_ERROR,"ob_start failed");
1235 	}
1236 
1237 	if (!arg) {
1238 		if (SG(request_info).request_body && 0 == php_stream_rewind(SG(request_info).request_body)) {
1239 			zval *server_vars, *encoding;
1240 			php_stream_filter *zf = NULL;
1241 			zend_string *server = ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER);
1242 
1243 			zend_is_auto_global(server);
1244 			if ((server_vars = zend_hash_find(&EG(symbol_table), server)) != NULL &&
1245 			    Z_TYPE_P(server_vars) == IS_ARRAY &&
1246 			    (encoding = zend_hash_str_find(Z_ARRVAL_P(server_vars), "HTTP_CONTENT_ENCODING", sizeof("HTTP_CONTENT_ENCODING")-1)) != NULL &&
1247 			    Z_TYPE_P(encoding) == IS_STRING) {
1248 
1249 				if (zend_string_equals_literal(Z_STR_P(encoding), "gzip")
1250 					|| zend_string_equals_literal(Z_STR_P(encoding), "x-gzip")
1251 					|| zend_string_equals_literal(Z_STR_P(encoding), "deflate")
1252 				) {
1253 					zval filter_params;
1254 
1255 					array_init_size(&filter_params, 1);
1256 					add_assoc_long_ex(&filter_params, "window", sizeof("window")-1, 0x2f); /* ANY WBITS */
1257 
1258 					zf = php_stream_filter_create("zlib.inflate", &filter_params, 0);
1259 					zend_array_destroy(Z_ARR(filter_params));
1260 
1261 					if (zf) {
1262 						php_stream_filter_append(&SG(request_info).request_body->readfilters, zf);
1263 					} else {
1264 						php_error_docref(NULL, E_WARNING,"Can't uncompress compressed request");
1265 						SOAP_SERVER_END_CODE();
1266 						return;
1267 					}
1268 				} else {
1269 					php_error_docref(NULL, E_WARNING,"Request is compressed with unknown compression '%s'",Z_STRVAL_P(encoding));
1270 					SOAP_SERVER_END_CODE();
1271 					return;
1272 				}
1273 			}
1274 
1275 			doc_request = soap_xmlParseFile("php://input");
1276 
1277 			if (zf) {
1278 				php_stream_filter_remove(zf, 1);
1279 			}
1280 		} else {
1281 			zval_ptr_dtor(&retval);
1282 			SOAP_SERVER_END_CODE();
1283 			return;
1284 		}
1285 	} else {
1286 		doc_request = soap_xmlParseMemory(arg,arg_len);
1287 	}
1288 
1289 	if (doc_request == NULL) {
1290 		soap_server_fault("Client", "Bad Request", NULL, NULL, NULL);
1291 	}
1292 	if (xmlGetIntSubset(doc_request) != NULL) {
1293 		xmlNodePtr env = get_node(doc_request->children,"Envelope");
1294 		if (env && env->ns) {
1295 			if (strcmp((char*)env->ns->href, SOAP_1_1_ENV_NAMESPACE) == 0) {
1296 				SOAP_GLOBAL(soap_version) = SOAP_1_1;
1297 			} else if (strcmp((char*)env->ns->href,SOAP_1_2_ENV_NAMESPACE) == 0) {
1298 				SOAP_GLOBAL(soap_version) = SOAP_1_2;
1299 			}
1300 		}
1301 		xmlFreeDoc(doc_request);
1302 		soap_server_fault("Server", "DTD are not supported by SOAP", NULL, NULL, NULL);
1303 	}
1304 
1305 	old_sdl = SOAP_GLOBAL(sdl);
1306 	SOAP_GLOBAL(sdl) = service->sdl;
1307 	old_encoding = SOAP_GLOBAL(encoding);
1308 	SOAP_GLOBAL(encoding) = service->encoding;
1309 	old_class_map = SOAP_GLOBAL(class_map);
1310 	SOAP_GLOBAL(class_map) = service->class_map;
1311 	old_typemap = SOAP_GLOBAL(typemap);
1312 	SOAP_GLOBAL(typemap) = service->typemap;
1313 	old_features = SOAP_GLOBAL(features);
1314 	SOAP_GLOBAL(features) = service->features;
1315 	old_soap_version = SOAP_GLOBAL(soap_version);
1316 
1317 	zend_try {
1318 		function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, &params, &soap_version, &soap_headers);
1319 	} zend_catch {
1320 		/* Avoid leaking persistent memory */
1321 		xmlFreeDoc(doc_request);
1322 		zend_bailout();
1323 	} zend_end_try();
1324 
1325 	xmlFreeDoc(doc_request);
1326 
1327 	if (EG(exception)) {
1328 		if (!zend_is_unwind_exit(EG(exception))) {
1329 			php_output_discard();
1330 			_soap_server_exception(service, function, ZEND_THIS);
1331 		}
1332 		goto fail;
1333 	}
1334 
1335 	service->soap_headers_ptr = &soap_headers;
1336 
1337 	soap_obj = NULL;
1338 	if (service->type == SOAP_OBJECT) {
1339 		soap_obj = &service->soap_object;
1340 		function_table = &((Z_OBJCE_P(soap_obj))->function_table);
1341 	} else if (service->type == SOAP_CLASS) {
1342 #if defined(HAVE_PHP_SESSION) && !defined(COMPILE_DL_SESSION)
1343 		/* If persistent then set soap_obj from from the previous created session (if available) */
1344 		if (service->soap_class.persistence == SOAP_PERSISTENCE_SESSION) {
1345 			zval *session_vars, *tmp_soap_p;
1346 
1347 			if (PS(session_status) != php_session_active &&
1348 			    PS(session_status) != php_session_disabled) {
1349 				php_session_start();
1350 			}
1351 
1352 			/* Find the soap object and assign */
1353 			session_vars = &PS(http_session_vars);
1354 			ZVAL_DEREF(session_vars);
1355 			if (Z_TYPE_P(session_vars) == IS_ARRAY &&
1356 			    (tmp_soap_p = zend_hash_str_find(Z_ARRVAL_P(session_vars), "_bogus_session_name", sizeof("_bogus_session_name")-1)) != NULL &&
1357 			    Z_TYPE_P(tmp_soap_p) == IS_OBJECT &&
1358 			    Z_OBJCE_P(tmp_soap_p) == service->soap_class.ce) {
1359 				soap_obj = tmp_soap_p;
1360 			}
1361 		}
1362 #endif
1363 		/* If new session or something weird happned */
1364 		if (soap_obj == NULL) {
1365 
1366 			object_init_ex(&tmp_soap, service->soap_class.ce);
1367 
1368 			/* Call constructor */
1369 			if (service->soap_class.ce->constructor) {
1370 				zend_call_known_instance_method(
1371 					service->soap_class.ce->constructor, Z_OBJ(tmp_soap), NULL,
1372 					service->soap_class.argc, service->soap_class.argv);
1373 				if (EG(exception)) {
1374 					php_output_discard();
1375 					_soap_server_exception(service, function, ZEND_THIS);
1376 					zval_ptr_dtor(&tmp_soap);
1377 					goto fail;
1378 				}
1379 			}
1380 #if defined(HAVE_PHP_SESSION) && !defined(COMPILE_DL_SESSION)
1381 			/* If session then update session hash with new object */
1382 			if (service->soap_class.persistence == SOAP_PERSISTENCE_SESSION) {
1383 				zval *session_vars = &PS(http_session_vars), *tmp_soap_p;
1384 
1385 				ZVAL_DEREF(session_vars);
1386 				if (Z_TYPE_P(session_vars) == IS_ARRAY &&
1387 				    (tmp_soap_p = zend_hash_str_update(Z_ARRVAL_P(session_vars), "_bogus_session_name", sizeof("_bogus_session_name")-1, &tmp_soap)) != NULL) {
1388 					soap_obj = tmp_soap_p;
1389 				} else {
1390 					soap_obj = &tmp_soap;
1391 				}
1392 			} else {
1393 				soap_obj = &tmp_soap;
1394 			}
1395 #else
1396 			soap_obj = &tmp_soap;
1397 #endif
1398 
1399 		}
1400 		function_table = &((Z_OBJCE_P(soap_obj))->function_table);
1401 	} else {
1402 		if (service->soap_functions.functions_all == TRUE) {
1403 			function_table = EG(function_table);
1404 		} else {
1405 			function_table = service->soap_functions.ft;
1406 		}
1407 	}
1408 
1409 	/* Process soap headers */
1410 	if (soap_headers != NULL) {
1411 		soapHeader *header = soap_headers;
1412 		while (header != NULL) {
1413 			soapHeader *h = header;
1414 
1415 			header = header->next;
1416 #if 0
1417 			if (service->sdl && !h->function && !h->hdr) {
1418 				if (h->mustUnderstand) {
1419 					soap_server_fault("MustUnderstand","Header not understood", NULL, NULL, NULL);
1420 				} else {
1421 					continue;
1422 				}
1423 			}
1424 #endif
1425 			if (zend_hash_find_ptr_lc(function_table, Z_STR(h->function_name)) != NULL ||
1426 			    ((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) &&
1427 			     zend_hash_str_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1428 				if (service->type == SOAP_CLASS || service->type == SOAP_OBJECT) {
1429 					call_status = call_user_function(NULL, soap_obj, &h->function_name, &h->retval, h->num_params, h->parameters);
1430 				} else {
1431 					call_status = call_user_function(EG(function_table), NULL, &h->function_name, &h->retval, h->num_params, h->parameters);
1432 				}
1433 				if (call_status != SUCCESS) {
1434 					php_error_docref(NULL, E_WARNING, "Function '%s' call failed", Z_STRVAL(h->function_name));
1435 					return;
1436 				}
1437 				if (Z_TYPE(h->retval) == IS_OBJECT &&
1438 				    instanceof_function(Z_OBJCE(h->retval), soap_fault_class_entry)) {
1439 					php_output_discard();
1440 					soap_server_fault_ex(function, &h->retval, h);
1441 					if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
1442 					goto fail;
1443 				} else if (EG(exception)) {
1444 					php_output_discard();
1445 					_soap_server_exception(service, function, ZEND_THIS);
1446 					if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
1447 					goto fail;
1448 				}
1449 			} else if (h->mustUnderstand) {
1450 				soap_server_fault("MustUnderstand","Header not understood", NULL, NULL, NULL);
1451 			}
1452 		}
1453 	}
1454 
1455 	if (zend_hash_find_ptr_lc(function_table, Z_STR(function_name)) != NULL ||
1456 	    ((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) &&
1457 	     zend_hash_str_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1458 		if (service->type == SOAP_CLASS || service->type == SOAP_OBJECT) {
1459 			call_status = call_user_function(NULL, soap_obj, &function_name, &retval, num_params, params);
1460 			if (service->type == SOAP_CLASS) {
1461 #if defined(HAVE_PHP_SESSION) && !defined(COMPILE_DL_SESSION)
1462 				if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1463 					zval_ptr_dtor(soap_obj);
1464 					soap_obj = NULL;
1465 				}
1466 #else
1467 				zval_ptr_dtor(soap_obj);
1468 				soap_obj = NULL;
1469 #endif
1470 			}
1471 		} else {
1472 			call_status = call_user_function(EG(function_table), NULL, &function_name, &retval, num_params, params);
1473 		}
1474 	} else {
1475 		php_error(E_ERROR, "Function '%s' doesn't exist", Z_STRVAL(function_name));
1476 	}
1477 
1478 	if (EG(exception)) {
1479 		if (!zend_is_unwind_exit(EG(exception))) {
1480 			php_output_discard();
1481 			_soap_server_exception(service, function, ZEND_THIS);
1482 			if (service->type == SOAP_CLASS) {
1483 #if defined(HAVE_PHP_SESSION) && !defined(COMPILE_DL_SESSION)
1484 				if (soap_obj && service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1485 #else
1486 				if (soap_obj) {
1487 #endif
1488 					zval_ptr_dtor(soap_obj);
1489 				}
1490 			}
1491 		}
1492 		goto fail;
1493 	}
1494 
1495 	if (call_status == SUCCESS) {
1496 		char *response_name;
1497 
1498 		if (Z_TYPE(retval) == IS_OBJECT &&
1499 		    instanceof_function(Z_OBJCE(retval), soap_fault_class_entry)) {
1500 			php_output_discard();
1501 			soap_server_fault_ex(function, &retval, NULL);
1502 			goto fail;
1503 		}
1504 
1505 		if (function && function->responseName) {
1506 			response_name = estrdup(function->responseName);
1507 		} else {
1508 			response_name = emalloc(Z_STRLEN(function_name) + sizeof("Response"));
1509 			memcpy(response_name,Z_STRVAL(function_name),Z_STRLEN(function_name));
1510 			memcpy(response_name+Z_STRLEN(function_name),"Response",sizeof("Response"));
1511 		}
1512 		doc_return = serialize_response_call(function, response_name, service->uri, &retval, soap_headers, soap_version);
1513 		efree(response_name);
1514 	} else {
1515 		php_error_docref(NULL, E_WARNING, "Function '%s' call failed", Z_STRVAL(function_name));
1516 		return;
1517 	}
1518 
1519 	if (EG(exception)) {
1520 		php_output_discard();
1521 		_soap_server_exception(service, function, ZEND_THIS);
1522 		if (service->type == SOAP_CLASS) {
1523 #if defined(HAVE_PHP_SESSION) && !defined(COMPILE_DL_SESSION)
1524 			if (soap_obj && service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1525 #else
1526 			if (soap_obj) {
1527 #endif
1528 				zval_ptr_dtor(soap_obj);
1529 			}
1530 		}
1531 		goto fail;
1532 	}
1533 
1534 	/* Flush buffer */
1535 	php_output_discard();
1536 
1537 	if (doc_return) {
1538 		/* xmlDocDumpMemoryEnc(doc_return, &buf, &size, XML_CHAR_ENCODING_UTF8); */
1539 		xmlDocDumpMemory(doc_return, &buf, &size);
1540 
1541 		if (size == 0) {
1542 			php_error_docref(NULL, E_ERROR, "Dump memory failed");
1543 		}
1544 
1545 		if (soap_version == SOAP_1_2) {
1546 			sapi_add_header("Content-Type: application/soap+xml; charset=utf-8", sizeof("Content-Type: application/soap+xml; charset=utf-8")-1, 1);
1547 		} else {
1548 			sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
1549 		}
1550 
1551 		if (INI_INT("zlib.output_compression")) {
1552 			sapi_add_header("Connection: close", sizeof("Connection: close")-1, 1);
1553 		} else {
1554 			snprintf(cont_len, sizeof(cont_len), "Content-Length: %d", size);
1555 			sapi_add_header(cont_len, strlen(cont_len), 1);
1556 		}
1557 		php_write(buf, size);
1558 		xmlFree(buf);
1559 	} else {
1560 		sapi_add_header("HTTP/1.1 202 Accepted", sizeof("HTTP/1.1 202 Accepted")-1, 1);
1561 		sapi_add_header("Content-Length: 0", sizeof("Content-Length: 0")-1, 1);
1562 	}
1563 
1564 fail:
1565 	SOAP_GLOBAL(soap_version) = old_soap_version;
1566 	SOAP_GLOBAL(encoding) = old_encoding;
1567 	SOAP_GLOBAL(sdl) = old_sdl;
1568 	SOAP_GLOBAL(class_map) = old_class_map;
1569 	SOAP_GLOBAL(typemap) = old_typemap;
1570 	SOAP_GLOBAL(features) = old_features;
1571 
1572 	if (doc_return) {
1573 		xmlFreeDoc(doc_return);
1574 	}
1575 
1576 	/* Free soap headers */
1577 	zval_ptr_dtor(&retval);
1578 	while (soap_headers != NULL) {
1579 		soapHeader *h = soap_headers;
1580 		int i;
1581 
1582 		soap_headers = soap_headers->next;
1583 		if (h->parameters) {
1584 			i = h->num_params;
1585 			while (i > 0) {
1586 				zval_ptr_dtor(&h->parameters[--i]);
1587 			}
1588 			efree(h->parameters);
1589 		}
1590 		zval_ptr_dtor_str(&h->function_name);
1591 		zval_ptr_dtor(&h->retval);
1592 		efree(h);
1593 	}
1594 	service->soap_headers_ptr = NULL;
1595 
1596 	/* Free Memory */
1597 	if (num_params > 0) {
1598 		for (i = 0; i < num_params;i++) {
1599 			zval_ptr_dtor(&params[i]);
1600 		}
1601 		efree(params);
1602 	}
1603 	zval_ptr_dtor_str(&function_name);
1604 
1605 	SOAP_SERVER_END_CODE();
1606 }
1607 /* }}} */
1608 
1609 /* {{{ Issue SoapFault indicating an error */
1610 PHP_METHOD(SoapServer, fault)
1611 {
1612 	char *code, *string, *actor=NULL, *name=NULL;
1613 	size_t code_len, string_len, actor_len = 0, name_len = 0;
1614 	zval* details = NULL;
1615 	soapServicePtr service;
1616 	xmlCharEncodingHandlerPtr old_encoding;
1617 
1618 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|szs",
1619 	    &code, &code_len, &string, &string_len, &actor, &actor_len, &details,
1620 	    &name, &name_len) == FAILURE) {
1621 		RETURN_THROWS();
1622 	}
1623 
1624 	SOAP_SERVER_BEGIN_CODE();
1625 	FETCH_THIS_SERVICE(service);
1626 	old_encoding = SOAP_GLOBAL(encoding);
1627 	SOAP_GLOBAL(encoding) = service->encoding;
1628 
1629 	soap_server_fault(code, string, actor, details, name);
1630 
1631 	SOAP_GLOBAL(encoding) = old_encoding;
1632 	SOAP_SERVER_END_CODE();
1633 }
1634 /* }}} */
1635 
1636 /* {{{ */
1637 PHP_METHOD(SoapServer, addSoapHeader)
1638 {
1639 	soapServicePtr service;
1640 	zval *fault;
1641 	soapHeader **p;
1642 
1643 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &fault, soap_header_class_entry) == FAILURE) {
1644 		RETURN_THROWS();
1645 	}
1646 
1647 	SOAP_SERVER_BEGIN_CODE();
1648 
1649 	FETCH_THIS_SERVICE(service);
1650 
1651 	if (!service || !service->soap_headers_ptr) {
1652 		zend_throw_error(NULL, "SoapServer::addSoapHeader() may be called only during SOAP request processing");
1653 		SOAP_SERVER_END_CODE();
1654 		RETURN_THROWS();
1655 	}
1656 
1657 	p = service->soap_headers_ptr;
1658 	while (*p != NULL) {
1659 		p = &(*p)->next;
1660 	}
1661 	*p = emalloc(sizeof(soapHeader));
1662 	memset(*p, 0, sizeof(soapHeader));
1663 	ZVAL_NULL(&(*p)->function_name);
1664 	ZVAL_OBJ_COPY(&(*p)->retval, Z_OBJ_P(fault));
1665 
1666 	SOAP_SERVER_END_CODE();
1667 }
1668 /* }}} */
1669 
1670 static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader *hdr) /* {{{ */
1671 {
1672 	int soap_version;
1673 	xmlChar *buf;
1674 	char cont_len[30];
1675 	int size;
1676 	xmlDocPtr doc_return;
1677 	zval *agent_name;
1678 	int use_http_error_status = 1;
1679 
1680 	soap_version = SOAP_GLOBAL(soap_version);
1681 
1682 	doc_return = serialize_response_call(function, NULL, NULL, fault, hdr, soap_version);
1683 
1684 	xmlDocDumpMemory(doc_return, &buf, &size);
1685 
1686 	if ((Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY || zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER))) &&
1687 		(agent_name = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_USER_AGENT", sizeof("HTTP_USER_AGENT")-1)) != NULL &&
1688 		Z_TYPE_P(agent_name) == IS_STRING) {
1689 		if (zend_string_equals_literal(Z_STR_P(agent_name), "Shockwave Flash")) {
1690 			use_http_error_status = 0;
1691 		}
1692 	}
1693 	/*
1694 	   Want to return HTTP 500 but apache wants to over write
1695 	   our fault code with their own handling... Figure this out later
1696 	*/
1697 	if (use_http_error_status) {
1698 		sapi_add_header("HTTP/1.1 500 Internal Server Error", sizeof("HTTP/1.1 500 Internal Server Error")-1, 1);
1699 	}
1700 	if (INI_INT("zlib.output_compression")) {
1701 		sapi_add_header("Connection: close", sizeof("Connection: close")-1, 1);
1702 	} else {
1703 		snprintf(cont_len, sizeof(cont_len), "Content-Length: %d", size);
1704 		sapi_add_header(cont_len, strlen(cont_len), 1);
1705 	}
1706 	if (soap_version == SOAP_1_2) {
1707 		sapi_add_header("Content-Type: application/soap+xml; charset=utf-8", sizeof("Content-Type: application/soap+xml; charset=utf-8")-1, 1);
1708 	} else {
1709 		sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
1710 	}
1711 
1712 	php_write(buf, size);
1713 
1714 	xmlFreeDoc(doc_return);
1715 	xmlFree(buf);
1716 	zend_clear_exception();
1717 }
1718 /* }}} */
1719 
1720 static ZEND_NORETURN void soap_server_fault(char* code, char* string, char *actor, zval* details, char* name) /* {{{ */
1721 {
1722 	zval ret;
1723 
1724 	ZVAL_NULL(&ret);
1725 	set_soap_fault(&ret, NULL, code, string, actor, details, name);
1726 	/* TODO: Which function */
1727 	soap_server_fault_ex(NULL, &ret, NULL);
1728 	zend_bailout();
1729 }
1730 /* }}} */
1731 
1732 static zend_never_inline ZEND_COLD void soap_real_error_handler(int error_num, zend_string *error_filename, const uint32_t error_lineno, zend_string *message) /* {{{ */
1733 {
1734 	bool _old_in_compilation;
1735 	zend_execute_data *_old_current_execute_data;
1736 	int _old_http_response_code;
1737 	char *_old_http_status_line;
1738 
1739 	_old_in_compilation = CG(in_compilation);
1740 	_old_current_execute_data = EG(current_execute_data);
1741 	_old_http_response_code = SG(sapi_headers).http_response_code;
1742 	_old_http_status_line = SG(sapi_headers).http_status_line;
1743 
1744 	if (Z_OBJ(SOAP_GLOBAL(error_object)) &&
1745 	    instanceof_function(Z_OBJCE(SOAP_GLOBAL(error_object)), soap_class_entry)) {
1746 		bool use_exceptions =
1747 			Z_TYPE_P(Z_CLIENT_EXCEPTIONS_P(&SOAP_GLOBAL(error_object))) != IS_FALSE;
1748 		if ((error_num & E_FATAL_ERRORS) && use_exceptions) {
1749 			zval fault;
1750 			char *code = SOAP_GLOBAL(error_code);
1751 			if (code == NULL) {
1752 				code = "Client";
1753 			}
1754 
1755 			add_soap_fault_ex(&fault, &SOAP_GLOBAL(error_object), code, ZSTR_VAL(message), NULL, NULL);
1756 			Z_ADDREF(fault);
1757 			zend_throw_exception_object(&fault);
1758 			zend_bailout();
1759 		} else if (!use_exceptions ||
1760 		           !SOAP_GLOBAL(error_code) ||
1761 		           strcmp(SOAP_GLOBAL(error_code),"WSDL") != 0) {
1762 			/* Ignore libxml warnings during WSDL parsing */
1763 			old_error_handler(error_num, error_filename, error_lineno, message);
1764 		}
1765 	} else {
1766 		int old = PG(display_errors);
1767 		int fault = 0;
1768 		zval fault_obj;
1769 
1770 		if (error_num & E_FATAL_ERRORS) {
1771 			char *code = SOAP_GLOBAL(error_code);
1772 			zval *error_object = &SOAP_GLOBAL(error_object);
1773 			zend_string *buffer;
1774 			zval outbuf;
1775 			soapServicePtr service;
1776 
1777 			ZVAL_UNDEF(&outbuf);
1778 			if (code == NULL) {
1779 				code = "Server";
1780 			}
1781 			if (Z_OBJ_P(error_object) &&
1782 			    instanceof_function(Z_OBJCE_P(error_object), soap_server_class_entry) &&
1783 				(service = soap_server_object_fetch(Z_OBJ_P(error_object))->service) &&
1784 				!service->send_errors) {
1785 				buffer = ZSTR_INIT_LITERAL("Internal Error", 0);
1786 			} else {
1787 				buffer = zend_string_copy(message);
1788 
1789 				/* Get output buffer and send as fault detials */
1790 				zval outbuflen;
1791 				if (php_output_get_length(&outbuflen) != FAILURE && Z_LVAL(outbuflen) != 0) {
1792 					php_output_get_contents(&outbuf);
1793 				}
1794 				php_output_discard();
1795 
1796 			}
1797 			ZVAL_NULL(&fault_obj);
1798 			set_soap_fault(&fault_obj, NULL, code, ZSTR_VAL(buffer), NULL, &outbuf, NULL);
1799 			zend_string_release(buffer);
1800 			fault = 1;
1801 		}
1802 
1803 		PG(display_errors) = 0;
1804 		SG(sapi_headers).http_status_line = NULL;
1805 		zend_try {
1806 			old_error_handler(error_num, error_filename, error_lineno, message);
1807 		} zend_catch {
1808 			CG(in_compilation) = _old_in_compilation;
1809 			EG(current_execute_data) = _old_current_execute_data;
1810 			if (SG(sapi_headers).http_status_line) {
1811 				efree(SG(sapi_headers).http_status_line);
1812 			}
1813 			SG(sapi_headers).http_status_line = _old_http_status_line;
1814 			SG(sapi_headers).http_response_code = _old_http_response_code;
1815 		} zend_end_try();
1816 		PG(display_errors) = old;
1817 
1818 		if (fault) {
1819 			soap_server_fault_ex(NULL, &fault_obj, NULL);
1820 			zend_bailout();
1821 		}
1822 	}
1823 }
1824 /* }}} */
1825 
1826 static void soap_error_handler(int error_num, zend_string *error_filename, const uint32_t error_lineno, zend_string *message) /* {{{ */
1827 {
1828 	if (EXPECTED(!SOAP_GLOBAL(use_soap_error_handler))) {
1829 		old_error_handler(error_num, error_filename, error_lineno, message);
1830 	} else {
1831 		soap_real_error_handler(error_num, error_filename, error_lineno, message);
1832 	}
1833 }
1834 /* }}} */
1835 
1836 /* {{{ */
1837 PHP_FUNCTION(use_soap_error_handler)
1838 {
1839 	bool handler = 1;
1840 
1841 	ZVAL_BOOL(return_value, SOAP_GLOBAL(use_soap_error_handler));
1842 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &handler) == SUCCESS) {
1843 		SOAP_GLOBAL(use_soap_error_handler) = handler;
1844 	}
1845 }
1846 /* }}} */
1847 
1848 /* {{{ */
1849 PHP_FUNCTION(is_soap_fault)
1850 {
1851 	zval *fault;
1852 
1853 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &fault) == SUCCESS &&
1854 	    Z_TYPE_P(fault) == IS_OBJECT &&
1855 	    instanceof_function(Z_OBJCE_P(fault), soap_fault_class_entry)) {
1856 		RETURN_TRUE;
1857 	}
1858 	RETURN_FALSE;
1859 }
1860 /* }}} */
1861 
1862 /* SoapClient functions */
1863 
1864 /* {{{ SoapClient constructor */
1865 PHP_METHOD(SoapClient, __construct)
1866 {
1867 
1868 	zval *options = NULL;
1869 	zend_string *wsdl;
1870 	int  soap_version = SOAP_1_1;
1871 	php_stream_context *context = NULL;
1872 	zend_long cache_wsdl;
1873 	sdlPtr sdl = NULL;
1874 	HashTable *typemap_ht = NULL;
1875 	zval *this_ptr = ZEND_THIS;
1876 
1877 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S!|a", &wsdl, &options) == FAILURE) {
1878 		RETURN_THROWS();
1879 	}
1880 
1881 	SOAP_CLIENT_BEGIN_CODE();
1882 
1883 	cache_wsdl = SOAP_GLOBAL(cache_enabled) ? SOAP_GLOBAL(cache_mode) : 0;
1884 
1885 	if (options != NULL) {
1886 		HashTable *ht = Z_ARRVAL_P(options);
1887 		zval *tmp, tmp2;
1888 
1889 		if (!wsdl) {
1890 			/* Fetching non-WSDL mode options */
1891 			if ((tmp = zend_hash_str_find(ht, "uri", sizeof("uri")-1)) != NULL &&
1892 			    Z_TYPE_P(tmp) == IS_STRING) {
1893 				ZVAL_STR_COPY(Z_CLIENT_URI_P(this_ptr), Z_STR_P(tmp));
1894 			} else {
1895 				php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
1896 			}
1897 
1898 			if ((tmp = zend_hash_str_find(ht, "style", sizeof("style")-1)) != NULL &&
1899 					Z_TYPE_P(tmp) == IS_LONG &&
1900 					(Z_LVAL_P(tmp) == SOAP_RPC || Z_LVAL_P(tmp) == SOAP_DOCUMENT)) {
1901 				ZVAL_LONG(Z_CLIENT_STYLE_P(this_ptr), Z_LVAL_P(tmp));
1902 			}
1903 
1904 			if ((tmp = zend_hash_str_find(ht, "use", sizeof("use")-1)) != NULL &&
1905 					Z_TYPE_P(tmp) == IS_LONG &&
1906 					(Z_LVAL_P(tmp) == SOAP_LITERAL || Z_LVAL_P(tmp) == SOAP_ENCODED)) {
1907 				ZVAL_LONG(Z_CLIENT_USE_P(this_ptr), Z_LVAL_P(tmp));
1908 			}
1909 		}
1910 
1911 		if ((tmp = zend_hash_str_find(ht, "stream_context", sizeof("stream_context")-1)) != NULL &&
1912 				Z_TYPE_P(tmp) == IS_RESOURCE) {
1913 			context = php_stream_context_from_zval(tmp, 1);
1914 			Z_ADDREF_P(tmp);
1915 		} else {
1916 			context = php_stream_context_alloc();
1917 		}
1918 
1919 		if ((tmp = zend_hash_str_find(ht, "location", sizeof("location")-1)) != NULL &&
1920 		    Z_TYPE_P(tmp) == IS_STRING) {
1921 			ZVAL_STR_COPY(Z_CLIENT_LOCATION_P(this_ptr), Z_STR_P(tmp));
1922 		} else if (!wsdl) {
1923 			php_error_docref(NULL, E_ERROR, "'location' option is required in nonWSDL mode");
1924 		}
1925 
1926 		if ((tmp = zend_hash_str_find(ht, "soap_version", sizeof("soap_version")-1)) != NULL) {
1927 			if (Z_TYPE_P(tmp) == IS_LONG &&
1928 			    (Z_LVAL_P(tmp) == SOAP_1_1 || Z_LVAL_P(tmp) == SOAP_1_2)) {
1929 				soap_version = Z_LVAL_P(tmp);
1930 			}
1931 		}
1932 		if ((tmp = zend_hash_str_find(ht, "login", sizeof("login")-1)) != NULL &&
1933 		    Z_TYPE_P(tmp) == IS_STRING) {
1934 			ZVAL_STR_COPY(Z_CLIENT_LOGIN_P(this_ptr), Z_STR_P(tmp));
1935 			if ((tmp = zend_hash_str_find(ht, "password", sizeof("password")-1)) != NULL &&
1936 			    Z_TYPE_P(tmp) == IS_STRING) {
1937 				ZVAL_STR_COPY(Z_CLIENT_PASSWORD_P(this_ptr), Z_STR_P(tmp));
1938 			}
1939 			if ((tmp = zend_hash_str_find(ht, "authentication", sizeof("authentication")-1)) != NULL &&
1940 			    Z_TYPE_P(tmp) == IS_LONG &&
1941 			    Z_LVAL_P(tmp) == SOAP_AUTHENTICATION_DIGEST) {
1942 				ZVAL_TRUE(Z_CLIENT_USE_DIGEST_P(this_ptr));
1943 			}
1944 		}
1945 		if ((tmp = zend_hash_str_find(ht, "proxy_host", sizeof("proxy_host")-1)) != NULL &&
1946 		    Z_TYPE_P(tmp) == IS_STRING) {
1947 			ZVAL_STR_COPY(Z_CLIENT_PROXY_HOST_P(this_ptr), Z_STR_P(tmp));
1948 			if ((tmp = zend_hash_str_find(ht, "proxy_port", sizeof("proxy_port")-1)) != NULL) {
1949 				if (Z_TYPE_P(tmp) != IS_LONG) {
1950 					ZVAL_LONG(&tmp2, zval_get_long(tmp));
1951 					tmp = &tmp2;
1952 				}
1953 				ZVAL_LONG(Z_CLIENT_PROXY_PORT_P(this_ptr), Z_LVAL_P(tmp));
1954 			}
1955 			if ((tmp = zend_hash_str_find(ht, "proxy_login", sizeof("proxy_login")-1)) != NULL &&
1956 			    Z_TYPE_P(tmp) == IS_STRING) {
1957 				ZVAL_STR_COPY(Z_CLIENT_PROXY_LOGIN_P(this_ptr), Z_STR_P(tmp));
1958 				if ((tmp = zend_hash_str_find(ht, "proxy_password", sizeof("proxy_password")-1)) != NULL &&
1959 				    Z_TYPE_P(tmp) == IS_STRING) {
1960 					ZVAL_STR_COPY(Z_CLIENT_PROXY_PASSWORD_P(this_ptr), Z_STR_P(tmp));
1961 				}
1962 			}
1963 		}
1964 		if ((tmp = zend_hash_str_find(ht, "local_cert", sizeof("local_cert")-1)) != NULL &&
1965 		    Z_TYPE_P(tmp) == IS_STRING) {
1966 			if (!context) {
1967 				context = php_stream_context_alloc();
1968 			}
1969 			php_stream_context_set_option(context, "ssl", "local_cert", tmp);
1970 			if ((tmp = zend_hash_str_find(ht, "passphrase", sizeof("passphrase")-1)) != NULL &&
1971 			    Z_TYPE_P(tmp) == IS_STRING) {
1972 				php_stream_context_set_option(context, "ssl", "passphrase", tmp);
1973 			}
1974 		}
1975 		if ((tmp = zend_hash_find(ht, ZSTR_KNOWN(ZEND_STR_TRACE))) != NULL &&
1976 		    (Z_TYPE_P(tmp) == IS_TRUE ||
1977 		     (Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 1))) {
1978 			ZVAL_TRUE(Z_CLIENT_TRACE_P(this_ptr));
1979 		}
1980 
1981 		if ((tmp = zend_hash_str_find(ht, "exceptions", sizeof("exceptions")-1)) != NULL &&
1982 		    (Z_TYPE_P(tmp) == IS_FALSE ||
1983 		     (Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 0))) {
1984 			ZVAL_FALSE(Z_CLIENT_EXCEPTIONS_P(this_ptr));
1985 		}
1986 
1987 		if ((tmp = zend_hash_str_find(ht, "compression", sizeof("compression")-1)) != NULL &&
1988 		    Z_TYPE_P(tmp) == IS_LONG &&
1989 	      zend_hash_str_exists(EG(function_table), "gzinflate", sizeof("gzinflate")-1) &&
1990 	      zend_hash_str_exists(EG(function_table), "gzdeflate", sizeof("gzdeflate")-1) &&
1991 	      zend_hash_str_exists(EG(function_table), "gzuncompress", sizeof("gzuncompress")-1) &&
1992 	      zend_hash_str_exists(EG(function_table), "gzcompress", sizeof("gzcompress")-1) &&
1993 	      zend_hash_str_exists(EG(function_table), "gzencode", sizeof("gzencode")-1)) {
1994 			ZVAL_LONG(Z_CLIENT_COMPRESSION_P(this_ptr), Z_LVAL_P(tmp));
1995 		}
1996 		if ((tmp = zend_hash_str_find(ht, "encoding", sizeof("encoding")-1)) != NULL &&
1997 		    Z_TYPE_P(tmp) == IS_STRING) {
1998 			xmlCharEncodingHandlerPtr encoding;
1999 
2000 			encoding = xmlFindCharEncodingHandler(Z_STRVAL_P(tmp));
2001 			if (encoding == NULL) {
2002 				php_error_docref(NULL, E_ERROR, "Invalid 'encoding' option - '%s'", Z_STRVAL_P(tmp));
2003 			} else {
2004 				xmlCharEncCloseFunc(encoding);
2005 				ZVAL_STR_COPY(Z_CLIENT_ENCODING_P(this_ptr), Z_STR_P(tmp));
2006 			}
2007 		}
2008 		if ((tmp = zend_hash_str_find(ht, "classmap", sizeof("classmap")-1)) != NULL &&
2009 			Z_TYPE_P(tmp) == IS_ARRAY) {
2010 			if (HT_IS_PACKED(Z_ARRVAL_P(tmp))) {
2011 				php_error_docref(NULL, E_ERROR, "'classmap' option must be an associative array");
2012 			}
2013 			ZVAL_COPY(Z_CLIENT_CLASSMAP_P(this_ptr), tmp);
2014 		}
2015 
2016 		if ((tmp = zend_hash_str_find(ht, "typemap", sizeof("typemap")-1)) != NULL &&
2017 			Z_TYPE_P(tmp) == IS_ARRAY &&
2018 			zend_hash_num_elements(Z_ARRVAL_P(tmp)) > 0) {
2019 			typemap_ht = Z_ARRVAL_P(tmp);
2020 		}
2021 
2022 		if ((tmp = zend_hash_str_find(ht, "features", sizeof("features")-1)) != NULL &&
2023 			Z_TYPE_P(tmp) == IS_LONG) {
2024 			ZVAL_LONG(Z_CLIENT_FEATURES_P(this_ptr), Z_LVAL_P(tmp));
2025 		}
2026 
2027 		if ((tmp = zend_hash_str_find(ht, "connection_timeout", sizeof("connection_timeout")-1)) != NULL) {
2028 			zend_long lval = zval_get_long(tmp);
2029 			if (lval > 0) {
2030 				ZVAL_LONG(Z_CLIENT_CONNECTION_TIMEOUT_P(this_ptr), lval);
2031 			}
2032 		}
2033 
2034 		if (context) {
2035 			ZVAL_RES(Z_CLIENT_STREAM_CONTEXT_P(this_ptr), context->res);
2036 		}
2037 
2038 		if ((tmp = zend_hash_str_find(ht, "cache_wsdl", sizeof("cache_wsdl")-1)) != NULL &&
2039 		    Z_TYPE_P(tmp) == IS_LONG) {
2040 			cache_wsdl = Z_LVAL_P(tmp);
2041 		}
2042 
2043 		if ((tmp = zend_hash_str_find(ht, "user_agent", sizeof("user_agent")-1)) != NULL &&
2044 		    Z_TYPE_P(tmp) == IS_STRING) {
2045 			ZVAL_STR_COPY(Z_CLIENT_USER_AGENT_P(this_ptr), Z_STR_P(tmp));
2046 		}
2047 
2048 		if ((tmp = zend_hash_str_find(ht, "keep_alive", sizeof("keep_alive")-1)) != NULL &&
2049 				(Z_TYPE_P(tmp) == IS_FALSE ||
2050 				 (Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 0))) {
2051 			ZVAL_FALSE(Z_CLIENT_KEEP_ALIVE_P(this_ptr));
2052 		}
2053 
2054 		if ((tmp = zend_hash_str_find(ht, "ssl_method", sizeof("ssl_method")-1)) != NULL &&
2055 			Z_TYPE_P(tmp) == IS_LONG) {
2056 			ZVAL_LONG(Z_CLIENT_SSL_METHOD_P(this_ptr), Z_LVAL_P(tmp));
2057 			php_error_docref(NULL, E_DEPRECATED,
2058 				"The \"ssl_method\" option is deprecated. "
2059 				"Use \"ssl\" stream context options instead");
2060 		}
2061 	} else if (!wsdl) {
2062 		php_error_docref(NULL, E_ERROR, "'location' and 'uri' options are required in nonWSDL mode");
2063 	}
2064 
2065 	ZVAL_LONG(Z_CLIENT_SOAP_VERSION_P(this_ptr), soap_version);
2066 
2067 	if (wsdl) {
2068 		int    old_soap_version;
2069 		zend_resource *res;
2070 
2071 		old_soap_version = SOAP_GLOBAL(soap_version);
2072 		SOAP_GLOBAL(soap_version) = soap_version;
2073 
2074 		sdl = get_sdl(this_ptr, ZSTR_VAL(wsdl), cache_wsdl);
2075 		res = zend_register_resource(sdl, le_sdl);
2076 
2077 		ZVAL_RES(Z_CLIENT_SDL_P(this_ptr), res);
2078 
2079 		SOAP_GLOBAL(soap_version) = old_soap_version;
2080 	}
2081 
2082 	if (typemap_ht) {
2083 		HashTable *typemap = soap_create_typemap(sdl, typemap_ht);
2084 		if (typemap) {
2085 			zend_resource *res = zend_register_resource(typemap, le_typemap);
2086 			ZVAL_RES(Z_CLIENT_TYPEMAP_P(this_ptr), res);
2087 		}
2088 	}
2089 	SOAP_CLIENT_END_CODE();
2090 }
2091 /* }}} */
2092 
2093 static int do_request(zval *this_ptr, xmlDoc *request, char *location, char *action, int version, bool one_way, zval *response) /* {{{ */
2094 {
2095 	int    ret = TRUE;
2096 	char  *buf;
2097 	int    buf_size;
2098 	zval   func;
2099 	zval  params[5];
2100 	int    _bailout = 0;
2101 
2102 	ZVAL_NULL(response);
2103 
2104 	xmlDocDumpMemory(request, (xmlChar**)&buf, &buf_size);
2105 	if (!buf) {
2106 		add_soap_fault(this_ptr, "HTTP", "Error build soap request", NULL, NULL);
2107 		return FALSE;
2108 	}
2109 
2110 	zend_try {
2111 		zval *trace = Z_CLIENT_TRACE_P(this_ptr);
2112 		if (Z_TYPE_P(trace) == IS_TRUE) {
2113 			zval_ptr_dtor(Z_CLIENT_LAST_REQUEST_P(this_ptr));
2114 			ZVAL_STRINGL(Z_CLIENT_LAST_REQUEST_P(this_ptr), buf, buf_size);
2115 		}
2116 
2117 		ZVAL_STRINGL(&func,"__doRequest",sizeof("__doRequest")-1);
2118 		ZVAL_STRINGL(&params[0], buf, buf_size);
2119 		ZVAL_STRING(&params[1], location);
2120 		if (action == NULL) {
2121 			ZVAL_EMPTY_STRING(&params[2]);
2122 		} else {
2123 			ZVAL_STRING(&params[2], action);
2124 		}
2125 		ZVAL_LONG(&params[3], version);
2126 		ZVAL_BOOL(&params[4], one_way);
2127 
2128 		if (call_user_function(NULL, this_ptr, &func, response, 5, params) != SUCCESS) {
2129 			add_soap_fault(this_ptr, "Client", "SoapClient::__doRequest() failed", NULL, NULL);
2130 			ret = FALSE;
2131 		} else if (Z_TYPE_P(response) != IS_STRING) {
2132 			if (EG(exception) && instanceof_function(EG(exception)->ce, zend_ce_error)) {
2133 				/* Programmer error in __doRequest() implementation, let it bubble up. */
2134 			} else if (Z_TYPE_P(Z_CLIENT_SOAP_FAULT_P(this_ptr)) != IS_OBJECT) {
2135 				add_soap_fault(this_ptr, "Client", "SoapClient::__doRequest() returned non string value", NULL, NULL);
2136 			}
2137 			ret = FALSE;
2138 		} else if (Z_TYPE_P(trace) == IS_TRUE) {
2139 			zval_ptr_dtor(Z_CLIENT_LAST_RESPONSE_P(this_ptr));
2140 			ZVAL_STR_COPY(Z_CLIENT_LAST_RESPONSE_P(this_ptr), Z_STR_P(response));
2141 		}
2142 	} zend_catch {
2143 		_bailout = 1;
2144 	} zend_end_try();
2145 	zval_ptr_dtor(&func);
2146 	zval_ptr_dtor(&params[2]);
2147 	zval_ptr_dtor(&params[1]);
2148 	zval_ptr_dtor(&params[0]);
2149 	xmlFree(buf);
2150 	if (_bailout) {
2151 		zend_bailout();
2152 	}
2153 	if (ret && Z_TYPE_P(Z_CLIENT_SOAP_FAULT_P(this_ptr)) == IS_OBJECT) {
2154 		ret = FALSE;
2155 	}
2156 	return ret;
2157 }
2158 /* }}} */
2159 
2160 static void do_soap_call(zend_execute_data *execute_data,
2161                          zval* this_ptr,
2162                          char* function,
2163                          size_t function_len,
2164                          int arg_count,
2165                          zval* real_args,
2166                          zval* return_value,
2167                          char* location,
2168                          char* soap_action,
2169                          char* call_uri,
2170                          HashTable* soap_headers,
2171                          zval* output_headers
2172                         ) /* {{{ */
2173 {
2174 	sdlPtr sdl = NULL;
2175 	sdlPtr old_sdl = NULL;
2176 	sdlFunctionPtr fn;
2177 	xmlDocPtr request = NULL;
2178 	int ret = FALSE;
2179 	int soap_version;
2180 	zval response;
2181 	xmlCharEncodingHandlerPtr old_encoding;
2182 	HashTable *old_class_map;
2183 	int old_features;
2184 	HashTable *old_typemap, *typemap = NULL;
2185 	smart_str action = {0};
2186 	int bailout = 0;
2187 
2188 	SOAP_CLIENT_BEGIN_CODE();
2189 
2190 	if (Z_TYPE_P(Z_CLIENT_TRACE_P(this_ptr)) == IS_TRUE) {
2191 		convert_to_null(Z_CLIENT_LAST_REQUEST_P(this_ptr));
2192 		convert_to_null(Z_CLIENT_LAST_RESPONSE_P(this_ptr));
2193 	}
2194 
2195 	zval *tmp = Z_CLIENT_SOAP_VERSION_P(this_ptr);
2196 	if (Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == SOAP_1_2) {
2197 		soap_version = SOAP_1_2;
2198 	} else {
2199 		soap_version = SOAP_1_1;
2200 	}
2201 
2202 	if (location == NULL) {
2203 		tmp = Z_CLIENT_LOCATION_P(this_ptr);
2204 		if (Z_TYPE_P(tmp) == IS_STRING) {
2205 			location = Z_STRVAL_P(tmp);
2206 		}
2207 	}
2208 
2209 	tmp = Z_CLIENT_SDL_P(this_ptr);
2210 	if (Z_TYPE_P(tmp) == IS_RESOURCE) {
2211 		FETCH_SDL_RES(sdl,tmp);
2212 	}
2213 
2214 	tmp = Z_CLIENT_TYPEMAP_P(this_ptr);
2215 	if (Z_TYPE_P(tmp) == IS_RESOURCE) {
2216 		FETCH_TYPEMAP_RES(typemap, tmp);
2217 	}
2218 
2219 	clear_soap_fault(this_ptr);
2220 
2221 	SOAP_GLOBAL(soap_version) = soap_version;
2222 	old_sdl = SOAP_GLOBAL(sdl);
2223 	SOAP_GLOBAL(sdl) = sdl;
2224 	old_encoding = SOAP_GLOBAL(encoding);
2225 	tmp = Z_CLIENT_ENCODING_P(this_ptr);
2226 	if (Z_TYPE_P(tmp) == IS_STRING) {
2227 		SOAP_GLOBAL(encoding) = xmlFindCharEncodingHandler(Z_STRVAL_P(tmp));
2228 	} else {
2229 		SOAP_GLOBAL(encoding) = NULL;
2230 	}
2231 	old_class_map = SOAP_GLOBAL(class_map);
2232 	tmp = Z_CLIENT_CLASSMAP_P(this_ptr);
2233 	if (Z_TYPE_P(tmp) == IS_ARRAY) {
2234 		SOAP_GLOBAL(class_map) = Z_ARRVAL_P(tmp);
2235 	} else {
2236 		SOAP_GLOBAL(class_map) = NULL;
2237 	}
2238 	old_typemap = SOAP_GLOBAL(typemap);
2239 	SOAP_GLOBAL(typemap) = typemap;
2240 	old_features = SOAP_GLOBAL(features);
2241 	tmp = Z_CLIENT_FEATURES_P(this_ptr);
2242 	if (Z_TYPE_P(tmp) == IS_LONG) {
2243 		SOAP_GLOBAL(features) = Z_LVAL_P(tmp);
2244 	} else {
2245 		SOAP_GLOBAL(features) = 0;
2246 	}
2247 
2248 	zend_try {
2249 	 	if (sdl != NULL) {
2250 			fn = get_function(sdl, function);
2251 			if (fn != NULL) {
2252 				sdlBindingPtr binding = fn->binding;
2253 				bool one_way = 0;
2254 
2255 				if (fn->responseName == NULL &&
2256 				    fn->responseParameters == NULL &&
2257 				    soap_headers == NULL) {
2258 					one_way = 1;
2259 				}
2260 
2261 				if (location == NULL) {
2262 					location = binding->location;
2263 					ZEND_ASSERT(location);
2264 				}
2265 				if (binding->bindingType == BINDING_SOAP) {
2266 					sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes;
2267 					request = serialize_function_call(this_ptr, fn, NULL, fnb->input.ns, real_args, arg_count, soap_version, soap_headers);
2268 	 				ret = do_request(this_ptr, request, location, fnb->soapAction, soap_version, one_way, &response);
2269 				} else {
2270 	 				request = serialize_function_call(this_ptr, fn, NULL, sdl->target_ns, real_args, arg_count, soap_version, soap_headers);
2271 	 				ret = do_request(this_ptr, request, location, NULL, soap_version, one_way, &response);
2272 				}
2273 
2274 				xmlFreeDoc(request);
2275 				request = NULL;
2276 
2277 				if (ret && Z_TYPE(response) == IS_STRING) {
2278 					encode_reset_ns();
2279 					ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), fn, NULL, return_value, output_headers);
2280 					encode_finish();
2281 				}
2282 
2283 				zval_ptr_dtor(&response);
2284 
2285 	 		} else {
2286 	 			smart_str error = {0};
2287 	 			smart_str_appends(&error,"Function (\"");
2288 	 			smart_str_appends(&error,function);
2289 	 			smart_str_appends(&error,"\") is not a valid method for this service");
2290 	 			smart_str_0(&error);
2291 				add_soap_fault(this_ptr, "Client", ZSTR_VAL(error.s), NULL, NULL);
2292 				smart_str_free(&error);
2293 			}
2294 		} else {
2295 			zval *uri = Z_CLIENT_URI_P(this_ptr);
2296 			if (Z_TYPE_P(uri) != IS_STRING) {
2297 				add_soap_fault(this_ptr, "Client", "Error finding \"uri\" property", NULL, NULL);
2298 			} else if (location == NULL) {
2299 				add_soap_fault(this_ptr, "Client", "Error could not find \"location\" property", NULL, NULL);
2300 			} else {
2301 				if (call_uri == NULL) {
2302 					call_uri = Z_STRVAL_P(uri);
2303 				}
2304 		 		request = serialize_function_call(this_ptr, NULL, function, call_uri, real_args, arg_count, soap_version, soap_headers);
2305 
2306 		 		if (soap_action == NULL) {
2307 					smart_str_appends(&action, call_uri);
2308 					smart_str_appendc(&action, '#');
2309 					smart_str_appends(&action, function);
2310 				} else {
2311 					smart_str_appends(&action, soap_action);
2312 				}
2313 				smart_str_0(&action);
2314 
2315 				ret = do_request(this_ptr, request, location, ZSTR_VAL(action.s), soap_version, 0, &response);
2316 
2317 		 		smart_str_free(&action);
2318 				xmlFreeDoc(request);
2319 				request = NULL;
2320 
2321 				if (ret && Z_TYPE(response) == IS_STRING) {
2322 					encode_reset_ns();
2323 					ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), NULL, function, return_value, output_headers);
2324 					encode_finish();
2325 				}
2326 
2327 				zval_ptr_dtor(&response);
2328 			}
2329 	 	}
2330 
2331 		zval *fault = Z_CLIENT_SOAP_FAULT_P(this_ptr);
2332 		if (!ret) {
2333 			if (Z_TYPE_P(fault) == IS_OBJECT) {
2334 				ZVAL_COPY(return_value, fault);
2335 			} else {
2336 				add_soap_fault_ex(return_value, this_ptr, "Client", "Unknown Error", NULL, NULL);
2337 				Z_ADDREF_P(return_value);
2338 			}
2339 		} else {
2340 			if (Z_TYPE_P(fault) == IS_OBJECT) {
2341 				ZVAL_COPY(return_value, fault);
2342 			}
2343 		}
2344 
2345 		if (!EG(exception) &&
2346 		    Z_TYPE_P(return_value) == IS_OBJECT &&
2347 		    instanceof_function(Z_OBJCE_P(return_value), soap_fault_class_entry) &&
2348 		    Z_TYPE_P(Z_CLIENT_EXCEPTIONS_P(this_ptr)) != IS_FALSE) {
2349 			Z_ADDREF_P(return_value);
2350 			zend_throw_exception_object(return_value);
2351 		}
2352 
2353 	} zend_catch {
2354 		bailout = 1;
2355 	} zend_end_try();
2356 
2357 	if (SOAP_GLOBAL(encoding) != NULL) {
2358 		xmlCharEncCloseFunc(SOAP_GLOBAL(encoding));
2359 	}
2360 
2361 	SOAP_GLOBAL(features) = old_features;
2362 	SOAP_GLOBAL(typemap) = old_typemap;
2363 	SOAP_GLOBAL(class_map) = old_class_map;
2364 	SOAP_GLOBAL(encoding) = old_encoding;
2365 	SOAP_GLOBAL(sdl) = old_sdl;
2366 	if (bailout) {
2367 		smart_str_free(&action);
2368 		if (request) {
2369 			xmlFreeDoc(request);
2370 		}
2371 		zend_bailout();
2372 	}
2373 	SOAP_CLIENT_END_CODE();
2374 }
2375 /* }}} */
2376 
2377 static void verify_soap_headers_array(HashTable *ht) /* {{{ */
2378 {
2379 	zval *tmp;
2380 
2381 	ZEND_HASH_FOREACH_VAL(ht, tmp) {
2382 		if (Z_TYPE_P(tmp) != IS_OBJECT ||
2383 		    !instanceof_function(Z_OBJCE_P(tmp), soap_header_class_entry)) {
2384 			php_error_docref(NULL, E_ERROR, "Invalid SOAP header");
2385 		}
2386 	} ZEND_HASH_FOREACH_END();
2387 }
2388 /* }}} */
2389 
2390 /* {{{ Calls a SOAP function */
2391 void soap_client_call_impl(INTERNAL_FUNCTION_PARAMETERS, bool is_soap_call)
2392 {
2393 	char *function, *location=NULL, *soap_action = NULL, *uri = NULL;
2394 	size_t function_len;
2395 	int i = 0;
2396 	HashTable* soap_headers = NULL;
2397 	zval *options = NULL;
2398 	zval *headers = NULL;
2399 	zval *output_headers = NULL;
2400 	zval *args;
2401 	zval *real_args = NULL;
2402 	zval *param;
2403 	int arg_count;
2404 	zval *tmp;
2405 	bool free_soap_headers = 0;
2406 	zval *this_ptr;
2407 
2408 	if (is_soap_call) {
2409 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa|a!zz",
2410 			&function, &function_len, &args, &options, &headers, &output_headers) == FAILURE) {
2411 			RETURN_THROWS();
2412 		}
2413 	} else {
2414 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa", &function, &function_len, &args) == FAILURE) {
2415 			RETURN_THROWS();
2416 		}
2417 	}
2418 
2419 	if (options) {
2420 		HashTable *hto = Z_ARRVAL_P(options);
2421 		if ((tmp = zend_hash_str_find(hto, "location", sizeof("location")-1)) != NULL &&
2422 			Z_TYPE_P(tmp) == IS_STRING) {
2423 			location = Z_STRVAL_P(tmp);
2424 		}
2425 
2426 		if ((tmp = zend_hash_str_find(hto, "soapaction", sizeof("soapaction")-1)) != NULL &&
2427 			Z_TYPE_P(tmp) == IS_STRING) {
2428 			soap_action = Z_STRVAL_P(tmp);
2429 		}
2430 
2431 		if ((tmp = zend_hash_str_find(hto, "uri", sizeof("uri")-1)) != NULL &&
2432 			Z_TYPE_P(tmp) == IS_STRING) {
2433 			uri = Z_STRVAL_P(tmp);
2434 		}
2435 	}
2436 
2437 	if (headers == NULL || Z_TYPE_P(headers) == IS_NULL) {
2438 	} else if (Z_TYPE_P(headers) == IS_ARRAY) {
2439 		soap_headers = Z_ARRVAL_P(headers);
2440 		verify_soap_headers_array(soap_headers);
2441 		free_soap_headers = 0;
2442 	} else if (Z_TYPE_P(headers) == IS_OBJECT &&
2443 	           instanceof_function(Z_OBJCE_P(headers), soap_header_class_entry)) {
2444 	    soap_headers = zend_new_array(0);
2445 		zend_hash_next_index_insert(soap_headers, headers);
2446 		Z_ADDREF_P(headers);
2447 		free_soap_headers = 1;
2448 	} else {
2449 		zend_argument_type_error(4, "must be of type SoapHeader|array|null, %s given", zend_zval_value_name(headers));
2450 		RETURN_THROWS();
2451 	}
2452 
2453 	/* Add default headers */
2454 	this_ptr = ZEND_THIS;
2455 	tmp = Z_CLIENT_DEFAULT_HEADERS_P(this_ptr);
2456 	if (Z_TYPE_P(tmp) == IS_ARRAY) {
2457 		HashTable *default_headers = Z_ARRVAL_P(tmp);
2458 		if (soap_headers) {
2459 			if (!free_soap_headers) {
2460 				soap_headers = zend_array_dup(soap_headers);
2461 				free_soap_headers = 1;
2462 			}
2463 			ZEND_HASH_FOREACH_VAL(default_headers, tmp) {
2464 				if(Z_TYPE_P(tmp) == IS_OBJECT) {
2465 					Z_ADDREF_P(tmp);
2466 					zend_hash_next_index_insert(soap_headers, tmp);
2467 				}
2468 			} ZEND_HASH_FOREACH_END();
2469 		} else {
2470 			soap_headers = Z_ARRVAL_P(tmp);
2471 			free_soap_headers = 0;
2472 		}
2473 	}
2474 
2475 	arg_count = zend_hash_num_elements(Z_ARRVAL_P(args));
2476 
2477 	if (arg_count > 0) {
2478 		real_args = safe_emalloc(sizeof(zval), arg_count, 0);
2479 		ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args), param) {
2480 			/*zval_add_ref(param);*/
2481 			ZVAL_DEREF(param);
2482 			ZVAL_COPY_VALUE(&real_args[i], param);
2483 			i++;
2484 		} ZEND_HASH_FOREACH_END();
2485 	}
2486 	if (output_headers) {
2487 		output_headers = zend_try_array_init(output_headers);
2488 		if (!output_headers) {
2489 			goto cleanup;
2490 		}
2491 	}
2492 
2493 	do_soap_call(execute_data, this_ptr, function, function_len, arg_count, real_args, return_value, location, soap_action, uri, soap_headers, output_headers);
2494 
2495 cleanup:
2496 	if (arg_count > 0) {
2497 		efree(real_args);
2498 	}
2499 	if (soap_headers && free_soap_headers) {
2500 		zend_hash_destroy(soap_headers);
2501 		efree(soap_headers);
2502 	}
2503 }
2504 /* }}} */
2505 
2506 PHP_METHOD(SoapClient, __call)
2507 {
2508 	soap_client_call_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2509 }
2510 
2511 PHP_METHOD(SoapClient, __soapCall)
2512 {
2513 	soap_client_call_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2514 }
2515 
2516 /* {{{ Returns list of SOAP functions */
2517 PHP_METHOD(SoapClient, __getFunctions)
2518 {
2519 	sdlPtr sdl;
2520 
2521 	FETCH_THIS_SDL(sdl);
2522 
2523 	if (zend_parse_parameters_none() == FAILURE) {
2524 		RETURN_THROWS();
2525 	}
2526 
2527 	if (sdl) {
2528 		smart_str buf = {0};
2529 		sdlFunctionPtr function;
2530 
2531 		array_init(return_value);
2532 		ZEND_HASH_MAP_FOREACH_PTR(&sdl->functions, function) {
2533 			function_to_string(function, &buf);
2534 			add_next_index_stringl(return_value, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
2535 			smart_str_free(&buf);
2536 		} ZEND_HASH_FOREACH_END();
2537 	}
2538 }
2539 /* }}} */
2540 
2541 
2542 /* {{{ Returns list of SOAP types */
2543 PHP_METHOD(SoapClient, __getTypes)
2544 {
2545 	sdlPtr sdl;
2546 
2547 	FETCH_THIS_SDL(sdl);
2548 
2549 	if (zend_parse_parameters_none() == FAILURE) {
2550 		RETURN_THROWS();
2551 	}
2552 
2553 	if (sdl) {
2554 		sdlTypePtr type;
2555 		smart_str buf = {0};
2556 
2557 		array_init(return_value);
2558 		if (sdl->types) {
2559 			ZEND_HASH_FOREACH_PTR(sdl->types, type) {
2560 				type_to_string(type, &buf, 0);
2561 				add_next_index_stringl(return_value, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
2562 				smart_str_free(&buf);
2563 			} ZEND_HASH_FOREACH_END();
2564 		}
2565 	}
2566 }
2567 /* }}} */
2568 
2569 
2570 /* {{{ Returns last SOAP request */
2571 PHP_METHOD(SoapClient, __getLastRequest)
2572 {
2573 	if (zend_parse_parameters_none() == FAILURE) {
2574 		RETURN_THROWS();
2575 	}
2576 
2577 	RETURN_COPY(Z_CLIENT_LAST_REQUEST_P(ZEND_THIS));
2578 }
2579 /* }}} */
2580 
2581 
2582 /* {{{ Returns last SOAP response */
2583 PHP_METHOD(SoapClient, __getLastResponse)
2584 {
2585 	if (zend_parse_parameters_none() == FAILURE) {
2586 		RETURN_THROWS();
2587 	}
2588 
2589 	RETURN_COPY(Z_CLIENT_LAST_RESPONSE_P(ZEND_THIS));
2590 }
2591 /* }}} */
2592 
2593 
2594 /* {{{ Returns last SOAP request headers */
2595 PHP_METHOD(SoapClient, __getLastRequestHeaders)
2596 {
2597 	if (zend_parse_parameters_none() == FAILURE) {
2598 		RETURN_THROWS();
2599 	}
2600 
2601 	RETURN_COPY(Z_CLIENT_LAST_REQUEST_HEADERS_P(ZEND_THIS));
2602 }
2603 /* }}} */
2604 
2605 
2606 /* {{{ Returns last SOAP response headers */
2607 PHP_METHOD(SoapClient, __getLastResponseHeaders)
2608 {
2609 	if (zend_parse_parameters_none() == FAILURE) {
2610 		RETURN_THROWS();
2611 	}
2612 
2613 	RETURN_COPY(Z_CLIENT_LAST_RESPONSE_HEADERS_P(ZEND_THIS));
2614 }
2615 /* }}} */
2616 
2617 
2618 /* {{{ SoapClient::__doRequest() */
2619 PHP_METHOD(SoapClient, __doRequest)
2620 {
2621 	zend_string *buf;
2622 	char      *location, *action;
2623 	size_t     location_size, action_size;
2624 	zend_long  version;
2625 	bool  one_way = 0;
2626 	zval      *this_ptr = ZEND_THIS;
2627 
2628 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sssl|b",
2629 	    &buf,
2630 	    &location, &location_size,
2631 	    &action, &action_size,
2632 	    &version, &one_way) == FAILURE) {
2633 		RETURN_THROWS();
2634 	}
2635 	if (SOAP_GLOBAL(features) & SOAP_WAIT_ONE_WAY_CALLS) {
2636 		one_way = 0;
2637 	}
2638 	if (one_way) {
2639 		if (make_http_soap_request(this_ptr, buf, location, action, version, NULL)) {
2640 			RETURN_EMPTY_STRING();
2641 		}
2642 	} else if (make_http_soap_request(this_ptr, buf, location, action, version,
2643 	    return_value)) {
2644 		return;
2645 	}
2646 	RETURN_NULL();
2647 }
2648 /* }}} */
2649 
2650 /* {{{ Sets cookie thet will sent with SOAP request.
2651    The call to this function will effect all following calls of SOAP methods.
2652    If value is not specified cookie is removed. */
2653 PHP_METHOD(SoapClient, __setCookie)
2654 {
2655 	zend_string *name, *val = NULL;
2656 
2657 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|S!", &name, &val) == FAILURE) {
2658 		RETURN_THROWS();
2659 	}
2660 
2661 	zval *cookies = Z_CLIENT_COOKIES_P(ZEND_THIS);
2662 	SEPARATE_ARRAY(cookies);
2663 	if (val == NULL) {
2664 		zend_hash_del(Z_ARRVAL_P(cookies), name);
2665 	} else {
2666 		zval zcookie;
2667 		array_init(&zcookie);
2668 		add_index_str(&zcookie, 0, zend_string_copy(val));
2669 		zend_hash_update(Z_ARRVAL_P(cookies), name, &zcookie);
2670 	}
2671 }
2672 /* }}} */
2673 
2674 /* {{{ Returns list of cookies */
2675 PHP_METHOD(SoapClient, __getCookies)
2676 {
2677 	if (zend_parse_parameters_none() == FAILURE) {
2678 		RETURN_THROWS();
2679 	}
2680 
2681 	RETURN_COPY(Z_CLIENT_COOKIES_P(ZEND_THIS));
2682 }
2683 /* }}} */
2684 
2685 /* {{{ Sets SOAP headers for subsequent calls (replaces any previous
2686    values).
2687    If no value is specified, all of the headers are removed. */
2688 PHP_METHOD(SoapClient, __setSoapHeaders)
2689 {
2690 	zval *headers = NULL;
2691 	zval *this_ptr = ZEND_THIS;
2692 
2693 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &headers) == FAILURE) {
2694 		RETURN_THROWS();
2695 	}
2696 
2697 	if (headers == NULL || Z_TYPE_P(headers) == IS_NULL) {
2698 		convert_to_null(Z_CLIENT_DEFAULT_HEADERS_P(this_ptr));
2699 	} else if (Z_TYPE_P(headers) == IS_ARRAY) {
2700 		verify_soap_headers_array(Z_ARRVAL_P(headers));
2701 		zval_ptr_dtor(Z_CLIENT_DEFAULT_HEADERS_P(this_ptr));
2702 		ZVAL_COPY(Z_CLIENT_DEFAULT_HEADERS_P(this_ptr), headers);
2703 	} else if (Z_TYPE_P(headers) == IS_OBJECT &&
2704 	           instanceof_function(Z_OBJCE_P(headers), soap_header_class_entry)) {
2705 		zval default_headers;
2706 		array_init(&default_headers);
2707 		Z_ADDREF_P(headers);
2708 		add_next_index_zval(&default_headers, headers);
2709 
2710 		zval_ptr_dtor(Z_CLIENT_DEFAULT_HEADERS_P(this_ptr));
2711 		ZVAL_COPY_VALUE(Z_CLIENT_DEFAULT_HEADERS_P(this_ptr), &default_headers);
2712 	} else {
2713 		zend_argument_type_error(1, "must be of type SoapHeader|array|null, %s given", zend_zval_value_name(headers));
2714 		RETURN_THROWS();
2715 	}
2716 	RETURN_TRUE;
2717 }
2718 /* }}} */
2719 
2720 /* {{{ Sets the location option (the endpoint URL that will be touched by the
2721    following SOAP requests).
2722    If new_location is not specified or null then SoapClient will use endpoint
2723    from WSDL file.
2724    The function returns old value of location options. */
2725 PHP_METHOD(SoapClient, __setLocation)
2726 {
2727 	zend_string *location = NULL;
2728 	zval *this_ptr = ZEND_THIS;
2729 
2730 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!", &location) == FAILURE) {
2731 		RETURN_THROWS();
2732 	}
2733 
2734 	RETVAL_COPY_VALUE(Z_CLIENT_LOCATION_P(this_ptr));
2735 
2736 	if (location && ZSTR_LEN(location) != 0) {
2737 		ZVAL_STR_COPY(Z_CLIENT_LOCATION_P(this_ptr), location);
2738 	} else {
2739 		ZVAL_NULL(Z_CLIENT_LOCATION_P(this_ptr));
2740 	}
2741 }
2742 /* }}} */
2743 
2744 static void clear_soap_fault(zval *obj) /* {{{ */
2745 {
2746 	ZEND_ASSERT(instanceof_function(Z_OBJCE_P(obj), soap_class_entry));
2747 	convert_to_null(Z_CLIENT_SOAP_FAULT_P(obj));
2748 }
2749 /* }}} */
2750 
2751 static void add_soap_fault_ex(zval *fault, zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail) /* {{{ */
2752 {
2753 	ZVAL_NULL(fault);
2754 	set_soap_fault(fault, NULL, fault_code, fault_string, fault_actor, fault_detail, NULL);
2755 	zval *target;
2756 	if (instanceof_function(Z_OBJCE_P(obj), soap_class_entry)) {
2757 		target = Z_CLIENT_SOAP_FAULT_P(obj);
2758 	} else if (instanceof_function(Z_OBJCE_P(obj), soap_server_class_entry)) {
2759 		target = Z_SERVER_SOAP_FAULT_P(obj);
2760 	} else {
2761 		ZEND_UNREACHABLE();
2762 	}
2763 	zval_ptr_dtor(target);
2764 	ZVAL_COPY_VALUE(target, fault);
2765 }
2766 /* }}} */
2767 
2768 void add_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail) /* {{{ */
2769 {
2770 	zval fault;
2771 	add_soap_fault_ex(&fault, obj, fault_code, fault_string, fault_actor, fault_detail);
2772 }
2773 /* }}} */
2774 
2775 static void set_soap_fault(zval *obj, char *fault_code_ns, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail, char *name) /* {{{ */
2776 {
2777 	if (Z_TYPE_P(obj) != IS_OBJECT) {
2778 		object_init_ex(obj, soap_fault_class_entry);
2779 	}
2780 
2781 	ZVAL_STRING(Z_FAULT_STRING_P(obj), fault_string ? fault_string : "");
2782 	zend_update_property_ex(zend_ce_exception, Z_OBJ_P(obj), ZSTR_KNOWN(ZEND_STR_MESSAGE), Z_FAULT_STRING_P(obj));
2783 
2784 	if (fault_code != NULL) {
2785 		int soap_version = SOAP_GLOBAL(soap_version);
2786 
2787 		if (fault_code_ns) {
2788 			ZVAL_STRING(Z_FAULT_CODE_P(obj), fault_code);
2789 			ZVAL_STRING(Z_FAULT_CODENS_P(obj), fault_code_ns);
2790 		} else {
2791 			if (soap_version == SOAP_1_1) {
2792 				ZVAL_STRING(Z_FAULT_CODE_P(obj), fault_code);
2793 				if (strcmp(fault_code,"Client") == 0 ||
2794 				    strcmp(fault_code,"Server") == 0 ||
2795 				    strcmp(fault_code,"VersionMismatch") == 0 ||
2796 			  	  strcmp(fault_code,"MustUnderstand") == 0) {
2797 					ZVAL_STRING(Z_FAULT_CODENS_P(obj), SOAP_1_1_ENV_NAMESPACE);
2798 				}
2799 			} else if (soap_version == SOAP_1_2) {
2800 				if (strcmp(fault_code,"Client") == 0) {
2801 					ZVAL_STRING(Z_FAULT_CODE_P(obj), "Sender");
2802 					ZVAL_STRING(Z_FAULT_CODENS_P(obj), SOAP_1_2_ENV_NAMESPACE);
2803 				} else if (strcmp(fault_code,"Server") == 0) {
2804 					ZVAL_STRING(Z_FAULT_CODE_P(obj), "Receiver");
2805 					ZVAL_STRING(Z_FAULT_CODENS_P(obj), SOAP_1_2_ENV_NAMESPACE);
2806 				} else if (strcmp(fault_code,"VersionMismatch") == 0 ||
2807 				           strcmp(fault_code,"MustUnderstand") == 0 ||
2808 				           strcmp(fault_code,"DataEncodingUnknown") == 0) {
2809 					ZVAL_STRING(Z_FAULT_CODE_P(obj), fault_code);
2810 					ZVAL_STRING(Z_FAULT_CODENS_P(obj), SOAP_1_2_ENV_NAMESPACE);
2811 				} else {
2812 					ZVAL_STRING(Z_FAULT_CODE_P(obj), fault_code);
2813 				}
2814 			}
2815 		}
2816 	}
2817 	if (fault_actor != NULL) {
2818 		ZVAL_STRING(Z_FAULT_ACTOR_P(obj), fault_actor);
2819 	}
2820 	if (fault_detail != NULL && Z_TYPE_P(fault_detail) != IS_UNDEF) {
2821 		ZVAL_COPY(Z_FAULT_DETAIL_P(obj), fault_detail);
2822 	}
2823 	if (name != NULL) {
2824 		ZVAL_STRING(Z_FAULT_NAME_P(obj), name);
2825 	}
2826 }
2827 /* }}} */
2828 
2829 static void deserialize_parameters(xmlNodePtr params, sdlFunctionPtr function, int *num_params, zval **parameters) /* {{{ */
2830 {
2831 	int cur_param = 0,num_of_params = 0;
2832 	zval *tmp_parameters = NULL;
2833 
2834 	if (function != NULL) {
2835 		sdlParamPtr param;
2836 		xmlNodePtr val;
2837 		int	use_names = 0;
2838 
2839 		if (function->requestParameters == NULL) {
2840 			return;
2841 		}
2842 		num_of_params = zend_hash_num_elements(function->requestParameters);
2843 		ZEND_HASH_FOREACH_PTR(function->requestParameters, param) {
2844 			if (get_node(params, param->paramName) != NULL) {
2845 				use_names = 1;
2846 			}
2847 		} ZEND_HASH_FOREACH_END();
2848 		if (use_names) {
2849 			tmp_parameters = safe_emalloc(num_of_params, sizeof(zval), 0);
2850 			ZEND_HASH_FOREACH_PTR(function->requestParameters, param) {
2851 				val = get_node(params, param->paramName);
2852 				if (!val) {
2853 					/* TODO: may be "nil" is not OK? */
2854 					ZVAL_NULL(&tmp_parameters[cur_param]);
2855 				} else {
2856 					master_to_zval(&tmp_parameters[cur_param], param->encode, val);
2857 				}
2858 				cur_param++;
2859 			} ZEND_HASH_FOREACH_END();
2860 			*parameters = tmp_parameters;
2861 			*num_params = num_of_params;
2862 			return;
2863 		}
2864 	}
2865 	if (params) {
2866 		xmlNodePtr trav;
2867 
2868 		num_of_params = 0;
2869 		trav = params;
2870 		while (trav != NULL) {
2871 			if (trav->type == XML_ELEMENT_NODE) {
2872 				num_of_params++;
2873 			}
2874 			trav = trav->next;
2875 		}
2876 
2877 		if (num_of_params == 1 &&
2878 		    function &&
2879 		    function->binding &&
2880 		    function->binding->bindingType == BINDING_SOAP &&
2881 		    ((sdlSoapBindingFunctionPtr)function->bindingAttributes)->style == SOAP_DOCUMENT &&
2882 		    (function->requestParameters == NULL ||
2883 		     zend_hash_num_elements(function->requestParameters) == 0) &&
2884 		    strcmp((char *)params->name, function->functionName) == 0) {
2885 			num_of_params = 0;
2886 		} else if (num_of_params > 0) {
2887 			tmp_parameters = safe_emalloc(num_of_params, sizeof(zval), 0);
2888 
2889 			trav = params;
2890 			while (trav != 0 && cur_param < num_of_params) {
2891 				if (trav->type == XML_ELEMENT_NODE) {
2892 					encodePtr enc;
2893 					sdlParamPtr param = NULL;
2894 					if (function != NULL &&
2895 					    (param = zend_hash_index_find_ptr(function->requestParameters, cur_param)) == NULL) {
2896 											soap_server_fault("Client", "Error cannot find parameter", NULL, NULL, NULL);
2897 					}
2898 					if (param == NULL) {
2899 						enc = NULL;
2900 					} else {
2901 						enc = param->encode;
2902 					}
2903 					master_to_zval(&tmp_parameters[cur_param], enc, trav);
2904 					cur_param++;
2905 				}
2906 				trav = trav->next;
2907 			}
2908 		}
2909 	}
2910 	if (num_of_params > cur_param) {
2911 		soap_server_fault("Client","Missing parameter", NULL, NULL, NULL);
2912 	}
2913 	(*parameters) = tmp_parameters;
2914 	(*num_params) = num_of_params;
2915 }
2916 /* }}} */
2917 
2918 static sdlFunctionPtr find_function(sdlPtr sdl, xmlNodePtr func, zval* function_name) /* {{{ */
2919 {
2920 	sdlFunctionPtr function;
2921 
2922 	function = get_function(sdl, (char*)func->name);
2923 	if (function && function->binding && function->binding->bindingType == BINDING_SOAP) {
2924 		sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
2925 		if (fnb->style == SOAP_DOCUMENT) {
2926 			if (func->children != NULL ||
2927 			    (function->requestParameters != NULL &&
2928 			     zend_hash_num_elements(function->requestParameters) > 0)) {
2929 				function = NULL;
2930 			}
2931 		}
2932 	}
2933 	if (sdl != NULL && function == NULL) {
2934 		function = get_doc_function(sdl, func);
2935 	}
2936 
2937 	if (function != NULL) {
2938 		ZVAL_STRING(function_name, (char *)function->functionName);
2939 	} else {
2940 		ZVAL_STRING(function_name, (char *)func->name);
2941 	}
2942 
2943 	return function;
2944 }
2945 /* }}} */
2946 
2947 static xmlNodePtr get_envelope(xmlNodePtr trav, int *version, char **envelope_ns) {
2948 	while (trav != NULL) {
2949 		if (trav->type == XML_ELEMENT_NODE) {
2950 			if (node_is_equal_ex(trav,"Envelope",SOAP_1_1_ENV_NAMESPACE)) {
2951 				*version = SOAP_1_1;
2952 				*envelope_ns = SOAP_1_1_ENV_NAMESPACE;
2953 				SOAP_GLOBAL(soap_version) = SOAP_1_1;
2954 				return trav;
2955 			}
2956 
2957 			if (node_is_equal_ex(trav,"Envelope",SOAP_1_2_ENV_NAMESPACE)) {
2958 				*version = SOAP_1_2;
2959 				*envelope_ns = SOAP_1_2_ENV_NAMESPACE;
2960 				SOAP_GLOBAL(soap_version) = SOAP_1_2;
2961 				return trav;
2962 			}
2963 
2964 			soap_server_fault("VersionMismatch", "Wrong Version", NULL, NULL, NULL);
2965 		}
2966 		trav = trav->next;
2967 	}
2968 
2969 	return NULL;
2970 }
2971 
2972 static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, char* actor, zval *function_name, int *num_params, zval **parameters, int *version, soapHeader **headers) /* {{{ */
2973 {
2974 	char* envelope_ns = NULL;
2975 	xmlNodePtr trav,env,head,body,func;
2976 	xmlAttrPtr attr;
2977 	sdlFunctionPtr function;
2978 
2979 	encode_reset_ns();
2980 
2981 	/* Get <Envelope> element */
2982 	env = get_envelope(request->children, version, &envelope_ns);
2983 	if (!env) {
2984 		soap_server_fault("Client", "looks like we got XML without \"Envelope\" element", NULL, NULL, NULL);
2985 	}
2986 
2987 	attr = env->properties;
2988 	while (attr != NULL) {
2989 		if (attr->ns == NULL) {
2990 			soap_server_fault("Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL, NULL);
2991 		} else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
2992 			if (*version == SOAP_1_2) {
2993 				soap_server_fault("Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL, NULL);
2994 			} else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
2995 				soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL);
2996 			}
2997 		}
2998 		attr = attr->next;
2999 	}
3000 
3001 	/* Get <Header> element */
3002 	head = NULL;
3003 	trav = env->children;
3004 	while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
3005 		trav = trav->next;
3006 	}
3007 	if (trav != NULL && node_is_equal_ex(trav,"Header",envelope_ns)) {
3008 		head = trav;
3009 		trav = trav->next;
3010 	}
3011 
3012 	/* Get <Body> element */
3013 	body = NULL;
3014 	while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
3015 		trav = trav->next;
3016 	}
3017 	if (trav != NULL && node_is_equal_ex(trav,"Body",envelope_ns)) {
3018 		body = trav;
3019 		trav = trav->next;
3020 	}
3021 	while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
3022 		trav = trav->next;
3023 	}
3024 	if (body == NULL) {
3025 		soap_server_fault("Client", "Body must be present in a SOAP envelope", NULL, NULL, NULL);
3026 	}
3027 	attr = body->properties;
3028 	while (attr != NULL) {
3029 		if (attr->ns == NULL) {
3030 			if (*version == SOAP_1_2) {
3031 				soap_server_fault("Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL, NULL);
3032 			}
3033 		} else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
3034 			if (*version == SOAP_1_2) {
3035 				soap_server_fault("Client", "encodingStyle cannot be specified on the Body", NULL, NULL, NULL);
3036 			} else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3037 				soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL);
3038 			}
3039 		}
3040 		attr = attr->next;
3041 	}
3042 
3043 	if (trav != NULL && *version == SOAP_1_2) {
3044 		soap_server_fault("Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL, NULL);
3045 	}
3046 
3047 	func = NULL;
3048 	trav = body->children;
3049 	while (trav != NULL) {
3050 		if (trav->type == XML_ELEMENT_NODE) {
3051 /*
3052 			if (func != NULL) {
3053 				soap_server_fault("Client", "looks like we got \"Body\" with several functions call", NULL, NULL, NULL);
3054 			}
3055 */
3056 			func = trav;
3057 			break; /* FIXME: the rest of body is ignored */
3058 		}
3059 		trav = trav->next;
3060 	}
3061 	if (func == NULL) {
3062 		function = get_doc_function(sdl, NULL);
3063 		if (function != NULL) {
3064 			ZVAL_STRING(function_name, (char *)function->functionName);
3065 		} else {
3066 			soap_server_fault("Client", "looks like we got \"Body\" without function call", NULL, NULL, NULL);
3067 		}
3068 	} else {
3069 		if (*version == SOAP_1_1) {
3070 			attr = get_attribute_ex(func->properties,"encodingStyle",SOAP_1_1_ENV_NAMESPACE);
3071 			if (attr && strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3072 				soap_server_fault("Client","Unknown Data Encoding Style", NULL, NULL, NULL);
3073 			}
3074 		} else {
3075 			attr = get_attribute_ex(func->properties,"encodingStyle",SOAP_1_2_ENV_NAMESPACE);
3076 			if (attr && strcmp((char*)attr->children->content,SOAP_1_2_ENC_NAMESPACE) != 0) {
3077 				soap_server_fault("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL);
3078 			}
3079 		}
3080 		function = find_function(sdl, func, function_name);
3081 		if (sdl != NULL && function == NULL) {
3082 			if (*version == SOAP_1_2) {
3083 				soap_server_fault("rpc:ProcedureNotPresent","Procedure not present", NULL, NULL, NULL);
3084 			} else {
3085 				php_error(E_ERROR, "Procedure '%s' not present", func->name);
3086 			}
3087 		}
3088 	}
3089 
3090 	*headers = NULL;
3091 	if (head) {
3092 		soapHeader *h, *last = NULL;
3093 
3094 		attr = head->properties;
3095 		while (attr != NULL) {
3096 			if (attr->ns == NULL) {
3097 				soap_server_fault("Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL, NULL);
3098 			} else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
3099 				if (*version == SOAP_1_2) {
3100 					soap_server_fault("Client", "encodingStyle cannot be specified on the Header", NULL, NULL, NULL);
3101 				} else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3102 					soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL);
3103 				}
3104 			}
3105 			attr = attr->next;
3106 		}
3107 		trav = head->children;
3108 		while (trav != NULL) {
3109 			if (trav->type == XML_ELEMENT_NODE) {
3110 				xmlNodePtr hdr_func = trav;
3111 				int mustUnderstand = 0;
3112 
3113 				if (*version == SOAP_1_1) {
3114 					attr = get_attribute_ex(hdr_func->properties,"encodingStyle",SOAP_1_1_ENV_NAMESPACE);
3115 					if (attr && strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3116 						soap_server_fault("Client","Unknown Data Encoding Style", NULL, NULL, NULL);
3117 					}
3118 					attr = get_attribute_ex(hdr_func->properties,"actor",envelope_ns);
3119 					if (attr != NULL) {
3120 						if (strcmp((char*)attr->children->content,SOAP_1_1_ACTOR_NEXT) != 0 &&
3121 						    (actor == NULL || strcmp((char*)attr->children->content,actor) != 0)) {
3122 						  goto ignore_header;
3123 						}
3124 					}
3125 				} else if (*version == SOAP_1_2) {
3126 					attr = get_attribute_ex(hdr_func->properties,"encodingStyle",SOAP_1_2_ENV_NAMESPACE);
3127 					if (attr && strcmp((char*)attr->children->content,SOAP_1_2_ENC_NAMESPACE) != 0) {
3128 						soap_server_fault("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL);
3129 					}
3130 					attr = get_attribute_ex(hdr_func->properties,"role",envelope_ns);
3131 					if (attr != NULL) {
3132 						if (strcmp((char*)attr->children->content,SOAP_1_2_ACTOR_UNLIMATERECEIVER) != 0 &&
3133 						    strcmp((char*)attr->children->content,SOAP_1_2_ACTOR_NEXT) != 0 &&
3134 						    (actor == NULL || strcmp((char*)attr->children->content,actor) != 0)) {
3135 						  goto ignore_header;
3136 						}
3137 					}
3138 				}
3139 				attr = get_attribute_ex(hdr_func->properties,"mustUnderstand",envelope_ns);
3140 				if (attr) {
3141 					if (strcmp((char*)attr->children->content,"1") == 0 ||
3142 					    strcmp((char*)attr->children->content,"true") == 0) {
3143 						mustUnderstand = 1;
3144 					} else if (strcmp((char*)attr->children->content,"0") == 0 ||
3145 					           strcmp((char*)attr->children->content,"false") == 0) {
3146 						mustUnderstand = 0;
3147 					} else {
3148 						soap_server_fault("Client","mustUnderstand value is not boolean", NULL, NULL, NULL);
3149 					}
3150 				}
3151 				h = emalloc(sizeof(soapHeader));
3152 				memset(h, 0, sizeof(soapHeader));
3153 				h->mustUnderstand = mustUnderstand;
3154 				h->function = find_function(sdl, hdr_func, &h->function_name);
3155 				if (!h->function && sdl && function && function->binding && function->binding->bindingType == BINDING_SOAP) {
3156 					sdlSoapBindingFunctionHeaderPtr hdr;
3157 					sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3158 					if (fnb->input.headers) {
3159 						smart_str key = {0};
3160 
3161 						if (hdr_func->ns) {
3162 							smart_str_appends(&key, (char*)hdr_func->ns->href);
3163 							smart_str_appendc(&key, ':');
3164 						}
3165 						smart_str_appendl(&key, Z_STRVAL(h->function_name), Z_STRLEN(h->function_name));
3166 						smart_str_0(&key);
3167 						if ((hdr = zend_hash_find_ptr(fnb->input.headers, key.s)) != NULL) {
3168 							h->hdr = hdr;
3169 						}
3170 						smart_str_free(&key);
3171 					}
3172 				}
3173 				if (h->hdr) {
3174 					h->num_params = 1;
3175 					h->parameters = emalloc(sizeof(zval));
3176 					master_to_zval(&h->parameters[0], h->hdr->encode, hdr_func);
3177 				} else {
3178 					if (h->function && h->function->binding && h->function->binding->bindingType == BINDING_SOAP) {
3179 						sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)h->function->bindingAttributes;
3180 						if (fnb->style == SOAP_RPC) {
3181 							hdr_func = hdr_func->children;
3182 						}
3183 					}
3184 					deserialize_parameters(hdr_func, h->function, &h->num_params, &h->parameters);
3185 				}
3186 				ZVAL_NULL(&h->retval);
3187 				if (last == NULL) {
3188 					*headers = h;
3189 				} else {
3190 					last->next = h;
3191 				}
3192 				last = h;
3193 			}
3194 ignore_header:
3195 			trav = trav->next;
3196 		}
3197 	}
3198 
3199 	if (function && function->binding && function->binding->bindingType == BINDING_SOAP) {
3200 		sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3201 		if (fnb->style == SOAP_RPC) {
3202 			func = func->children;
3203 		}
3204 	} else {
3205 		func = func->children;
3206 	}
3207 	deserialize_parameters(func, function, num_params, parameters);
3208 
3209 	encode_finish();
3210 
3211 	return function;
3212 }
3213 /* }}} */
3214 
3215 static void set_soap_header_attributes(xmlNodePtr h, zval *header, int version) /* {{{ */
3216 {
3217 	if (Z_TYPE_P(Z_HEADER_MUST_UNDERSTAND_P(header)) == IS_TRUE) {
3218 		if (version == SOAP_1_1) {
3219 			xmlSetProp(h, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":mustUnderstand"), BAD_CAST("1"));
3220 		} else {
3221 			xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":mustUnderstand"), BAD_CAST("true"));
3222 		}
3223 	}
3224 
3225 	zval *tmp = Z_HEADER_ACTOR_P(header);
3226 	if (Z_TYPE_P(tmp) == IS_STRING) {
3227 		if (version == SOAP_1_1) {
3228 			xmlSetProp(h, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":actor"), BAD_CAST(Z_STRVAL_P(tmp)));
3229 		} else {
3230 			xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(Z_STRVAL_P(tmp)));
3231 		}
3232 	} else if (Z_TYPE_P(tmp) == IS_LONG) {
3233 		if (version == SOAP_1_1) {
3234 			if (Z_LVAL_P(tmp) == SOAP_ACTOR_NEXT) {
3235 				xmlSetProp(h, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":actor"), BAD_CAST(SOAP_1_1_ACTOR_NEXT));
3236 			}
3237 		} else {
3238 			if (Z_LVAL_P(tmp) == SOAP_ACTOR_NEXT) {
3239 				xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(SOAP_1_2_ACTOR_NEXT));
3240 			} else if (Z_LVAL_P(tmp) == SOAP_ACTOR_NONE) {
3241 				xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(SOAP_1_2_ACTOR_NONE));
3242 			} else if (Z_LVAL_P(tmp) == SOAP_ACTOR_UNLIMATERECEIVER) {
3243 				xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(SOAP_1_2_ACTOR_UNLIMATERECEIVER));
3244 			}
3245 		}
3246 	}
3247 }
3248 /* }}} */
3249 
3250 static int serialize_response_call2(xmlNodePtr body, sdlFunctionPtr function, char *function_name, char *uri, zval *ret, int version, int main, xmlNodePtr *node) /* {{{ */
3251 {
3252 	xmlNodePtr method = NULL, param;
3253 	sdlParamPtr parameter = NULL;
3254 	int param_count;
3255 	int style, use;
3256 	xmlNsPtr ns = NULL;
3257 
3258 	if (function != NULL && function->binding->bindingType == BINDING_SOAP) {
3259 		sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3260 
3261 		style = fnb->style;
3262 		use = fnb->output.use;
3263 		if (style == SOAP_RPC) {
3264 			ns = encode_add_ns(body, fnb->output.ns);
3265 			if (function->responseName) {
3266 				method = xmlNewChild(body, ns, BAD_CAST(function->responseName), NULL);
3267 			} else if (function->responseParameters) {
3268 				method = xmlNewChild(body, ns, BAD_CAST(function->functionName), NULL);
3269 			}
3270 		}
3271 	} else {
3272 		style = main?SOAP_RPC:SOAP_DOCUMENT;
3273 		use = main?SOAP_ENCODED:SOAP_LITERAL;
3274 		if (style == SOAP_RPC) {
3275 			ns = encode_add_ns(body, uri);
3276 			method = xmlNewChild(body, ns, BAD_CAST(function_name), NULL);
3277 		}
3278 	}
3279 
3280 	if (function != NULL) {
3281 		if (function->responseParameters) {
3282 			param_count = zend_hash_num_elements(function->responseParameters);
3283 		} else {
3284 		  param_count = 0;
3285 		}
3286 	} else {
3287 	  param_count = 1;
3288 	}
3289 
3290 	if (param_count == 1) {
3291 		parameter = get_param(function, NULL, 0, TRUE);
3292 
3293 		if (style == SOAP_RPC) {
3294 		  xmlNode *rpc_result;
3295 			if (main && version == SOAP_1_2) {
3296 				xmlNs *rpc_ns = xmlNewNs(body, BAD_CAST(RPC_SOAP12_NAMESPACE), BAD_CAST(RPC_SOAP12_NS_PREFIX));
3297 				rpc_result = xmlNewChild(method, rpc_ns, BAD_CAST("result"), NULL);
3298 				param = serialize_parameter(parameter, ret, 0, "return", use, method);
3299 				xmlNodeSetContent(rpc_result,param->name);
3300 			} else {
3301 				param = serialize_parameter(parameter, ret, 0, "return", use, method);
3302 			}
3303 		} else {
3304 			param = serialize_parameter(parameter, ret, 0, "return", use, body);
3305 			if (function && function->binding->bindingType == BINDING_SOAP) {
3306 				if (parameter && parameter->element) {
3307 					ns = encode_add_ns(param, parameter->element->namens);
3308 					xmlNodeSetName(param, BAD_CAST(parameter->element->name));
3309 					xmlSetNs(param, ns);
3310 				}
3311 			} else if (strcmp((char*)param->name,"return") == 0) {
3312 				ns = encode_add_ns(param, uri);
3313 				xmlNodeSetName(param, BAD_CAST(function_name));
3314 				xmlSetNs(param, ns);
3315 			}
3316 		}
3317 	} else if (param_count > 1 && Z_TYPE_P(ret) == IS_ARRAY) {
3318 		zval *data;
3319 		int i = 0;
3320 		zend_string *param_name;
3321 		zend_ulong param_index = i;
3322 
3323 		ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(ret), param_index, param_name, data) {
3324 			parameter = get_param(function, param_name ? ZSTR_VAL(param_name) : NULL, param_index, TRUE);
3325 			if (style == SOAP_RPC) {
3326 				param = serialize_parameter(parameter, data, i, param_name ? ZSTR_VAL(param_name) : NULL, use, method);
3327 			} else {
3328 				param = serialize_parameter(parameter, data, i, param_name ? ZSTR_VAL(param_name) : NULL, use, body);
3329 				if (function && function->binding->bindingType == BINDING_SOAP) {
3330 					if (parameter && parameter->element) {
3331 						ns = encode_add_ns(param, parameter->element->namens);
3332 						xmlNodeSetName(param, BAD_CAST(parameter->element->name));
3333 						xmlSetNs(param, ns);
3334 					}
3335 				}
3336 			}
3337 
3338 			i++;
3339 			param_index = i;
3340 		} ZEND_HASH_FOREACH_END();
3341 	}
3342 	if (use == SOAP_ENCODED && version == SOAP_1_2 && method != NULL) {
3343 		xmlSetNsProp(method, body->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
3344 	}
3345 	if (node) {
3346 		*node = method;
3347 	}
3348 	return use;
3349 }
3350 /* }}} */
3351 
3352 static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function_name, char *uri, zval *ret, soapHeader* headers, int version) /* {{{ */
3353 {
3354 	xmlDocPtr doc;
3355 	xmlNodePtr envelope = NULL, body, param;
3356 	xmlNsPtr ns = NULL;
3357 	int use = SOAP_LITERAL;
3358 	xmlNodePtr head = NULL;
3359 
3360 	encode_reset_ns();
3361 
3362 	doc = xmlNewDoc(BAD_CAST("1.0"));
3363 	zend_try {
3364 
3365 	doc->charset = XML_CHAR_ENCODING_UTF8;
3366 	doc->encoding = xmlCharStrdup("UTF-8");
3367 
3368 	if (version == SOAP_1_1) {
3369 		envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
3370 		ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENV_NAMESPACE), BAD_CAST(SOAP_1_1_ENV_NS_PREFIX));
3371 		xmlSetNs(envelope,ns);
3372 	} else if (version == SOAP_1_2) {
3373 		envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
3374 		ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENV_NAMESPACE), BAD_CAST(SOAP_1_2_ENV_NS_PREFIX));
3375 		xmlSetNs(envelope,ns);
3376 	} else {
3377 		soap_server_fault("Server", "Unknown SOAP version", NULL, NULL, NULL);
3378 	}
3379 	xmlDocSetRootElement(doc, envelope);
3380 
3381 	if (Z_TYPE_P(ret) == IS_OBJECT &&
3382 	    instanceof_function(Z_OBJCE_P(ret), soap_fault_class_entry)) {
3383 		char *detail_name;
3384 		sdlFaultPtr fault = NULL;
3385 		char *fault_ns = NULL;
3386 		zval *tmp = Z_FAULT_HEADERFAULT_P(ret);
3387 		if (headers && Z_TYPE_P(tmp) > IS_NULL) {
3388 			encodePtr hdr_enc = NULL;
3389 			int hdr_use = SOAP_LITERAL;
3390 			zval *hdr_ret  = tmp;
3391 			char *hdr_ns   = headers->hdr?headers->hdr->ns:NULL;
3392 			char *hdr_name = Z_STRVAL(headers->function_name);
3393 
3394 			head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL);
3395 			if (Z_TYPE_P(hdr_ret) == IS_OBJECT &&
3396 			    instanceof_function(Z_OBJCE_P(hdr_ret), soap_header_class_entry)) {
3397 				sdlSoapBindingFunctionHeaderPtr hdr;
3398 				smart_str key = {0};
3399 
3400 				tmp = Z_HEADER_NAMESPACE_P(hdr_ret);
3401 				if (Z_TYPE_P(tmp) == IS_STRING) {
3402 					smart_str_appendl(&key, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
3403 					smart_str_appendc(&key, ':');
3404 					hdr_ns = Z_STRVAL_P(tmp);
3405 				}
3406 
3407 				tmp = Z_HEADER_NAME_P(hdr_ret);
3408 				if (Z_TYPE_P(tmp) == IS_STRING) {
3409 					smart_str_appendl(&key, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
3410 					hdr_name = Z_STRVAL_P(tmp);
3411 				}
3412 				smart_str_0(&key);
3413 				if (headers->hdr && headers->hdr->headerfaults &&
3414 				    (hdr = zend_hash_find_ptr(headers->hdr->headerfaults, key.s)) != NULL) {
3415 					hdr_enc = hdr->encode;
3416 					hdr_use = hdr->use;
3417 				}
3418 				smart_str_free(&key);
3419 				tmp = Z_HEADER_DATA_P(hdr_ret);
3420 				if (Z_TYPE_P(tmp) > IS_NULL) {
3421 					hdr_ret = tmp;
3422 				} else {
3423 					hdr_ret = NULL;
3424 				}
3425 			}
3426 
3427 			if (headers->function) {
3428 				if (serialize_response_call2(head, headers->function, Z_STRVAL(headers->function_name), uri, hdr_ret, version, 0, NULL) == SOAP_ENCODED) {
3429 					use = SOAP_ENCODED;
3430 				}
3431 			} else {
3432 				xmlNodePtr xmlHdr = master_to_xml(hdr_enc, hdr_ret, hdr_use, head);
3433 				if (hdr_name) {
3434 					xmlNodeSetName(xmlHdr, BAD_CAST(hdr_name));
3435 				}
3436 				if (hdr_ns) {
3437 					xmlNsPtr nsptr = encode_add_ns(xmlHdr, hdr_ns);
3438 					xmlSetNs(xmlHdr, nsptr);
3439 				}
3440 			}
3441 		}
3442 
3443 		body = xmlNewChild(envelope, ns, BAD_CAST("Body"), NULL);
3444 		param = xmlNewChild(body, ns, BAD_CAST("Fault"), NULL);
3445 
3446 		tmp = Z_FAULT_CODENS_P(ret);
3447 		if (Z_TYPE_P(tmp) == IS_STRING) {
3448 			fault_ns = Z_STRVAL_P(tmp);
3449 		}
3450 		use = SOAP_LITERAL;
3451 
3452 		tmp = Z_FAULT_NAME_P(ret);
3453 		if (Z_TYPE_P(tmp) == IS_STRING) {
3454 			sdlFaultPtr tmp_fault;
3455 			if (function && function->faults &&
3456 			    (tmp_fault = zend_hash_find_ptr(function->faults, Z_STR_P(tmp))) != NULL) {
3457 				fault = tmp_fault;
3458 				if (function->binding &&
3459 				    function->binding->bindingType == BINDING_SOAP &&
3460 				    fault->bindingAttributes) {
3461 					sdlSoapBindingFunctionFaultPtr fb = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
3462 					use = fb->use;
3463 					if (fault_ns == NULL) {
3464 						fault_ns = fb->ns;
3465 					}
3466 				}
3467 			}
3468 		} else if (function && function->faults &&
3469 		           zend_hash_num_elements(function->faults) == 1) {
3470 
3471 			zend_hash_internal_pointer_reset(function->faults);
3472 			fault = zend_hash_get_current_data_ptr(function->faults);
3473 			if (function->binding &&
3474 			    function->binding->bindingType == BINDING_SOAP &&
3475 			    fault->bindingAttributes) {
3476 				sdlSoapBindingFunctionFaultPtr fb = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
3477 				use = fb->use;
3478 				if (fault_ns == NULL) {
3479 					fault_ns = fb->ns;
3480 				}
3481 			}
3482 		}
3483 
3484 		if (fault_ns == NULL &&
3485 		    fault &&
3486 		    fault->details &&
3487 		    zend_hash_num_elements(fault->details) == 1) {
3488 			sdlParamPtr sparam;
3489 
3490 			zend_hash_internal_pointer_reset(fault->details);
3491 			sparam = zend_hash_get_current_data_ptr(fault->details);
3492 			if (sparam->element) {
3493 				fault_ns = sparam->element->namens;
3494 			}
3495 		}
3496 
3497 		if (version == SOAP_1_1) {
3498 			tmp = Z_FAULT_CODE_P(ret);
3499 			if (Z_TYPE_P(tmp) == IS_STRING) {
3500 				xmlNodePtr node = xmlNewNode(NULL, BAD_CAST("faultcode"));
3501 				zend_string *str = php_escape_html_entities((unsigned char*)Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 0, 0, NULL);
3502 				xmlAddChild(param, node);
3503 				if (fault_ns) {
3504 					xmlNsPtr nsptr = encode_add_ns(node, fault_ns);
3505 					xmlChar *code = xmlBuildQName(BAD_CAST(ZSTR_VAL(str)), nsptr->prefix, NULL, 0);
3506 					xmlNodeSetContent(node, code);
3507 					xmlFree(code);
3508 				} else {
3509 					xmlNodeSetContentLen(node, BAD_CAST(ZSTR_VAL(str)), (int)ZSTR_LEN(str));
3510 				}
3511 				zend_string_release_ex(str, 0);
3512 			}
3513 			tmp = Z_FAULT_STRING_P(ret);
3514 			if (Z_TYPE_P(tmp) == IS_STRING) {
3515 				xmlNodePtr node = master_to_xml(get_conversion(IS_STRING), tmp, SOAP_LITERAL, param);
3516 				xmlNodeSetName(node, BAD_CAST("faultstring"));
3517 			}
3518 			tmp = Z_FAULT_ACTOR_P(ret);
3519 			if (Z_TYPE_P(tmp) == IS_STRING) {
3520 				xmlNodePtr node = master_to_xml(get_conversion(IS_STRING), tmp, SOAP_LITERAL, param);
3521 				xmlNodeSetName(node, BAD_CAST("faultactor"));
3522 			}
3523 			detail_name = "detail";
3524 		} else {
3525 			tmp = Z_FAULT_CODE_P(ret);
3526 			if (Z_TYPE_P(tmp) == IS_STRING) {
3527 				xmlNodePtr node = xmlNewChild(param, ns, BAD_CAST("Code"), NULL);
3528 				zend_string *str = php_escape_html_entities((unsigned char*)Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 0, 0, NULL);
3529 				node = xmlNewChild(node, ns, BAD_CAST("Value"), NULL);
3530 				if (fault_ns) {
3531 					xmlNsPtr nsptr = encode_add_ns(node, fault_ns);
3532 					xmlChar *code = xmlBuildQName(BAD_CAST(ZSTR_VAL(str)), nsptr->prefix, NULL, 0);
3533 					xmlNodeSetContent(node, code);
3534 					xmlFree(code);
3535 				} else {
3536 					xmlNodeSetContentLen(node, BAD_CAST(ZSTR_VAL(str)), (int)ZSTR_LEN(str));
3537 				}
3538 				zend_string_release_ex(str, 0);
3539 			}
3540 			tmp = Z_FAULT_STRING_P(ret);
3541 			if (Z_TYPE_P(tmp) == IS_STRING) {
3542 				xmlNodePtr node = xmlNewChild(param, ns, BAD_CAST("Reason"), NULL);
3543 				node = master_to_xml(get_conversion(IS_STRING), tmp, SOAP_LITERAL, node);
3544 				xmlNodeSetName(node, BAD_CAST("Text"));
3545 				xmlSetNs(node, ns);
3546 			}
3547 			detail_name = SOAP_1_2_ENV_NS_PREFIX":Detail";
3548 		}
3549 		if (fault && fault->details && zend_hash_num_elements(fault->details) == 1) {
3550 			xmlNodePtr node;
3551 			zval *detail = NULL;
3552 			sdlParamPtr sparam;
3553 			xmlNodePtr x;
3554 
3555 			tmp = Z_FAULT_DETAIL_P(ret);
3556 			if (Z_TYPE_P(tmp) > IS_NULL) {
3557 				detail = tmp;
3558 			}
3559 			node = xmlNewNode(NULL, BAD_CAST(detail_name));
3560 			xmlAddChild(param, node);
3561 
3562 			zend_hash_internal_pointer_reset(fault->details);
3563 			sparam = zend_hash_get_current_data_ptr(fault->details);
3564 
3565 			if (detail &&
3566 			    Z_TYPE_P(detail) == IS_OBJECT &&
3567 			    sparam->element &&
3568 			    zend_hash_num_elements(Z_OBJPROP_P(detail)) == 1 &&
3569 			    (tmp = zend_hash_str_find(Z_OBJPROP_P(detail), sparam->element->name, strlen(sparam->element->name))) != NULL) {
3570 				detail = tmp;
3571 			}
3572 
3573 			x = serialize_parameter(sparam, detail, 1, NULL, use, node);
3574 
3575 			if (function &&
3576 			    function->binding &&
3577 			    function->binding->bindingType == BINDING_SOAP &&
3578 			    function->bindingAttributes) {
3579 				sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3580 				if (fnb->style == SOAP_RPC && !sparam->element) {
3581 				  if (fault->bindingAttributes) {
3582 						sdlSoapBindingFunctionFaultPtr fb = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
3583 						if (fb->ns) {
3584 							xmlNsPtr ns = encode_add_ns(x, fb->ns);
3585 							xmlSetNs(x, ns);
3586 						}
3587 					}
3588 				} else {
3589 					if (sparam->element) {
3590 						ns = encode_add_ns(x, sparam->element->namens);
3591 						xmlNodeSetName(x, BAD_CAST(sparam->element->name));
3592 						xmlSetNs(x, ns);
3593 					}
3594 				}
3595 			}
3596 			if (use == SOAP_ENCODED && version == SOAP_1_2) {
3597 				xmlSetNsProp(x, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
3598 			}
3599 		} else {
3600 			tmp = Z_FAULT_DETAIL_P(ret);
3601 			if (Z_TYPE_P(tmp) > IS_NULL) {
3602 				serialize_zval(tmp, NULL, detail_name, use, param);
3603 			}
3604 		}
3605 	} else {
3606 
3607 		if (headers) {
3608 			soapHeader *h;
3609 
3610 			head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL);
3611 			h = headers;
3612 			while (h != NULL) {
3613 				if (Z_TYPE(h->retval) != IS_NULL) {
3614 					encodePtr hdr_enc = NULL;
3615 					int hdr_use = SOAP_LITERAL;
3616 					zval *hdr_ret = &h->retval;
3617 					char *hdr_ns   = h->hdr?h->hdr->ns:NULL;
3618 					char *hdr_name = Z_TYPE(h->function_name) == IS_STRING
3619 						? Z_STRVAL(h->function_name) : NULL;
3620 					bool is_header_object = Z_TYPE(h->retval) == IS_OBJECT &&
3621 					    instanceof_function(Z_OBJCE(h->retval), soap_header_class_entry);
3622 
3623 					if (is_header_object) {
3624 						zval *tmp;
3625 						sdlSoapBindingFunctionHeaderPtr hdr;
3626 						smart_str key = {0};
3627 
3628 						tmp = Z_HEADER_NAMESPACE_P(&h->retval);
3629 						if (Z_TYPE_P(tmp) == IS_STRING) {
3630 							smart_str_appendl(&key, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
3631 							smart_str_appendc(&key, ':');
3632 							hdr_ns = Z_STRVAL_P(tmp);
3633 						}
3634 						tmp = Z_HEADER_NAME_P(&h->retval);
3635 						if (Z_TYPE_P(tmp) == IS_STRING) {
3636 							smart_str_appendl(&key, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
3637 							hdr_name = Z_STRVAL_P(tmp);
3638 						}
3639 						smart_str_0(&key);
3640 						if (function && function->binding && function->binding->bindingType == BINDING_SOAP) {
3641 							sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3642 
3643 							if (fnb->output.headers &&
3644 							    (hdr = zend_hash_find_ptr(fnb->output.headers, key.s)) != NULL) {
3645 								hdr_enc = hdr->encode;
3646 								hdr_use = hdr->use;
3647 							}
3648 						}
3649 						smart_str_free(&key);
3650 						tmp = Z_HEADER_DATA_P(&h->retval);
3651 						if (Z_TYPE_P(tmp) > IS_NULL) {
3652 							hdr_ret = tmp;
3653 						} else {
3654 							hdr_ret = NULL;
3655 						}
3656 					}
3657 
3658 					if (h->function) {
3659 						xmlNodePtr xmlHdr = NULL;
3660 
3661 						if (serialize_response_call2(head, h->function, Z_STRVAL(h->function_name), uri, hdr_ret, version, 0, &xmlHdr) == SOAP_ENCODED) {
3662 							use = SOAP_ENCODED;
3663 						}
3664 						if (is_header_object) {
3665 							set_soap_header_attributes(xmlHdr, &h->retval, version);
3666 						}
3667 					} else {
3668 						xmlNodePtr xmlHdr = master_to_xml(hdr_enc, hdr_ret, hdr_use, head);
3669 						if (hdr_name) {
3670 							xmlNodeSetName(xmlHdr, BAD_CAST(hdr_name));
3671 						}
3672 						if (hdr_ns) {
3673 							xmlNsPtr nsptr = encode_add_ns(xmlHdr,hdr_ns);
3674 							xmlSetNs(xmlHdr, nsptr);
3675 						}
3676 						if (is_header_object) {
3677 							set_soap_header_attributes(xmlHdr, &h->retval, version);
3678 						}
3679 					}
3680 				}
3681 				h = h->next;
3682 			}
3683 
3684 			if (head->children == NULL) {
3685 				xmlUnlinkNode(head);
3686 				xmlFreeNode(head);
3687 			}
3688 		}
3689 
3690 		body = xmlNewChild(envelope, ns, BAD_CAST("Body"), NULL);
3691 
3692 		if (serialize_response_call2(body, function, function_name, uri, ret, version, 1, NULL) == SOAP_ENCODED) {
3693 			use = SOAP_ENCODED;
3694 		}
3695 
3696 	}
3697 
3698 	if (use == SOAP_ENCODED) {
3699 		xmlNewNs(envelope, BAD_CAST(XSD_NAMESPACE), BAD_CAST(XSD_NS_PREFIX));
3700 		if (version == SOAP_1_1) {
3701 			xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENC_NAMESPACE), BAD_CAST(SOAP_1_1_ENC_NS_PREFIX));
3702 			xmlSetNsProp(envelope, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_1_ENC_NAMESPACE));
3703 		} else if (version == SOAP_1_2) {
3704 			xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENC_NAMESPACE), BAD_CAST(SOAP_1_2_ENC_NS_PREFIX));
3705 		}
3706 	}
3707 
3708 	encode_finish();
3709 
3710 	} zend_catch {
3711 		/* Avoid persistent memory leak. */
3712 		xmlFreeDoc(doc);
3713 		zend_bailout();
3714 	} zend_end_try();
3715 
3716 	if (function && function->responseName == NULL &&
3717 	    body->children == NULL && head == NULL) {
3718 		xmlFreeDoc(doc);
3719 		return NULL;
3720 	}
3721 	return doc;
3722 }
3723 /* }}} */
3724 
3725 static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function, char *function_name, char *uri, zval *arguments, int arg_count, int version, HashTable *soap_headers) /* {{{ */
3726 {
3727 	xmlDoc *doc;
3728 	xmlNodePtr envelope = NULL, body, method = NULL, head = NULL;
3729 	xmlNsPtr ns = NULL;
3730 	zval *zstyle, *zuse;
3731 	int i, style, use;
3732 	HashTable *hdrs = NULL;
3733 
3734 	encode_reset_ns();
3735 
3736 	doc = xmlNewDoc(BAD_CAST("1.0"));
3737 	zend_try {
3738 
3739 	doc->encoding = xmlCharStrdup("UTF-8");
3740 	doc->charset = XML_CHAR_ENCODING_UTF8;
3741 	if (version == SOAP_1_1) {
3742 		envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
3743 		ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENV_NAMESPACE), BAD_CAST(SOAP_1_1_ENV_NS_PREFIX));
3744 		xmlSetNs(envelope, ns);
3745 	} else if (version == SOAP_1_2) {
3746 		envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
3747 		ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENV_NAMESPACE), BAD_CAST(SOAP_1_2_ENV_NS_PREFIX));
3748 		xmlSetNs(envelope, ns);
3749 	} else {
3750 		soap_error0(E_ERROR, "Unknown SOAP version");
3751 	}
3752 	xmlDocSetRootElement(doc, envelope);
3753 
3754 	if (soap_headers) {
3755 		head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL);
3756 	}
3757 
3758 	body = xmlNewChild(envelope, ns, BAD_CAST("Body"), NULL);
3759 
3760 	if (function && function->binding->bindingType == BINDING_SOAP) {
3761 		sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3762 
3763 		hdrs = fnb->input.headers;
3764 		style = fnb->style;
3765 		/*FIXME: how to pass method name if style is SOAP_DOCUMENT */
3766 		/*style = SOAP_RPC;*/
3767 		use = fnb->input.use;
3768 		if (style == SOAP_RPC) {
3769 			ns = encode_add_ns(body, fnb->input.ns);
3770 			if (function->requestName) {
3771 				method = xmlNewChild(body, ns, BAD_CAST(function->requestName), NULL);
3772 			} else {
3773 				method = xmlNewChild(body, ns, BAD_CAST(function->functionName), NULL);
3774 			}
3775 		}
3776 	} else {
3777 		zstyle = Z_CLIENT_STYLE_P(this_ptr);
3778 		if (Z_TYPE_P(zstyle) == IS_LONG) {
3779 			style = Z_LVAL_P(zstyle);
3780 		} else {
3781 			style = SOAP_RPC;
3782 		}
3783 		/*FIXME: how to pass method name if style is SOAP_DOCUMENT */
3784 		/*style = SOAP_RPC;*/
3785 		if (style == SOAP_RPC) {
3786 			ns = encode_add_ns(body, uri);
3787 			if (function_name) {
3788 				method = xmlNewChild(body, ns, BAD_CAST(function_name), NULL);
3789 			} else if (function && function->requestName) {
3790 				method = xmlNewChild(body, ns, BAD_CAST(function->requestName), NULL);
3791 			} else if (function && function->functionName) {
3792 				method = xmlNewChild(body, ns, BAD_CAST(function->functionName), NULL);
3793 			} else {
3794 				method = body;
3795 			}
3796 		} else {
3797 			method = body;
3798 		}
3799 
3800 		zuse = Z_CLIENT_USE_P(this_ptr);
3801 		if (Z_TYPE_P(zuse) == IS_LONG && Z_LVAL_P(zuse) == SOAP_LITERAL) {
3802 			use = SOAP_LITERAL;
3803 		} else {
3804 			use = SOAP_ENCODED;
3805 		}
3806 	}
3807 
3808 	for (i = 0;i < arg_count;i++) {
3809 		xmlNodePtr param;
3810 		sdlParamPtr parameter = get_param(function, NULL, i, FALSE);
3811 
3812 		if (style == SOAP_RPC) {
3813 			param = serialize_parameter(parameter, &arguments[i], i, NULL, use, method);
3814 		} else if (style == SOAP_DOCUMENT) {
3815 			param = serialize_parameter(parameter, &arguments[i], i, NULL, use, body);
3816 			if (function && function->binding->bindingType == BINDING_SOAP) {
3817 				if (parameter && parameter->element) {
3818 					ns = encode_add_ns(param, parameter->element->namens);
3819 					xmlNodeSetName(param, BAD_CAST(parameter->element->name));
3820 					xmlSetNs(param, ns);
3821 				}
3822 			}
3823 		}
3824 	}
3825 
3826 	if (function && function->requestParameters) {
3827 		int n = zend_hash_num_elements(function->requestParameters);
3828 
3829 		if (n > arg_count) {
3830 			for (i = arg_count; i < n; i++) {
3831 				xmlNodePtr param;
3832 				sdlParamPtr parameter = get_param(function, NULL, i, FALSE);
3833 
3834 				if (style == SOAP_RPC) {
3835 					param = serialize_parameter(parameter, NULL, i, NULL, use, method);
3836 				} else if (style == SOAP_DOCUMENT) {
3837 					param = serialize_parameter(parameter, NULL, i, NULL, use, body);
3838 					if (function && function->binding->bindingType == BINDING_SOAP) {
3839 						if (parameter && parameter->element) {
3840 							ns = encode_add_ns(param, parameter->element->namens);
3841 							xmlNodeSetName(param, BAD_CAST(parameter->element->name));
3842 							xmlSetNs(param, ns);
3843 						}
3844 					}
3845 				}
3846 			}
3847 		}
3848 	}
3849 
3850 	if (head) {
3851 		zval* header;
3852 
3853 		ZEND_HASH_FOREACH_VAL(soap_headers, header) {
3854 			if (Z_TYPE_P(header) != IS_OBJECT
3855 					|| !instanceof_function(Z_OBJCE_P(header), soap_header_class_entry)) {
3856 				continue;
3857 			}
3858 
3859 			zval *name = Z_HEADER_NAME_P(header);
3860 			zval *ns = Z_HEADER_NAMESPACE_P(header);
3861 			if (Z_TYPE_P(name) == IS_STRING && Z_TYPE_P(ns) == IS_STRING) {
3862 				xmlNodePtr h;
3863 				xmlNsPtr nsptr;
3864 				int hdr_use = SOAP_LITERAL;
3865 				encodePtr enc = NULL;
3866 
3867 				if (hdrs) {
3868 					smart_str key = {0};
3869 					sdlSoapBindingFunctionHeaderPtr hdr;
3870 
3871 					smart_str_appendl(&key, Z_STRVAL_P(ns), Z_STRLEN_P(ns));
3872 					smart_str_appendc(&key, ':');
3873 					smart_str_appendl(&key, Z_STRVAL_P(name), Z_STRLEN_P(name));
3874 					smart_str_0(&key);
3875 					if ((hdr = zend_hash_find_ptr(hdrs, key.s)) != NULL) {
3876 						hdr_use = hdr->use;
3877 						enc = hdr->encode;
3878 						if (hdr_use == SOAP_ENCODED) {
3879 							use = SOAP_ENCODED;
3880 						}
3881 					}
3882 					smart_str_free(&key);
3883 				}
3884 
3885 				zval *data = Z_HEADER_DATA_P(header);
3886 				if (Z_TYPE_P(data) > IS_NULL) {
3887 					h = master_to_xml(enc, data, hdr_use, head);
3888 					xmlNodeSetName(h, BAD_CAST(Z_STRVAL_P(name)));
3889 				} else {
3890 					h = xmlNewNode(NULL, BAD_CAST(Z_STRVAL_P(name)));
3891 					xmlAddChild(head, h);
3892 				}
3893 				nsptr = encode_add_ns(h, Z_STRVAL_P(ns));
3894 				xmlSetNs(h, nsptr);
3895 				set_soap_header_attributes(h, header, version);
3896 			}
3897 		} ZEND_HASH_FOREACH_END();
3898 	}
3899 
3900 	if (use == SOAP_ENCODED) {
3901 		xmlNewNs(envelope, BAD_CAST(XSD_NAMESPACE), BAD_CAST(XSD_NS_PREFIX));
3902 		if (version == SOAP_1_1) {
3903 			xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENC_NAMESPACE), BAD_CAST(SOAP_1_1_ENC_NS_PREFIX));
3904 			xmlSetNsProp(envelope, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_1_ENC_NAMESPACE));
3905 		} else if (version == SOAP_1_2) {
3906 			xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENC_NAMESPACE), BAD_CAST(SOAP_1_2_ENC_NS_PREFIX));
3907 			if (method) {
3908 				xmlSetNsProp(method, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
3909 			}
3910 		}
3911 	}
3912 
3913 	encode_finish();
3914 
3915 	} zend_catch {
3916 		/* Avoid persistent memory leak. */
3917 		xmlFreeDoc(doc);
3918 		zend_bailout();
3919 	} zend_end_try();
3920 
3921 	return doc;
3922 }
3923 /* }}} */
3924 
3925 static xmlNodePtr serialize_parameter(sdlParamPtr param, zval *param_val, int index, char *name, int style, xmlNodePtr parent) /* {{{ */
3926 {
3927 	char *paramName;
3928 	xmlNodePtr xmlParam;
3929 	char paramNameBuf[10];
3930 
3931 	if (param_val && Z_TYPE_P(param_val) == IS_OBJECT
3932 			&& Z_OBJCE_P(param_val) == soap_param_class_entry) {
3933 		zval *param_name = Z_PARAM_NAME_P(param_val);
3934 		zval *param_data = Z_PARAM_DATA_P(param_val);
3935 		if (Z_TYPE_P(param_name) == IS_STRING && Z_TYPE_P(param_data) != IS_UNDEF) {
3936 			param_val = param_data;
3937 			name = Z_STRVAL_P(param_name);
3938 		}
3939 	}
3940 
3941 	if (param != NULL && param->paramName != NULL) {
3942 		paramName = param->paramName;
3943 	} else {
3944 		if (name == NULL) {
3945 			paramName = paramNameBuf;
3946 			snprintf(paramName, sizeof(paramNameBuf), "param%d",index);
3947 		} else {
3948 			paramName = name;
3949 		}
3950 	}
3951 
3952 	xmlParam = serialize_zval(param_val, param, paramName, style, parent);
3953 
3954 	return xmlParam;
3955 }
3956 /* }}} */
3957 
3958 static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName, int style, xmlNodePtr parent) /* {{{ */
3959 {
3960 	xmlNodePtr xmlParam;
3961 	encodePtr enc;
3962 	zval defval;
3963 
3964 	ZVAL_UNDEF(&defval);
3965 	if (param != NULL) {
3966 		enc = param->encode;
3967 		if (val == NULL) {
3968 			if (param->element) {
3969 				if (param->element->fixed) {
3970 					ZVAL_STRING(&defval, param->element->fixed);
3971 					val = &defval;
3972 				} else if (param->element->def && !param->element->nillable) {
3973 					ZVAL_STRING(&defval, param->element->def);
3974 					val = &defval;
3975 				}
3976 			}
3977 		}
3978 	} else {
3979 		enc = NULL;
3980 	}
3981 	xmlParam = master_to_xml(enc, val, style, parent);
3982 	zval_ptr_dtor(&defval);
3983 	if (!strcmp((char*)xmlParam->name, "BOGUS")) {
3984 		xmlNodeSetName(xmlParam, BAD_CAST(paramName));
3985 	}
3986 	return xmlParam;
3987 }
3988 /* }}} */
3989 
3990 static sdlParamPtr get_param(sdlFunctionPtr function, char *param_name, int index, int response) /* {{{ */
3991 {
3992 	sdlParamPtr tmp;
3993 	HashTable   *ht;
3994 
3995 	if (function == NULL) {
3996 		return NULL;
3997 	}
3998 
3999 	if (response == FALSE) {
4000 		ht = function->requestParameters;
4001 	} else {
4002 		ht = function->responseParameters;
4003 	}
4004 
4005 	if (ht == NULL) {
4006 	  return NULL;
4007 	}
4008 
4009 	if (param_name != NULL) {
4010 		if ((tmp = zend_hash_str_find_ptr(ht, param_name, strlen(param_name))) != NULL) {
4011 			return tmp;
4012 		} else {
4013 			ZEND_HASH_FOREACH_PTR(ht, tmp) {
4014 				if (tmp->paramName && strcmp(param_name, tmp->paramName) == 0) {
4015 					return tmp;
4016 				}
4017 			} ZEND_HASH_FOREACH_END();
4018 		}
4019 	} else {
4020 		if ((tmp = zend_hash_index_find_ptr(ht, index)) != NULL) {
4021 			return tmp;
4022 		}
4023 	}
4024 	return NULL;
4025 }
4026 /* }}} */
4027 
4028 static sdlFunctionPtr get_function(sdlPtr sdl, const char *function_name) /* {{{ */
4029 {
4030 	sdlFunctionPtr tmp;
4031 
4032 	int len = strlen(function_name);
4033 	char *str = estrndup(function_name,len);
4034 	zend_str_tolower(str,len);
4035 	if (sdl != NULL) {
4036 		if ((tmp = zend_hash_str_find_ptr(&sdl->functions, str, len)) != NULL) {
4037 			efree(str);
4038 			return tmp;
4039 		} else if (sdl->requests != NULL && (tmp = zend_hash_str_find_ptr(sdl->requests, str, len)) != NULL) {
4040 			efree(str);
4041 			return tmp;
4042 		}
4043 	}
4044 	efree(str);
4045 	return NULL;
4046 }
4047 /* }}} */
4048 
4049 static sdlFunctionPtr get_doc_function(sdlPtr sdl, xmlNodePtr params) /* {{{ */
4050 {
4051 	if (sdl) {
4052 		sdlFunctionPtr tmp;
4053 		sdlParamPtr    param;
4054 
4055 		ZEND_HASH_MAP_FOREACH_PTR(&sdl->functions, tmp) {
4056 			if (tmp->binding && tmp->binding->bindingType == BINDING_SOAP) {
4057 				sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)tmp->bindingAttributes;
4058 				if (fnb->style == SOAP_DOCUMENT) {
4059 					if (params == NULL) {
4060 						if (tmp->requestParameters == NULL ||
4061 						    zend_hash_num_elements(tmp->requestParameters) == 0) {
4062 						  return tmp;
4063 						}
4064 					} else if (tmp->requestParameters != NULL &&
4065 					           zend_hash_num_elements(tmp->requestParameters) > 0) {
4066 						int ok = 1;
4067 						xmlNodePtr node = params;
4068 
4069 						ZEND_HASH_FOREACH_PTR(tmp->requestParameters, param) {
4070 							if (param->element) {
4071 								if (strcmp(param->element->name, (char*)node->name) != 0) {
4072 									ok = 0;
4073 									break;
4074 								}
4075 								if (param->element->namens != NULL && node->ns != NULL) {
4076 									if (strcmp(param->element->namens, (char*)node->ns->href) != 0) {
4077 										ok = 0;
4078 										break;
4079 									}
4080 								} else if ((void*)param->element->namens != (void*)node->ns) {
4081 									ok = 0;
4082 									break;
4083 								}
4084 							} else if (strcmp(param->paramName, (char*)node->name) != 0) {
4085 								ok = 0;
4086 								break;
4087 							}
4088 							node = node->next;
4089 						} ZEND_HASH_FOREACH_END();
4090 						if (ok /*&& node == NULL*/) {
4091 							return tmp;
4092 						}
4093 					}
4094 				}
4095 			}
4096 		} ZEND_HASH_FOREACH_END();
4097 	}
4098 	return NULL;
4099 }
4100 /* }}} */
4101 
4102 static void function_to_string(sdlFunctionPtr function, smart_str *buf) /* {{{ */
4103 {
4104 	int i = 0;
4105 	sdlParamPtr param;
4106 
4107 	if (function->responseParameters &&
4108 	    zend_hash_num_elements(function->responseParameters) > 0) {
4109 		if (zend_hash_num_elements(function->responseParameters) == 1) {
4110 			zend_hash_internal_pointer_reset(function->responseParameters);
4111 			param = zend_hash_get_current_data_ptr(function->responseParameters);
4112 			if (param->encode && param->encode->details.type_str) {
4113 				smart_str_appendl(buf, param->encode->details.type_str, strlen(param->encode->details.type_str));
4114 				smart_str_appendc(buf, ' ');
4115 			} else {
4116 				smart_str_appendl(buf, "UNKNOWN ", 8);
4117 			}
4118 		} else {
4119 			i = 0;
4120 			smart_str_appendl(buf, "list(", 5);
4121 			ZEND_HASH_FOREACH_PTR(function->responseParameters, param) {
4122 				if (i > 0) {
4123 					smart_str_appendl(buf, ", ", 2);
4124 				}
4125 				if (param->encode && param->encode->details.type_str) {
4126 					smart_str_appendl(buf, param->encode->details.type_str, strlen(param->encode->details.type_str));
4127 				} else {
4128 					smart_str_appendl(buf, "UNKNOWN", 7);
4129 				}
4130 				smart_str_appendl(buf, " $", 2);
4131 				smart_str_appendl(buf, param->paramName, strlen(param->paramName));
4132 				i++;
4133 			} ZEND_HASH_FOREACH_END();
4134 			smart_str_appendl(buf, ") ", 2);
4135 		}
4136 	} else {
4137 		smart_str_appendl(buf, "void ", 5);
4138 	}
4139 
4140 	smart_str_appendl(buf, function->functionName, strlen(function->functionName));
4141 
4142 	smart_str_appendc(buf, '(');
4143 	if (function->requestParameters) {
4144 		i = 0;
4145 		ZEND_HASH_FOREACH_PTR(function->requestParameters, param) {
4146 			if (i > 0) {
4147 				smart_str_appendl(buf, ", ", 2);
4148 			}
4149 			if (param->encode && param->encode->details.type_str) {
4150 				smart_str_appendl(buf, param->encode->details.type_str, strlen(param->encode->details.type_str));
4151 			} else {
4152 				smart_str_appendl(buf, "UNKNOWN", 7);
4153 			}
4154 			smart_str_appendl(buf, " $", 2);
4155 			smart_str_appendl(buf, param->paramName, strlen(param->paramName));
4156 			i++;
4157 		} ZEND_HASH_FOREACH_END();
4158 	}
4159 	smart_str_appendc(buf, ')');
4160 	smart_str_0(buf);
4161 }
4162 /* }}} */
4163 
4164 static void model_to_string(sdlContentModelPtr model, smart_str *buf, int level) /* {{{ */
4165 {
4166 	int i;
4167 
4168 	switch (model->kind) {
4169 		case XSD_CONTENT_ELEMENT:
4170 			type_to_string(model->u.element, buf, level);
4171 			smart_str_appendl(buf, ";\n", 2);
4172 			break;
4173 		case XSD_CONTENT_ANY:
4174 			for (i = 0;i < level;i++) {
4175 				smart_str_appendc(buf, ' ');
4176 			}
4177 			smart_str_appendl(buf, "<anyXML> any;\n", sizeof("<anyXML> any;\n")-1);
4178 			break;
4179 		case XSD_CONTENT_SEQUENCE:
4180 		case XSD_CONTENT_ALL:
4181 		case XSD_CONTENT_CHOICE: {
4182 			sdlContentModelPtr tmp;
4183 
4184 			ZEND_HASH_FOREACH_PTR(model->u.content, tmp) {
4185 				model_to_string(tmp, buf, level);
4186 			} ZEND_HASH_FOREACH_END();
4187 			break;
4188 		}
4189 		case XSD_CONTENT_GROUP:
4190 			model_to_string(model->u.group->model, buf, level);
4191 		default:
4192 		  break;
4193 	}
4194 }
4195 /* }}} */
4196 
4197 static void type_to_string(sdlTypePtr type, smart_str *buf, int level) /* {{{ */
4198 {
4199 	int i;
4200 	smart_str spaces = {0};
4201 
4202 	for (i = 0;i < level;i++) {
4203 		smart_str_appendc(&spaces, ' ');
4204 	}
4205 	if (spaces.s) {
4206 		smart_str_appendl(buf, ZSTR_VAL(spaces.s), ZSTR_LEN(spaces.s));
4207 	}
4208 	switch (type->kind) {
4209 		case XSD_TYPEKIND_SIMPLE:
4210 			if (type->encode) {
4211 				smart_str_appendl(buf, type->encode->details.type_str, strlen(type->encode->details.type_str));
4212 				smart_str_appendc(buf, ' ');
4213 			} else {
4214 				smart_str_appendl(buf, "anyType ", sizeof("anyType ")-1);
4215 			}
4216 			smart_str_appendl(buf, type->name, strlen(type->name));
4217 			break;
4218 		case XSD_TYPEKIND_LIST:
4219 			smart_str_appendl(buf, "list ", 5);
4220 			smart_str_appendl(buf, type->name, strlen(type->name));
4221 			if (type->elements) {
4222 				sdlTypePtr item_type;
4223 
4224 				smart_str_appendl(buf, " {", 2);
4225 				ZEND_HASH_FOREACH_PTR(type->elements, item_type) {
4226 					smart_str_appendl(buf, item_type->name, strlen(item_type->name));
4227 				} ZEND_HASH_FOREACH_END();
4228 				smart_str_appendc(buf, '}');
4229 			}
4230 			break;
4231 		case XSD_TYPEKIND_UNION:
4232 			smart_str_appendl(buf, "union ", 6);
4233 			smart_str_appendl(buf, type->name, strlen(type->name));
4234 			if (type->elements) {
4235 				sdlTypePtr item_type;
4236 				int first = 0;
4237 
4238 				smart_str_appendl(buf, " {", 2);
4239 				ZEND_HASH_FOREACH_PTR(type->elements, item_type) {
4240 					if (!first) {
4241 						smart_str_appendc(buf, ',');
4242 						first = 0;
4243 					}
4244 					smart_str_appendl(buf, item_type->name, strlen(item_type->name));
4245 				} ZEND_HASH_FOREACH_END();
4246 				smart_str_appendc(buf, '}');
4247 			}
4248 			break;
4249 		case XSD_TYPEKIND_COMPLEX:
4250 		case XSD_TYPEKIND_RESTRICTION:
4251 		case XSD_TYPEKIND_EXTENSION:
4252 			if (type->encode &&
4253 			    (type->encode->details.type == IS_ARRAY ||
4254 			     type->encode->details.type == SOAP_ENC_ARRAY)) {
4255 			  sdlAttributePtr attr;
4256 			  sdlExtraAttributePtr ext;
4257 
4258 				if (type->attributes &&
4259 				    (attr = zend_hash_str_find_ptr(type->attributes, SOAP_1_1_ENC_NAMESPACE":arrayType",
4260 				      sizeof(SOAP_1_1_ENC_NAMESPACE":arrayType")-1)) != NULL &&
4261 					attr->extraAttributes &&
4262 				    (ext = zend_hash_str_find_ptr(attr->extraAttributes, WSDL_NAMESPACE":arrayType", sizeof(WSDL_NAMESPACE":arrayType")-1)) != NULL) {
4263 					char *end = strchr(ext->val, '[');
4264 					int len;
4265 					if (end == NULL) {
4266 						len = strlen(ext->val);
4267 					} else {
4268 						len = end - ext->val;
4269 					}
4270 					if (len == 0) {
4271 						smart_str_appendl(buf, "anyType", sizeof("anyType")-1);
4272 					} else {
4273 						smart_str_appendl(buf, ext->val, len);
4274 					}
4275 					smart_str_appendc(buf, ' ');
4276 					smart_str_appendl(buf, type->name, strlen(type->name));
4277 					if (end != NULL) {
4278 						smart_str_appends(buf, end);
4279 					}
4280 				} else {
4281 					sdlTypePtr elementType;
4282 					if (type->attributes &&
4283 					    (attr = zend_hash_str_find_ptr(type->attributes, SOAP_1_2_ENC_NAMESPACE":itemType",
4284 					      sizeof(SOAP_1_2_ENC_NAMESPACE":itemType")-1)) != NULL &&
4285 						attr->extraAttributes &&
4286 				    (ext = zend_hash_str_find_ptr(attr->extraAttributes, WSDL_NAMESPACE":itemType", sizeof(WSDL_NAMESPACE":arrayType")-1)) != NULL) {
4287 						smart_str_appends(buf, ext->val);
4288 						smart_str_appendc(buf, ' ');
4289 					} else if (type->elements &&
4290 					           zend_hash_num_elements(type->elements) == 1 &&
4291 					           (zend_hash_internal_pointer_reset(type->elements),
4292 					            (elementType = zend_hash_get_current_data_ptr(type->elements)) != NULL) &&
4293 					           elementType->encode && elementType->encode->details.type_str) {
4294 						smart_str_appends(buf, elementType->encode->details.type_str);
4295 						smart_str_appendc(buf, ' ');
4296 					} else {
4297 						smart_str_appendl(buf, "anyType ", 8);
4298 					}
4299 					smart_str_appendl(buf, type->name, strlen(type->name));
4300 					if (type->attributes &&
4301 					    (attr = zend_hash_str_find_ptr(type->attributes, SOAP_1_2_ENC_NAMESPACE":arraySize",
4302 					      sizeof(SOAP_1_2_ENC_NAMESPACE":arraySize")-1)) != NULL &&
4303 						attr->extraAttributes &&
4304 					    (ext = zend_hash_str_find_ptr(attr->extraAttributes, WSDL_NAMESPACE":itemType", sizeof(WSDL_NAMESPACE":arraySize")-1)) != NULL) {
4305 						smart_str_appendc(buf, '[');
4306 						smart_str_appends(buf, ext->val);
4307 						smart_str_appendc(buf, ']');
4308 					} else {
4309 						smart_str_appendl(buf, "[]", 2);
4310 					}
4311 				}
4312 			} else {
4313 				smart_str_appendl(buf, "struct ", 7);
4314 				smart_str_appendl(buf, type->name, strlen(type->name));
4315 				smart_str_appendc(buf, ' ');
4316 				smart_str_appendl(buf, "{\n", 2);
4317 				if ((type->kind == XSD_TYPEKIND_RESTRICTION ||
4318 				     type->kind == XSD_TYPEKIND_EXTENSION) && type->encode) {
4319 					encodePtr enc = type->encode;
4320 					while (enc && enc->details.sdl_type &&
4321 					       enc != enc->details.sdl_type->encode &&
4322 					       enc->details.sdl_type->kind != XSD_TYPEKIND_SIMPLE &&
4323 					       enc->details.sdl_type->kind != XSD_TYPEKIND_LIST &&
4324 					       enc->details.sdl_type->kind != XSD_TYPEKIND_UNION) {
4325 						enc = enc->details.sdl_type->encode;
4326 					}
4327 					if (enc) {
4328 						if (spaces.s) {
4329 							smart_str_appendl(buf, ZSTR_VAL(spaces.s), ZSTR_LEN(spaces.s));
4330 						}
4331 						smart_str_appendc(buf, ' ');
4332 						smart_str_appendl(buf, type->encode->details.type_str, strlen(type->encode->details.type_str));
4333 						smart_str_appendl(buf, " _;\n", 4);
4334 					}
4335 				}
4336 				if (type->model) {
4337 					model_to_string(type->model, buf, level+1);
4338 				}
4339 				if (type->attributes) {
4340 					sdlAttributePtr attr;
4341 
4342 					ZEND_HASH_FOREACH_PTR(type->attributes, attr) {
4343 						if (spaces.s) {
4344 							smart_str_appendl(buf, ZSTR_VAL(spaces.s), ZSTR_LEN(spaces.s));
4345 						}
4346 						smart_str_appendc(buf, ' ');
4347 						if (attr->encode && attr->encode->details.type_str) {
4348 							smart_str_appends(buf, attr->encode->details.type_str);
4349 							smart_str_appendc(buf, ' ');
4350 						} else {
4351 							smart_str_appendl(buf, "UNKNOWN ", 8);
4352 						}
4353 						smart_str_appends(buf, attr->name);
4354 						smart_str_appendl(buf, ";\n", 2);
4355 					} ZEND_HASH_FOREACH_END();
4356 				}
4357 				if (spaces.s) {
4358 					smart_str_appendl(buf, ZSTR_VAL(spaces.s), ZSTR_LEN(spaces.s));
4359 				}
4360 				smart_str_appendc(buf, '}');
4361 			}
4362 			break;
4363 		default:
4364 			break;
4365 	}
4366 	smart_str_free(&spaces);
4367 	smart_str_0(buf);
4368 }
4369 /* }}} */
4370 
4371 static void delete_url(void *handle) /* {{{ */
4372 {
4373 	php_url_free((php_url*)handle);
4374 }
4375 /* }}} */
4376 
4377 static void delete_argv(struct _soap_class *class)
4378 {
4379 	if (class->argc) {
4380 		for (int i = 0; i < class->argc; i++) {
4381 			zval_ptr_dtor(&class->argv[i]);
4382 		}
4383 		efree(class->argv);
4384 	}
4385 }
4386 
4387 static void delete_service(void *data) /* {{{ */
4388 {
4389 	soapServicePtr service = (soapServicePtr)data;
4390 
4391 	if (service->soap_functions.ft) {
4392 		zend_hash_destroy(service->soap_functions.ft);
4393 		efree(service->soap_functions.ft);
4394 	}
4395 
4396 	if (service->typemap) {
4397 		zend_hash_destroy(service->typemap);
4398 		efree(service->typemap);
4399 	}
4400 
4401 	delete_argv(&service->soap_class);
4402 
4403 	if (service->actor) {
4404 		efree(service->actor);
4405 	}
4406 	if (service->uri) {
4407 		efree(service->uri);
4408 	}
4409 	if (service->sdl) {
4410 		delete_sdl(service->sdl);
4411 	}
4412 	if (service->encoding) {
4413 		xmlCharEncCloseFunc(service->encoding);
4414 	}
4415 	if (service->class_map) {
4416 		zend_hash_destroy(service->class_map);
4417 		FREE_HASHTABLE(service->class_map);
4418 	}
4419 	zval_ptr_dtor(&service->soap_object);
4420 	efree(service);
4421 }
4422 /* }}} */
4423 
4424 static void delete_hashtable(void *data) /* {{{ */
4425 {
4426 	HashTable *ht = (HashTable*)data;
4427 	zend_hash_destroy(ht);
4428 	efree(ht);
4429 }
4430 /* }}} */
4431