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