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    /* New SOAP SSL Method Constants */
762    REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_TLS",    SOAP_SSL_METHOD_TLS,    CONST_CS | CONST_PERSISTENT);
763    REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv2",  SOAP_SSL_METHOD_SSLv2,  CONST_CS | CONST_PERSISTENT);
764    REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv3",  SOAP_SSL_METHOD_SSLv3,  CONST_CS | CONST_PERSISTENT);
765    REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv23", SOAP_SSL_METHOD_SSLv23, CONST_CS | CONST_PERSISTENT);
766
767    old_error_handler = zend_error_cb;
768    zend_error_cb = soap_error_handler;
769
770    return SUCCESS;
771}
772
773PHP_MINFO_FUNCTION(soap)
774{
775    php_info_print_table_start();
776    php_info_print_table_row(2, "Soap Client", "enabled");
777    php_info_print_table_row(2, "Soap Server", "enabled");
778    php_info_print_table_end();
779    DISPLAY_INI_ENTRIES();
780}
781
782
783/* {{{ proto object SoapParam::SoapParam ( mixed data, string name)
784   SoapParam constructor */
785PHP_METHOD(SoapParam, SoapParam)
786{
787    zval *data;
788    char *name;
789    int name_length;
790
791    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs", &data, &name, &name_length) == FAILURE) {
792        return;
793    }
794    if (name_length == 0) {
795        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid parameter name");
796        return;
797    }
798
799    add_property_stringl(this_ptr, "param_name", name, name_length, 1);
800    add_property_zval(this_ptr, "param_data", data);
801}
802/* }}} */
803
804
805/* {{{ proto object SoapHeader::SoapHeader ( string namespace, string name [, mixed data [, bool mustUnderstand [, mixed actor]]])
806   SoapHeader constructor */
807PHP_METHOD(SoapHeader, SoapHeader)
808{
809    zval *data = NULL, *actor = NULL;
810    char *name, *ns;
811    int name_len, ns_len;
812    zend_bool must_understand = 0;
813
814    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|zbz", &ns, &ns_len, &name, &name_len, &data, &must_understand, &actor) == FAILURE) {
815        return;
816    }
817    if (ns_len == 0) {
818        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid namespace");
819        return;
820    }
821    if (name_len == 0) {
822        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid header name");
823        return;
824    }
825
826    add_property_stringl(this_ptr, "namespace", ns, ns_len, 1);
827    add_property_stringl(this_ptr, "name", name, name_len, 1);
828    if (data) {
829        add_property_zval(this_ptr, "data", data);
830    }
831    add_property_bool(this_ptr, "mustUnderstand", must_understand);
832    if (actor == NULL) {
833    } else if (Z_TYPE_P(actor) == IS_LONG &&
834      (Z_LVAL_P(actor) == SOAP_ACTOR_NEXT ||
835       Z_LVAL_P(actor) == SOAP_ACTOR_NONE ||
836       Z_LVAL_P(actor) == SOAP_ACTOR_UNLIMATERECEIVER)) {
837        add_property_long(this_ptr, "actor", Z_LVAL_P(actor));
838    } else if (Z_TYPE_P(actor) == IS_STRING && Z_STRLEN_P(actor) > 0) {
839        add_property_stringl(this_ptr, "actor", Z_STRVAL_P(actor), Z_STRLEN_P(actor), 1);
840    } else {
841        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid actor");
842    }
843}
844
845/* {{{ proto object SoapFault::SoapFault ( string faultcode, string faultstring [, string faultactor [, mixed detail [, string faultname [, mixed headerfault]]]])
846   SoapFault constructor */
847PHP_METHOD(SoapFault, SoapFault)
848{
849    char *fault_string = NULL, *fault_code = NULL, *fault_actor = NULL, *name = NULL, *fault_code_ns = NULL;
850    int fault_string_len, fault_actor_len = 0, name_len = 0, fault_code_len = 0;
851    zval *code = NULL, *details = NULL, *headerfault = NULL;
852
853    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs|s!z!s!z",
854        &code,
855        &fault_string, &fault_string_len,
856        &fault_actor, &fault_actor_len,
857        &details, &name, &name_len, &headerfault) == FAILURE) {
858        return;
859    }
860
861    if (Z_TYPE_P(code) == IS_NULL) {
862    } else if (Z_TYPE_P(code) == IS_STRING) {
863        fault_code = Z_STRVAL_P(code);
864        fault_code_len = Z_STRLEN_P(code);
865    } else if (Z_TYPE_P(code) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(code)) == 2) {
866        zval **t_ns, **t_code;
867
868        zend_hash_internal_pointer_reset(Z_ARRVAL_P(code));
869        zend_hash_get_current_data(Z_ARRVAL_P(code), (void**)&t_ns);
870        zend_hash_move_forward(Z_ARRVAL_P(code));
871        zend_hash_get_current_data(Z_ARRVAL_P(code), (void**)&t_code);
872        if (Z_TYPE_PP(t_ns) == IS_STRING && Z_TYPE_PP(t_code) == IS_STRING) {
873          fault_code_ns = Z_STRVAL_PP(t_ns);
874          fault_code = Z_STRVAL_PP(t_code);
875          fault_code_len = Z_STRLEN_PP(t_code);
876        } else {
877            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid fault code");
878            return;
879        }
880    } else  {
881        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid fault code");
882        return;
883    }
884    if (fault_code != NULL && fault_code_len == 0) {
885        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid fault code");
886        return;
887    }
888    if (name != NULL && name_len == 0) {
889        name = NULL;
890    }
891
892    set_soap_fault(this_ptr, fault_code_ns, fault_code, fault_string, fault_actor, details, name TSRMLS_CC);
893    if (headerfault != NULL) {
894        add_property_zval(this_ptr, "headerfault", headerfault);
895    }
896}
897/* }}} */
898
899
900/* {{{ proto object SoapFault::SoapFault ( string faultcode, string faultstring [, string faultactor [, mixed detail [, string faultname [, mixed headerfault]]]])
901   SoapFault constructor */
902PHP_METHOD(SoapFault, __toString)
903{
904    zval *faultcode, *faultstring, *file, *line, *trace;
905    char *str;
906    int len;
907    zend_fcall_info fci;
908    zval fname;
909
910    if (zend_parse_parameters_none() == FAILURE) {
911        return;
912    }
913
914    faultcode   = zend_read_property(soap_fault_class_entry, this_ptr, "faultcode", sizeof("faultcode")-1, 1 TSRMLS_CC);
915    faultstring = zend_read_property(soap_fault_class_entry, this_ptr, "faultstring", sizeof("faultstring")-1, 1 TSRMLS_CC);
916    file = zend_read_property(soap_fault_class_entry, this_ptr, "file", sizeof("file")-1, 1 TSRMLS_CC);
917    line = zend_read_property(soap_fault_class_entry, this_ptr, "line", sizeof("line")-1, 1 TSRMLS_CC);
918
919    ZVAL_STRINGL(&fname, "gettraceasstring", sizeof("gettraceasstring")-1, 0);
920
921    fci.size = sizeof(fci);
922    fci.function_table = &Z_OBJCE_P(getThis())->function_table;
923    fci.function_name = &fname;
924    fci.symbol_table = NULL;
925    fci.object_ptr = getThis();
926    fci.retval_ptr_ptr = &trace;
927    fci.param_count = 0;
928    fci.params = NULL;
929    fci.no_separation = 1;
930
931    zend_call_function(&fci, NULL TSRMLS_CC);
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).request_body && 0 == php_stream_rewind(SG(request_info).request_body)) {
1569            zval **server_vars, **encoding;
1570            php_stream_filter *zf = NULL;
1571
1572            zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC);
1573            if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server_vars) == SUCCESS &&
1574                Z_TYPE_PP(server_vars) == IS_ARRAY &&
1575                zend_hash_find(Z_ARRVAL_PP(server_vars), "HTTP_CONTENT_ENCODING", sizeof("HTTP_CONTENT_ENCODING"), (void **) &encoding)==SUCCESS &&
1576                Z_TYPE_PP(encoding) == IS_STRING) {
1577
1578                if (strcmp(Z_STRVAL_PP(encoding),"gzip") == 0
1579                ||  strcmp(Z_STRVAL_PP(encoding),"x-gzip") == 0
1580                ||  strcmp(Z_STRVAL_PP(encoding),"deflate") == 0
1581                ) {
1582                    zval filter_params;
1583
1584                    INIT_PZVAL(&filter_params);
1585                    array_init_size(&filter_params, 1);
1586                    add_assoc_long_ex(&filter_params, ZEND_STRS("window"), 0x2f); /* ANY WBITS */
1587
1588                    zf = php_stream_filter_create("zlib.inflate", &filter_params, 0 TSRMLS_CC);
1589                    zval_dtor(&filter_params);
1590
1591                    if (zf) {
1592                        php_stream_filter_append(&SG(request_info).request_body->readfilters, zf);
1593                    } else {
1594                        php_error_docref(NULL TSRMLS_CC, E_WARNING,"Can't uncompress compressed request");
1595                        return;
1596                    }
1597                } else {
1598                    php_error_docref(NULL TSRMLS_CC, E_WARNING,"Request is compressed with unknown compression '%s'",Z_STRVAL_PP(encoding));
1599                    return;
1600                }
1601            }
1602
1603            doc_request = soap_xmlParseFile("php://input" TSRMLS_CC);
1604
1605            if (zf) {
1606                php_stream_filter_remove(zf, 1 TSRMLS_CC);
1607            }
1608        } else {
1609            zval_ptr_dtor(&retval);
1610            return;
1611        }
1612    } else {
1613        doc_request = soap_xmlParseMemory(arg,arg_len);
1614    }
1615
1616    if (doc_request == NULL) {
1617        soap_server_fault("Client", "Bad Request", NULL, NULL, NULL TSRMLS_CC);
1618    }
1619    if (xmlGetIntSubset(doc_request) != NULL) {
1620        xmlNodePtr env = get_node(doc_request->children,"Envelope");
1621        if (env && env->ns) {
1622            if (strcmp((char*)env->ns->href, SOAP_1_1_ENV_NAMESPACE) == 0) {
1623                SOAP_GLOBAL(soap_version) = SOAP_1_1;
1624            } else if (strcmp((char*)env->ns->href,SOAP_1_2_ENV_NAMESPACE) == 0) {
1625                SOAP_GLOBAL(soap_version) = SOAP_1_2;
1626            }
1627        }
1628        xmlFreeDoc(doc_request);
1629        soap_server_fault("Server", "DTD are not supported by SOAP", NULL, NULL, NULL TSRMLS_CC);
1630    }
1631
1632    old_sdl = SOAP_GLOBAL(sdl);
1633    SOAP_GLOBAL(sdl) = service->sdl;
1634    old_encoding = SOAP_GLOBAL(encoding);
1635    SOAP_GLOBAL(encoding) = service->encoding;
1636    old_class_map = SOAP_GLOBAL(class_map);
1637    SOAP_GLOBAL(class_map) = service->class_map;
1638    old_typemap = SOAP_GLOBAL(typemap);
1639    SOAP_GLOBAL(typemap) = service->typemap;
1640    old_features = SOAP_GLOBAL(features);
1641    SOAP_GLOBAL(features) = service->features;
1642    old_soap_version = SOAP_GLOBAL(soap_version);
1643    function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, &params, &soap_version, &soap_headers TSRMLS_CC);
1644    xmlFreeDoc(doc_request);
1645
1646    if (EG(exception)) {
1647        php_output_discard(TSRMLS_C);
1648        if (Z_TYPE_P(EG(exception)) == IS_OBJECT &&
1649            instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {
1650            soap_server_fault_ex(function, EG(exception), NULL TSRMLS_CC);
1651        }
1652        goto fail;
1653    }
1654
1655    service->soap_headers_ptr = &soap_headers;
1656
1657    soap_obj = NULL;
1658    if (service->type == SOAP_OBJECT) {
1659        soap_obj = service->soap_object;
1660        function_table = &((Z_OBJCE_P(soap_obj))->function_table);
1661    } else if (service->type == SOAP_CLASS) {
1662#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
1663        /* If persistent then set soap_obj from from the previous created session (if available) */
1664        if (service->soap_class.persistance == SOAP_PERSISTENCE_SESSION) {
1665            zval **tmp_soap;
1666
1667            if (PS(session_status) != php_session_active &&
1668                PS(session_status) != php_session_disabled) {
1669                php_session_start(TSRMLS_C);
1670            }
1671
1672            /* Find the soap object and assign */
1673            if (zend_hash_find(Z_ARRVAL_P(PS(http_session_vars)), "_bogus_session_name", sizeof("_bogus_session_name"), (void **) &tmp_soap) == SUCCESS &&
1674                Z_TYPE_PP(tmp_soap) == IS_OBJECT &&
1675                Z_OBJCE_PP(tmp_soap) == service->soap_class.ce) {
1676                soap_obj = *tmp_soap;
1677            }
1678        }
1679#endif
1680        /* If new session or something weird happned */
1681        if (soap_obj == NULL) {
1682            zval *tmp_soap;
1683
1684            MAKE_STD_ZVAL(tmp_soap);
1685            object_init_ex(tmp_soap, service->soap_class.ce);
1686
1687            /* Call constructor */
1688            if (zend_hash_exists(&Z_OBJCE_P(tmp_soap)->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME))) {
1689                zval c_ret, constructor;
1690
1691                INIT_ZVAL(c_ret);
1692                INIT_ZVAL(constructor);
1693
1694                ZVAL_STRING(&constructor, ZEND_CONSTRUCTOR_FUNC_NAME, 1);
1695                if (call_user_function(NULL, &tmp_soap, &constructor, &c_ret, service->soap_class.argc, service->soap_class.argv TSRMLS_CC) == FAILURE) {
1696                    php_error_docref(NULL TSRMLS_CC, E_ERROR, "Error calling constructor");
1697                }
1698                if (EG(exception)) {
1699                    php_output_discard(TSRMLS_C);
1700                    if (Z_TYPE_P(EG(exception)) == IS_OBJECT &&
1701                        instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {
1702                        soap_server_fault_ex(function, EG(exception), NULL TSRMLS_CC);
1703                    }
1704                    zval_dtor(&constructor);
1705                    zval_dtor(&c_ret);
1706                    zval_ptr_dtor(&tmp_soap);
1707                    goto fail;
1708                }
1709                zval_dtor(&constructor);
1710                zval_dtor(&c_ret);
1711            } else {
1712                int class_name_len = strlen(service->soap_class.ce->name);
1713                char *class_name = emalloc(class_name_len+1);
1714
1715                memcpy(class_name, service->soap_class.ce->name,class_name_len+1);
1716                if (zend_hash_exists(&Z_OBJCE_P(tmp_soap)->function_table, php_strtolower(class_name, class_name_len), class_name_len+1)) {
1717                    zval c_ret, constructor;
1718
1719                    INIT_ZVAL(c_ret);
1720                    INIT_ZVAL(constructor);
1721
1722                    ZVAL_STRING(&constructor, service->soap_class.ce->name, 1);
1723                    if (call_user_function(NULL, &tmp_soap, &constructor, &c_ret, service->soap_class.argc, service->soap_class.argv TSRMLS_CC) == FAILURE) {
1724                        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Error calling constructor");
1725                    }
1726
1727                    if (EG(exception)) {
1728                        php_output_discard(TSRMLS_C);
1729                        if (Z_TYPE_P(EG(exception)) == IS_OBJECT &&
1730                            instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {
1731                            soap_server_fault_ex(function, EG(exception), NULL TSRMLS_CC);
1732                        }
1733                        zval_dtor(&constructor);
1734                        zval_dtor(&c_ret);
1735                        efree(class_name);
1736                        zval_ptr_dtor(&tmp_soap);
1737                        goto fail;
1738                    }
1739
1740                    zval_dtor(&constructor);
1741                    zval_dtor(&c_ret);
1742                }
1743                efree(class_name);
1744            }
1745#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
1746            /* If session then update session hash with new object */
1747            if (service->soap_class.persistance == SOAP_PERSISTENCE_SESSION) {
1748                zval **tmp_soap_pp;
1749                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) {
1750                    soap_obj = *tmp_soap_pp;
1751                }
1752            } else {
1753                soap_obj = tmp_soap;
1754            }
1755#else
1756            soap_obj = tmp_soap;
1757#endif
1758
1759        }
1760        function_table = &((Z_OBJCE_P(soap_obj))->function_table);
1761    } else {
1762        if (service->soap_functions.functions_all == TRUE) {
1763            function_table = EG(function_table);
1764        } else {
1765            function_table = service->soap_functions.ft;
1766        }
1767    }
1768
1769    doc_return = NULL;
1770
1771    /* Process soap headers */
1772    if (soap_headers != NULL) {
1773        soapHeader *header = soap_headers;
1774        while (header != NULL) {
1775            soapHeader *h = header;
1776
1777            header = header->next;
1778#if 0
1779            if (service->sdl && !h->function && !h->hdr) {
1780                if (h->mustUnderstand) {
1781                    soap_server_fault("MustUnderstand","Header not understood", NULL, NULL, NULL TSRMLS_CC);
1782                } else {
1783                    continue;
1784                }
1785            }
1786#endif
1787            fn_name = estrndup(Z_STRVAL(h->function_name),Z_STRLEN(h->function_name));
1788            if (zend_hash_exists(function_table, php_strtolower(fn_name, Z_STRLEN(h->function_name)), Z_STRLEN(h->function_name) + 1) ||
1789                ((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) &&
1790                 zend_hash_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)))) {
1791                if (service->type == SOAP_CLASS || service->type == SOAP_OBJECT) {
1792                    call_status = call_user_function(NULL, &soap_obj, &h->function_name, &h->retval, h->num_params, h->parameters TSRMLS_CC);
1793                } else {
1794                    call_status = call_user_function(EG(function_table), NULL, &h->function_name, &h->retval, h->num_params, h->parameters TSRMLS_CC);
1795                }
1796                if (call_status != SUCCESS) {
1797                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function '%s' call failed", Z_STRVAL(h->function_name));
1798                    return;
1799                }
1800                if (Z_TYPE(h->retval) == IS_OBJECT &&
1801                    instanceof_function(Z_OBJCE(h->retval), soap_fault_class_entry TSRMLS_CC)) {
1802                    zval *headerfault = NULL, **tmp;
1803
1804                    if (zend_hash_find(Z_OBJPROP(h->retval), "headerfault", sizeof("headerfault"), (void**)&tmp) == SUCCESS &&
1805                        Z_TYPE_PP(tmp) != IS_NULL) {
1806                        headerfault = *tmp;
1807                    }
1808                    php_output_discard(TSRMLS_C);
1809                    soap_server_fault_ex(function, &h->retval, h TSRMLS_CC);
1810                    efree(fn_name);
1811                    if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(&soap_obj);}
1812                    goto fail;
1813                } else if (EG(exception)) {
1814                    php_output_discard(TSRMLS_C);
1815                    if (Z_TYPE_P(EG(exception)) == IS_OBJECT &&
1816                        instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {
1817                        zval *headerfault = NULL, **tmp;
1818
1819                        if (zend_hash_find(Z_OBJPROP_P(EG(exception)), "headerfault", sizeof("headerfault"), (void**)&tmp) == SUCCESS &&
1820                            Z_TYPE_PP(tmp) != IS_NULL) {
1821                            headerfault = *tmp;
1822                        }
1823                        soap_server_fault_ex(function, EG(exception), h TSRMLS_CC);
1824                    }
1825                    efree(fn_name);
1826                    if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(&soap_obj);}
1827                    goto fail;
1828                }
1829            } else if (h->mustUnderstand) {
1830                soap_server_fault("MustUnderstand","Header not understood", NULL, NULL, NULL TSRMLS_CC);
1831            }
1832            efree(fn_name);
1833        }
1834    }
1835
1836    fn_name = estrndup(Z_STRVAL(function_name),Z_STRLEN(function_name));
1837    if (zend_hash_exists(function_table, php_strtolower(fn_name, Z_STRLEN(function_name)), Z_STRLEN(function_name) + 1) ||
1838        ((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) &&
1839         zend_hash_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)))) {
1840        if (service->type == SOAP_CLASS || service->type == SOAP_OBJECT) {
1841            call_status = call_user_function(NULL, &soap_obj, &function_name, retval, num_params, params TSRMLS_CC);
1842            if (service->type == SOAP_CLASS) {
1843#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
1844                if (service->soap_class.persistance != SOAP_PERSISTENCE_SESSION) {
1845                    zval_ptr_dtor(&soap_obj);
1846                    soap_obj = NULL;
1847                }
1848#else
1849                zval_ptr_dtor(&soap_obj);
1850                soap_obj = NULL;
1851#endif
1852            }
1853        } else {
1854            call_status = call_user_function(EG(function_table), NULL, &function_name, retval, num_params, params TSRMLS_CC);
1855        }
1856    } else {
1857        php_error(E_ERROR, "Function '%s' doesn't exist", Z_STRVAL(function_name));
1858    }
1859    efree(fn_name);
1860
1861    if (EG(exception)) {
1862        php_output_discard(TSRMLS_C);
1863        if (Z_TYPE_P(EG(exception)) == IS_OBJECT &&
1864            instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {
1865            soap_server_fault_ex(function, EG(exception), NULL TSRMLS_CC);
1866        }
1867        if (service->type == SOAP_CLASS) {
1868#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
1869            if (soap_obj && service->soap_class.persistance != SOAP_PERSISTENCE_SESSION) {
1870#else
1871            if (soap_obj) {
1872#endif
1873              zval_ptr_dtor(&soap_obj);
1874            }
1875        }
1876        goto fail;
1877    }
1878
1879    if (call_status == SUCCESS) {
1880        char *response_name;
1881
1882        if (Z_TYPE_P(retval) == IS_OBJECT &&
1883            instanceof_function(Z_OBJCE_P(retval), soap_fault_class_entry TSRMLS_CC)) {
1884            php_output_discard(TSRMLS_C);
1885            soap_server_fault_ex(function, retval, NULL TSRMLS_CC);
1886            goto fail;
1887        }
1888
1889        if (function && function->responseName) {
1890            response_name = estrdup(function->responseName);
1891        } else {
1892            response_name = emalloc(Z_STRLEN(function_name) + sizeof("Response"));
1893            memcpy(response_name,Z_STRVAL(function_name),Z_STRLEN(function_name));
1894            memcpy(response_name+Z_STRLEN(function_name),"Response",sizeof("Response"));
1895        }
1896        doc_return = serialize_response_call(function, response_name, service->uri, retval, soap_headers, soap_version TSRMLS_CC);
1897        efree(response_name);
1898    } else {
1899        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function '%s' call failed", Z_STRVAL(function_name));
1900        return;
1901    }
1902
1903    if (EG(exception)) {
1904        php_output_discard(TSRMLS_C);
1905        if (Z_TYPE_P(EG(exception)) == IS_OBJECT &&
1906            instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {
1907            soap_server_fault_ex(function, EG(exception), NULL TSRMLS_CC);
1908        }
1909        if (service->type == SOAP_CLASS) {
1910#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
1911            if (soap_obj && service->soap_class.persistance != SOAP_PERSISTENCE_SESSION) {
1912#else
1913            if (soap_obj) {
1914#endif
1915              zval_ptr_dtor(&soap_obj);
1916            }
1917        }
1918        goto fail;
1919    }
1920
1921    /* Flush buffer */
1922    php_output_discard(TSRMLS_C);
1923
1924    if (doc_return) {
1925        /* xmlDocDumpMemoryEnc(doc_return, &buf, &size, XML_CHAR_ENCODING_UTF8); */
1926        xmlDocDumpMemory(doc_return, &buf, &size);
1927
1928        if (size == 0) {
1929            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Dump memory failed");
1930        }
1931
1932        if (soap_version == SOAP_1_2) {
1933            sapi_add_header("Content-Type: application/soap+xml; charset=utf-8", sizeof("Content-Type: application/soap+xml; charset=utf-8")-1, 1);
1934        } else {
1935            sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
1936        }
1937
1938        xmlFreeDoc(doc_return);
1939
1940        if (zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0)) {
1941            sapi_add_header("Connection: close", sizeof("Connection: close")-1, 1);
1942        } else {
1943            snprintf(cont_len, sizeof(cont_len), "Content-Length: %d", size);
1944            sapi_add_header(cont_len, strlen(cont_len), 1);
1945        }
1946        php_write(buf, size TSRMLS_CC);
1947        xmlFree(buf);
1948    } else {
1949        sapi_add_header("HTTP/1.1 202 Accepted", sizeof("HTTP/1.1 202 Accepted")-1, 1);
1950        sapi_add_header("Content-Length: 0", sizeof("Content-Length: 0")-1, 1);
1951    }
1952
1953fail:
1954    SOAP_GLOBAL(soap_version) = old_soap_version;
1955    SOAP_GLOBAL(encoding) = old_encoding;
1956    SOAP_GLOBAL(sdl) = old_sdl;
1957    SOAP_GLOBAL(class_map) = old_class_map;
1958    SOAP_GLOBAL(typemap) = old_typemap;
1959    SOAP_GLOBAL(features) = old_features;
1960
1961    /* Free soap headers */
1962    zval_ptr_dtor(&retval);
1963    while (soap_headers != NULL) {
1964        soapHeader *h = soap_headers;
1965        int i;
1966
1967        soap_headers = soap_headers->next;
1968        if (h->parameters) {
1969            i = h->num_params;
1970            while (i > 0) {
1971                zval_ptr_dtor(&h->parameters[--i]);
1972            }
1973            efree(h->parameters);
1974        }
1975        zval_dtor(&h->function_name);
1976        zval_dtor(&h->retval);
1977        efree(h);
1978    }
1979    service->soap_headers_ptr = NULL;
1980
1981    /* Free Memory */
1982    if (num_params > 0) {
1983        for (i = 0; i < num_params;i++) {
1984            zval_ptr_dtor(&params[i]);
1985        }
1986        efree(params);
1987    }
1988    zval_dtor(&function_name);
1989
1990    SOAP_SERVER_END_CODE();
1991}
1992/* }}} */
1993
1994
1995/* {{{ proto SoapServer::fault ( staring code, string string [, string actor [, mixed details [, string name]]] )
1996   Issue SoapFault indicating an error */
1997PHP_METHOD(SoapServer, fault)
1998{
1999    char *code, *string, *actor=NULL, *name=NULL;
2000    int code_len, string_len, actor_len = 0, name_len = 0;
2001    zval* details = NULL;
2002    soapServicePtr service;
2003    xmlCharEncodingHandlerPtr old_encoding;
2004
2005    SOAP_SERVER_BEGIN_CODE();
2006    FETCH_THIS_SERVICE(service);
2007    old_encoding = SOAP_GLOBAL(encoding);
2008    SOAP_GLOBAL(encoding) = service->encoding;
2009
2010    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|szs",
2011        &code, &code_len, &string, &string_len, &actor, &actor_len, &details,
2012        &name, &name_len) == FAILURE) {
2013        return;
2014    }
2015
2016    soap_server_fault(code, string, actor, details, name TSRMLS_CC);
2017
2018    SOAP_GLOBAL(encoding) = old_encoding;
2019    SOAP_SERVER_END_CODE();
2020}
2021/* }}} */
2022
2023PHP_METHOD(SoapServer, addSoapHeader)
2024{
2025    soapServicePtr service;
2026    zval *fault;
2027    soapHeader **p;
2028
2029    SOAP_SERVER_BEGIN_CODE();
2030
2031    FETCH_THIS_SERVICE(service);
2032
2033    if (!service || !service->soap_headers_ptr) {
2034        php_error_docref(NULL TSRMLS_CC, E_WARNING, "The SoapServer::addSoapHeader function may be called only during SOAP request processing");
2035        return;
2036    }
2037
2038    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &fault, soap_header_class_entry) == FAILURE) {
2039        return;
2040    }
2041
2042    p = service->soap_headers_ptr;
2043    while (*p != NULL) {
2044        p = &(*p)->next;
2045    }
2046    *p = emalloc(sizeof(soapHeader));
2047    memset(*p, 0, sizeof(soapHeader));
2048    ZVAL_NULL(&(*p)->function_name);
2049    (*p)->retval = *fault;
2050    zval_copy_ctor(&(*p)->retval);
2051
2052    SOAP_SERVER_END_CODE();
2053}
2054
2055static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader *hdr TSRMLS_DC)
2056{
2057    int soap_version;
2058    xmlChar *buf;
2059    char cont_len[30];
2060    int size;
2061    xmlDocPtr doc_return;
2062    zval **agent_name;
2063    int use_http_error_status = 1;
2064
2065    soap_version = SOAP_GLOBAL(soap_version);
2066
2067    doc_return = serialize_response_call(function, NULL, NULL, fault, hdr, soap_version TSRMLS_CC);
2068
2069    xmlDocDumpMemory(doc_return, &buf, &size);
2070
2071    zend_is_auto_global("_SERVER", sizeof("_SERVER") - 1 TSRMLS_CC);
2072    if (PG(http_globals)[TRACK_VARS_SERVER] &&
2073        zend_hash_find(PG(http_globals)[TRACK_VARS_SERVER]->value.ht, "HTTP_USER_AGENT", sizeof("HTTP_USER_AGENT"), (void **) &agent_name) == SUCCESS &&
2074        Z_TYPE_PP(agent_name) == IS_STRING) {
2075        if (strncmp(Z_STRVAL_PP(agent_name), "Shockwave Flash", sizeof("Shockwave Flash")-1) == 0) {
2076            use_http_error_status = 0;
2077        }
2078    }
2079    /*
2080       Want to return HTTP 500 but apache wants to over write
2081       our fault code with their own handling... Figure this out later
2082    */
2083    if (use_http_error_status) {
2084        sapi_add_header("HTTP/1.1 500 Internal Service Error", sizeof("HTTP/1.1 500 Internal Service Error")-1, 1);
2085    }
2086    if (zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0)) {
2087        sapi_add_header("Connection: close", sizeof("Connection: close")-1, 1);
2088    } else {
2089        snprintf(cont_len, sizeof(cont_len), "Content-Length: %d", size);
2090        sapi_add_header(cont_len, strlen(cont_len), 1);
2091    }
2092    if (soap_version == SOAP_1_2) {
2093        sapi_add_header("Content-Type: application/soap+xml; charset=utf-8", sizeof("Content-Type: application/soap+xml; charset=utf-8")-1, 1);
2094    } else {
2095        sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
2096    }
2097
2098    php_write(buf, size TSRMLS_CC);
2099
2100    xmlFreeDoc(doc_return);
2101    xmlFree(buf);
2102    zend_clear_exception(TSRMLS_C);
2103}
2104
2105static void soap_server_fault(char* code, char* string, char *actor, zval* details, char* name TSRMLS_DC)
2106{
2107    zval ret;
2108
2109    INIT_ZVAL(ret);
2110
2111    set_soap_fault(&ret, NULL, code, string, actor, details, name TSRMLS_CC);
2112    /* TODO: Which function */
2113    soap_server_fault_ex(NULL, &ret, NULL TSRMLS_CC);
2114    zend_bailout();
2115}
2116
2117static void soap_error_handler(int error_num, const char *error_filename, const uint error_lineno, const char *format, va_list args)
2118{
2119    zend_bool _old_in_compilation, _old_in_execution;
2120    zend_execute_data *_old_current_execute_data;
2121    int _old_http_response_code;
2122    char *_old_http_status_line;
2123    TSRMLS_FETCH();
2124
2125    _old_in_compilation = CG(in_compilation);
2126    _old_in_execution = EG(in_execution);
2127    _old_current_execute_data = EG(current_execute_data);
2128    _old_http_response_code = SG(sapi_headers).http_response_code;
2129    _old_http_status_line = SG(sapi_headers).http_status_line;
2130
2131    if (!SOAP_GLOBAL(use_soap_error_handler) || !EG(objects_store).object_buckets) {
2132        call_old_error_handler(error_num, error_filename, error_lineno, format, args);
2133        return;
2134    }
2135
2136    if (SOAP_GLOBAL(error_object) &&
2137        Z_TYPE_P(SOAP_GLOBAL(error_object)) == IS_OBJECT &&
2138        instanceof_function(Z_OBJCE_P(SOAP_GLOBAL(error_object)), soap_class_entry TSRMLS_CC)) {
2139        zval **tmp;
2140        int use_exceptions = 0;
2141
2142        if (zend_hash_find(Z_OBJPROP_P(SOAP_GLOBAL(error_object)), "_exceptions", sizeof("_exceptions"), (void **) &tmp) != SUCCESS ||
2143             Z_TYPE_PP(tmp) != IS_BOOL || Z_LVAL_PP(tmp) != 0) {
2144             use_exceptions = 1;
2145        }
2146
2147        if ((error_num == E_USER_ERROR ||
2148             error_num == E_COMPILE_ERROR ||
2149             error_num == E_CORE_ERROR ||
2150             error_num == E_ERROR ||
2151             error_num == E_PARSE) &&
2152            use_exceptions) {
2153            zval *fault, *exception;
2154            char* code = SOAP_GLOBAL(error_code);
2155            char buffer[1024];
2156            int buffer_len;
2157            zval outbuf, outbuflen;
2158#ifdef va_copy
2159            va_list argcopy;
2160#endif
2161            zend_object_store_bucket *old_objects;
2162            int old = PG(display_errors);
2163
2164            INIT_ZVAL(outbuf);
2165            INIT_ZVAL(outbuflen);
2166#ifdef va_copy
2167            va_copy(argcopy, args);
2168            buffer_len = vslprintf(buffer, sizeof(buffer)-1, format, argcopy);
2169            va_end(argcopy);
2170#else
2171            buffer_len = vslprintf(buffer, sizeof(buffer)-1, format, args);
2172#endif
2173            buffer[sizeof(buffer)-1]=0;
2174            if (buffer_len > sizeof(buffer) - 1 || buffer_len < 0) {
2175                buffer_len = sizeof(buffer) - 1;
2176            }
2177
2178            if (code == NULL) {
2179                code = "Client";
2180            }
2181            fault = add_soap_fault(SOAP_GLOBAL(error_object), code, buffer, NULL, NULL TSRMLS_CC);
2182            MAKE_STD_ZVAL(exception);
2183            MAKE_COPY_ZVAL(&fault, exception);
2184            zend_throw_exception_object(exception TSRMLS_CC);
2185
2186            old_objects = EG(objects_store).object_buckets;
2187            EG(objects_store).object_buckets = NULL;
2188            PG(display_errors) = 0;
2189            SG(sapi_headers).http_status_line = NULL;
2190            zend_try {
2191                call_old_error_handler(error_num, error_filename, error_lineno, format, args);
2192            } zend_catch {
2193                CG(in_compilation) = _old_in_compilation;
2194                EG(in_execution) = _old_in_execution;
2195                EG(current_execute_data) = _old_current_execute_data;
2196                if (SG(sapi_headers).http_status_line) {
2197                    efree(SG(sapi_headers).http_status_line);
2198                }
2199                SG(sapi_headers).http_status_line = _old_http_status_line;
2200                SG(sapi_headers).http_response_code = _old_http_response_code;
2201            } zend_end_try();
2202            EG(objects_store).object_buckets = old_objects;
2203            PG(display_errors) = old;
2204            zend_bailout();
2205        } else if (!use_exceptions ||
2206                   !SOAP_GLOBAL(error_code) ||
2207                   strcmp(SOAP_GLOBAL(error_code),"WSDL") != 0) {
2208            /* Ignore libxml warnings during WSDL parsing */
2209            call_old_error_handler(error_num, error_filename, error_lineno, format, args);
2210        }
2211    } else {
2212        int old = PG(display_errors);
2213        int fault = 0;
2214        zval fault_obj;
2215#ifdef va_copy
2216        va_list argcopy;
2217#endif
2218
2219        if (error_num == E_USER_ERROR ||
2220            error_num == E_COMPILE_ERROR ||
2221            error_num == E_CORE_ERROR ||
2222            error_num == E_ERROR ||
2223            error_num == E_PARSE) {
2224
2225            char* code = SOAP_GLOBAL(error_code);
2226            char buffer[1024];
2227            zval *outbuf = NULL;
2228            zval **tmp;
2229            soapServicePtr service;
2230
2231            if (code == NULL) {
2232                code = "Server";
2233            }
2234            if (SOAP_GLOBAL(error_object) &&
2235                Z_TYPE_P(SOAP_GLOBAL(error_object)) == IS_OBJECT &&
2236                instanceof_function(Z_OBJCE_P(SOAP_GLOBAL(error_object)), soap_server_class_entry TSRMLS_CC) &&
2237                zend_hash_find(Z_OBJPROP_P(SOAP_GLOBAL(error_object)), "service", sizeof("service"), (void **)&tmp) != FAILURE &&
2238                (service = (soapServicePtr)zend_fetch_resource(tmp TSRMLS_CC, -1, "service", NULL, 1, le_service)) &&
2239                !service->send_errors) {
2240                strcpy(buffer, "Internal Error");
2241            } else {
2242                int buffer_len;
2243                zval outbuflen;
2244
2245                INIT_ZVAL(outbuflen);
2246
2247#ifdef va_copy
2248                va_copy(argcopy, args);
2249                buffer_len = vslprintf(buffer, sizeof(buffer)-1, format, argcopy);
2250                va_end(argcopy);
2251#else
2252                buffer_len = vslprintf(buffer, sizeof(buffer)-1, format, args);
2253#endif
2254                buffer[sizeof(buffer)-1]=0;
2255                if (buffer_len > sizeof(buffer) - 1 || buffer_len < 0) {
2256                    buffer_len = sizeof(buffer) - 1;
2257                }
2258
2259                /* Get output buffer and send as fault detials */
2260                if (php_output_get_length(&outbuflen TSRMLS_CC) != FAILURE && Z_LVAL(outbuflen) != 0) {
2261                    ALLOC_INIT_ZVAL(outbuf);
2262                    php_output_get_contents(outbuf TSRMLS_CC);
2263                }
2264                php_output_discard(TSRMLS_C);
2265
2266            }
2267            INIT_ZVAL(fault_obj);
2268            set_soap_fault(&fault_obj, NULL, code, buffer, NULL, outbuf, NULL TSRMLS_CC);
2269            fault = 1;
2270        }
2271
2272        PG(display_errors) = 0;
2273        SG(sapi_headers).http_status_line = NULL;
2274        zend_try {
2275            call_old_error_handler(error_num, error_filename, error_lineno, format, args);
2276        } zend_catch {
2277            CG(in_compilation) = _old_in_compilation;
2278            EG(in_execution) = _old_in_execution;
2279            EG(current_execute_data) = _old_current_execute_data;
2280            if (SG(sapi_headers).http_status_line) {
2281                efree(SG(sapi_headers).http_status_line);
2282            }
2283            SG(sapi_headers).http_status_line = _old_http_status_line;
2284            SG(sapi_headers).http_response_code = _old_http_response_code;
2285        } zend_end_try();
2286        PG(display_errors) = old;
2287
2288        if (fault) {
2289            soap_server_fault_ex(NULL, &fault_obj, NULL TSRMLS_CC);
2290            zend_bailout();
2291        }
2292    }
2293}
2294
2295PHP_FUNCTION(use_soap_error_handler)
2296{
2297    zend_bool handler = 1;
2298
2299    ZVAL_BOOL(return_value, SOAP_GLOBAL(use_soap_error_handler));
2300    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &handler) == SUCCESS) {
2301        SOAP_GLOBAL(use_soap_error_handler) = handler;
2302    }
2303}
2304
2305PHP_FUNCTION(is_soap_fault)
2306{
2307    zval *fault;
2308
2309    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &fault) == SUCCESS &&
2310        Z_TYPE_P(fault) == IS_OBJECT &&
2311        instanceof_function(Z_OBJCE_P(fault), soap_fault_class_entry TSRMLS_CC)) {
2312        RETURN_TRUE;
2313    }
2314    RETURN_FALSE
2315}
2316
2317/* SoapClient functions */
2318
2319/* {{{ proto object SoapClient::SoapClient ( mixed wsdl [, array options])
2320   SoapClient constructor */
2321PHP_METHOD(SoapClient, SoapClient)
2322{
2323
2324    zval *wsdl, *options = NULL;
2325    int  soap_version = SOAP_1_1;
2326    php_stream_context *context = NULL;
2327    long cache_wsdl;
2328    sdlPtr sdl = NULL;
2329    HashTable *typemap_ht = NULL;
2330
2331    SOAP_CLIENT_BEGIN_CODE();
2332
2333    if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z|a", &wsdl, &options) == FAILURE) {
2334        php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid parameters");
2335    }
2336
2337    if (Z_TYPE_P(wsdl) != IS_STRING && Z_TYPE_P(wsdl) != IS_NULL) {
2338        php_error_docref(NULL TSRMLS_CC, E_ERROR, "$wsdl must be string or null");
2339    }
2340
2341    cache_wsdl = SOAP_GLOBAL(cache_enabled) ? SOAP_GLOBAL(cache_mode) : 0;
2342
2343    if (options != NULL) {
2344        HashTable *ht = Z_ARRVAL_P(options);
2345        zval **tmp;
2346
2347        if (Z_TYPE_P(wsdl) == IS_NULL) {
2348            /* Fetching non-WSDL mode options */
2349            if (zend_hash_find(ht, "uri", sizeof("uri"), (void**)&tmp) == SUCCESS &&
2350                Z_TYPE_PP(tmp) == IS_STRING) {
2351                add_property_stringl(this_ptr, "uri", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
2352            } else {
2353                php_error_docref(NULL TSRMLS_CC, E_ERROR, "'uri' option is required in nonWSDL mode");
2354            }
2355
2356            if (zend_hash_find(ht, "style", sizeof("style"), (void**)&tmp) == SUCCESS &&
2357                    Z_TYPE_PP(tmp) == IS_LONG &&
2358                    (Z_LVAL_PP(tmp) == SOAP_RPC || Z_LVAL_PP(tmp) == SOAP_DOCUMENT)) {
2359                add_property_long(this_ptr, "style", Z_LVAL_PP(tmp));
2360            }
2361
2362            if (zend_hash_find(ht, "use", sizeof("use"), (void**)&tmp) == SUCCESS &&
2363                    Z_TYPE_PP(tmp) == IS_LONG &&
2364                    (Z_LVAL_PP(tmp) == SOAP_LITERAL || Z_LVAL_PP(tmp) == SOAP_ENCODED)) {
2365                add_property_long(this_ptr, "use", Z_LVAL_PP(tmp));
2366            }
2367        }
2368
2369        if (zend_hash_find(ht, "stream_context", sizeof("stream_context"), (void**)&tmp) == SUCCESS &&
2370                Z_TYPE_PP(tmp) == IS_RESOURCE) {
2371            context = php_stream_context_from_zval(*tmp, 1);
2372            zend_list_addref(context->rsrc_id);
2373        }
2374
2375        if (zend_hash_find(ht, "location", sizeof("location"), (void**)&tmp) == SUCCESS &&
2376            Z_TYPE_PP(tmp) == IS_STRING) {
2377            add_property_stringl(this_ptr, "location", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
2378        } else if (Z_TYPE_P(wsdl) == IS_NULL) {
2379            php_error_docref(NULL TSRMLS_CC, E_ERROR, "'location' option is required in nonWSDL mode");
2380        }
2381
2382        if (zend_hash_find(ht, "soap_version", sizeof("soap_version"), (void**)&tmp) == SUCCESS) {
2383            if (Z_TYPE_PP(tmp) == IS_LONG ||
2384                (Z_LVAL_PP(tmp) == SOAP_1_1 && Z_LVAL_PP(tmp) == SOAP_1_2)) {
2385                soap_version = Z_LVAL_PP(tmp);
2386            }
2387        }
2388        if (zend_hash_find(ht, "login", sizeof("login"), (void**)&tmp) == SUCCESS &&
2389            Z_TYPE_PP(tmp) == IS_STRING) {
2390            add_property_stringl(this_ptr, "_login", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
2391            if (zend_hash_find(ht, "password", sizeof("password"), (void**)&tmp) == SUCCESS &&
2392                Z_TYPE_PP(tmp) == IS_STRING) {
2393                add_property_stringl(this_ptr, "_password", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
2394            }
2395            if (zend_hash_find(ht, "authentication", sizeof("authentication"), (void**)&tmp) == SUCCESS &&
2396                Z_TYPE_PP(tmp) == IS_LONG &&
2397                Z_LVAL_PP(tmp) == SOAP_AUTHENTICATION_DIGEST) {
2398                add_property_null(this_ptr, "_digest");
2399            }
2400        }
2401        if (zend_hash_find(ht, "proxy_host", sizeof("proxy_host"), (void**)&tmp) == SUCCESS &&
2402            Z_TYPE_PP(tmp) == IS_STRING) {
2403            add_property_stringl(this_ptr, "_proxy_host", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
2404            if (zend_hash_find(ht, "proxy_port", sizeof("proxy_port"), (void**)&tmp) == SUCCESS) {
2405                convert_to_long(*tmp);
2406                add_property_long(this_ptr, "_proxy_port", Z_LVAL_PP(tmp));
2407            }
2408            if (zend_hash_find(ht, "proxy_login", sizeof("proxy_login"), (void**)&tmp) == SUCCESS &&
2409                Z_TYPE_PP(tmp) == IS_STRING) {
2410                add_property_stringl(this_ptr, "_proxy_login", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
2411                if (zend_hash_find(ht, "proxy_password", sizeof("proxy_password"), (void**)&tmp) == SUCCESS &&
2412                    Z_TYPE_PP(tmp) == IS_STRING) {
2413                    add_property_stringl(this_ptr, "_proxy_password", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
2414                }
2415            }
2416        }
2417        if (zend_hash_find(ht, "local_cert", sizeof("local_cert"), (void**)&tmp) == SUCCESS &&
2418            Z_TYPE_PP(tmp) == IS_STRING) {
2419          if (!context) {
2420            context = php_stream_context_alloc(TSRMLS_C);
2421          }
2422            php_stream_context_set_option(context, "ssl", "local_cert", *tmp);
2423            if (zend_hash_find(ht, "passphrase", sizeof("passphrase"), (void**)&tmp) == SUCCESS &&
2424                Z_TYPE_PP(tmp) == IS_STRING) {
2425                php_stream_context_set_option(context, "ssl", "passphrase", *tmp);
2426            }
2427        }
2428        if (zend_hash_find(ht, "trace", sizeof("trace"), (void**)&tmp) == SUCCESS &&
2429            (Z_TYPE_PP(tmp) == IS_BOOL || Z_TYPE_PP(tmp) == IS_LONG) &&
2430                Z_LVAL_PP(tmp) == 1) {
2431            add_property_long(this_ptr, "trace", 1);
2432        }
2433
2434        if (zend_hash_find(ht, "exceptions", sizeof("exceptions"), (void**)&tmp) == SUCCESS &&
2435            (Z_TYPE_PP(tmp) == IS_BOOL || Z_TYPE_PP(tmp) == IS_LONG) &&
2436                Z_LVAL_PP(tmp) == 0) {
2437            add_property_bool(this_ptr, "_exceptions", 0);
2438        }
2439
2440        if (zend_hash_find(ht, "compression", sizeof("compression"), (void**)&tmp) == SUCCESS &&
2441            Z_TYPE_PP(tmp) == IS_LONG &&
2442          zend_hash_exists(EG(function_table), "gzinflate", sizeof("gzinflate")) &&
2443          zend_hash_exists(EG(function_table), "gzdeflate", sizeof("gzdeflate")) &&
2444          zend_hash_exists(EG(function_table), "gzuncompress", sizeof("gzuncompress")) &&
2445          zend_hash_exists(EG(function_table), "gzcompress", sizeof("gzcompress")) &&
2446          zend_hash_exists(EG(function_table), "gzencode", sizeof("gzencode"))) {
2447            add_property_long(this_ptr, "compression", Z_LVAL_PP(tmp));
2448        }
2449        if (zend_hash_find(ht, "encoding", sizeof("encoding"), (void**)&tmp) == SUCCESS &&
2450            Z_TYPE_PP(tmp) == IS_STRING) {
2451            xmlCharEncodingHandlerPtr encoding;
2452
2453            encoding = xmlFindCharEncodingHandler(Z_STRVAL_PP(tmp));
2454            if (encoding == NULL) {
2455                php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid 'encoding' option - '%s'", Z_STRVAL_PP(tmp));
2456            } else {
2457                xmlCharEncCloseFunc(encoding);
2458                add_property_stringl(this_ptr, "_encoding", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
2459            }
2460        }
2461        if (zend_hash_find(ht, "classmap", sizeof("classmap"), (void**)&tmp) == SUCCESS &&
2462            Z_TYPE_PP(tmp) == IS_ARRAY) {
2463            zval *class_map;
2464
2465            MAKE_STD_ZVAL(class_map);
2466            MAKE_COPY_ZVAL(tmp, class_map);
2467            Z_DELREF_P(class_map);
2468
2469            add_property_zval(this_ptr, "_classmap", class_map);
2470        }
2471
2472        if (zend_hash_find(ht, "typemap", sizeof("typemap"), (void**)&tmp) == SUCCESS &&
2473            Z_TYPE_PP(tmp) == IS_ARRAY &&
2474            zend_hash_num_elements(Z_ARRVAL_PP(tmp)) > 0) {
2475            typemap_ht = Z_ARRVAL_PP(tmp);
2476        }
2477
2478        if (zend_hash_find(ht, "features", sizeof("features"), (void**)&tmp) == SUCCESS &&
2479            Z_TYPE_PP(tmp) == IS_LONG) {
2480            add_property_long(this_ptr, "_features", Z_LVAL_PP(tmp));
2481        }
2482
2483        if (zend_hash_find(ht, "connection_timeout", sizeof("connection_timeout"), (void**)&tmp) == SUCCESS) {
2484            convert_to_long(*tmp);
2485            if (Z_LVAL_PP(tmp) > 0) {
2486                add_property_long(this_ptr, "_connection_timeout", Z_LVAL_PP(tmp));
2487            }
2488        }
2489
2490        if (context) {
2491            add_property_resource(this_ptr, "_stream_context", context->rsrc_id);
2492        }
2493
2494        if (zend_hash_find(ht, "cache_wsdl", sizeof("cache_wsdl"), (void**)&tmp) == SUCCESS &&
2495            Z_TYPE_PP(tmp) == IS_LONG) {
2496            cache_wsdl = Z_LVAL_PP(tmp);
2497        }
2498
2499        if (zend_hash_find(ht, "user_agent", sizeof("user_agent"), (void**)&tmp) == SUCCESS &&
2500            Z_TYPE_PP(tmp) == IS_STRING) {
2501            add_property_stringl(this_ptr, "_user_agent", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
2502        }
2503
2504        if (zend_hash_find(ht, "keep_alive", sizeof("keep_alive"), (void**)&tmp) == SUCCESS &&
2505                (Z_TYPE_PP(tmp) == IS_BOOL || Z_TYPE_PP(tmp) == IS_LONG) && Z_LVAL_PP(tmp) == 0) {
2506            add_property_long(this_ptr, "_keep_alive", 0);
2507        }
2508
2509        if (zend_hash_find(ht, "ssl_method", sizeof("ssl_method"), (void**)&tmp) == SUCCESS &&
2510            Z_TYPE_PP(tmp) == IS_LONG) {
2511            add_property_long(this_ptr, "_ssl_method", Z_LVAL_PP(tmp));
2512        }
2513    } else if (Z_TYPE_P(wsdl) == IS_NULL) {
2514        php_error_docref(NULL TSRMLS_CC, E_ERROR, "'location' and 'uri' options are required in nonWSDL mode");
2515    }
2516
2517    add_property_long(this_ptr, "_soap_version", soap_version);
2518
2519    if (Z_TYPE_P(wsdl) != IS_NULL) {
2520        int    old_soap_version, ret;
2521
2522        old_soap_version = SOAP_GLOBAL(soap_version);
2523        SOAP_GLOBAL(soap_version) = soap_version;
2524
2525        sdl = get_sdl(this_ptr, Z_STRVAL_P(wsdl), cache_wsdl TSRMLS_CC);
2526        ret = zend_list_insert(sdl, le_sdl TSRMLS_CC);
2527
2528        add_property_resource(this_ptr, "sdl", ret);
2529
2530        SOAP_GLOBAL(soap_version) = old_soap_version;
2531    }
2532
2533    if (typemap_ht) {
2534        HashTable *typemap = soap_create_typemap(sdl, typemap_ht TSRMLS_CC);
2535        if (typemap) {
2536            int ret;
2537
2538            ret = zend_list_insert(typemap, le_typemap TSRMLS_CC);
2539            add_property_resource(this_ptr, "typemap", ret);
2540        }
2541    }
2542    SOAP_CLIENT_END_CODE();
2543}
2544/* }}} */
2545
2546static int do_request(zval *this_ptr, xmlDoc *request, char *location, char *action, int version, int one_way, zval *response TSRMLS_DC)
2547{
2548    int    ret = TRUE;
2549    char  *buf;
2550    int    buf_size;
2551    zval   func;
2552    zval  *params[5];
2553    zval **trace;
2554    zval **fault;
2555
2556    INIT_ZVAL(*response);
2557
2558    xmlDocDumpMemory(request, (xmlChar**)&buf, &buf_size);
2559    if (!buf) {
2560        add_soap_fault(this_ptr, "HTTP", "Error build soap request", NULL, NULL TSRMLS_CC);
2561        return FALSE;
2562    }
2563
2564    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace"), (void **) &trace) == SUCCESS &&
2565        Z_LVAL_PP(trace) > 0) {
2566        add_property_stringl(this_ptr, "__last_request", buf, buf_size, 1);
2567    }
2568
2569    INIT_ZVAL(func);
2570    ZVAL_STRINGL(&func,"__doRequest",sizeof("__doRequest")-1,0);
2571    ALLOC_INIT_ZVAL(params[0]);
2572    ZVAL_STRINGL(params[0], buf, buf_size, 1);
2573    ALLOC_INIT_ZVAL(params[1]);
2574    if (location == NULL) {
2575        ZVAL_NULL(params[1]);
2576    } else {
2577        ZVAL_STRING(params[1], location, 1);
2578    }
2579    ALLOC_INIT_ZVAL(params[2]);
2580    if (action == NULL) {
2581        ZVAL_NULL(params[2]);
2582    } else {
2583        ZVAL_STRING(params[2], action, 1);
2584    }
2585    ALLOC_INIT_ZVAL(params[3]);
2586    ZVAL_LONG(params[3], version);
2587
2588    ALLOC_INIT_ZVAL(params[4]);
2589    ZVAL_LONG(params[4], one_way);
2590
2591    if (call_user_function(NULL, &this_ptr, &func, response, 5, params TSRMLS_CC) != SUCCESS) {
2592        add_soap_fault(this_ptr, "Client", "SoapClient::__doRequest() failed", NULL, NULL TSRMLS_CC);
2593        ret = FALSE;
2594    } else if (Z_TYPE_P(response) != IS_STRING) {
2595        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault"), (void **) &fault) == FAILURE) {
2596            add_soap_fault(this_ptr, "Client", "SoapClient::__doRequest() returned non string value", NULL, NULL TSRMLS_CC);
2597        }
2598        ret = FALSE;
2599    } else if (zend_hash_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace"), (void **) &trace) == SUCCESS &&
2600        Z_LVAL_PP(trace) > 0) {
2601        add_property_stringl(this_ptr, "__last_response", Z_STRVAL_P(response), Z_STRLEN_P(response), 1);
2602    }
2603    zval_ptr_dtor(&params[4]);
2604    zval_ptr_dtor(&params[3]);
2605    zval_ptr_dtor(&params[2]);
2606    zval_ptr_dtor(&params[1]);
2607    zval_ptr_dtor(&params[0]);
2608    xmlFree(buf);
2609    if (ret && zend_hash_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault"), (void **) &fault) == SUCCESS) {
2610      return FALSE;
2611    }
2612  return ret;
2613}
2614
2615static void do_soap_call(zval* this_ptr,
2616                         char* function,
2617                         int function_len,
2618                         int arg_count,
2619                         zval** real_args,
2620                         zval* return_value,
2621                         char* location,
2622                         char* soap_action,
2623                         char* call_uri,
2624                         HashTable* soap_headers,
2625                         zval* output_headers
2626                         TSRMLS_DC)
2627{
2628    zval **tmp;
2629    zval **trace;
2630    sdlPtr sdl = NULL;
2631    sdlPtr old_sdl = NULL;
2632    sdlFunctionPtr fn;
2633    xmlDocPtr request = NULL;
2634    int ret = FALSE;
2635    int soap_version;
2636    zval response;
2637    xmlCharEncodingHandlerPtr old_encoding;
2638    HashTable *old_class_map;
2639    int old_features;
2640    HashTable *old_typemap, *typemap = NULL;
2641
2642    SOAP_CLIENT_BEGIN_CODE();
2643
2644    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace"), (void **) &trace) == SUCCESS
2645        && Z_LVAL_PP(trace) > 0) {
2646        zend_hash_del(Z_OBJPROP_P(this_ptr), "__last_request", sizeof("__last_request"));
2647        zend_hash_del(Z_OBJPROP_P(this_ptr), "__last_response", sizeof("__last_response"));
2648    }
2649    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_soap_version", sizeof("_soap_version"), (void **) &tmp) == SUCCESS
2650        && Z_LVAL_PP(tmp) == SOAP_1_2) {
2651        soap_version = SOAP_1_2;
2652    } else {
2653        soap_version = SOAP_1_1;
2654    }
2655
2656    if (location == NULL) {
2657        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "location", sizeof("location"),(void **) &tmp) == SUCCESS &&
2658            Z_TYPE_PP(tmp) == IS_STRING) {
2659          location = Z_STRVAL_PP(tmp);
2660        }
2661    }
2662
2663    if (FIND_SDL_PROPERTY(this_ptr,tmp) != FAILURE) {
2664        FETCH_SDL_RES(sdl,tmp);
2665    }
2666    if (FIND_TYPEMAP_PROPERTY(this_ptr,tmp) != FAILURE) {
2667        FETCH_TYPEMAP_RES(typemap,tmp);
2668    }
2669
2670    clear_soap_fault(this_ptr TSRMLS_CC);
2671
2672    SOAP_GLOBAL(soap_version) = soap_version;
2673    old_sdl = SOAP_GLOBAL(sdl);
2674    SOAP_GLOBAL(sdl) = sdl;
2675    old_encoding = SOAP_GLOBAL(encoding);
2676    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_encoding", sizeof("_encoding"), (void **) &tmp) == SUCCESS &&
2677        Z_TYPE_PP(tmp) == IS_STRING) {
2678        SOAP_GLOBAL(encoding) = xmlFindCharEncodingHandler(Z_STRVAL_PP(tmp));
2679    } else {
2680        SOAP_GLOBAL(encoding) = NULL;
2681    }
2682    old_class_map = SOAP_GLOBAL(class_map);
2683    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_classmap", sizeof("_classmap"), (void **) &tmp) == SUCCESS &&
2684        Z_TYPE_PP(tmp) == IS_ARRAY) {
2685        SOAP_GLOBAL(class_map) = (*tmp)->value.ht;
2686    } else {
2687        SOAP_GLOBAL(class_map) = NULL;
2688    }
2689    old_typemap = SOAP_GLOBAL(typemap);
2690    SOAP_GLOBAL(typemap) = typemap;
2691    old_features = SOAP_GLOBAL(features);
2692    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_features", sizeof("_features"), (void **) &tmp) == SUCCESS &&
2693        Z_TYPE_PP(tmp) == IS_LONG) {
2694        SOAP_GLOBAL(features) = Z_LVAL_PP(tmp);
2695    } else {
2696        SOAP_GLOBAL(features) = 0;
2697    }
2698
2699    zend_try {
2700        if (sdl != NULL) {
2701            fn = get_function(sdl, function);
2702            if (fn != NULL) {
2703                sdlBindingPtr binding = fn->binding;
2704                int one_way = 0;
2705
2706                if (fn->responseName == NULL &&
2707                    fn->responseParameters == NULL &&
2708                    soap_headers == NULL) {
2709                    one_way = 1;
2710                }
2711
2712                if (location == NULL) {
2713                    location = binding->location;
2714                }
2715                if (binding->bindingType == BINDING_SOAP) {
2716                    sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes;
2717                    request = serialize_function_call(this_ptr, fn, NULL, fnb->input.ns, real_args, arg_count, soap_version, soap_headers TSRMLS_CC);
2718                    ret = do_request(this_ptr, request, location, fnb->soapAction, soap_version, one_way, &response TSRMLS_CC);
2719                } else {
2720                    request = serialize_function_call(this_ptr, fn, NULL, sdl->target_ns, real_args, arg_count, soap_version, soap_headers TSRMLS_CC);
2721                    ret = do_request(this_ptr, request, location, NULL, soap_version, one_way, &response TSRMLS_CC);
2722                }
2723
2724                xmlFreeDoc(request);
2725
2726                if (ret && Z_TYPE(response) == IS_STRING) {
2727                    encode_reset_ns();
2728                    ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), fn, NULL, return_value, output_headers TSRMLS_CC);
2729                    encode_finish();
2730                }
2731
2732                zval_dtor(&response);
2733
2734            } else {
2735                smart_str error = {0};
2736                smart_str_appends(&error,"Function (\"");
2737                smart_str_appends(&error,function);
2738                smart_str_appends(&error,"\") is not a valid method for this service");
2739                smart_str_0(&error);
2740                add_soap_fault(this_ptr, "Client", error.c, NULL, NULL TSRMLS_CC);
2741                smart_str_free(&error);
2742            }
2743        } else {
2744            zval **uri;
2745            smart_str action = {0};
2746
2747            if (zend_hash_find(Z_OBJPROP_P(this_ptr), "uri", sizeof("uri"), (void *)&uri) == FAILURE) {
2748                add_soap_fault(this_ptr, "Client", "Error finding \"uri\" property", NULL, NULL TSRMLS_CC);
2749            } else if (location == NULL) {
2750                add_soap_fault(this_ptr, "Client", "Error could not find \"location\" property", NULL, NULL TSRMLS_CC);
2751            } else {
2752                if (call_uri == NULL) {
2753                    call_uri = Z_STRVAL_PP(uri);
2754                }
2755                request = serialize_function_call(this_ptr, NULL, function, call_uri, real_args, arg_count, soap_version, soap_headers TSRMLS_CC);
2756
2757                if (soap_action == NULL) {
2758                    smart_str_appends(&action, call_uri);
2759                    smart_str_appendc(&action, '#');
2760                    smart_str_appends(&action, function);
2761                } else {
2762                    smart_str_appends(&action, soap_action);
2763                }
2764                smart_str_0(&action);
2765
2766                ret = do_request(this_ptr, request, location, action.c, soap_version, 0, &response TSRMLS_CC);
2767
2768                smart_str_free(&action);
2769                xmlFreeDoc(request);
2770
2771                if (ret && Z_TYPE(response) == IS_STRING) {
2772                    encode_reset_ns();
2773                    ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), NULL, function, return_value, output_headers TSRMLS_CC);
2774                    encode_finish();
2775                }
2776
2777                zval_dtor(&response);
2778            }
2779        }
2780
2781        if (!ret) {
2782            zval** fault;
2783            if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault"), (void **) &fault) == SUCCESS) {
2784                *return_value = **fault;
2785                zval_copy_ctor(return_value);
2786            } else {
2787                *return_value = *add_soap_fault(this_ptr, "Client", "Unknown Error", NULL, NULL TSRMLS_CC);
2788                zval_copy_ctor(return_value);
2789            }
2790        } else {
2791            zval** fault;
2792            if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault"), (void **) &fault) == SUCCESS) {
2793                *return_value = **fault;
2794                zval_copy_ctor(return_value);
2795            }
2796        }
2797
2798        if (!EG(exception) &&
2799            Z_TYPE_P(return_value) == IS_OBJECT &&
2800            instanceof_function(Z_OBJCE_P(return_value), soap_fault_class_entry TSRMLS_CC) &&
2801            (zend_hash_find(Z_OBJPROP_P(this_ptr), "_exceptions", sizeof("_exceptions"), (void **) &tmp) != SUCCESS ||
2802               Z_TYPE_PP(tmp) != IS_BOOL || Z_LVAL_PP(tmp) != 0)) {
2803            zval *exception;
2804
2805            MAKE_STD_ZVAL(exception);
2806            MAKE_COPY_ZVAL(&return_value, exception);
2807            zend_throw_exception_object(exception TSRMLS_CC);
2808        }
2809
2810    } zend_catch {
2811        _bailout = 1;
2812    } zend_end_try();
2813
2814    if (SOAP_GLOBAL(encoding) != NULL) {
2815        xmlCharEncCloseFunc(SOAP_GLOBAL(encoding));
2816    }
2817
2818    SOAP_GLOBAL(features) = old_features;
2819    SOAP_GLOBAL(typemap) = old_typemap;
2820    SOAP_GLOBAL(class_map) = old_class_map;
2821    SOAP_GLOBAL(encoding) = old_encoding;
2822    SOAP_GLOBAL(sdl) = old_sdl;
2823    if (_bailout) {
2824        _bailout = 0;
2825        zend_bailout();
2826    }
2827    SOAP_CLIENT_END_CODE();
2828}
2829
2830static void verify_soap_headers_array(HashTable *ht TSRMLS_DC)
2831{
2832    zval **tmp;
2833
2834    zend_hash_internal_pointer_reset(ht);
2835    while (zend_hash_get_current_data(ht, (void**)&tmp) == SUCCESS) {
2836        if (Z_TYPE_PP(tmp) != IS_OBJECT ||
2837            !instanceof_function(Z_OBJCE_PP(tmp), soap_header_class_entry TSRMLS_CC)) {
2838            php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid SOAP header");
2839        }
2840        zend_hash_move_forward(ht);
2841    }
2842}
2843
2844
2845/* {{{ proto mixed SoapClient::__call ( string function_name, array arguments [, array options [, array input_headers [, array output_headers]]])
2846   Calls a SOAP function */
2847PHP_METHOD(SoapClient, __call)
2848{
2849    char *function, *location=NULL, *soap_action = NULL, *uri = NULL;
2850    int function_len, i = 0;
2851    HashTable* soap_headers = NULL;
2852    zval *options = NULL;
2853    zval *headers = NULL;
2854    zval *output_headers = NULL;
2855    zval *args;
2856    zval **real_args = NULL;
2857    zval **param;
2858    int arg_count;
2859    zval **tmp;
2860    zend_bool free_soap_headers = 0;
2861
2862    HashPosition pos;
2863
2864    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|a!zz",
2865        &function, &function_len, &args, &options, &headers, &output_headers) == FAILURE) {
2866        return;
2867    }
2868
2869    if (options) {
2870        HashTable *hto = Z_ARRVAL_P(options);
2871        if (zend_hash_find(hto, "location", sizeof("location"), (void**)&tmp) == SUCCESS &&
2872            Z_TYPE_PP(tmp) == IS_STRING) {
2873            location = Z_STRVAL_PP(tmp);
2874        }
2875
2876        if (zend_hash_find(hto, "soapaction", sizeof("soapaction"), (void**)&tmp) == SUCCESS &&
2877            Z_TYPE_PP(tmp) == IS_STRING) {
2878            soap_action = Z_STRVAL_PP(tmp);
2879        }
2880
2881        if (zend_hash_find(hto, "uri", sizeof("uri"), (void**)&tmp) == SUCCESS &&
2882            Z_TYPE_PP(tmp) == IS_STRING) {
2883            uri = Z_STRVAL_PP(tmp);
2884        }
2885    }
2886
2887    if (headers == NULL || Z_TYPE_P(headers) == IS_NULL) {
2888    } else if (Z_TYPE_P(headers) == IS_ARRAY) {
2889        soap_headers = Z_ARRVAL_P(headers);
2890        verify_soap_headers_array(soap_headers TSRMLS_CC);
2891        free_soap_headers = 0;
2892    } else if (Z_TYPE_P(headers) == IS_OBJECT &&
2893               instanceof_function(Z_OBJCE_P(headers), soap_header_class_entry TSRMLS_CC)) {
2894        soap_headers = emalloc(sizeof(HashTable));
2895        zend_hash_init(soap_headers, 0, NULL, ZVAL_PTR_DTOR, 0);
2896        zend_hash_next_index_insert(soap_headers, &headers, sizeof(zval*), NULL);
2897        Z_ADDREF_P(headers);
2898        free_soap_headers = 1;
2899    } else{
2900        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid SOAP header");
2901        return;
2902    }
2903
2904    /* Add default headers */
2905    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__default_headers", sizeof("__default_headers"), (void **) &tmp)==SUCCESS) {
2906        HashTable *default_headers = Z_ARRVAL_P(*tmp);
2907        if (soap_headers) {
2908            if (!free_soap_headers) {
2909                HashTable *t =  emalloc(sizeof(HashTable));
2910                zend_hash_init(t, 0, NULL, ZVAL_PTR_DTOR, 0);
2911                zend_hash_copy(t, soap_headers, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
2912                soap_headers = t;
2913                free_soap_headers = 1;
2914            }
2915            zend_hash_internal_pointer_reset(default_headers);
2916            while (zend_hash_get_current_data(default_headers, (void**)&tmp) == SUCCESS) {
2917                Z_ADDREF_PP(tmp);
2918                zend_hash_next_index_insert(soap_headers, tmp, sizeof(zval *), NULL);
2919                zend_hash_move_forward(default_headers);
2920            }
2921        } else {
2922            soap_headers = Z_ARRVAL_P(*tmp);
2923            free_soap_headers = 0;
2924        }
2925    }
2926
2927    arg_count = zend_hash_num_elements(Z_ARRVAL_P(args));
2928
2929    if (arg_count > 0) {
2930        real_args = safe_emalloc(sizeof(zval *), arg_count, 0);
2931        for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(args), &pos);
2932            zend_hash_get_current_data_ex(Z_ARRVAL_P(args), (void **) &param, &pos) == SUCCESS;
2933            zend_hash_move_forward_ex(Z_ARRVAL_P(args), &pos)) {
2934                /*zval_add_ref(param);*/
2935                real_args[i++] = *param;
2936        }
2937    }
2938    if (output_headers) {
2939        array_init(output_headers);
2940    }
2941    do_soap_call(this_ptr, function, function_len, arg_count, real_args, return_value, location, soap_action, uri, soap_headers, output_headers TSRMLS_CC);
2942    if (arg_count > 0) {
2943        efree(real_args);
2944    }
2945
2946    if (soap_headers && free_soap_headers) {
2947        zend_hash_destroy(soap_headers);
2948        efree(soap_headers);
2949    }
2950}
2951/* }}} */
2952
2953
2954/* {{{ proto array SoapClient::__getFunctions ( void )
2955   Returns list of SOAP functions */
2956PHP_METHOD(SoapClient, __getFunctions)
2957{
2958    sdlPtr sdl;
2959    HashPosition pos;
2960
2961    FETCH_THIS_SDL(sdl);
2962
2963    if (zend_parse_parameters_none() == FAILURE) {
2964        return;
2965    }
2966
2967    if (sdl) {
2968        smart_str buf = {0};
2969        sdlFunctionPtr *function;
2970
2971        array_init(return_value);
2972        zend_hash_internal_pointer_reset_ex(&sdl->functions, &pos);
2973        while (zend_hash_get_current_data_ex(&sdl->functions, (void **)&function, &pos) != FAILURE) {
2974            function_to_string((*function), &buf);
2975            add_next_index_stringl(return_value, buf.c, buf.len, 1);
2976            smart_str_free(&buf);
2977            zend_hash_move_forward_ex(&sdl->functions, &pos);
2978        }
2979    }
2980}
2981/* }}} */
2982
2983
2984/* {{{ proto array SoapClient::__getTypes ( void )
2985   Returns list of SOAP types */
2986PHP_METHOD(SoapClient, __getTypes)
2987{
2988    sdlPtr sdl;
2989    HashPosition pos;
2990
2991    FETCH_THIS_SDL(sdl);
2992
2993    if (zend_parse_parameters_none() == FAILURE) {
2994        return;
2995    }
2996
2997    if (sdl) {
2998        sdlTypePtr *type;
2999        smart_str buf = {0};
3000
3001        array_init(return_value);
3002        if (sdl->types) {
3003            zend_hash_internal_pointer_reset_ex(sdl->types, &pos);
3004            while (zend_hash_get_current_data_ex(sdl->types, (void **)&type, &pos) != FAILURE) {
3005                type_to_string((*type), &buf, 0);
3006                add_next_index_stringl(return_value, buf.c, buf.len, 1);
3007                smart_str_free(&buf);
3008                zend_hash_move_forward_ex(sdl->types, &pos);
3009            }
3010        }
3011    }
3012}
3013/* }}} */
3014
3015
3016/* {{{ proto string SoapClient::__getLastRequest ( void )
3017   Returns last SOAP request */
3018PHP_METHOD(SoapClient, __getLastRequest)
3019{
3020    zval **tmp;
3021
3022    if (zend_parse_parameters_none() == FAILURE) {
3023        return;
3024    }
3025
3026    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__last_request", sizeof("__last_request"), (void **)&tmp) == SUCCESS) {
3027        RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
3028    }
3029    RETURN_NULL();
3030}
3031/* }}} */
3032
3033
3034/* {{{ proto object SoapClient::__getLastResponse ( void )
3035   Returns last SOAP response */
3036PHP_METHOD(SoapClient, __getLastResponse)
3037{
3038    zval **tmp;
3039
3040    if (zend_parse_parameters_none() == FAILURE) {
3041        return;
3042    }
3043
3044    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__last_response", sizeof("__last_response"), (void **)&tmp) == SUCCESS) {
3045        RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
3046    }
3047    RETURN_NULL();
3048}
3049/* }}} */
3050
3051
3052/* {{{ proto string SoapClient::__getLastRequestHeaders(void)
3053   Returns last SOAP request headers */
3054PHP_METHOD(SoapClient, __getLastRequestHeaders)
3055{
3056    zval **tmp;
3057
3058    if (zend_parse_parameters_none() == FAILURE) {
3059        return;
3060    }
3061
3062    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__last_request_headers", sizeof("__last_request_headers"), (void **)&tmp) == SUCCESS) {
3063        RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
3064    }
3065    RETURN_NULL();
3066}
3067/* }}} */
3068
3069
3070/* {{{ proto string SoapClient::__getLastResponseHeaders(void)
3071   Returns last SOAP response headers */
3072PHP_METHOD(SoapClient, __getLastResponseHeaders)
3073{
3074    zval **tmp;
3075
3076    if (zend_parse_parameters_none() == FAILURE) {
3077        return;
3078    }
3079
3080    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__last_response_headers", sizeof("__last_response_headers"), (void **)&tmp) == SUCCESS) {
3081        RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
3082    }
3083    RETURN_NULL();
3084}
3085/* }}} */
3086
3087
3088/* {{{ proto string SoapClient::__doRequest()
3089   SoapClient::__doRequest() */
3090PHP_METHOD(SoapClient, __doRequest)
3091{
3092  char *buf, *location, *action;
3093  int   buf_size, location_size, action_size;
3094  long  version;
3095  long  one_way = 0;
3096
3097    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sssl|l",
3098        &buf, &buf_size,
3099        &location, &location_size,
3100        &action, &action_size,
3101        &version, &one_way) == FAILURE) {
3102        return;
3103    }
3104    if (SOAP_GLOBAL(features) & SOAP_WAIT_ONE_WAY_CALLS) {
3105        one_way = 0;
3106    }
3107    if (one_way) {
3108        if (make_http_soap_request(this_ptr, buf, buf_size, location, action, version, NULL, NULL TSRMLS_CC)) {
3109            RETURN_EMPTY_STRING();
3110        }
3111    } else if (make_http_soap_request(this_ptr, buf, buf_size, location, action, version,
3112        &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value) TSRMLS_CC)) {
3113        return_value->type = IS_STRING;
3114        return;
3115    }
3116    RETURN_NULL();
3117}
3118/* }}} */
3119
3120/* {{{ proto void SoapClient::__setCookie(string name [, strung value])
3121   Sets cookie thet will sent with SOAP request.
3122   The call to this function will effect all folowing calls of SOAP methods.
3123   If value is not specified cookie is removed. */
3124PHP_METHOD(SoapClient, __setCookie)
3125{
3126    char *name;
3127    char *val = NULL;
3128    int  name_len, val_len = 0;
3129    zval **cookies;
3130
3131    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &name, &name_len, &val, &val_len) == FAILURE) {
3132        return;
3133    }
3134
3135    if (val == NULL) {
3136        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) == SUCCESS) {
3137            zend_hash_del(Z_ARRVAL_PP(cookies), name, name_len+1);
3138        }
3139    } else {
3140        zval *zcookie;
3141
3142        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) == FAILURE) {
3143            zval *tmp_cookies;
3144
3145            MAKE_STD_ZVAL(tmp_cookies);
3146            array_init(tmp_cookies);
3147            zend_hash_update(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), &tmp_cookies, sizeof(zval *), (void **)&cookies);
3148        }
3149
3150        ALLOC_INIT_ZVAL(zcookie);
3151        array_init(zcookie);
3152        add_index_stringl(zcookie, 0, val, val_len, 1);
3153        add_assoc_zval_ex(*cookies, name, name_len+1, zcookie);
3154    }
3155}
3156/* }}} */
3157
3158/* {{{ proto array SoapClient::__getCookies ( void )
3159   Returns list of cookies */
3160PHP_METHOD(SoapClient, __getCookies)
3161{
3162    zval **cookies, *tmp;
3163
3164    if (zend_parse_parameters_none() == FAILURE) {
3165        return;
3166    }
3167
3168    array_init(return_value);
3169
3170    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) != FAILURE) {
3171        zend_hash_copy(Z_ARRVAL_P(return_value), Z_ARRVAL_P(*cookies), (copy_ctor_func_t) zval_add_ref, (void *)&tmp, sizeof(zval*));
3172    }
3173}
3174/* }}} */
3175
3176/* {{{ proto void SoapClient::__setSoapHeaders(array SoapHeaders)
3177   Sets SOAP headers for subsequent calls (replaces any previous
3178   values).
3179   If no value is specified, all of the headers are removed. */
3180PHP_METHOD(SoapClient, __setSoapHeaders)
3181{
3182    zval *headers = NULL;
3183
3184    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z", &headers) == FAILURE) {
3185        return;
3186    }
3187
3188    if (headers == NULL || Z_TYPE_P(headers) == IS_NULL) {
3189        zend_hash_del(Z_OBJPROP_P(this_ptr), "__default_headers", sizeof("__default_headers"));
3190    } else if (Z_TYPE_P(headers) == IS_ARRAY) {
3191        zval *default_headers;
3192
3193        verify_soap_headers_array(Z_ARRVAL_P(headers) TSRMLS_CC);
3194        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__default_headers", sizeof("__default_headers"), (void **) &default_headers)==FAILURE) {
3195            add_property_zval(this_ptr, "__default_headers", headers);
3196        }
3197    } else if (Z_TYPE_P(headers) == IS_OBJECT &&
3198               instanceof_function(Z_OBJCE_P(headers), soap_header_class_entry TSRMLS_CC)) {
3199        zval *default_headers;
3200        ALLOC_INIT_ZVAL(default_headers);
3201        array_init(default_headers);
3202        Z_ADDREF_P(headers);
3203        add_next_index_zval(default_headers, headers);
3204        Z_DELREF_P(default_headers);
3205        add_property_zval(this_ptr, "__default_headers", default_headers);
3206    } else{
3207        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid SOAP header");
3208    }
3209    RETURN_TRUE;
3210}
3211/* }}} */
3212
3213
3214
3215/* {{{ proto string SoapClient::__setLocation([string new_location])
3216   Sets the location option (the endpoint URL that will be touched by the
3217   following SOAP requests).
3218   If new_location is not specified or null then SoapClient will use endpoint
3219   from WSDL file.
3220   The function returns old value of location options. */
3221PHP_METHOD(SoapClient, __setLocation)
3222{
3223    char *location = NULL;
3224    int  location_len = 0;
3225    zval **tmp;
3226
3227    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &location, &location_len) == FAILURE) {
3228        return;
3229    }
3230
3231    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "location", sizeof("location"),(void **) &tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) {
3232        RETVAL_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
3233    } else {
3234      RETVAL_NULL();
3235    }
3236
3237    if (location && location_len) {
3238        add_property_stringl(this_ptr, "location", location, location_len, 1);
3239    } else {
3240        zend_hash_del(Z_OBJPROP_P(this_ptr), "location", sizeof("location"));
3241    }
3242}
3243/* }}} */
3244
3245static void clear_soap_fault(zval *obj TSRMLS_DC)
3246{
3247    if (obj != NULL && obj->type == IS_OBJECT) {
3248        zend_hash_del(Z_OBJPROP_P(obj), "__soap_fault", sizeof("__soap_fault"));
3249    }
3250}
3251
3252zval* add_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail TSRMLS_DC)
3253{
3254    zval *fault;
3255    ALLOC_INIT_ZVAL(fault);
3256    set_soap_fault(fault, NULL, fault_code, fault_string, fault_actor, fault_detail, NULL TSRMLS_CC);
3257    Z_DELREF_P(fault);
3258
3259    add_property_zval(obj, "__soap_fault", fault);
3260    return fault;
3261}
3262
3263static 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)
3264{
3265    if (Z_TYPE_P(obj) != IS_OBJECT) {
3266        object_init_ex(obj, soap_fault_class_entry);
3267    }
3268
3269    add_property_string(obj, "faultstring", fault_string ? fault_string : "", 1);
3270    zend_update_property_string(zend_exception_get_default(TSRMLS_C), obj, "message", sizeof("message")-1, (fault_string ? fault_string : "") TSRMLS_CC);
3271
3272    if (fault_code != NULL) {
3273        int soap_version = SOAP_GLOBAL(soap_version);
3274
3275        if (fault_code_ns) {
3276            add_property_string(obj, "faultcode", fault_code, 1);
3277            add_property_string(obj, "faultcodens", fault_code_ns, 1);
3278        } else {
3279            if (soap_version == SOAP_1_1) {
3280                add_property_string(obj, "faultcode", fault_code, 1);
3281                if (strcmp(fault_code,"Client") == 0 ||
3282                    strcmp(fault_code,"Server") == 0 ||
3283                    strcmp(fault_code,"VersionMismatch") == 0 ||
3284                  strcmp(fault_code,"MustUnderstand") == 0) {
3285                    add_property_string(obj, "faultcodens", SOAP_1_1_ENV_NAMESPACE, 1);
3286                }
3287            } else if (soap_version == SOAP_1_2) {
3288                if (strcmp(fault_code,"Client") == 0) {
3289                    add_property_string(obj, "faultcode", "Sender", 1);
3290                    add_property_string(obj, "faultcodens", SOAP_1_2_ENV_NAMESPACE, 1);
3291                } else if (strcmp(fault_code,"Server") == 0) {
3292                    add_property_string(obj, "faultcode", "Receiver", 1);
3293                    add_property_string(obj, "faultcodens", SOAP_1_2_ENV_NAMESPACE, 1);
3294                } else if (strcmp(fault_code,"VersionMismatch") == 0 ||
3295                           strcmp(fault_code,"MustUnderstand") == 0 ||
3296                           strcmp(fault_code,"DataEncodingUnknown") == 0) {
3297                    add_property_string(obj, "faultcode", fault_code, 1);
3298                    add_property_string(obj, "faultcodens", SOAP_1_2_ENV_NAMESPACE, 1);
3299                } else {
3300                    add_property_string(obj, "faultcode", fault_code, 1);
3301                }
3302            }
3303        }
3304    }
3305    if (fault_actor != NULL) {
3306        add_property_string(obj, "faultactor", fault_actor, 1);
3307    }
3308    if (fault_detail != NULL) {
3309        add_property_zval(obj, "detail", fault_detail);
3310    }
3311    if (name != NULL) {
3312        add_property_string(obj, "_name", name, 1);
3313    }
3314}
3315
3316static void deserialize_parameters(xmlNodePtr params, sdlFunctionPtr function, int *num_params, zval ***parameters TSRMLS_DC)
3317{
3318    int cur_param = 0,num_of_params = 0;
3319    zval **tmp_parameters = NULL;
3320
3321    if (function != NULL) {
3322        sdlParamPtr *param;
3323        xmlNodePtr val;
3324        int use_names = 0;
3325
3326        if (function->requestParameters == NULL) {
3327            return;
3328        }
3329        num_of_params = zend_hash_num_elements(function->requestParameters);
3330        zend_hash_internal_pointer_reset(function->requestParameters);
3331        while (zend_hash_get_current_data(function->requestParameters, (void **)&param) == SUCCESS) {
3332            if (get_node(params, (*param)->paramName) != NULL) {
3333                use_names = 1;
3334            }
3335            zend_hash_move_forward(function->requestParameters);
3336        }
3337        if (use_names) {
3338            tmp_parameters = safe_emalloc(num_of_params, sizeof(zval *), 0);
3339            zend_hash_internal_pointer_reset(function->requestParameters);
3340            while (zend_hash_get_current_data(function->requestParameters, (void **)&param) == SUCCESS) {
3341                val = get_node(params, (*param)->paramName);
3342                if (!val) {
3343                    /* TODO: may be "nil" is not OK? */
3344                    MAKE_STD_ZVAL(tmp_parameters[cur_param]);
3345                    ZVAL_NULL(tmp_parameters[cur_param]);
3346                } else {
3347                    tmp_parameters[cur_param] = master_to_zval((*param)->encode, val TSRMLS_CC);
3348                }
3349                cur_param++;
3350
3351                zend_hash_move_forward(function->requestParameters);
3352            }
3353            (*parameters) = tmp_parameters;
3354            (*num_params) = num_of_params;
3355            return;
3356        }
3357    }
3358    if (params) {
3359        xmlNodePtr trav;
3360
3361        num_of_params = 0;
3362        trav = params;
3363        while (trav != NULL) {
3364            if (trav->type == XML_ELEMENT_NODE) {
3365                num_of_params++;
3366            }
3367            trav = trav->next;
3368        }
3369
3370        if (num_of_params == 1 &&
3371            function &&
3372            function->binding &&
3373            function->binding->bindingType == BINDING_SOAP &&
3374            ((sdlSoapBindingFunctionPtr)function->bindingAttributes)->style == SOAP_DOCUMENT &&
3375            (function->requestParameters == NULL ||
3376             zend_hash_num_elements(function->requestParameters) == 0) &&
3377            strcmp((char *)params->name, function->functionName) == 0) {
3378            num_of_params = 0;
3379        } else if (num_of_params > 0) {
3380            tmp_parameters = safe_emalloc(num_of_params, sizeof(zval *), 0);
3381
3382            trav = params;
3383            while (trav != 0 && cur_param < num_of_params) {
3384                if (trav->type == XML_ELEMENT_NODE) {
3385                    encodePtr enc;
3386                    sdlParamPtr *param = NULL;
3387                    if (function != NULL &&
3388                        zend_hash_index_find(function->requestParameters, cur_param, (void **)&param) == FAILURE) {
3389                        TSRMLS_FETCH();
3390                        soap_server_fault("Client", "Error cannot find parameter", NULL, NULL, NULL TSRMLS_CC);
3391                    }
3392                    if (param == NULL) {
3393                        enc = NULL;
3394                    } else {
3395                        enc = (*param)->encode;
3396                    }
3397                    tmp_parameters[cur_param] = master_to_zval(enc, trav TSRMLS_CC);
3398                    cur_param++;
3399                }
3400                trav = trav->next;
3401            }
3402        }
3403    }
3404    if (num_of_params > cur_param) {
3405        soap_server_fault("Client","Missing parameter", NULL, NULL, NULL TSRMLS_CC);
3406    }
3407    (*parameters) = tmp_parameters;
3408    (*num_params) = num_of_params;
3409}
3410
3411static sdlFunctionPtr find_function(sdlPtr sdl, xmlNodePtr func, zval* function_name)
3412{
3413    sdlFunctionPtr function;
3414
3415    function = get_function(sdl, (char*)func->name);
3416    if (function && function->binding && function->binding->bindingType == BINDING_SOAP) {
3417        sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3418        if (fnb->style == SOAP_DOCUMENT) {
3419            if (func->children != NULL ||
3420                (function->requestParameters != NULL &&
3421                 zend_hash_num_elements(function->requestParameters) > 0)) {
3422                function = NULL;
3423            }
3424        }
3425    }
3426    if (sdl != NULL && function == NULL) {
3427        function = get_doc_function(sdl, func);
3428    }
3429
3430    INIT_ZVAL(*function_name);
3431    if (function != NULL) {
3432        ZVAL_STRING(function_name, (char *)function->functionName, 1);
3433    } else {
3434        ZVAL_STRING(function_name, (char *)func->name, 1);
3435    }
3436
3437    return function;
3438}
3439
3440static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, char* actor, zval *function_name, int *num_params, zval ***parameters, int *version, soapHeader **headers TSRMLS_DC)
3441{
3442    char* envelope_ns = NULL;
3443    xmlNodePtr trav,env,head,body,func;
3444    xmlAttrPtr attr;
3445    sdlFunctionPtr function;
3446
3447    encode_reset_ns();
3448
3449    /* Get <Envelope> element */
3450    env = NULL;
3451    trav = request->children;
3452    while (trav != NULL) {
3453        if (trav->type == XML_ELEMENT_NODE) {
3454            if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_1_ENV_NAMESPACE)) {
3455                env = trav;
3456                *version = SOAP_1_1;
3457                envelope_ns = SOAP_1_1_ENV_NAMESPACE;
3458                SOAP_GLOBAL(soap_version) = SOAP_1_1;
3459            } else if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_2_ENV_NAMESPACE)) {
3460                env = trav;
3461                *version = SOAP_1_2;
3462                envelope_ns = SOAP_1_2_ENV_NAMESPACE;
3463                SOAP_GLOBAL(soap_version) = SOAP_1_2;
3464            } else {
3465                soap_server_fault("VersionMismatch", "Wrong Version", NULL, NULL, NULL TSRMLS_CC);
3466            }
3467        }
3468        trav = trav->next;
3469    }
3470    if (env == NULL) {
3471        soap_server_fault("Client", "looks like we got XML without \"Envelope\" element", NULL, NULL, NULL TSRMLS_CC);
3472    }
3473
3474    attr = env->properties;
3475    while (attr != NULL) {
3476        if (attr->ns == NULL) {
3477            soap_server_fault("Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL, NULL TSRMLS_CC);
3478        } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
3479            if (*version == SOAP_1_2) {
3480                soap_server_fault("Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL, NULL TSRMLS_CC);
3481            } else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3482                soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL TSRMLS_CC);
3483            }
3484        }
3485        attr = attr->next;
3486    }
3487
3488    /* Get <Header> element */
3489    head = NULL;
3490    trav = env->children;
3491    while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
3492        trav = trav->next;
3493    }
3494    if (trav != NULL && node_is_equal_ex(trav,"Header",envelope_ns)) {
3495        head = trav;
3496        trav = trav->next;
3497    }
3498
3499    /* Get <Body> element */
3500    body = NULL;
3501    while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
3502        trav = trav->next;
3503    }
3504    if (trav != NULL && node_is_equal_ex(trav,"Body",envelope_ns)) {
3505        body = trav;
3506        trav = trav->next;
3507    }
3508    while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
3509        trav = trav->next;
3510    }
3511    if (body == NULL) {
3512        soap_server_fault("Client", "Body must be present in a SOAP envelope", NULL, NULL, NULL TSRMLS_CC);
3513    }
3514    attr = body->properties;
3515    while (attr != NULL) {
3516        if (attr->ns == NULL) {
3517            if (*version == SOAP_1_2) {
3518                soap_server_fault("Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL, NULL TSRMLS_CC);
3519            }
3520        } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
3521            if (*version == SOAP_1_2) {
3522                soap_server_fault("Client", "encodingStyle cannot be specified on the Body", NULL, NULL, NULL TSRMLS_CC);
3523            } else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3524                soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL TSRMLS_CC);
3525            }
3526        }
3527        attr = attr->next;
3528    }
3529
3530    if (trav != NULL && *version == SOAP_1_2) {
3531        soap_server_fault("Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL, NULL TSRMLS_CC);
3532    }
3533
3534    func = NULL;
3535    trav = body->children;
3536    while (trav != NULL) {
3537        if (trav->type == XML_ELEMENT_NODE) {
3538/*
3539            if (func != NULL) {
3540                soap_server_fault("Client", "looks like we got \"Body\" with several functions call", NULL, NULL, NULL TSRMLS_CC);
3541            }
3542*/
3543            func = trav;
3544            break; /* FIXME: the rest of body is ignored */
3545        }
3546        trav = trav->next;
3547    }
3548    if (func == NULL) {
3549        function = get_doc_function(sdl, NULL);
3550        if (function != NULL) {
3551            INIT_ZVAL(*function_name);
3552            ZVAL_STRING(function_name, (char *)function->functionName, 1);
3553        } else {
3554            soap_server_fault("Client", "looks like we got \"Body\" without function call", NULL, NULL, NULL TSRMLS_CC);
3555        }
3556    } else {
3557        if (*version == SOAP_1_1) {
3558            attr = get_attribute_ex(func->properties,"encodingStyle",SOAP_1_1_ENV_NAMESPACE);
3559            if (attr && strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3560                soap_server_fault("Client","Unknown Data Encoding Style", NULL, NULL, NULL TSRMLS_CC);
3561            }
3562        } else {
3563            attr = get_attribute_ex(func->properties,"encodingStyle",SOAP_1_2_ENV_NAMESPACE);
3564            if (attr && strcmp((char*)attr->children->content,SOAP_1_2_ENC_NAMESPACE) != 0) {
3565                soap_server_fault("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL TSRMLS_CC);
3566            }
3567        }
3568        function = find_function(sdl, func, function_name);
3569        if (sdl != NULL && function == NULL) {
3570            if (*version == SOAP_1_2) {
3571                soap_server_fault("rpc:ProcedureNotPresent","Procedure not present", NULL, NULL, NULL TSRMLS_CC);
3572            } else {
3573                php_error(E_ERROR, "Procedure '%s' not present", func->name);
3574            }
3575        }
3576    }
3577
3578    *headers = NULL;
3579    if (head) {
3580        soapHeader *h, *last = NULL;
3581
3582        attr = head->properties;
3583        while (attr != NULL) {
3584            if (attr->ns == NULL) {
3585                soap_server_fault("Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL, NULL TSRMLS_CC);
3586            } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
3587                if (*version == SOAP_1_2) {
3588                    soap_server_fault("Client", "encodingStyle cannot be specified on the Header", NULL, NULL, NULL TSRMLS_CC);
3589                } else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3590                    soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL TSRMLS_CC);
3591                }
3592            }
3593            attr = attr->next;
3594        }
3595        trav = head->children;
3596        while (trav != NULL) {
3597            if (trav->type == XML_ELEMENT_NODE) {
3598                xmlNodePtr hdr_func = trav;
3599                int mustUnderstand = 0;
3600
3601                if (*version == SOAP_1_1) {
3602                    attr = get_attribute_ex(hdr_func->properties,"encodingStyle",SOAP_1_1_ENV_NAMESPACE);
3603                    if (attr && strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3604                        soap_server_fault("Client","Unknown Data Encoding Style", NULL, NULL, NULL TSRMLS_CC);
3605                    }
3606                    attr = get_attribute_ex(hdr_func->properties,"actor",envelope_ns);
3607                    if (attr != NULL) {
3608                        if (strcmp((char*)attr->children->content,SOAP_1_1_ACTOR_NEXT) != 0 &&
3609                            (actor == NULL || strcmp((char*)attr->children->content,actor) != 0)) {
3610                          goto ignore_header;
3611                        }
3612                    }
3613                } else if (*version == SOAP_1_2) {
3614                    attr = get_attribute_ex(hdr_func->properties,"encodingStyle",SOAP_1_2_ENV_NAMESPACE);
3615                    if (attr && strcmp((char*)attr->children->content,SOAP_1_2_ENC_NAMESPACE) != 0) {
3616                        soap_server_fault("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL TSRMLS_CC);
3617                    }
3618                    attr = get_attribute_ex(hdr_func->properties,"role",envelope_ns);
3619                    if (attr != NULL) {
3620                        if (strcmp((char*)attr->children->content,SOAP_1_2_ACTOR_UNLIMATERECEIVER) != 0 &&
3621                            strcmp((char*)attr->children->content,SOAP_1_2_ACTOR_NEXT) != 0 &&
3622                            (actor == NULL || strcmp((char*)attr->children->content,actor) != 0)) {
3623                          goto ignore_header;
3624                        }
3625                    }
3626                }
3627                attr = get_attribute_ex(hdr_func->properties,"mustUnderstand",envelope_ns);
3628                if (attr) {
3629                    if (strcmp((char*)attr->children->content,"1") == 0 ||
3630                        strcmp((char*)attr->children->content,"true") == 0) {
3631                        mustUnderstand = 1;
3632                    } else if (strcmp((char*)attr->children->content,"0") == 0 ||
3633                               strcmp((char*)attr->children->content,"false") == 0) {
3634                        mustUnderstand = 0;
3635                    } else {
3636                        soap_server_fault("Client","mustUnderstand value is not boolean", NULL, NULL, NULL TSRMLS_CC);
3637                    }
3638                }
3639                h = emalloc(sizeof(soapHeader));
3640                memset(h, 0, sizeof(soapHeader));
3641                h->mustUnderstand = mustUnderstand;
3642                h->function = find_function(sdl, hdr_func, &h->function_name);
3643                if (!h->function && sdl && function && function->binding && function->binding->bindingType == BINDING_SOAP) {
3644                    sdlSoapBindingFunctionHeaderPtr *hdr;
3645                    sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3646                    if (fnb->input.headers) {
3647                        smart_str key = {0};
3648
3649                        if (hdr_func->ns) {
3650                            smart_str_appends(&key, (char*)hdr_func->ns->href);
3651                            smart_str_appendc(&key, ':');
3652                        }
3653                        smart_str_appendl(&key, Z_STRVAL(h->function_name), Z_STRLEN(h->function_name));
3654                        smart_str_0(&key);
3655                        if (zend_hash_find(fnb->input.headers, key.c, key.len+1, (void**)&hdr) == SUCCESS) {
3656                            h->hdr = *hdr;
3657                        }
3658                        smart_str_free(&key);
3659                    }
3660                }
3661                if (h->hdr) {
3662                    h->num_params = 1;
3663                    h->parameters = emalloc(sizeof(zval*));
3664                    h->parameters[0] = master_to_zval(h->hdr->encode, hdr_func TSRMLS_CC);
3665                } else {
3666                    if (h->function && h->function->binding && h->function->binding->bindingType == BINDING_SOAP) {
3667                        sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)h->function->bindingAttributes;
3668                        if (fnb->style == SOAP_RPC) {
3669                            hdr_func = hdr_func->children;
3670                        }
3671                    }
3672                    deserialize_parameters(hdr_func, h->function, &h->num_params, &h->parameters TSRMLS_CC);
3673                }
3674                INIT_ZVAL(h->retval);
3675                if (last == NULL) {
3676                    *headers = h;
3677                } else {
3678                    last->next = h;
3679                }
3680                last = h;
3681            }
3682ignore_header:
3683            trav = trav->next;
3684        }
3685    }
3686
3687    if (function && function->binding && function->binding->bindingType == BINDING_SOAP) {
3688        sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3689        if (fnb->style == SOAP_RPC) {
3690            func = func->children;
3691        }
3692    } else {
3693        func = func->children;
3694    }
3695    deserialize_parameters(func, function, num_params, parameters TSRMLS_CC);
3696
3697    encode_finish();
3698
3699    return function;
3700}
3701
3702static void set_soap_header_attributes(xmlNodePtr h, HashTable *ht, int version)
3703{
3704    zval **tmp;
3705
3706    if (zend_hash_find(ht, "mustUnderstand", sizeof("mustUnderstand"), (void**)&tmp) == SUCCESS &&
3707        Z_TYPE_PP(tmp) == IS_BOOL && Z_LVAL_PP(tmp)) {
3708        if (version == SOAP_1_1) {
3709            xmlSetProp(h, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":mustUnderstand"), BAD_CAST("1"));
3710        } else {
3711            xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":mustUnderstand"), BAD_CAST("true"));
3712        }
3713    }
3714    if (zend_hash_find(ht, "actor", sizeof("actor"), (void**)&tmp) == SUCCESS) {
3715        if (Z_TYPE_PP(tmp) == IS_STRING) {
3716            if (version == SOAP_1_1) {
3717                xmlSetProp(h, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":actor"), BAD_CAST(Z_STRVAL_PP(tmp)));
3718            } else {
3719                xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(Z_STRVAL_PP(tmp)));
3720            }
3721        } else if (Z_TYPE_PP(tmp) == IS_LONG) {
3722            if (version == SOAP_1_1) {
3723                if (Z_LVAL_PP(tmp) == SOAP_ACTOR_NEXT) {
3724                    xmlSetProp(h, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":actor"), BAD_CAST(SOAP_1_1_ACTOR_NEXT));
3725                }
3726            } else {
3727                if (Z_LVAL_PP(tmp) == SOAP_ACTOR_NEXT) {
3728                    xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(SOAP_1_2_ACTOR_NEXT));
3729                } else if (Z_LVAL_PP(tmp) == SOAP_ACTOR_NONE) {
3730                    xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(SOAP_1_2_ACTOR_NONE));
3731                } else if (Z_LVAL_PP(tmp) == SOAP_ACTOR_UNLIMATERECEIVER) {
3732                    xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(SOAP_1_2_ACTOR_UNLIMATERECEIVER));
3733                }
3734            }
3735        }
3736    }
3737}
3738
3739static int serialize_response_call2(xmlNodePtr body, sdlFunctionPtr function, char *function_name, char *uri, zval *ret, int version, int main, xmlNodePtr *node TSRMLS_DC)
3740{
3741    xmlNodePtr method = NULL, param;
3742    sdlParamPtr parameter = NULL;
3743    int param_count;
3744    int style, use;
3745    xmlNsPtr ns = NULL;
3746
3747    if (function != NULL && function->binding->bindingType == BINDING_SOAP) {
3748        sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3749
3750        style = fnb->style;
3751        use = fnb->output.use;
3752        if (style == SOAP_RPC) {
3753            ns = encode_add_ns(body, fnb->output.ns);
3754            if (function->responseName) {
3755                method = xmlNewChild(body, ns, BAD_CAST(function->responseName), NULL);
3756            } else if (function->responseParameters) {
3757                method = xmlNewChild(body, ns, BAD_CAST(function->functionName), NULL);
3758            }
3759        }
3760    } else {
3761        style = main?SOAP_RPC:SOAP_DOCUMENT;
3762        use = main?SOAP_ENCODED:SOAP_LITERAL;
3763        if (style == SOAP_RPC) {
3764            ns = encode_add_ns(body, uri);
3765            method = xmlNewChild(body, ns, BAD_CAST(function_name), NULL);
3766        }
3767    }
3768
3769    if (function != NULL) {
3770        if (function->responseParameters) {
3771            param_count = zend_hash_num_elements(function->responseParameters);
3772        } else {
3773          param_count = 0;
3774        }
3775    } else {
3776      param_count = 1;
3777    }
3778
3779    if (param_count == 1) {
3780        parameter = get_param(function, NULL, 0, TRUE);
3781
3782        if (style == SOAP_RPC) {
3783          xmlNode *rpc_result;
3784            if (main && version == SOAP_1_2) {
3785                xmlNs *rpc_ns = xmlNewNs(body, BAD_CAST(RPC_SOAP12_NAMESPACE), BAD_CAST(RPC_SOAP12_NS_PREFIX));
3786                rpc_result = xmlNewChild(method, rpc_ns, BAD_CAST("result"), NULL);
3787                param = serialize_parameter(parameter, ret, 0, "return", use, method TSRMLS_CC);
3788                xmlNodeSetContent(rpc_result,param->name);
3789            } else {
3790                param = serialize_parameter(parameter, ret, 0, "return", use, method TSRMLS_CC);
3791            }
3792        } else {
3793            param = serialize_parameter(parameter, ret, 0, "return", use, body TSRMLS_CC);
3794            if (function && function->binding->bindingType == BINDING_SOAP) {
3795                if (parameter && parameter->element) {
3796                    ns = encode_add_ns(param, parameter->element->namens);
3797                    xmlNodeSetName(param, BAD_CAST(parameter->element->name));
3798                    xmlSetNs(param, ns);
3799                }
3800            } else if (strcmp((char*)param->name,"return") == 0) {
3801                ns = encode_add_ns(param, uri);
3802                xmlNodeSetName(param, BAD_CAST(function_name));
3803                xmlSetNs(param, ns);
3804            }
3805        }
3806    } else if (param_count > 1 && Z_TYPE_P(ret) == IS_ARRAY) {
3807        HashPosition pos;
3808        zval **data;
3809        int i = 0;
3810
3811        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ret), &pos);
3812        while (zend_hash_get_current_data_ex(Z_ARRVAL_P(ret), (void **)&data, &pos) != FAILURE) {
3813            char *param_name = NULL;
3814            unsigned int param_name_len;
3815            ulong param_index = i;
3816
3817            zend_hash_get_current_key_ex(Z_ARRVAL_P(ret), &param_name, &param_name_len, &param_index, 0, &pos);
3818            parameter = get_param(function, param_name, param_index, TRUE);
3819            if (style == SOAP_RPC) {
3820                param = serialize_parameter(parameter, *data, i, param_name, use, method TSRMLS_CC);
3821            } else {
3822                param = serialize_parameter(parameter, *data, i, param_name, use, body TSRMLS_CC);
3823                if (function && function->binding->bindingType == BINDING_SOAP) {
3824                    if (parameter && parameter->element) {
3825                        ns = encode_add_ns(param, parameter->element->namens);
3826                        xmlNodeSetName(param, BAD_CAST(parameter->element->name));
3827                        xmlSetNs(param, ns);
3828                    }
3829                }
3830            }
3831
3832            zend_hash_move_forward_ex(Z_ARRVAL_P(ret), &pos);
3833            i++;
3834        }
3835    }
3836    if (use == SOAP_ENCODED && version == SOAP_1_2 && method != NULL) {
3837        xmlSetNsProp(method, body->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
3838    }
3839    if (node) {
3840        *node = method;
3841    }
3842    return use;
3843}
3844
3845static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function_name, char *uri, zval *ret, soapHeader* headers, int version TSRMLS_DC)
3846{
3847    xmlDocPtr doc;
3848    xmlNodePtr envelope = NULL, body, param;
3849    xmlNsPtr ns = NULL;
3850    int use = SOAP_LITERAL;
3851    xmlNodePtr head = NULL;
3852
3853    encode_reset_ns();
3854
3855    doc = xmlNewDoc(BAD_CAST("1.0"));
3856    doc->charset = XML_CHAR_ENCODING_UTF8;
3857    doc->encoding = xmlCharStrdup("UTF-8");
3858
3859    if (version == SOAP_1_1) {
3860        envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
3861        ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENV_NAMESPACE), BAD_CAST(SOAP_1_1_ENV_NS_PREFIX));
3862        xmlSetNs(envelope,ns);
3863    } else if (version == SOAP_1_2) {
3864        envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
3865        ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENV_NAMESPACE), BAD_CAST(SOAP_1_2_ENV_NS_PREFIX));
3866        xmlSetNs(envelope,ns);
3867    } else {
3868        soap_server_fault("Server", "Unknown SOAP version", NULL, NULL, NULL TSRMLS_CC);
3869    }
3870    xmlDocSetRootElement(doc, envelope);
3871
3872    if (Z_TYPE_P(ret) == IS_OBJECT &&
3873        instanceof_function(Z_OBJCE_P(ret), soap_fault_class_entry TSRMLS_CC)) {
3874      char *detail_name;
3875        HashTable* prop;
3876        zval **tmp;
3877        sdlFaultPtr fault = NULL;
3878        char *fault_ns = NULL;
3879
3880        prop = Z_OBJPROP_P(ret);
3881
3882        if (headers &&
3883            zend_hash_find(prop, "headerfault", sizeof("headerfault"), (void**)&tmp) == SUCCESS) {
3884            encodePtr hdr_enc = NULL;
3885            int hdr_use = SOAP_LITERAL;
3886            zval *hdr_ret  = *tmp;
3887            char *hdr_ns   = headers->hdr?headers->hdr->ns:NULL;
3888            char *hdr_name = Z_STRVAL(headers->function_name);
3889
3890            head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL);
3891            if (Z_TYPE_P(hdr_ret) == IS_OBJECT &&
3892                instanceof_function(Z_OBJCE_P(hdr_ret), soap_header_class_entry TSRMLS_CC)) {
3893                HashTable* ht = Z_OBJPROP_P(hdr_ret);
3894                sdlSoapBindingFunctionHeaderPtr *hdr;
3895                smart_str key = {0};
3896
3897                if (zend_hash_find(ht, "namespace", sizeof("namespace"), (void**)&tmp) == SUCCESS &&
3898                  Z_TYPE_PP(tmp) == IS_STRING) {
3899                    smart_str_appendl(&key, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
3900                    smart_str_appendc(&key, ':');
3901                    hdr_ns = Z_STRVAL_PP(tmp);
3902                }
3903                if (zend_hash_find(ht, "name", sizeof("name"), (void**)&tmp) == SUCCESS &&
3904                    Z_TYPE_PP(tmp) == IS_STRING) {
3905                    smart_str_appendl(&key, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
3906                    hdr_name = Z_STRVAL_PP(tmp);
3907                }
3908                smart_str_0(&key);
3909                if (headers->hdr && headers->hdr->headerfaults &&
3910                    zend_hash_find(headers->hdr->headerfaults, key.c, key.len+1, (void**)&hdr) == SUCCESS) {
3911                    hdr_enc = (*hdr)->encode;
3912                    hdr_use = (*hdr)->use;
3913                }
3914                smart_str_free(&key);
3915                if (zend_hash_find(ht, "data", sizeof("data"), (void**)&tmp) == SUCCESS) {
3916                    hdr_ret = *tmp;
3917                } else {
3918                    hdr_ret = NULL;
3919                }
3920            }
3921
3922            if (headers->function) {
3923                if (serialize_response_call2(head, headers->function, Z_STRVAL(headers->function_name), uri, hdr_ret, version, 0, NULL TSRMLS_CC) == SOAP_ENCODED) {
3924                    use = SOAP_ENCODED;
3925                }
3926            } else {
3927                xmlNodePtr xmlHdr = master_to_xml(hdr_enc, hdr_ret, hdr_use, head TSRMLS_CC);
3928                if (hdr_name) {
3929                    xmlNodeSetName(xmlHdr, BAD_CAST(hdr_name));
3930                }
3931                if (hdr_ns) {
3932                    xmlNsPtr nsptr = encode_add_ns(xmlHdr, hdr_ns);
3933                    xmlSetNs(xmlHdr, nsptr);
3934                }
3935            }
3936        }
3937
3938        body = xmlNewChild(envelope, ns, BAD_CAST("Body"), NULL);
3939        param = xmlNewChild(body, ns, BAD_CAST("Fault"), NULL);
3940
3941        if (zend_hash_find(prop, "faultcodens", sizeof("faultcodens"), (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) {
3942            fault_ns = Z_STRVAL_PP(tmp);
3943        }
3944        use = SOAP_LITERAL;
3945        if (zend_hash_find(prop, "_name", sizeof("_name"), (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) {
3946            sdlFaultPtr *tmp_fault;
3947            if (function && function->faults &&
3948                zend_hash_find(function->faults, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)+1, (void**)&tmp_fault) == SUCCESS) {
3949              fault = *tmp_fault;
3950                if (function->binding &&
3951                    function->binding->bindingType == BINDING_SOAP &&
3952                    fault->bindingAttributes) {
3953                    sdlSoapBindingFunctionFaultPtr fb = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
3954                    use = fb->use;
3955                    if (fault_ns == NULL) {
3956                        fault_ns = fb->ns;
3957                    }
3958                }
3959            }
3960        } else if (function && function->faults &&
3961                   zend_hash_num_elements(function->faults) == 1) {
3962
3963            zend_hash_internal_pointer_reset(function->faults);
3964            zend_hash_get_current_data(function->faults, (void**)&fault);
3965            fault = *(sdlFaultPtr*)fault;
3966            if (function->binding &&
3967                function->binding->bindingType == BINDING_SOAP &&
3968                fault->bindingAttributes) {
3969                sdlSoapBindingFunctionFaultPtr fb = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
3970                use = fb->use;
3971                if (fault_ns == NULL) {
3972                  fault_ns = fb->ns;
3973                }
3974            }
3975        }
3976
3977        if (fault_ns == NULL &&
3978            fault &&
3979            fault->details &&
3980            zend_hash_num_elements(fault->details) == 1) {
3981            sdlParamPtr sparam;
3982
3983            zend_hash_internal_pointer_reset(fault->details);
3984            zend_hash_get_current_data(fault->details, (void**)&sparam);
3985            sparam = *(sdlParamPtr*)sparam;
3986            if (sparam->element) {
3987                fault_ns = sparam->element->namens;
3988            }
3989        }
3990
3991        if (version == SOAP_1_1) {
3992            if (zend_hash_find(prop, "faultcode", sizeof("faultcode"), (void**)&tmp) == SUCCESS) {
3993                size_t new_len;
3994                xmlNodePtr node = xmlNewNode(NULL, BAD_CAST("faultcode"));
3995                char *str = php_escape_html_entities((unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), &new_len, 0, 0, NULL TSRMLS_CC);
3996                xmlAddChild(param, node);
3997                if (fault_ns) {
3998                    xmlNsPtr nsptr = encode_add_ns(node, fault_ns);
3999                    xmlChar *code = xmlBuildQName(BAD_CAST(str), nsptr->prefix, NULL, 0);
4000                    xmlNodeSetContent(node, code);
4001                    xmlFree(code);
4002                } else {
4003                    xmlNodeSetContentLen(node, BAD_CAST(str), (int)new_len);
4004                }
4005                efree(str);
4006            }
4007            if (zend_hash_find(prop, "faultstring", sizeof("faultstring"), (void**)&tmp) == SUCCESS) {
4008                xmlNodePtr node = master_to_xml(get_conversion(IS_STRING), *tmp, SOAP_LITERAL, param TSRMLS_CC);
4009                xmlNodeSetName(node, BAD_CAST("faultstring"));
4010            }
4011            if (zend_hash_find(prop, "faultactor", sizeof("faultactor"), (void**)&tmp) == SUCCESS) {
4012                xmlNodePtr node = master_to_xml(get_conversion(IS_STRING), *tmp, SOAP_LITERAL, param TSRMLS_CC);
4013                xmlNodeSetName(node, BAD_CAST("faultactor"));
4014            }
4015            detail_name = "detail";
4016        } else {
4017            if (zend_hash_find(prop, "faultcode", sizeof("faultcode"), (void**)&tmp) == SUCCESS) {
4018                size_t new_len;
4019                xmlNodePtr node = xmlNewChild(param, ns, BAD_CAST("Code"), NULL);
4020                char *str = php_escape_html_entities((unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), &new_len, 0, 0, NULL TSRMLS_CC);
4021                node = xmlNewChild(node, ns, BAD_CAST("Value"), NULL);
4022                if (fault_ns) {
4023                    xmlNsPtr nsptr = encode_add_ns(node, fault_ns);
4024                    xmlChar *code = xmlBuildQName(BAD_CAST(str), nsptr->prefix, NULL, 0);
4025                    xmlNodeSetContent(node, code);
4026                    xmlFree(code);
4027                } else {
4028                    xmlNodeSetContentLen(node, BAD_CAST(str), (int)new_len);
4029                }
4030                efree(str);
4031            }
4032            if (zend_hash_find(prop, "faultstring", sizeof("faultstring"), (void**)&tmp) == SUCCESS) {
4033                xmlNodePtr node = xmlNewChild(param, ns, BAD_CAST("Reason"), NULL);
4034                node = master_to_xml(get_conversion(IS_STRING), *tmp, SOAP_LITERAL, node TSRMLS_CC);
4035                xmlNodeSetName(node, BAD_CAST("Text"));
4036                xmlSetNs(node, ns);
4037            }
4038            detail_name = SOAP_1_2_ENV_NS_PREFIX":Detail";
4039        }
4040        if (fault && fault->details && zend_hash_num_elements(fault->details) == 1) {
4041            xmlNodePtr node;
4042            zval *detail = NULL;
4043            sdlParamPtr sparam;
4044            xmlNodePtr x;
4045
4046            if (zend_hash_find(prop, "detail", sizeof("detail"), (void**)&tmp) == SUCCESS &&
4047                Z_TYPE_PP(tmp) != IS_NULL) {
4048                detail = *tmp;
4049            }
4050            node = xmlNewNode(NULL, BAD_CAST(detail_name));
4051            xmlAddChild(param, node);
4052
4053            zend_hash_internal_pointer_reset(fault->details);
4054            zend_hash_get_current_data(fault->details, (void**)&sparam);
4055            sparam = *(sdlParamPtr*)sparam;
4056
4057            if (detail &&
4058                Z_TYPE_P(detail) == IS_OBJECT &&
4059                sparam->element &&
4060                zend_hash_num_elements(Z_OBJPROP_P(detail)) == 1 &&
4061                zend_hash_find(Z_OBJPROP_P(detail), sparam->element->name, strlen(sparam->element->name)+1, (void**)&tmp) == SUCCESS) {
4062                detail = *tmp;
4063            }
4064
4065            x = serialize_parameter(sparam, detail, 1, NULL, use, node TSRMLS_CC);
4066
4067            if (function &&
4068                function->binding &&
4069                function->binding->bindingType == BINDING_SOAP &&
4070                function->bindingAttributes) {
4071                sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
4072                if (fnb->style == SOAP_RPC && !sparam->element) {
4073                  if (fault->bindingAttributes) {
4074                        sdlSoapBindingFunctionFaultPtr fb = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
4075                        if (fb->ns) {
4076                            xmlNsPtr ns = encode_add_ns(x, fb->ns);
4077                            xmlSetNs(x, ns);
4078                        }
4079                    }
4080                } else {
4081                    if (sparam->element) {
4082                        ns = encode_add_ns(x, sparam->element->namens);
4083                        xmlNodeSetName(x, BAD_CAST(sparam->element->name));
4084                        xmlSetNs(x, ns);
4085                    }
4086                }
4087            }
4088            if (use == SOAP_ENCODED && version == SOAP_1_2) {
4089                xmlSetNsProp(x, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
4090            }
4091        } else if (zend_hash_find(prop, "detail", sizeof("detail"), (void**)&tmp) == SUCCESS &&
4092            Z_TYPE_PP(tmp) != IS_NULL) {
4093            serialize_zval(*tmp, NULL, detail_name, use, param TSRMLS_CC);
4094        }
4095    } else {
4096
4097        if (headers) {
4098            soapHeader *h;
4099
4100            head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL);
4101            h = headers;
4102            while (h != NULL) {
4103                if (Z_TYPE(h->retval) != IS_NULL) {
4104                    encodePtr hdr_enc = NULL;
4105                    int hdr_use = SOAP_LITERAL;
4106                    zval *hdr_ret = &h->retval;
4107                    char *hdr_ns   = h->hdr?h->hdr->ns:NULL;
4108                    char *hdr_name = Z_STRVAL(h->function_name);
4109                    HashTable *ht = NULL;
4110
4111                    if (Z_TYPE(h->retval) == IS_OBJECT &&
4112                        instanceof_function(Z_OBJCE(h->retval), soap_header_class_entry TSRMLS_CC)) {
4113                        zval **tmp;
4114                        sdlSoapBindingFunctionHeaderPtr *hdr;
4115                        smart_str key = {0};
4116
4117                        ht = Z_OBJPROP(h->retval);
4118                        if (zend_hash_find(ht, "namespace", sizeof("namespace"), (void**)&tmp) == SUCCESS &&
4119                          Z_TYPE_PP(tmp) == IS_STRING) {
4120                            smart_str_appendl(&key, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
4121                            smart_str_appendc(&key, ':');
4122                            hdr_ns = Z_STRVAL_PP(tmp);
4123                        }
4124                        if (zend_hash_find(ht, "name", sizeof("name"), (void**)&tmp) == SUCCESS &&
4125                            Z_TYPE_PP(tmp) == IS_STRING) {
4126                            smart_str_appendl(&key, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
4127                            hdr_name = Z_STRVAL_PP(tmp);
4128                        }
4129                        smart_str_0(&key);
4130                        if (function && function->binding && function->binding->bindingType == BINDING_SOAP) {
4131                            sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
4132
4133                            if (fnb->output.headers &&
4134                                zend_hash_find(fnb->output.headers, key.c, key.len+1, (void**)&hdr) == SUCCESS) {
4135                                hdr_enc = (*hdr)->encode;
4136                                hdr_use = (*hdr)->use;
4137                            }
4138                        }
4139                        smart_str_free(&key);
4140                        if (zend_hash_find(ht, "data", sizeof("data"), (void**)&tmp) == SUCCESS) {
4141                            hdr_ret = *tmp;
4142                        } else {
4143                            hdr_ret = NULL;
4144                        }
4145                    }
4146
4147                    if (h->function) {
4148                        xmlNodePtr xmlHdr = NULL;
4149
4150                        if (serialize_response_call2(head, h->function, Z_STRVAL(h->function_name), uri, hdr_ret, version, 0, &xmlHdr TSRMLS_CC) == SOAP_ENCODED) {
4151                            use = SOAP_ENCODED;
4152                        }
4153                        if (ht) {
4154                            set_soap_header_attributes(xmlHdr, ht, version);
4155                        }
4156                    } else {
4157                        xmlNodePtr xmlHdr = master_to_xml(hdr_enc, hdr_ret, hdr_use, head TSRMLS_CC);
4158                        if (hdr_name) {
4159                            xmlNodeSetName(xmlHdr, BAD_CAST(hdr_name));
4160                        }
4161                        if (hdr_ns) {
4162                            xmlNsPtr nsptr = encode_add_ns(xmlHdr,hdr_ns);
4163                            xmlSetNs(xmlHdr, nsptr);
4164                        }
4165                        if (ht) {
4166                            set_soap_header_attributes(xmlHdr, ht, version);
4167                        }
4168                    }
4169                }
4170                h = h->next;
4171            }
4172
4173            if (head->children == NULL) {
4174                xmlUnlinkNode(head);
4175                xmlFreeNode(head);
4176            }
4177        }
4178
4179        body = xmlNewChild(envelope, ns, BAD_CAST("Body"), NULL);
4180
4181        if (serialize_response_call2(body, function, function_name, uri, ret, version, 1, NULL TSRMLS_CC) == SOAP_ENCODED) {
4182            use = SOAP_ENCODED;
4183        }
4184
4185    }
4186
4187    if (use == SOAP_ENCODED) {
4188        xmlNewNs(envelope, BAD_CAST(XSD_NAMESPACE), BAD_CAST(XSD_NS_PREFIX));
4189        if (version == SOAP_1_1) {
4190            xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENC_NAMESPACE), BAD_CAST(SOAP_1_1_ENC_NS_PREFIX));
4191            xmlSetNsProp(envelope, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_1_ENC_NAMESPACE));
4192        } else if (version == SOAP_1_2) {
4193            xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENC_NAMESPACE), BAD_CAST(SOAP_1_2_ENC_NS_PREFIX));
4194        }
4195    }
4196
4197    encode_finish();
4198
4199    if (function && function->responseName == NULL &&
4200        body->children == NULL && head == NULL) {
4201        xmlFreeDoc(doc);
4202        return NULL;
4203    }
4204    return doc;
4205}
4206
4207static 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)
4208{
4209    xmlDoc *doc;
4210    xmlNodePtr envelope = NULL, body, method = NULL, head = NULL;
4211    xmlNsPtr ns = NULL;
4212    zval **zstyle, **zuse;
4213    int i, style, use;
4214    HashTable *hdrs = NULL;
4215
4216    encode_reset_ns();
4217
4218    doc = xmlNewDoc(BAD_CAST("1.0"));
4219    doc->encoding = xmlCharStrdup("UTF-8");
4220    doc->charset = XML_CHAR_ENCODING_UTF8;
4221    if (version == SOAP_1_1) {
4222        envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
4223        ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENV_NAMESPACE), BAD_CAST(SOAP_1_1_ENV_NS_PREFIX));
4224        xmlSetNs(envelope, ns);
4225    } else if (version == SOAP_1_2) {
4226        envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
4227        ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENV_NAMESPACE), BAD_CAST(SOAP_1_2_ENV_NS_PREFIX));
4228        xmlSetNs(envelope, ns);
4229    } else {
4230        soap_error0(E_ERROR, "Unknown SOAP version");
4231    }
4232    xmlDocSetRootElement(doc, envelope);
4233
4234    if (soap_headers) {
4235        head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL);
4236    }
4237
4238    body = xmlNewChild(envelope, ns, BAD_CAST("Body"), NULL);
4239
4240    if (function && function->binding->bindingType == BINDING_SOAP) {
4241        sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
4242
4243        hdrs = fnb->input.headers;
4244        style = fnb->style;
4245        /*FIXME: how to pass method name if style is SOAP_DOCUMENT */
4246        /*style = SOAP_RPC;*/
4247        use = fnb->input.use;
4248        if (style == SOAP_RPC) {
4249            ns = encode_add_ns(body, fnb->input.ns);
4250            if (function->requestName) {
4251                method = xmlNewChild(body, ns, BAD_CAST(function->requestName), NULL);
4252            } else {
4253                method = xmlNewChild(body, ns, BAD_CAST(function->functionName), NULL);
4254            }
4255        }
4256    } else {
4257        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "style", sizeof("style"), (void **)&zstyle) == SUCCESS) {
4258            style = Z_LVAL_PP(zstyle);
4259        } else {
4260            style = SOAP_RPC;
4261        }
4262        /*FIXME: how to pass method name if style is SOAP_DOCUMENT */
4263        /*style = SOAP_RPC;*/
4264        if (style == SOAP_RPC) {
4265            ns = encode_add_ns(body, uri);
4266            if (function_name) {
4267                method = xmlNewChild(body, ns, BAD_CAST(function_name), NULL);
4268            } else if (function && function->requestName) {
4269                method = xmlNewChild(body, ns, BAD_CAST(function->requestName), NULL);
4270            } else if (function && function->functionName) {
4271                method = xmlNewChild(body, ns, BAD_CAST(function->functionName), NULL);
4272            } else {
4273                method = body;
4274            }
4275        } else {
4276            method = body;
4277        }
4278
4279        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "use", sizeof("use"), (void **)&zuse) == SUCCESS &&
4280              Z_LVAL_PP(zuse) == SOAP_LITERAL) {
4281            use = SOAP_LITERAL;
4282        } else {
4283            use = SOAP_ENCODED;
4284        }
4285    }
4286
4287    for (i = 0;i < arg_count;i++) {
4288        xmlNodePtr param;
4289        sdlParamPtr parameter = get_param(function, NULL, i, FALSE);
4290
4291        if (style == SOAP_RPC) {
4292            param = serialize_parameter(parameter, arguments[i], i, NULL, use, method TSRMLS_CC);
4293        } else if (style == SOAP_DOCUMENT) {
4294            param = serialize_parameter(parameter, arguments[i], i, NULL, use, body TSRMLS_CC);
4295            if (function && function->binding->bindingType == BINDING_SOAP) {
4296                if (parameter && parameter->element) {
4297                    ns = encode_add_ns(param, parameter->element->namens);
4298                    xmlNodeSetName(param, BAD_CAST(parameter->element->name));
4299                    xmlSetNs(param, ns);
4300                }
4301            }
4302        }
4303    }
4304
4305    if (function && function->requestParameters) {
4306        int n = zend_hash_num_elements(function->requestParameters);
4307
4308        if (n > arg_count) {
4309            for (i = arg_count; i < n; i++) {
4310                xmlNodePtr param;
4311                sdlParamPtr parameter = get_param(function, NULL, i, FALSE);
4312
4313                if (style == SOAP_RPC) {
4314                    param = serialize_parameter(parameter, NULL, i, NULL, use, method TSRMLS_CC);
4315                } else if (style == SOAP_DOCUMENT) {
4316                    param = serialize_parameter(parameter, NULL, i, NULL, use, body TSRMLS_CC);
4317                    if (function && function->binding->bindingType == BINDING_SOAP) {
4318                        if (parameter && parameter->element) {
4319                            ns = encode_add_ns(param, parameter->element->namens);
4320                            xmlNodeSetName(param, BAD_CAST(parameter->element->name));
4321                            xmlSetNs(param, ns);
4322                        }
4323                    }
4324                }
4325            }
4326        }
4327    }
4328
4329    if (head) {
4330        zval** header;
4331
4332        zend_hash_internal_pointer_reset(soap_headers);
4333        while (zend_hash_get_current_data(soap_headers,(void**)&header) == SUCCESS) {
4334            HashTable *ht = Z_OBJPROP_PP(header);
4335            zval **name, **ns, **tmp;
4336
4337            if (zend_hash_find(ht, "name", sizeof("name"), (void**)&name) == SUCCESS &&
4338                Z_TYPE_PP(name) == IS_STRING &&
4339                zend_hash_find(ht, "namespace", sizeof("namespace"), (void**)&ns) == SUCCESS &&
4340                Z_TYPE_PP(ns) == IS_STRING) {
4341                xmlNodePtr h;
4342                xmlNsPtr nsptr;
4343                int hdr_use = SOAP_LITERAL;
4344                encodePtr enc = NULL;
4345
4346                if (hdrs) {
4347                    smart_str key = {0};
4348                    sdlSoapBindingFunctionHeaderPtr *hdr;
4349
4350                    smart_str_appendl(&key, Z_STRVAL_PP(ns), Z_STRLEN_PP(ns));
4351                    smart_str_appendc(&key, ':');
4352                    smart_str_appendl(&key, Z_STRVAL_PP(name), Z_STRLEN_PP(name));
4353                    smart_str_0(&key);
4354                    if (zend_hash_find(hdrs, key.c, key.len+1,(void**)&hdr) == SUCCESS) {
4355                        hdr_use = (*hdr)->use;
4356                        enc = (*hdr)->encode;
4357                        if (hdr_use == SOAP_ENCODED) {
4358                            use = SOAP_ENCODED;
4359                        }
4360                    }
4361                    smart_str_free(&key);
4362                }
4363
4364                if (zend_hash_find(ht, "data", sizeof("data"), (void**)&tmp) == SUCCESS) {
4365                    h = master_to_xml(enc, *tmp, hdr_use, head TSRMLS_CC);
4366                    xmlNodeSetName(h, BAD_CAST(Z_STRVAL_PP(name)));
4367                } else {
4368                    h = xmlNewNode(NULL, BAD_CAST(Z_STRVAL_PP(name)));
4369                    xmlAddChild(head, h);
4370                }
4371                nsptr = encode_add_ns(h, Z_STRVAL_PP(ns));
4372                xmlSetNs(h, nsptr);
4373                set_soap_header_attributes(h, ht, version);
4374            }
4375            zend_hash_move_forward(soap_headers);
4376        }
4377    }
4378
4379    if (use == SOAP_ENCODED) {
4380        xmlNewNs(envelope, BAD_CAST(XSD_NAMESPACE), BAD_CAST(XSD_NS_PREFIX));
4381        if (version == SOAP_1_1) {
4382            xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENC_NAMESPACE), BAD_CAST(SOAP_1_1_ENC_NS_PREFIX));
4383            xmlSetNsProp(envelope, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_1_ENC_NAMESPACE));
4384        } else if (version == SOAP_1_2) {
4385            xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENC_NAMESPACE), BAD_CAST(SOAP_1_2_ENC_NS_PREFIX));
4386            if (method) {
4387                xmlSetNsProp(method, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
4388            }
4389        }
4390    }
4391
4392    encode_finish();
4393
4394    return doc;
4395}
4396
4397static xmlNodePtr serialize_parameter(sdlParamPtr param, zval *param_val, int index, char *name, int style, xmlNodePtr parent TSRMLS_DC)
4398{
4399    char *paramName;
4400    xmlNodePtr xmlParam;
4401    char paramNameBuf[10];
4402
4403    if (param_val &&
4404        Z_TYPE_P(param_val) == IS_OBJECT &&
4405        Z_OBJCE_P(param_val) == soap_param_class_entry) {
4406        zval **param_name;
4407        zval **param_data;
4408
4409        if (zend_hash_find(Z_OBJPROP_P(param_val), "param_name", sizeof("param_name"), (void **)&param_name) == SUCCESS &&
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