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