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