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