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