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