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