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