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