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