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