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