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