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