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