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