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