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