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