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