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                if(Z_TYPE_PP(tmp) == IS_OBJECT) {
2926                    Z_ADDREF_PP(tmp);
2927                    zend_hash_next_index_insert(soap_headers, tmp, sizeof(zval *), NULL);
2928                }
2929                zend_hash_move_forward(default_headers);
2930            }
2931        } else {
2932            soap_headers = Z_ARRVAL_P(*tmp);
2933            free_soap_headers = 0;
2934        }
2935    }
2936
2937    arg_count = zend_hash_num_elements(Z_ARRVAL_P(args));
2938
2939    if (arg_count > 0) {
2940        real_args = safe_emalloc(sizeof(zval *), arg_count, 0);
2941        for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(args), &pos);
2942            zend_hash_get_current_data_ex(Z_ARRVAL_P(args), (void **) &param, &pos) == SUCCESS;
2943            zend_hash_move_forward_ex(Z_ARRVAL_P(args), &pos)) {
2944                /*zval_add_ref(param);*/
2945                real_args[i++] = *param;
2946        }
2947    }
2948    if (output_headers) {
2949        array_init(output_headers);
2950    }
2951    do_soap_call(this_ptr, function, function_len, arg_count, real_args, return_value, location, soap_action, uri, soap_headers, output_headers TSRMLS_CC);
2952    if (arg_count > 0) {
2953        efree(real_args);
2954    }
2955
2956    if (soap_headers && free_soap_headers) {
2957        zend_hash_destroy(soap_headers);
2958        efree(soap_headers);
2959    }
2960}
2961/* }}} */
2962
2963
2964/* {{{ proto array SoapClient::__getFunctions ( void )
2965   Returns list of SOAP functions */
2966PHP_METHOD(SoapClient, __getFunctions)
2967{
2968    sdlPtr sdl;
2969    HashPosition pos;
2970
2971    FETCH_THIS_SDL(sdl);
2972
2973    if (zend_parse_parameters_none() == FAILURE) {
2974        return;
2975    }
2976
2977    if (sdl) {
2978        smart_str buf = {0};
2979        sdlFunctionPtr *function;
2980
2981        array_init(return_value);
2982        zend_hash_internal_pointer_reset_ex(&sdl->functions, &pos);
2983        while (zend_hash_get_current_data_ex(&sdl->functions, (void **)&function, &pos) != FAILURE) {
2984            function_to_string((*function), &buf);
2985            add_next_index_stringl(return_value, buf.c, buf.len, 1);
2986            smart_str_free(&buf);
2987            zend_hash_move_forward_ex(&sdl->functions, &pos);
2988        }
2989    }
2990}
2991/* }}} */
2992
2993
2994/* {{{ proto array SoapClient::__getTypes ( void )
2995   Returns list of SOAP types */
2996PHP_METHOD(SoapClient, __getTypes)
2997{
2998    sdlPtr sdl;
2999    HashPosition pos;
3000
3001    FETCH_THIS_SDL(sdl);
3002
3003    if (zend_parse_parameters_none() == FAILURE) {
3004        return;
3005    }
3006
3007    if (sdl) {
3008        sdlTypePtr *type;
3009        smart_str buf = {0};
3010
3011        array_init(return_value);
3012        if (sdl->types) {
3013            zend_hash_internal_pointer_reset_ex(sdl->types, &pos);
3014            while (zend_hash_get_current_data_ex(sdl->types, (void **)&type, &pos) != FAILURE) {
3015                type_to_string((*type), &buf, 0);
3016                add_next_index_stringl(return_value, buf.c, buf.len, 1);
3017                smart_str_free(&buf);
3018                zend_hash_move_forward_ex(sdl->types, &pos);
3019            }
3020        }
3021    }
3022}
3023/* }}} */
3024
3025
3026/* {{{ proto string SoapClient::__getLastRequest ( void )
3027   Returns last SOAP request */
3028PHP_METHOD(SoapClient, __getLastRequest)
3029{
3030    zval **tmp;
3031
3032    if (zend_parse_parameters_none() == FAILURE) {
3033        return;
3034    }
3035
3036    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__last_request", sizeof("__last_request"), (void **)&tmp) == SUCCESS &&
3037        Z_TYPE_PP(tmp) == IS_STRING) {
3038        RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
3039    }
3040    RETURN_NULL();
3041}
3042/* }}} */
3043
3044
3045/* {{{ proto object SoapClient::__getLastResponse ( void )
3046   Returns last SOAP response */
3047PHP_METHOD(SoapClient, __getLastResponse)
3048{
3049    zval **tmp;
3050
3051    if (zend_parse_parameters_none() == FAILURE) {
3052        return;
3053    }
3054
3055    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__last_response", sizeof("__last_response"), (void **)&tmp) == SUCCESS &&
3056        Z_TYPE_PP(tmp) == IS_STRING) {
3057        RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
3058    }
3059    RETURN_NULL();
3060}
3061/* }}} */
3062
3063
3064/* {{{ proto string SoapClient::__getLastRequestHeaders(void)
3065   Returns last SOAP request headers */
3066PHP_METHOD(SoapClient, __getLastRequestHeaders)
3067{
3068    zval **tmp;
3069
3070    if (zend_parse_parameters_none() == FAILURE) {
3071        return;
3072    }
3073
3074    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__last_request_headers", sizeof("__last_request_headers"), (void **)&tmp) == SUCCESS &&
3075        Z_TYPE_PP(tmp) == IS_STRING) {
3076        RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
3077    }
3078    RETURN_NULL();
3079}
3080/* }}} */
3081
3082
3083/* {{{ proto string SoapClient::__getLastResponseHeaders(void)
3084   Returns last SOAP response headers */
3085PHP_METHOD(SoapClient, __getLastResponseHeaders)
3086{
3087    zval **tmp;
3088
3089    if (zend_parse_parameters_none() == FAILURE) {
3090        return;
3091    }
3092
3093    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__last_response_headers", sizeof("__last_response_headers"), (void **)&tmp) == SUCCESS &&
3094        Z_TYPE_PP(tmp) == IS_STRING) {
3095        RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
3096    }
3097    RETURN_NULL();
3098}
3099/* }}} */
3100
3101
3102/* {{{ proto string SoapClient::__doRequest()
3103   SoapClient::__doRequest() */
3104PHP_METHOD(SoapClient, __doRequest)
3105{
3106  char *buf, *location, *action;
3107  int   buf_size, location_size, action_size;
3108  long  version;
3109  long  one_way = 0;
3110
3111    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sssl|l",
3112        &buf, &buf_size,
3113        &location, &location_size,
3114        &action, &action_size,
3115        &version, &one_way) == FAILURE) {
3116        return;
3117    }
3118    if (SOAP_GLOBAL(features) & SOAP_WAIT_ONE_WAY_CALLS) {
3119        one_way = 0;
3120    }
3121    if (one_way) {
3122        if (make_http_soap_request(this_ptr, buf, buf_size, location, action, version, NULL, NULL TSRMLS_CC)) {
3123            RETURN_EMPTY_STRING();
3124        }
3125    } else if (make_http_soap_request(this_ptr, buf, buf_size, location, action, version,
3126        &Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value) TSRMLS_CC)) {
3127        return_value->type = IS_STRING;
3128        return;
3129    }
3130    RETURN_NULL();
3131}
3132/* }}} */
3133
3134/* {{{ proto void SoapClient::__setCookie(string name [, strung value])
3135   Sets cookie thet will sent with SOAP request.
3136   The call to this function will effect all folowing calls of SOAP methods.
3137   If value is not specified cookie is removed. */
3138PHP_METHOD(SoapClient, __setCookie)
3139{
3140    char *name;
3141    char *val = NULL;
3142    int  name_len, val_len = 0;
3143    zval **cookies;
3144
3145    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &name, &name_len, &val, &val_len) == FAILURE) {
3146        return;
3147    }
3148
3149    if (val == NULL) {
3150        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) == SUCCESS &&
3151            Z_TYPE_PP(cookies) == IS_ARRAY) {
3152            zend_hash_del(Z_ARRVAL_PP(cookies), name, name_len+1);
3153        }
3154    } else {
3155        zval *zcookie;
3156
3157        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) == FAILURE ||
3158            Z_TYPE_PP(cookies) != IS_ARRAY) {
3159            zval *tmp_cookies;
3160
3161            MAKE_STD_ZVAL(tmp_cookies);
3162            array_init(tmp_cookies);
3163            zend_hash_update(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), &tmp_cookies, sizeof(zval *), (void **)&cookies);
3164        }
3165
3166        ALLOC_INIT_ZVAL(zcookie);
3167        array_init(zcookie);
3168        add_index_stringl(zcookie, 0, val, val_len, 1);
3169        add_assoc_zval_ex(*cookies, name, name_len+1, zcookie);
3170    }
3171}
3172/* }}} */
3173
3174/* {{{ proto array SoapClient::__getCookies ( void )
3175   Returns list of cookies */
3176PHP_METHOD(SoapClient, __getCookies)
3177{
3178    zval **cookies, *tmp;
3179
3180    if (zend_parse_parameters_none() == FAILURE) {
3181        return;
3182    }
3183
3184    array_init(return_value);
3185
3186    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) != FAILURE &&
3187        Z_TYPE_PP(cookies) == IS_ARRAY) {
3188        zend_hash_copy(Z_ARRVAL_P(return_value), Z_ARRVAL_P(*cookies), (copy_ctor_func_t) zval_add_ref, (void *)&tmp, sizeof(zval*));
3189    }
3190}
3191/* }}} */
3192
3193/* {{{ proto void SoapClient::__setSoapHeaders(array SoapHeaders)
3194   Sets SOAP headers for subsequent calls (replaces any previous
3195   values).
3196   If no value is specified, all of the headers are removed. */
3197PHP_METHOD(SoapClient, __setSoapHeaders)
3198{
3199    zval *headers = NULL;
3200
3201    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z", &headers) == FAILURE) {
3202        return;
3203    }
3204
3205    if (headers == NULL || Z_TYPE_P(headers) == IS_NULL) {
3206        zend_hash_del(Z_OBJPROP_P(this_ptr), "__default_headers", sizeof("__default_headers"));
3207    } else if (Z_TYPE_P(headers) == IS_ARRAY) {
3208        zval *default_headers;
3209
3210        verify_soap_headers_array(Z_ARRVAL_P(headers) TSRMLS_CC);
3211        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__default_headers", sizeof("__default_headers"), (void **) &default_headers)==FAILURE) {
3212            add_property_zval(this_ptr, "__default_headers", headers);
3213        }
3214    } else if (Z_TYPE_P(headers) == IS_OBJECT &&
3215               instanceof_function(Z_OBJCE_P(headers), soap_header_class_entry TSRMLS_CC)) {
3216        zval *default_headers;
3217        ALLOC_INIT_ZVAL(default_headers);
3218        array_init(default_headers);
3219        Z_ADDREF_P(headers);
3220        add_next_index_zval(default_headers, headers);
3221        Z_DELREF_P(default_headers);
3222        add_property_zval(this_ptr, "__default_headers", default_headers);
3223    } else{
3224        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid SOAP header");
3225    }
3226    RETURN_TRUE;
3227}
3228/* }}} */
3229
3230
3231
3232/* {{{ proto string SoapClient::__setLocation([string new_location])
3233   Sets the location option (the endpoint URL that will be touched by the
3234   following SOAP requests).
3235   If new_location is not specified or null then SoapClient will use endpoint
3236   from WSDL file.
3237   The function returns old value of location options. */
3238PHP_METHOD(SoapClient, __setLocation)
3239{
3240    char *location = NULL;
3241    int  location_len = 0;
3242    zval **tmp;
3243
3244    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &location, &location_len) == FAILURE) {
3245        return;
3246    }
3247
3248    if (zend_hash_find(Z_OBJPROP_P(this_ptr), "location", sizeof("location"),(void **) &tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) {
3249        RETVAL_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1);
3250    } else {
3251      RETVAL_NULL();
3252    }
3253
3254    if (location && location_len) {
3255        add_property_stringl(this_ptr, "location", location, location_len, 1);
3256    } else {
3257        zend_hash_del(Z_OBJPROP_P(this_ptr), "location", sizeof("location"));
3258    }
3259}
3260/* }}} */
3261
3262static void clear_soap_fault(zval *obj TSRMLS_DC)
3263{
3264    if (obj != NULL && obj->type == IS_OBJECT) {
3265        zend_hash_del(Z_OBJPROP_P(obj), "__soap_fault", sizeof("__soap_fault"));
3266    }
3267}
3268
3269zval* add_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail TSRMLS_DC)
3270{
3271    zval *fault;
3272    ALLOC_INIT_ZVAL(fault);
3273    set_soap_fault(fault, NULL, fault_code, fault_string, fault_actor, fault_detail, NULL TSRMLS_CC);
3274    Z_DELREF_P(fault);
3275
3276    add_property_zval(obj, "__soap_fault", fault);
3277    return fault;
3278}
3279
3280static 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)
3281{
3282    if (Z_TYPE_P(obj) != IS_OBJECT) {
3283        object_init_ex(obj, soap_fault_class_entry);
3284    }
3285
3286    add_property_string(obj, "faultstring", fault_string ? fault_string : "", 1);
3287    zend_update_property_string(zend_exception_get_default(TSRMLS_C), obj, "message", sizeof("message")-1, (fault_string ? fault_string : "") TSRMLS_CC);
3288
3289    if (fault_code != NULL) {
3290        int soap_version = SOAP_GLOBAL(soap_version);
3291
3292        if (fault_code_ns) {
3293            add_property_string(obj, "faultcode", fault_code, 1);
3294            add_property_string(obj, "faultcodens", fault_code_ns, 1);
3295        } else {
3296            if (soap_version == SOAP_1_1) {
3297                add_property_string(obj, "faultcode", fault_code, 1);
3298                if (strcmp(fault_code,"Client") == 0 ||
3299                    strcmp(fault_code,"Server") == 0 ||
3300                    strcmp(fault_code,"VersionMismatch") == 0 ||
3301                  strcmp(fault_code,"MustUnderstand") == 0) {
3302                    add_property_string(obj, "faultcodens", SOAP_1_1_ENV_NAMESPACE, 1);
3303                }
3304            } else if (soap_version == SOAP_1_2) {
3305                if (strcmp(fault_code,"Client") == 0) {
3306                    add_property_string(obj, "faultcode", "Sender", 1);
3307                    add_property_string(obj, "faultcodens", SOAP_1_2_ENV_NAMESPACE, 1);
3308                } else if (strcmp(fault_code,"Server") == 0) {
3309                    add_property_string(obj, "faultcode", "Receiver", 1);
3310                    add_property_string(obj, "faultcodens", SOAP_1_2_ENV_NAMESPACE, 1);
3311                } else if (strcmp(fault_code,"VersionMismatch") == 0 ||
3312                           strcmp(fault_code,"MustUnderstand") == 0 ||
3313                           strcmp(fault_code,"DataEncodingUnknown") == 0) {
3314                    add_property_string(obj, "faultcode", fault_code, 1);
3315                    add_property_string(obj, "faultcodens", SOAP_1_2_ENV_NAMESPACE, 1);
3316                } else {
3317                    add_property_string(obj, "faultcode", fault_code, 1);
3318                }
3319            }
3320        }
3321    }
3322    if (fault_actor != NULL) {
3323        add_property_string(obj, "faultactor", fault_actor, 1);
3324    }
3325    if (fault_detail != NULL) {
3326        add_property_zval(obj, "detail", fault_detail);
3327    }
3328    if (name != NULL) {
3329        add_property_string(obj, "_name", name, 1);
3330    }
3331}
3332
3333static void deserialize_parameters(xmlNodePtr params, sdlFunctionPtr function, int *num_params, zval ***parameters TSRMLS_DC)
3334{
3335    int cur_param = 0,num_of_params = 0;
3336    zval **tmp_parameters = NULL;
3337
3338    if (function != NULL) {
3339        sdlParamPtr *param;
3340        xmlNodePtr val;
3341        int use_names = 0;
3342
3343        if (function->requestParameters == NULL) {
3344            return;
3345        }
3346        num_of_params = zend_hash_num_elements(function->requestParameters);
3347        zend_hash_internal_pointer_reset(function->requestParameters);
3348        while (zend_hash_get_current_data(function->requestParameters, (void **)&param) == SUCCESS) {
3349            if (get_node(params, (*param)->paramName) != NULL) {
3350                use_names = 1;
3351            }
3352            zend_hash_move_forward(function->requestParameters);
3353        }
3354        if (use_names) {
3355            tmp_parameters = safe_emalloc(num_of_params, sizeof(zval *), 0);
3356            zend_hash_internal_pointer_reset(function->requestParameters);
3357            while (zend_hash_get_current_data(function->requestParameters, (void **)&param) == SUCCESS) {
3358                val = get_node(params, (*param)->paramName);
3359                if (!val) {
3360                    /* TODO: may be "nil" is not OK? */
3361                    MAKE_STD_ZVAL(tmp_parameters[cur_param]);
3362                    ZVAL_NULL(tmp_parameters[cur_param]);
3363                } else {
3364                    tmp_parameters[cur_param] = master_to_zval((*param)->encode, val TSRMLS_CC);
3365                }
3366                cur_param++;
3367
3368                zend_hash_move_forward(function->requestParameters);
3369            }
3370            (*parameters) = tmp_parameters;
3371            (*num_params) = num_of_params;
3372            return;
3373        }
3374    }
3375    if (params) {
3376        xmlNodePtr trav;
3377
3378        num_of_params = 0;
3379        trav = params;
3380        while (trav != NULL) {
3381            if (trav->type == XML_ELEMENT_NODE) {
3382                num_of_params++;
3383            }
3384            trav = trav->next;
3385        }
3386
3387        if (num_of_params == 1 &&
3388            function &&
3389            function->binding &&
3390            function->binding->bindingType == BINDING_SOAP &&
3391            ((sdlSoapBindingFunctionPtr)function->bindingAttributes)->style == SOAP_DOCUMENT &&
3392            (function->requestParameters == NULL ||
3393             zend_hash_num_elements(function->requestParameters) == 0) &&
3394            strcmp((char *)params->name, function->functionName) == 0) {
3395            num_of_params = 0;
3396        } else if (num_of_params > 0) {
3397            tmp_parameters = safe_emalloc(num_of_params, sizeof(zval *), 0);
3398
3399            trav = params;
3400            while (trav != 0 && cur_param < num_of_params) {
3401                if (trav->type == XML_ELEMENT_NODE) {
3402                    encodePtr enc;
3403                    sdlParamPtr *param = NULL;
3404                    if (function != NULL &&
3405                        zend_hash_index_find(function->requestParameters, cur_param, (void **)&param) == FAILURE) {
3406                        TSRMLS_FETCH();
3407                        soap_server_fault("Client", "Error cannot find parameter", NULL, NULL, NULL TSRMLS_CC);
3408                    }
3409                    if (param == NULL) {
3410                        enc = NULL;
3411                    } else {
3412                        enc = (*param)->encode;
3413                    }
3414                    tmp_parameters[cur_param] = master_to_zval(enc, trav TSRMLS_CC);
3415                    cur_param++;
3416                }
3417                trav = trav->next;
3418            }
3419        }
3420    }
3421    if (num_of_params > cur_param) {
3422        soap_server_fault("Client","Missing parameter", NULL, NULL, NULL TSRMLS_CC);
3423    }
3424    (*parameters) = tmp_parameters;
3425    (*num_params) = num_of_params;
3426}
3427
3428static sdlFunctionPtr find_function(sdlPtr sdl, xmlNodePtr func, zval* function_name)
3429{
3430    sdlFunctionPtr function;
3431
3432    function = get_function(sdl, (char*)func->name);
3433    if (function && function->binding && function->binding->bindingType == BINDING_SOAP) {
3434        sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3435        if (fnb->style == SOAP_DOCUMENT) {
3436            if (func->children != NULL ||
3437                (function->requestParameters != NULL &&
3438                 zend_hash_num_elements(function->requestParameters) > 0)) {
3439                function = NULL;
3440            }
3441        }
3442    }
3443    if (sdl != NULL && function == NULL) {
3444        function = get_doc_function(sdl, func);
3445    }
3446
3447    INIT_ZVAL(*function_name);
3448    if (function != NULL) {
3449        ZVAL_STRING(function_name, (char *)function->functionName, 1);
3450    } else {
3451        ZVAL_STRING(function_name, (char *)func->name, 1);
3452    }
3453
3454    return function;
3455}
3456
3457static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, char* actor, zval *function_name, int *num_params, zval ***parameters, int *version, soapHeader **headers TSRMLS_DC)
3458{
3459    char* envelope_ns = NULL;
3460    xmlNodePtr trav,env,head,body,func;
3461    xmlAttrPtr attr;
3462    sdlFunctionPtr function;
3463
3464    encode_reset_ns();
3465
3466    /* Get <Envelope> element */
3467    env = NULL;
3468    trav = request->children;
3469    while (trav != NULL) {
3470        if (trav->type == XML_ELEMENT_NODE) {
3471            if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_1_ENV_NAMESPACE)) {
3472                env = trav;
3473                *version = SOAP_1_1;
3474                envelope_ns = SOAP_1_1_ENV_NAMESPACE;
3475                SOAP_GLOBAL(soap_version) = SOAP_1_1;
3476            } else if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_2_ENV_NAMESPACE)) {
3477                env = trav;
3478                *version = SOAP_1_2;
3479                envelope_ns = SOAP_1_2_ENV_NAMESPACE;
3480                SOAP_GLOBAL(soap_version) = SOAP_1_2;
3481            } else {
3482                soap_server_fault("VersionMismatch", "Wrong Version", NULL, NULL, NULL TSRMLS_CC);
3483            }
3484        }
3485        trav = trav->next;
3486    }
3487    if (env == NULL) {
3488        soap_server_fault("Client", "looks like we got XML without \"Envelope\" element", NULL, NULL, NULL TSRMLS_CC);
3489    }
3490
3491    attr = env->properties;
3492    while (attr != NULL) {
3493        if (attr->ns == NULL) {
3494            soap_server_fault("Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL, NULL TSRMLS_CC);
3495        } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
3496            if (*version == SOAP_1_2) {
3497                soap_server_fault("Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL, NULL TSRMLS_CC);
3498            } else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3499                soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL TSRMLS_CC);
3500            }
3501        }
3502        attr = attr->next;
3503    }
3504
3505    /* Get <Header> element */
3506    head = NULL;
3507    trav = env->children;
3508    while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
3509        trav = trav->next;
3510    }
3511    if (trav != NULL && node_is_equal_ex(trav,"Header",envelope_ns)) {
3512        head = trav;
3513        trav = trav->next;
3514    }
3515
3516    /* Get <Body> element */
3517    body = NULL;
3518    while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
3519        trav = trav->next;
3520    }
3521    if (trav != NULL && node_is_equal_ex(trav,"Body",envelope_ns)) {
3522        body = trav;
3523        trav = trav->next;
3524    }
3525    while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
3526        trav = trav->next;
3527    }
3528    if (body == NULL) {
3529        soap_server_fault("Client", "Body must be present in a SOAP envelope", NULL, NULL, NULL TSRMLS_CC);
3530    }
3531    attr = body->properties;
3532    while (attr != NULL) {
3533        if (attr->ns == NULL) {
3534            if (*version == SOAP_1_2) {
3535                soap_server_fault("Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL, NULL TSRMLS_CC);
3536            }
3537        } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
3538            if (*version == SOAP_1_2) {
3539                soap_server_fault("Client", "encodingStyle cannot be specified on the Body", NULL, NULL, NULL TSRMLS_CC);
3540            } else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3541                soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL TSRMLS_CC);
3542            }
3543        }
3544        attr = attr->next;
3545    }
3546
3547    if (trav != NULL && *version == SOAP_1_2) {
3548        soap_server_fault("Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL, NULL TSRMLS_CC);
3549    }
3550
3551    func = NULL;
3552    trav = body->children;
3553    while (trav != NULL) {
3554        if (trav->type == XML_ELEMENT_NODE) {
3555/*
3556            if (func != NULL) {
3557                soap_server_fault("Client", "looks like we got \"Body\" with several functions call", NULL, NULL, NULL TSRMLS_CC);
3558            }
3559*/
3560            func = trav;
3561            break; /* FIXME: the rest of body is ignored */
3562        }
3563        trav = trav->next;
3564    }
3565    if (func == NULL) {
3566        function = get_doc_function(sdl, NULL);
3567        if (function != NULL) {
3568            INIT_ZVAL(*function_name);
3569            ZVAL_STRING(function_name, (char *)function->functionName, 1);
3570        } else {
3571            soap_server_fault("Client", "looks like we got \"Body\" without function call", NULL, NULL, NULL TSRMLS_CC);
3572        }
3573    } else {
3574        if (*version == SOAP_1_1) {
3575            attr = get_attribute_ex(func->properties,"encodingStyle",SOAP_1_1_ENV_NAMESPACE);
3576            if (attr && strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3577                soap_server_fault("Client","Unknown Data Encoding Style", NULL, NULL, NULL TSRMLS_CC);
3578            }
3579        } else {
3580            attr = get_attribute_ex(func->properties,"encodingStyle",SOAP_1_2_ENV_NAMESPACE);
3581            if (attr && strcmp((char*)attr->children->content,SOAP_1_2_ENC_NAMESPACE) != 0) {
3582                soap_server_fault("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL TSRMLS_CC);
3583            }
3584        }
3585        function = find_function(sdl, func, function_name);
3586        if (sdl != NULL && function == NULL) {
3587            if (*version == SOAP_1_2) {
3588                soap_server_fault("rpc:ProcedureNotPresent","Procedure not present", NULL, NULL, NULL TSRMLS_CC);
3589            } else {
3590                php_error(E_ERROR, "Procedure '%s' not present", func->name);
3591            }
3592        }
3593    }
3594
3595    *headers = NULL;
3596    if (head) {
3597        soapHeader *h, *last = NULL;
3598
3599        attr = head->properties;
3600        while (attr != NULL) {
3601            if (attr->ns == NULL) {
3602                soap_server_fault("Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL, NULL TSRMLS_CC);
3603            } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
3604                if (*version == SOAP_1_2) {
3605                    soap_server_fault("Client", "encodingStyle cannot be specified on the Header", NULL, NULL, NULL TSRMLS_CC);
3606                } else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3607                    soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL TSRMLS_CC);
3608                }
3609            }
3610            attr = attr->next;
3611        }
3612        trav = head->children;
3613        while (trav != NULL) {
3614            if (trav->type == XML_ELEMENT_NODE) {
3615                xmlNodePtr hdr_func = trav;
3616                int mustUnderstand = 0;
3617
3618                if (*version == SOAP_1_1) {
3619                    attr = get_attribute_ex(hdr_func->properties,"encodingStyle",SOAP_1_1_ENV_NAMESPACE);
3620                    if (attr && strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
3621                        soap_server_fault("Client","Unknown Data Encoding Style", NULL, NULL, NULL TSRMLS_CC);
3622                    }
3623                    attr = get_attribute_ex(hdr_func->properties,"actor",envelope_ns);
3624                    if (attr != NULL) {
3625                        if (strcmp((char*)attr->children->content,SOAP_1_1_ACTOR_NEXT) != 0 &&
3626                            (actor == NULL || strcmp((char*)attr->children->content,actor) != 0)) {
3627                          goto ignore_header;
3628                        }
3629                    }
3630                } else if (*version == SOAP_1_2) {
3631                    attr = get_attribute_ex(hdr_func->properties,"encodingStyle",SOAP_1_2_ENV_NAMESPACE);
3632                    if (attr && strcmp((char*)attr->children->content,SOAP_1_2_ENC_NAMESPACE) != 0) {
3633                        soap_server_fault("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL TSRMLS_CC);
3634                    }
3635                    attr = get_attribute_ex(hdr_func->properties,"role",envelope_ns);
3636                    if (attr != NULL) {
3637                        if (strcmp((char*)attr->children->content,SOAP_1_2_ACTOR_UNLIMATERECEIVER) != 0 &&
3638                            strcmp((char*)attr->children->content,SOAP_1_2_ACTOR_NEXT) != 0 &&
3639                            (actor == NULL || strcmp((char*)attr->children->content,actor) != 0)) {
3640                          goto ignore_header;
3641                        }
3642                    }
3643                }
3644                attr = get_attribute_ex(hdr_func->properties,"mustUnderstand",envelope_ns);
3645                if (attr) {
3646                    if (strcmp((char*)attr->children->content,"1") == 0 ||
3647                        strcmp((char*)attr->children->content,"true") == 0) {
3648                        mustUnderstand = 1;
3649                    } else if (strcmp((char*)attr->children->content,"0") == 0 ||
3650                               strcmp((char*)attr->children->content,"false") == 0) {
3651                        mustUnderstand = 0;
3652                    } else {
3653                        soap_server_fault("Client","mustUnderstand value is not boolean", NULL, NULL, NULL TSRMLS_CC);
3654                    }
3655                }
3656                h = emalloc(sizeof(soapHeader));
3657                memset(h, 0, sizeof(soapHeader));
3658                h->mustUnderstand = mustUnderstand;
3659                h->function = find_function(sdl, hdr_func, &h->function_name);
3660                if (!h->function && sdl && function && function->binding && function->binding->bindingType == BINDING_SOAP) {
3661                    sdlSoapBindingFunctionHeaderPtr *hdr;
3662                    sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3663                    if (fnb->input.headers) {
3664                        smart_str key = {0};
3665
3666                        if (hdr_func->ns) {
3667                            smart_str_appends(&key, (char*)hdr_func->ns->href);
3668                            smart_str_appendc(&key, ':');
3669                        }
3670                        smart_str_appendl(&key, Z_STRVAL(h->function_name), Z_STRLEN(h->function_name));
3671                        smart_str_0(&key);
3672                        if (zend_hash_find(fnb->input.headers, key.c, key.len+1, (void**)&hdr) == SUCCESS) {
3673                            h->hdr = *hdr;
3674                        }
3675                        smart_str_free(&key);
3676                    }
3677                }
3678                if (h->hdr) {
3679                    h->num_params = 1;
3680                    h->parameters = emalloc(sizeof(zval*));
3681                    h->parameters[0] = master_to_zval(h->hdr->encode, hdr_func TSRMLS_CC);
3682                } else {
3683                    if (h->function && h->function->binding && h->function->binding->bindingType == BINDING_SOAP) {
3684                        sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)h->function->bindingAttributes;
3685                        if (fnb->style == SOAP_RPC) {
3686                            hdr_func = hdr_func->children;
3687                        }
3688                    }
3689                    deserialize_parameters(hdr_func, h->function, &h->num_params, &h->parameters TSRMLS_CC);
3690                }
3691                INIT_ZVAL(h->retval);
3692                if (last == NULL) {
3693                    *headers = h;
3694                } else {
3695                    last->next = h;
3696                }
3697                last = h;
3698            }
3699ignore_header:
3700            trav = trav->next;
3701        }
3702    }
3703
3704    if (function && function->binding && function->binding->bindingType == BINDING_SOAP) {
3705        sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3706        if (fnb->style == SOAP_RPC) {
3707            func = func->children;
3708        }
3709    } else {
3710        func = func->children;
3711    }
3712    deserialize_parameters(func, function, num_params, parameters TSRMLS_CC);
3713
3714    encode_finish();
3715
3716    return function;
3717}
3718
3719static void set_soap_header_attributes(xmlNodePtr h, HashTable *ht, int version)
3720{
3721    zval **tmp;
3722
3723    if (zend_hash_find(ht, "mustUnderstand", sizeof("mustUnderstand"), (void**)&tmp) == SUCCESS &&
3724        Z_TYPE_PP(tmp) == IS_BOOL && Z_LVAL_PP(tmp)) {
3725        if (version == SOAP_1_1) {
3726            xmlSetProp(h, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":mustUnderstand"), BAD_CAST("1"));
3727        } else {
3728            xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":mustUnderstand"), BAD_CAST("true"));
3729        }
3730    }
3731    if (zend_hash_find(ht, "actor", sizeof("actor"), (void**)&tmp) == SUCCESS) {
3732        if (Z_TYPE_PP(tmp) == IS_STRING) {
3733            if (version == SOAP_1_1) {
3734                xmlSetProp(h, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":actor"), BAD_CAST(Z_STRVAL_PP(tmp)));
3735            } else {
3736                xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(Z_STRVAL_PP(tmp)));
3737            }
3738        } else if (Z_TYPE_PP(tmp) == IS_LONG) {
3739            if (version == SOAP_1_1) {
3740                if (Z_LVAL_PP(tmp) == SOAP_ACTOR_NEXT) {
3741                    xmlSetProp(h, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":actor"), BAD_CAST(SOAP_1_1_ACTOR_NEXT));
3742                }
3743            } else {
3744                if (Z_LVAL_PP(tmp) == SOAP_ACTOR_NEXT) {
3745                    xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(SOAP_1_2_ACTOR_NEXT));
3746                } else if (Z_LVAL_PP(tmp) == SOAP_ACTOR_NONE) {
3747                    xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(SOAP_1_2_ACTOR_NONE));
3748                } else if (Z_LVAL_PP(tmp) == SOAP_ACTOR_UNLIMATERECEIVER) {
3749                    xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(SOAP_1_2_ACTOR_UNLIMATERECEIVER));
3750                }
3751            }
3752        }
3753    }
3754}
3755
3756static int serialize_response_call2(xmlNodePtr body, sdlFunctionPtr function, char *function_name, char *uri, zval *ret, int version, int main, xmlNodePtr *node TSRMLS_DC)
3757{
3758    xmlNodePtr method = NULL, param;
3759    sdlParamPtr parameter = NULL;
3760    int param_count;
3761    int style, use;
3762    xmlNsPtr ns = NULL;
3763
3764    if (function != NULL && function->binding->bindingType == BINDING_SOAP) {
3765        sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
3766
3767        style = fnb->style;
3768        use = fnb->output.use;
3769        if (style == SOAP_RPC) {
3770            ns = encode_add_ns(body, fnb->output.ns);
3771            if (function->responseName) {
3772                method = xmlNewChild(body, ns, BAD_CAST(function->responseName), NULL);
3773            } else if (function->responseParameters) {
3774                method = xmlNewChild(body, ns, BAD_CAST(function->functionName), NULL);
3775            }
3776        }
3777    } else {
3778        style = main?SOAP_RPC:SOAP_DOCUMENT;
3779        use = main?SOAP_ENCODED:SOAP_LITERAL;
3780        if (style == SOAP_RPC) {
3781            ns = encode_add_ns(body, uri);
3782            method = xmlNewChild(body, ns, BAD_CAST(function_name), NULL);
3783        }
3784    }
3785
3786    if (function != NULL) {
3787        if (function->responseParameters) {
3788            param_count = zend_hash_num_elements(function->responseParameters);
3789        } else {
3790          param_count = 0;
3791        }
3792    } else {
3793      param_count = 1;
3794    }
3795
3796    if (param_count == 1) {
3797        parameter = get_param(function, NULL, 0, TRUE);
3798
3799        if (style == SOAP_RPC) {
3800          xmlNode *rpc_result;
3801            if (main && version == SOAP_1_2) {
3802                xmlNs *rpc_ns = xmlNewNs(body, BAD_CAST(RPC_SOAP12_NAMESPACE), BAD_CAST(RPC_SOAP12_NS_PREFIX));
3803                rpc_result = xmlNewChild(method, rpc_ns, BAD_CAST("result"), NULL);
3804                param = serialize_parameter(parameter, ret, 0, "return", use, method TSRMLS_CC);
3805                xmlNodeSetContent(rpc_result,param->name);
3806            } else {
3807                param = serialize_parameter(parameter, ret, 0, "return", use, method TSRMLS_CC);
3808            }
3809        } else {
3810            param = serialize_parameter(parameter, ret, 0, "return", use, body TSRMLS_CC);
3811            if (function && function->binding->bindingType == BINDING_SOAP) {
3812                if (parameter && parameter->element) {
3813                    ns = encode_add_ns(param, parameter->element->namens);
3814                    xmlNodeSetName(param, BAD_CAST(parameter->element->name));
3815                    xmlSetNs(param, ns);
3816                }
3817            } else if (strcmp((char*)param->name,"return") == 0) {
3818                ns = encode_add_ns(param, uri);
3819                xmlNodeSetName(param, BAD_CAST(function_name));
3820                xmlSetNs(param, ns);
3821            }
3822        }
3823    } else if (param_count > 1 && Z_TYPE_P(ret) == IS_ARRAY) {
3824        HashPosition pos;
3825        zval **data;
3826        int i = 0;
3827
3828        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(ret), &pos);
3829        while (zend_hash_get_current_data_ex(Z_ARRVAL_P(ret), (void **)&data, &pos) != FAILURE) {
3830            char *param_name = NULL;
3831            unsigned int param_name_len;
3832            ulong param_index = i;
3833
3834            zend_hash_get_current_key_ex(Z_ARRVAL_P(ret), &param_name, &param_name_len, &param_index, 0, &pos);
3835            parameter = get_param(function, param_name, param_index, TRUE);
3836            if (style == SOAP_RPC) {
3837                param = serialize_parameter(parameter, *data, i, param_name, use, method TSRMLS_CC);
3838            } else {
3839                param = serialize_parameter(parameter, *data, i, param_name, use, body TSRMLS_CC);
3840                if (function && function->binding->bindingType == BINDING_SOAP) {
3841                    if (parameter && parameter->element) {
3842                        ns = encode_add_ns(param, parameter->element->namens);
3843                        xmlNodeSetName(param, BAD_CAST(parameter->element->name));
3844                        xmlSetNs(param, ns);
3845                    }
3846                }
3847            }
3848
3849            zend_hash_move_forward_ex(Z_ARRVAL_P(ret), &pos);
3850            i++;
3851        }
3852    }
3853    if (use == SOAP_ENCODED && version == SOAP_1_2 && method != NULL) {
3854        xmlSetNsProp(method, body->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
3855    }
3856    if (node) {
3857        *node = method;
3858    }
3859    return use;
3860}
3861
3862static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function_name, char *uri, zval *ret, soapHeader* headers, int version TSRMLS_DC)
3863{
3864    xmlDocPtr doc;
3865    xmlNodePtr envelope = NULL, body, param;
3866    xmlNsPtr ns = NULL;
3867    int use = SOAP_LITERAL;
3868    xmlNodePtr head = NULL;
3869
3870    encode_reset_ns();
3871
3872    doc = xmlNewDoc(BAD_CAST("1.0"));
3873    doc->charset = XML_CHAR_ENCODING_UTF8;
3874    doc->encoding = xmlCharStrdup("UTF-8");
3875
3876    if (version == SOAP_1_1) {
3877        envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
3878        ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENV_NAMESPACE), BAD_CAST(SOAP_1_1_ENV_NS_PREFIX));
3879        xmlSetNs(envelope,ns);
3880    } else if (version == SOAP_1_2) {
3881        envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
3882        ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENV_NAMESPACE), BAD_CAST(SOAP_1_2_ENV_NS_PREFIX));
3883        xmlSetNs(envelope,ns);
3884    } else {
3885        soap_server_fault("Server", "Unknown SOAP version", NULL, NULL, NULL TSRMLS_CC);
3886    }
3887    xmlDocSetRootElement(doc, envelope);
3888
3889    if (Z_TYPE_P(ret) == IS_OBJECT &&
3890        instanceof_function(Z_OBJCE_P(ret), soap_fault_class_entry TSRMLS_CC)) {
3891      char *detail_name;
3892        HashTable* prop;
3893        zval **tmp;
3894        sdlFaultPtr fault = NULL;
3895        char *fault_ns = NULL;
3896
3897        prop = Z_OBJPROP_P(ret);
3898
3899        if (headers &&
3900            zend_hash_find(prop, "headerfault", sizeof("headerfault"), (void**)&tmp) == SUCCESS) {
3901            encodePtr hdr_enc = NULL;
3902            int hdr_use = SOAP_LITERAL;
3903            zval *hdr_ret  = *tmp;
3904            char *hdr_ns   = headers->hdr?headers->hdr->ns:NULL;
3905            char *hdr_name = Z_STRVAL(headers->function_name);
3906
3907            head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL);
3908            if (Z_TYPE_P(hdr_ret) == IS_OBJECT &&
3909                instanceof_function(Z_OBJCE_P(hdr_ret), soap_header_class_entry TSRMLS_CC)) {
3910                HashTable* ht = Z_OBJPROP_P(hdr_ret);
3911                sdlSoapBindingFunctionHeaderPtr *hdr;
3912                smart_str key = {0};
3913
3914                if (zend_hash_find(ht, "namespace", sizeof("namespace"), (void**)&tmp) == SUCCESS &&
3915                  Z_TYPE_PP(tmp) == IS_STRING) {
3916                    smart_str_appendl(&key, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
3917                    smart_str_appendc(&key, ':');
3918                    hdr_ns = Z_STRVAL_PP(tmp);
3919                }
3920                if (zend_hash_find(ht, "name", sizeof("name"), (void**)&tmp) == SUCCESS &&
3921                    Z_TYPE_PP(tmp) == IS_STRING) {
3922                    smart_str_appendl(&key, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
3923                    hdr_name = Z_STRVAL_PP(tmp);
3924                }
3925                smart_str_0(&key);
3926                if (headers->hdr && headers->hdr->headerfaults &&
3927                    zend_hash_find(headers->hdr->headerfaults, key.c, key.len+1, (void**)&hdr) == SUCCESS) {
3928                    hdr_enc = (*hdr)->encode;
3929                    hdr_use = (*hdr)->use;
3930                }
3931                smart_str_free(&key);
3932                if (zend_hash_find(ht, "data", sizeof("data"), (void**)&tmp) == SUCCESS) {
3933                    hdr_ret = *tmp;
3934                } else {
3935                    hdr_ret = NULL;
3936                }
3937            }
3938
3939            if (headers->function) {
3940                if (serialize_response_call2(head, headers->function, Z_STRVAL(headers->function_name), uri, hdr_ret, version, 0, NULL TSRMLS_CC) == SOAP_ENCODED) {
3941                    use = SOAP_ENCODED;
3942                }
3943            } else {
3944                xmlNodePtr xmlHdr = master_to_xml(hdr_enc, hdr_ret, hdr_use, head TSRMLS_CC);
3945                if (hdr_name) {
3946                    xmlNodeSetName(xmlHdr, BAD_CAST(hdr_name));
3947                }
3948                if (hdr_ns) {
3949                    xmlNsPtr nsptr = encode_add_ns(xmlHdr, hdr_ns);
3950                    xmlSetNs(xmlHdr, nsptr);
3951                }
3952            }
3953        }
3954
3955        body = xmlNewChild(envelope, ns, BAD_CAST("Body"), NULL);
3956        param = xmlNewChild(body, ns, BAD_CAST("Fault"), NULL);
3957
3958        if (zend_hash_find(prop, "faultcodens", sizeof("faultcodens"), (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) {
3959            fault_ns = Z_STRVAL_PP(tmp);
3960        }
3961        use = SOAP_LITERAL;
3962        if (zend_hash_find(prop, "_name", sizeof("_name"), (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) {
3963            sdlFaultPtr *tmp_fault;
3964            if (function && function->faults &&
3965                zend_hash_find(function->faults, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)+1, (void**)&tmp_fault) == SUCCESS) {
3966              fault = *tmp_fault;
3967                if (function->binding &&
3968                    function->binding->bindingType == BINDING_SOAP &&
3969                    fault->bindingAttributes) {
3970                    sdlSoapBindingFunctionFaultPtr fb = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
3971                    use = fb->use;
3972                    if (fault_ns == NULL) {
3973                        fault_ns = fb->ns;
3974                    }
3975                }
3976            }
3977        } else if (function && function->faults &&
3978                   zend_hash_num_elements(function->faults) == 1) {
3979
3980            zend_hash_internal_pointer_reset(function->faults);
3981            zend_hash_get_current_data(function->faults, (void**)&fault);
3982            fault = *(sdlFaultPtr*)fault;
3983            if (function->binding &&
3984                function->binding->bindingType == BINDING_SOAP &&
3985                fault->bindingAttributes) {
3986                sdlSoapBindingFunctionFaultPtr fb = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
3987                use = fb->use;
3988                if (fault_ns == NULL) {
3989                  fault_ns = fb->ns;
3990                }
3991            }
3992        }
3993
3994        if (fault_ns == NULL &&
3995            fault &&
3996            fault->details &&
3997            zend_hash_num_elements(fault->details) == 1) {
3998            sdlParamPtr sparam;
3999
4000            zend_hash_internal_pointer_reset(fault->details);
4001            zend_hash_get_current_data(fault->details, (void**)&sparam);
4002            sparam = *(sdlParamPtr*)sparam;
4003            if (sparam->element) {
4004                fault_ns = sparam->element->namens;
4005            }
4006        }
4007
4008        if (version == SOAP_1_1) {
4009            if (zend_hash_find(prop, "faultcode", sizeof("faultcode"), (void**)&tmp) == SUCCESS &&
4010                Z_TYPE_PP(tmp) == IS_STRING) {
4011                size_t new_len;
4012                xmlNodePtr node = xmlNewNode(NULL, BAD_CAST("faultcode"));
4013                char *str = php_escape_html_entities((unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), &new_len, 0, 0, NULL TSRMLS_CC);
4014                xmlAddChild(param, node);
4015                if (fault_ns) {
4016                    xmlNsPtr nsptr = encode_add_ns(node, fault_ns);
4017                    xmlChar *code = xmlBuildQName(BAD_CAST(str), nsptr->prefix, NULL, 0);
4018                    xmlNodeSetContent(node, code);
4019                    xmlFree(code);
4020                } else {
4021                    xmlNodeSetContentLen(node, BAD_CAST(str), (int)new_len);
4022                }
4023                efree(str);
4024            }
4025            if (zend_hash_find(prop, "faultstring", sizeof("faultstring"), (void**)&tmp) == SUCCESS) {
4026                xmlNodePtr node = master_to_xml(get_conversion(IS_STRING), *tmp, SOAP_LITERAL, param TSRMLS_CC);
4027                xmlNodeSetName(node, BAD_CAST("faultstring"));
4028            }
4029            if (zend_hash_find(prop, "faultactor", sizeof("faultactor"), (void**)&tmp) == SUCCESS) {
4030                xmlNodePtr node = master_to_xml(get_conversion(IS_STRING), *tmp, SOAP_LITERAL, param TSRMLS_CC);
4031                xmlNodeSetName(node, BAD_CAST("faultactor"));
4032            }
4033            detail_name = "detail";
4034        } else {
4035            if (zend_hash_find(prop, "faultcode", sizeof("faultcode"), (void**)&tmp) == SUCCESS &&
4036                Z_TYPE_PP(tmp) == IS_STRING) {
4037                size_t new_len;
4038                xmlNodePtr node = xmlNewChild(param, ns, BAD_CAST("Code"), NULL);
4039                char *str = php_escape_html_entities((unsigned char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), &new_len, 0, 0, NULL TSRMLS_CC);
4040                node = xmlNewChild(node, ns, BAD_CAST("Value"), NULL);
4041                if (fault_ns) {
4042                    xmlNsPtr nsptr = encode_add_ns(node, fault_ns);
4043                    xmlChar *code = xmlBuildQName(BAD_CAST(str), nsptr->prefix, NULL, 0);
4044                    xmlNodeSetContent(node, code);
4045                    xmlFree(code);
4046                } else {
4047                    xmlNodeSetContentLen(node, BAD_CAST(str), (int)new_len);
4048                }
4049                efree(str);
4050            }
4051            if (zend_hash_find(prop, "faultstring", sizeof("faultstring"), (void**)&tmp) == SUCCESS) {
4052                xmlNodePtr node = xmlNewChild(param, ns, BAD_CAST("Reason"), NULL);
4053                node = master_to_xml(get_conversion(IS_STRING), *tmp, SOAP_LITERAL, node TSRMLS_CC);
4054                xmlNodeSetName(node, BAD_CAST("Text"));
4055                xmlSetNs(node, ns);
4056            }
4057            detail_name = SOAP_1_2_ENV_NS_PREFIX":Detail";
4058        }
4059        if (fault && fault->details && zend_hash_num_elements(fault->details) == 1) {
4060            xmlNodePtr node;
4061            zval *detail = NULL;
4062            sdlParamPtr sparam;
4063            xmlNodePtr x;
4064
4065            if (zend_hash_find(prop, "detail", sizeof("detail"), (void**)&tmp) == SUCCESS &&
4066                Z_TYPE_PP(tmp) != IS_NULL) {
4067                detail = *tmp;
4068            }
4069            node = xmlNewNode(NULL, BAD_CAST(detail_name));
4070            xmlAddChild(param, node);
4071
4072            zend_hash_internal_pointer_reset(fault->details);
4073            zend_hash_get_current_data(fault->details, (void**)&sparam);
4074            sparam = *(sdlParamPtr*)sparam;
4075
4076            if (detail &&
4077                Z_TYPE_P(detail) == IS_OBJECT &&
4078                sparam->element &&
4079                zend_hash_num_elements(Z_OBJPROP_P(detail)) == 1 &&
4080                zend_hash_find(Z_OBJPROP_P(detail), sparam->element->name, strlen(sparam->element->name)+1, (void**)&tmp) == SUCCESS) {
4081                detail = *tmp;
4082            }
4083
4084            x = serialize_parameter(sparam, detail, 1, NULL, use, node TSRMLS_CC);
4085
4086            if (function &&
4087                function->binding &&
4088                function->binding->bindingType == BINDING_SOAP &&
4089                function->bindingAttributes) {
4090                sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
4091                if (fnb->style == SOAP_RPC && !sparam->element) {
4092                  if (fault->bindingAttributes) {
4093                        sdlSoapBindingFunctionFaultPtr fb = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
4094                        if (fb->ns) {
4095                            xmlNsPtr ns = encode_add_ns(x, fb->ns);
4096                            xmlSetNs(x, ns);
4097                        }
4098                    }
4099                } else {
4100                    if (sparam->element) {
4101                        ns = encode_add_ns(x, sparam->element->namens);
4102                        xmlNodeSetName(x, BAD_CAST(sparam->element->name));
4103                        xmlSetNs(x, ns);
4104                    }
4105                }
4106            }
4107            if (use == SOAP_ENCODED && version == SOAP_1_2) {
4108                xmlSetNsProp(x, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
4109            }
4110        } else if (zend_hash_find(prop, "detail", sizeof("detail"), (void**)&tmp) == SUCCESS &&
4111            Z_TYPE_PP(tmp) != IS_NULL) {
4112            serialize_zval(*tmp, NULL, detail_name, use, param TSRMLS_CC);
4113        }
4114    } else {
4115
4116        if (headers) {
4117            soapHeader *h;
4118
4119            head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL);
4120            h = headers;
4121            while (h != NULL) {
4122                if (Z_TYPE(h->retval) != IS_NULL) {
4123                    encodePtr hdr_enc = NULL;
4124                    int hdr_use = SOAP_LITERAL;
4125                    zval *hdr_ret = &h->retval;
4126                    char *hdr_ns   = h->hdr?h->hdr->ns:NULL;
4127                    char *hdr_name = Z_STRVAL(h->function_name);
4128                    HashTable *ht = NULL;
4129
4130                    if (Z_TYPE(h->retval) == IS_OBJECT &&
4131                        instanceof_function(Z_OBJCE(h->retval), soap_header_class_entry TSRMLS_CC)) {
4132                        zval **tmp;
4133                        sdlSoapBindingFunctionHeaderPtr *hdr;
4134                        smart_str key = {0};
4135
4136                        ht = Z_OBJPROP(h->retval);
4137                        if (zend_hash_find(ht, "namespace", sizeof("namespace"), (void**)&tmp) == SUCCESS &&
4138                          Z_TYPE_PP(tmp) == IS_STRING) {
4139                            smart_str_appendl(&key, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
4140                            smart_str_appendc(&key, ':');
4141                            hdr_ns = Z_STRVAL_PP(tmp);
4142                        }
4143                        if (zend_hash_find(ht, "name", sizeof("name"), (void**)&tmp) == SUCCESS &&
4144                            Z_TYPE_PP(tmp) == IS_STRING) {
4145                            smart_str_appendl(&key, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
4146                            hdr_name = Z_STRVAL_PP(tmp);
4147                        }
4148                        smart_str_0(&key);
4149                        if (function && function->binding && function->binding->bindingType == BINDING_SOAP) {
4150                            sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
4151
4152                            if (fnb->output.headers &&
4153                                zend_hash_find(fnb->output.headers, key.c, key.len+1, (void**)&hdr) == SUCCESS) {
4154                                hdr_enc = (*hdr)->encode;
4155                                hdr_use = (*hdr)->use;
4156                            }
4157                        }
4158                        smart_str_free(&key);
4159                        if (zend_hash_find(ht, "data", sizeof("data"), (void**)&tmp) == SUCCESS) {
4160                            hdr_ret = *tmp;
4161                        } else {
4162                            hdr_ret = NULL;
4163                        }
4164                    }
4165
4166                    if (h->function) {
4167                        xmlNodePtr xmlHdr = NULL;
4168
4169                        if (serialize_response_call2(head, h->function, Z_STRVAL(h->function_name), uri, hdr_ret, version, 0, &xmlHdr TSRMLS_CC) == SOAP_ENCODED) {
4170                            use = SOAP_ENCODED;
4171                        }
4172                        if (ht) {
4173                            set_soap_header_attributes(xmlHdr, ht, version);
4174                        }
4175                    } else {
4176                        xmlNodePtr xmlHdr = master_to_xml(hdr_enc, hdr_ret, hdr_use, head TSRMLS_CC);
4177                        if (hdr_name) {
4178                            xmlNodeSetName(xmlHdr, BAD_CAST(hdr_name));
4179                        }
4180                        if (hdr_ns) {
4181                            xmlNsPtr nsptr = encode_add_ns(xmlHdr,hdr_ns);
4182                            xmlSetNs(xmlHdr, nsptr);
4183                        }
4184                        if (ht) {
4185                            set_soap_header_attributes(xmlHdr, ht, version);
4186                        }
4187                    }
4188                }
4189                h = h->next;
4190            }
4191
4192            if (head->children == NULL) {
4193                xmlUnlinkNode(head);
4194                xmlFreeNode(head);
4195            }
4196        }
4197
4198        body = xmlNewChild(envelope, ns, BAD_CAST("Body"), NULL);
4199
4200        if (serialize_response_call2(body, function, function_name, uri, ret, version, 1, NULL TSRMLS_CC) == SOAP_ENCODED) {
4201            use = SOAP_ENCODED;
4202        }
4203
4204    }
4205
4206    if (use == SOAP_ENCODED) {
4207        xmlNewNs(envelope, BAD_CAST(XSD_NAMESPACE), BAD_CAST(XSD_NS_PREFIX));
4208        if (version == SOAP_1_1) {
4209            xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENC_NAMESPACE), BAD_CAST(SOAP_1_1_ENC_NS_PREFIX));
4210            xmlSetNsProp(envelope, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_1_ENC_NAMESPACE));
4211        } else if (version == SOAP_1_2) {
4212            xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENC_NAMESPACE), BAD_CAST(SOAP_1_2_ENC_NS_PREFIX));
4213        }
4214    }
4215
4216    encode_finish();
4217
4218    if (function && function->responseName == NULL &&
4219        body->children == NULL && head == NULL) {
4220        xmlFreeDoc(doc);
4221        return NULL;
4222    }
4223    return doc;
4224}
4225
4226static 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)
4227{
4228    xmlDoc *doc;
4229    xmlNodePtr envelope = NULL, body, method = NULL, head = NULL;
4230    xmlNsPtr ns = NULL;
4231    zval **zstyle, **zuse;
4232    int i, style, use;
4233    HashTable *hdrs = NULL;
4234
4235    encode_reset_ns();
4236
4237    doc = xmlNewDoc(BAD_CAST("1.0"));
4238    doc->encoding = xmlCharStrdup("UTF-8");
4239    doc->charset = XML_CHAR_ENCODING_UTF8;
4240    if (version == SOAP_1_1) {
4241        envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
4242        ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENV_NAMESPACE), BAD_CAST(SOAP_1_1_ENV_NS_PREFIX));
4243        xmlSetNs(envelope, ns);
4244    } else if (version == SOAP_1_2) {
4245        envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
4246        ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENV_NAMESPACE), BAD_CAST(SOAP_1_2_ENV_NS_PREFIX));
4247        xmlSetNs(envelope, ns);
4248    } else {
4249        soap_error0(E_ERROR, "Unknown SOAP version");
4250    }
4251    xmlDocSetRootElement(doc, envelope);
4252
4253    if (soap_headers) {
4254        head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL);
4255    }
4256
4257    body = xmlNewChild(envelope, ns, BAD_CAST("Body"), NULL);
4258
4259    if (function && function->binding->bindingType == BINDING_SOAP) {
4260        sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
4261
4262        hdrs = fnb->input.headers;
4263        style = fnb->style;
4264        /*FIXME: how to pass method name if style is SOAP_DOCUMENT */
4265        /*style = SOAP_RPC;*/
4266        use = fnb->input.use;
4267        if (style == SOAP_RPC) {
4268            ns = encode_add_ns(body, fnb->input.ns);
4269            if (function->requestName) {
4270                method = xmlNewChild(body, ns, BAD_CAST(function->requestName), NULL);
4271            } else {
4272                method = xmlNewChild(body, ns, BAD_CAST(function->functionName), NULL);
4273            }
4274        }
4275    } else {
4276        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "style", sizeof("style"), (void **)&zstyle) == SUCCESS &&
4277            Z_TYPE_PP(zstyle) == IS_LONG) {
4278            style = Z_LVAL_PP(zstyle);
4279        } else {
4280            style = SOAP_RPC;
4281        }
4282        /*FIXME: how to pass method name if style is SOAP_DOCUMENT */
4283        /*style = SOAP_RPC;*/
4284        if (style == SOAP_RPC) {
4285            ns = encode_add_ns(body, uri);
4286            if (function_name) {
4287                method = xmlNewChild(body, ns, BAD_CAST(function_name), NULL);
4288            } else if (function && function->requestName) {
4289                method = xmlNewChild(body, ns, BAD_CAST(function->requestName), NULL);
4290            } else if (function && function->functionName) {
4291                method = xmlNewChild(body, ns, BAD_CAST(function->functionName), NULL);
4292            } else {
4293                method = body;
4294            }
4295        } else {
4296            method = body;
4297        }
4298
4299        if (zend_hash_find(Z_OBJPROP_P(this_ptr), "use", sizeof("use"), (void **)&zuse) == SUCCESS &&
4300            Z_TYPE_PP(zuse) == IS_LONG && Z_LVAL_PP(zuse) == SOAP_LITERAL) {
4301            use = SOAP_LITERAL;
4302        } else {
4303            use = SOAP_ENCODED;
4304        }
4305    }
4306
4307    for (i = 0;i < arg_count;i++) {
4308        xmlNodePtr param;
4309        sdlParamPtr parameter = get_param(function, NULL, i, FALSE);
4310
4311        if (style == SOAP_RPC) {
4312            param = serialize_parameter(parameter, arguments[i], i, NULL, use, method TSRMLS_CC);
4313        } else if (style == SOAP_DOCUMENT) {
4314            param = serialize_parameter(parameter, arguments[i], i, NULL, use, body TSRMLS_CC);
4315            if (function && function->binding->bindingType == BINDING_SOAP) {
4316                if (parameter && parameter->element) {
4317                    ns = encode_add_ns(param, parameter->element->namens);
4318                    xmlNodeSetName(param, BAD_CAST(parameter->element->name));
4319                    xmlSetNs(param, ns);
4320                }
4321            }
4322        }
4323    }
4324
4325    if (function && function->requestParameters) {
4326        int n = zend_hash_num_elements(function->requestParameters);
4327
4328        if (n > arg_count) {
4329            for (i = arg_count; i < n; i++) {
4330                xmlNodePtr param;
4331                sdlParamPtr parameter = get_param(function, NULL, i, FALSE);
4332
4333                if (style == SOAP_RPC) {
4334                    param = serialize_parameter(parameter, NULL, i, NULL, use, method TSRMLS_CC);
4335                } else if (style == SOAP_DOCUMENT) {
4336                    param = serialize_parameter(parameter, NULL, i, NULL, use, body TSRMLS_CC);
4337                    if (function && function->binding->bindingType == BINDING_SOAP) {
4338                        if (parameter && parameter->element) {
4339                            ns = encode_add_ns(param, parameter->element->namens);
4340                            xmlNodeSetName(param, BAD_CAST(parameter->element->name));
4341                            xmlSetNs(param, ns);
4342                        }
4343                    }
4344                }
4345            }
4346        }
4347    }
4348
4349    if (head) {
4350        zval** header;
4351
4352        for(zend_hash_internal_pointer_reset(soap_headers);
4353                zend_hash_get_current_data(soap_headers,(void**)&header) == SUCCESS;
4354                zend_hash_move_forward(soap_headers)
4355            ) {
4356            HashTable *ht;
4357            zval **name, **ns, **tmp;
4358
4359            if (Z_TYPE_PP(header) != IS_OBJECT) {
4360                continue;
4361            }
4362
4363            ht = Z_OBJPROP_PP(header);
4364            if (zend_hash_find(ht, "name", sizeof("name"), (void**)&name) == SUCCESS &&
4365                Z_TYPE_PP(name) == IS_STRING &&
4366                zend_hash_find(ht, "namespace", sizeof("namespace"), (void**)&ns) == SUCCESS &&
4367                Z_TYPE_PP(ns) == IS_STRING) {
4368                xmlNodePtr h;
4369                xmlNsPtr nsptr;
4370                int hdr_use = SOAP_LITERAL;
4371                encodePtr enc = NULL;
4372
4373                if (hdrs) {
4374                    smart_str key = {0};
4375                    sdlSoapBindingFunctionHeaderPtr *hdr;
4376
4377                    smart_str_appendl(&key, Z_STRVAL_PP(ns), Z_STRLEN_PP(ns));
4378                    smart_str_appendc(&key, ':');
4379                    smart_str_appendl(&key, Z_STRVAL_PP(name), Z_STRLEN_PP(name));
4380                    smart_str_0(&key);
4381                    if (zend_hash_find(hdrs, key.c, key.len+1,(void**)&hdr) == SUCCESS) {
4382                        hdr_use = (*hdr)->use;
4383                        enc = (*hdr)->encode;
4384                        if (hdr_use == SOAP_ENCODED) {
4385                            use = SOAP_ENCODED;
4386                        }
4387                    }
4388                    smart_str_free(&key);
4389                }
4390
4391                if (zend_hash_find(ht, "data", sizeof("data"), (void**)&tmp) == SUCCESS) {
4392                    h = master_to_xml(enc, *tmp, hdr_use, head TSRMLS_CC);
4393                    xmlNodeSetName(h, BAD_CAST(Z_STRVAL_PP(name)));
4394                } else {
4395                    h = xmlNewNode(NULL, BAD_CAST(Z_STRVAL_PP(name)));
4396                    xmlAddChild(head, h);
4397                }
4398                nsptr = encode_add_ns(h, Z_STRVAL_PP(ns));
4399                xmlSetNs(h, nsptr);
4400                set_soap_header_attributes(h, ht, version);
4401            }
4402        }
4403    }
4404
4405    if (use == SOAP_ENCODED) {
4406        xmlNewNs(envelope, BAD_CAST(XSD_NAMESPACE), BAD_CAST(XSD_NS_PREFIX));
4407        if (version == SOAP_1_1) {
4408            xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENC_NAMESPACE), BAD_CAST(SOAP_1_1_ENC_NS_PREFIX));
4409            xmlSetNsProp(envelope, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_1_ENC_NAMESPACE));
4410        } else if (version == SOAP_1_2) {
4411            xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENC_NAMESPACE), BAD_CAST(SOAP_1_2_ENC_NS_PREFIX));
4412            if (method) {
4413                xmlSetNsProp(method, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
4414            }
4415        }
4416    }
4417
4418    encode_finish();
4419
4420    return doc;
4421}
4422
4423static xmlNodePtr serialize_parameter(sdlParamPtr param, zval *param_val, int index, char *name, int style, xmlNodePtr parent TSRMLS_DC)
4424{
4425    char *paramName;
4426    xmlNodePtr xmlParam;
4427    char paramNameBuf[10];
4428
4429    if (param_val &&
4430        Z_TYPE_P(param_val) == IS_OBJECT &&
4431        Z_OBJCE_P(param_val) == soap_param_class_entry) {
4432        zval **param_name;
4433        zval **param_data;
4434
4435        if (zend_hash_find(Z_OBJPROP_P(param_val), "param_name", sizeof("param_name"), (void **)&param_name) == SUCCESS &&
4436            Z_TYPE_PP(param_name) == IS_STRING &&
4437            zend_hash_find(Z_OBJPROP_P(param_val), "param_data", sizeof("param_data"), (void **)&param_data) == SUCCESS) {
4438            param_val = *param_data;
4439            name = Z_STRVAL_PP(param_name);
4440        }
4441    }
4442
4443    if (param != NULL && param->paramName != NULL) {
4444        paramName = param->paramName;
4445    } else {
4446        if (name == NULL) {
4447            paramName = paramNameBuf;
4448            snprintf(paramName, sizeof(paramNameBuf), "param%d",index);
4449        } else {
4450            paramName = name;
4451        }
4452    }
4453
4454    xmlParam = serialize_zval(param_val, param, paramName, style, parent TSRMLS_CC);
4455
4456    return xmlParam;
4457}
4458
4459static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName, int style, xmlNodePtr parent TSRMLS_DC)
4460{
4461    xmlNodePtr xmlParam;
4462    encodePtr enc;
4463    zval defval;
4464
4465    if (param != NULL) {
4466        enc = param->encode;
4467        if (val == NULL) {
4468            if (param->element) {
4469                if (param->element->fixed) {
4470                    ZVAL_STRING(&defval, param->element->fixed, 0);
4471                    val = &defval;
4472                } else if (param->element->def && !param->element->nillable) {
4473                    ZVAL_STRING(&defval, param->element->def, 0);
4474                    val = &defval;
4475                }
4476            }
4477        }
4478    } else {
4479        enc = NULL;
4480    }
4481    xmlParam = master_to_xml(enc, val, style, parent TSRMLS_CC);
4482    if (!strcmp((char*)xmlParam->name, "BOGUS")) {
4483        xmlNodeSetName(xmlParam, BAD_CAST(paramName));
4484    }
4485    return xmlParam;
4486}
4487
4488static sdlParamPtr get_param(sdlFunctionPtr function, char *param_name, int index, int response)
4489{
4490    sdlParamPtr *tmp;
4491    HashTable   *ht;
4492
4493    if (function == NULL) {
4494        return NULL;
4495    }
4496
4497    if (response == FALSE) {
4498        ht = function->requestParameters;
4499    } else {
4500        ht = function->responseParameters;
4501    }
4502
4503    if (ht == NULL) {
4504      return NULL;
4505    }
4506
4507    if (param_name != NULL) {
4508        if (zend_hash_find(ht, param_name, strlen(param_name), (void **)&tmp) != FAILURE) {
4509            return *tmp;
4510        } else {
4511            HashPosition pos;
4512
4513            zend_hash_internal_pointer_reset_ex(ht, &pos);
4514            while (zend_hash_get_current_data_ex(ht, (void **)&tmp, &pos) != FAILURE) {
4515                if ((*tmp)->paramName && strcmp(param_name, (*tmp)->paramName) == 0) {
4516                    return *tmp;
4517                }
4518                zend_hash_move_forward_ex(ht, &pos);
4519            }
4520        }
4521    } else {
4522        if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE) {
4523            return (*tmp);
4524        }
4525    }
4526    return NULL;
4527}
4528
4529static sdlFunctionPtr get_function(sdlPtr sdl, const char *function_name)
4530{
4531    sdlFunctionPtr *tmp;
4532
4533    int len = strlen(function_name);
4534    char *str = estrndup(function_name,len);
4535    php_strtolower(str,len);
4536    if (sdl != NULL) {
4537        if (zend_hash_find(&sdl->functions, str, len+1, (void **)&tmp) != FAILURE) {
4538            efree(str);
4539            return (*tmp);
4540        } else if (sdl->requests != NULL && zend_hash_find(sdl->requests, str, len+1, (void **)&tmp) != FAILURE) {
4541            efree(str);
4542            return (*tmp);
4543        }
4544    }
4545    efree(str);
4546    return NULL;
4547}
4548
4549static sdlFunctionPtr get_doc_function(sdlPtr sdl, xmlNodePtr params)
4550{
4551    if (sdl) {
4552        sdlFunctionPtr *tmp;
4553        sdlParamPtr    *param;
4554
4555        zend_hash_internal_pointer_reset(&sdl->functions);
4556        while (zend_hash_get_current_data(&sdl->functions, (void**)&tmp) == SUCCESS) {
4557            if ((*tmp)->binding && (*tmp)->binding->bindingType == BINDING_SOAP) {
4558                sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)(*tmp)->bindingAttributes;
4559                if (fnb->style == SOAP_DOCUMENT) {
4560                    if (params == NULL) {
4561                        if ((*tmp)->requestParameters == NULL ||
4562                            zend_hash_num_elements((*tmp)->requestParameters) == 0) {
4563                          return *tmp;
4564                        }
4565                    } else if ((*tmp)->requestParameters != NULL &&
4566                               zend_hash_num_elements((*tmp)->requestParameters) > 0) {
4567                        int ok = 1;
4568                        xmlNodePtr node = params;
4569
4570                        zend_hash_internal_pointer_reset((*tmp)->requestParameters);
4571                        while (zend_hash_get_current_data((*tmp)->requestParameters, (void**)&param) == SUCCESS) {
4572                            if ((*param)->element) {
4573                                if (strcmp((*param)->element->name, (char*)node->name) != 0) {
4574                                    ok = 0;
4575                                    break;
4576                                }
4577                                if ((*param)->element->namens != NULL && node->ns != NULL) {
4578                                    if (strcmp((*param)->element->namens, (char*)node->ns->href) != 0) {
4579                                        ok = 0;
4580                                        break;
4581                                    }
4582                                } else if ((void*)(*param)->element->namens != (void*)node->ns) {
4583                                    ok = 0;
4584                                    break;
4585                                }
4586                            } else if (strcmp((*param)->paramName, (char*)node->name) != 0) {
4587                                ok = 0;
4588                                break;
4589                            }
4590                            zend_hash_move_forward((*tmp)->requestParameters);
4591                            node = node->next;
4592                        }
4593                        if (ok /*&& node == NULL*/) {
4594                            return (*tmp);
4595                        }
4596                    }
4597                }
4598            }
4599            zend_hash_move_forward(&sdl->functions);
4600        }
4601    }
4602    return NULL;
4603}
4604
4605static void function_to_string(sdlFunctionPtr function, smart_str *buf)
4606{
4607    int i = 0;
4608    HashPosition pos;
4609    sdlParamPtr *param;
4610
4611    if (function->responseParameters &&
4612        zend_hash_num_elements(function->responseParameters) > 0) {
4613        if (zend_hash_num_elements(function->responseParameters) == 1) {
4614            zend_hash_internal_pointer_reset(function->responseParameters);
4615            zend_hash_get_current_data(function->responseParameters, (void**)&param);
4616            if ((*param)->encode && (*param)->encode->details.type_str) {
4617                smart_str_appendl(buf, (*param)->encode->details.type_str, strlen((*param)->encode->details.type_str));
4618                smart_str_appendc(buf, ' ');
4619            } else {
4620                smart_str_appendl(buf, "UNKNOWN ", 8);
4621            }
4622        } else {
4623            i = 0;
4624            smart_str_appendl(buf, "list(", 5);
4625            zend_hash_internal_pointer_reset_ex(function->responseParameters, &pos);
4626            while (zend_hash_get_current_data_ex(function->responseParameters, (void **)&param, &pos) != FAILURE) {
4627                if (i > 0) {
4628                    smart_str_appendl(buf, ", ", 2);
4629                }
4630                if ((*param)->encode && (*param)->encode->details.type_str) {
4631                    smart_str_appendl(buf, (*param)->encode->details.type_str, strlen((*param)->encode->details.type_str));
4632                } else {
4633                    smart_str_appendl(buf, "UNKNOWN", 7);
4634                }
4635                smart_str_appendl(buf, " $", 2);
4636                smart_str_appendl(buf, (*param)->paramName, strlen((*param)->paramName));
4637                zend_hash_move_forward_ex(function->responseParameters, &pos);
4638                i++;
4639            }
4640            smart_str_appendl(buf, ") ", 2);
4641        }
4642    } else {
4643        smart_str_appendl(buf, "void ", 5);
4644    }
4645
4646    smart_str_appendl(buf, function->functionName, strlen(function->functionName));
4647
4648    smart_str_appendc(buf, '(');
4649    if (function->requestParameters) {
4650        i = 0;
4651        zend_hash_internal_pointer_reset_ex(function->requestParameters, &pos);
4652        while (zend_hash_get_current_data_ex(function->requestParameters, (void **)&param, &pos) != FAILURE) {
4653            if (i > 0) {
4654                smart_str_appendl(buf, ", ", 2);
4655            }
4656            if ((*param)->encode && (*param)->encode->details.type_str) {
4657                smart_str_appendl(buf, (*param)->encode->details.type_str, strlen((*param)->encode->details.type_str));
4658            } else {
4659                smart_str_appendl(buf, "UNKNOWN", 7);
4660            }
4661            smart_str_appendl(buf, " $", 2);
4662            smart_str_appendl(buf, (*param)->paramName, strlen((*param)->paramName));
4663            zend_hash_move_forward_ex(function->requestParameters, &pos);
4664            i++;
4665        }
4666    }
4667    smart_str_appendc(buf, ')');
4668    smart_str_0(buf);
4669}
4670
4671static void model_to_string(sdlContentModelPtr model, smart_str *buf, int level)
4672{
4673    int i;
4674
4675    switch (model->kind) {
4676        case XSD_CONTENT_ELEMENT:
4677            type_to_string(model->u.element, buf, level);
4678            smart_str_appendl(buf, ";\n", 2);
4679            break;
4680        case XSD_CONTENT_ANY:
4681            for (i = 0;i < level;i++) {
4682                smart_str_appendc(buf, ' ');
4683            }
4684            smart_str_appendl(buf, "<anyXML> any;\n", sizeof("<anyXML> any;\n")-1);
4685            break;
4686        case XSD_CONTENT_SEQUENCE:
4687        case XSD_CONTENT_ALL:
4688        case XSD_CONTENT_CHOICE: {
4689            sdlContentModelPtr *tmp;
4690
4691            zend_hash_internal_pointer_reset(model->u.content);
4692            while (zend_hash_get_current_data(model->u.content, (void**)&tmp) == SUCCESS) {
4693                model_to_string(*tmp, buf, level);
4694                zend_hash_move_forward(model->u.content);
4695            }
4696            break;
4697        }
4698        case XSD_CONTENT_GROUP:
4699            model_to_string(model->u.group->model, buf, level);
4700        default:
4701          break;
4702    }
4703}
4704
4705static void type_to_string(sdlTypePtr type, smart_str *buf, int level)
4706{
4707    int i;
4708    smart_str spaces = {0};
4709    HashPosition pos;
4710
4711    for (i = 0;i < level;i++) {
4712        smart_str_appendc(&spaces, ' ');
4713    }
4714    smart_str_appendl(buf, spaces.c, spaces.len);
4715
4716    switch (type->kind) {
4717        case XSD_TYPEKIND_SIMPLE:
4718            if (type->encode) {
4719                smart_str_appendl(buf, type->encode->details.type_str, strlen(type->encode->details.type_str));
4720                smart_str_appendc(buf, ' ');
4721            } else {
4722                smart_str_appendl(buf, "anyType ", sizeof("anyType ")-1);
4723            }
4724            smart_str_appendl(buf, type->name, strlen(type->name));
4725            break;
4726        case XSD_TYPEKIND_LIST:
4727            smart_str_appendl(buf, "list ", 5);
4728            smart_str_appendl(buf, type->name, strlen(type->name));
4729            if (type->elements) {
4730                sdlTypePtr *item_type;
4731
4732                smart_str_appendl(buf, " {", 2);
4733                zend_hash_internal_pointer_reset_ex(type->elements, &pos);
4734                if (zend_hash_get_current_data_ex(type->elements, (void **)&item_type, &pos) != FAILURE) {
4735                    smart_str_appendl(buf, (*item_type)->name, strlen((*item_type)->name));
4736                }
4737                smart_str_appendc(buf, '}');
4738            }
4739            break;
4740        case XSD_TYPEKIND_UNION:
4741            smart_str_appendl(buf, "union ", 6);
4742            smart_str_appendl(buf, type->name, strlen(type->name));
4743            if (type->elements) {
4744                sdlTypePtr *item_type;
4745                int first = 0;
4746
4747                smart_str_appendl(buf, " {", 2);
4748                zend_hash_internal_pointer_reset_ex(type->elements, &pos);
4749                while (zend_hash_get_current_data_ex(type->elements, (void **)&item_type, &pos) != FAILURE) {
4750                    if (!first) {
4751                        smart_str_appendc(buf, ',');
4752                        first = 0;
4753                    }
4754                    smart_str_appendl(buf, (*item_type)->name, strlen((*item_type)->name));
4755                    zend_hash_move_forward_ex(type->elements, &pos);
4756                }
4757                smart_str_appendc(buf, '}');
4758            }
4759            break;
4760        case XSD_TYPEKIND_COMPLEX:
4761        case XSD_TYPEKIND_RESTRICTION:
4762        case XSD_TYPEKIND_EXTENSION:
4763            if (type->encode &&
4764                (type->encode->details.type == IS_ARRAY ||
4765                 type->encode->details.type == SOAP_ENC_ARRAY)) {
4766              sdlAttributePtr *attr;
4767              sdlExtraAttributePtr *ext;
4768
4769                if (type->attributes &&
4770                    zend_hash_find(type->attributes, SOAP_1_1_ENC_NAMESPACE":arrayType",
4771                      sizeof(SOAP_1_1_ENC_NAMESPACE":arrayType"),
4772                      (void **)&attr) == SUCCESS &&
4773                      (*attr)->extraAttributes &&
4774                      zend_hash_find((*attr)->extraAttributes, WSDL_NAMESPACE":arrayType", sizeof(WSDL_NAMESPACE":arrayType"), (void **)&ext) == SUCCESS) {
4775                    char *end = strchr((*ext)->val, '[');
4776                    int len;
4777                    if (end == NULL) {
4778                        len = strlen((*ext)->val);
4779                    } else {
4780                        len = end-(*ext)->val;
4781                    }
4782                    if (len == 0) {
4783                        smart_str_appendl(buf, "anyType", sizeof("anyType")-1);
4784                    } else {
4785                        smart_str_appendl(buf, (*ext)->val, len);
4786                    }
4787                    smart_str_appendc(buf, ' ');
4788                    smart_str_appendl(buf, type->name, strlen(type->name));
4789                    if (end != NULL) {
4790                        smart_str_appends(buf, end);
4791                    }
4792                } else {
4793                    sdlTypePtr elementType;
4794                    if (type->attributes &&
4795                        zend_hash_find(type->attributes, SOAP_1_2_ENC_NAMESPACE":itemType",
4796                          sizeof(SOAP_1_2_ENC_NAMESPACE":itemType"),
4797                          (void **)&attr) == SUCCESS &&
4798                          (*attr)->extraAttributes &&
4799                          zend_hash_find((*attr)->extraAttributes, WSDL_NAMESPACE":itemType", sizeof(WSDL_NAMESPACE":arrayType"), (void **)&ext) == SUCCESS) {
4800                        smart_str_appends(buf, (*ext)->val);
4801                        smart_str_appendc(buf, ' ');
4802                    } else if (type->elements &&
4803                               zend_hash_num_elements(type->elements) == 1 &&
4804                               (zend_hash_internal_pointer_reset(type->elements),
4805                                zend_hash_get_current_data(type->elements, (void**)&elementType) == SUCCESS) &&
4806                               (elementType = *(sdlTypePtr*)elementType) != NULL &&
4807                               elementType->encode && elementType->encode->details.type_str) {
4808                        smart_str_appends(buf, elementType->encode->details.type_str);
4809                        smart_str_appendc(buf, ' ');
4810                    } else {
4811                        smart_str_appendl(buf, "anyType ", 8);
4812                    }
4813                    smart_str_appendl(buf, type->name, strlen(type->name));
4814                    if (type->attributes &&
4815                        zend_hash_find(type->attributes, SOAP_1_2_ENC_NAMESPACE":arraySize",
4816                          sizeof(SOAP_1_2_ENC_NAMESPACE":arraySize"),
4817                          (void **)&attr) == SUCCESS &&
4818                          (*attr)->extraAttributes &&
4819                          zend_hash_find((*attr)->extraAttributes, WSDL_NAMESPACE":itemType", sizeof(WSDL_NAMESPACE":arraySize"), (void **)&ext) == SUCCESS) {
4820                        smart_str_appendc(buf, '[');
4821                        smart_str_appends(buf, (*ext)->val);
4822                        smart_str_appendc(buf, ']');
4823                    } else {
4824                        smart_str_appendl(buf, "[]", 2);
4825                    }
4826                }
4827            } else {
4828                smart_str_appendl(buf, "struct ", 7);
4829                smart_str_appendl(buf, type->name, strlen(type->name));
4830                smart_str_appendc(buf, ' ');
4831                smart_str_appendl(buf, "{\n", 2);
4832                if ((type->kind == XSD_TYPEKIND_RESTRICTION ||
4833                     type->kind == XSD_TYPEKIND_EXTENSION) && type->encode) {
4834                    encodePtr enc = type->encode;
4835                    while (enc && enc->details.sdl_type &&
4836                           enc != enc->details.sdl_type->encode &&
4837                           enc->details.sdl_type->kind != XSD_TYPEKIND_SIMPLE &&
4838                           enc->details.sdl_type->kind != XSD_TYPEKIND_LIST &&
4839                           enc->details.sdl_type->kind != XSD_TYPEKIND_UNION) {
4840                        enc = enc->details.sdl_type->encode;
4841                    }
4842                    if (enc) {
4843                        smart_str_appendl(buf, spaces.c, spaces.len);
4844                        smart_str_appendc(buf, ' ');
4845                        smart_str_appendl(buf, type->encode->details.type_str, strlen(type->encode->details.type_str));
4846                        smart_str_appendl(buf, " _;\n", 4);
4847                    }
4848                }
4849                if (type->model) {
4850                    model_to_string(type->model, buf, level+1);
4851                }
4852                if (type->attributes) {
4853                    sdlAttributePtr *attr;
4854
4855                    zend_hash_internal_pointer_reset_ex(type->attributes, &pos);
4856                    while (zend_hash_get_current_data_ex(type->attributes, (void **)&attr, &pos) != FAILURE) {
4857                        smart_str_appendl(buf, spaces.c, spaces.len);
4858                        smart_str_appendc(buf, ' ');
4859                        if ((*attr)->encode && (*attr)->encode->details.type_str) {
4860                            smart_str_appends(buf, (*attr)->encode->details.type_str);
4861                            smart_str_appendc(buf, ' ');
4862                        } else {
4863                            smart_str_appendl(buf, "UNKNOWN ", 8);
4864                        }
4865                        smart_str_appends(buf, (*attr)->name);
4866                        smart_str_appendl(buf, ";\n", 2);
4867                        zend_hash_move_forward_ex(type->attributes, &pos);
4868                    }
4869                }
4870                smart_str_appendl(buf, spaces.c, spaces.len);
4871                smart_str_appendc(buf, '}');
4872            }
4873            break;
4874        default:
4875            break;
4876    }
4877    smart_str_free(&spaces);
4878    smart_str_0(buf);
4879}
4880
4881static void delete_url(void *handle)
4882{
4883    php_url_free((php_url*)handle);
4884}
4885
4886static void delete_service(void *data)
4887{
4888    soapServicePtr service = (soapServicePtr)data;
4889
4890    if (service->soap_functions.ft) {
4891        zend_hash_destroy(service->soap_functions.ft);
4892        efree(service->soap_functions.ft);
4893    }
4894
4895    if (service->typemap) {
4896        zend_hash_destroy(service->typemap);
4897        efree(service->typemap);
4898    }
4899
4900    if (service->soap_class.argc) {
4901        int i;
4902        for (i = 0; i < service->soap_class.argc;i++) {
4903            zval_ptr_dtor(&service->soap_class.argv[i]);
4904        }
4905        efree(service->soap_class.argv);
4906    }
4907
4908    if (service->actor) {
4909        efree(service->actor);
4910    }
4911    if (service->uri) {
4912        efree(service->uri);
4913    }
4914    if (service->sdl) {
4915        delete_sdl(service->sdl);
4916    }
4917    if (service->encoding) {
4918        xmlCharEncCloseFunc(service->encoding);
4919    }
4920    if (service->class_map) {
4921        zend_hash_destroy(service->class_map);
4922        FREE_HASHTABLE(service->class_map);
4923    }
4924    if (service->soap_object) {
4925        zval_ptr_dtor(&service->soap_object);
4926    }
4927    efree(service);
4928}
4929
4930static void delete_hashtable(void *data)
4931{
4932    HashTable *ht = (HashTable*)data;
4933    zend_hash_destroy(ht);
4934    efree(ht);
4935}
4936