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