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