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