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