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