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