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