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