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