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