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