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