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