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