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