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