xref: /PHP-5.3/ext/soap/soap.c (revision fe21accf)
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 
33 static int le_sdl = 0;
34 int le_url = 0;
35 static int le_service = 0;
36 static int le_typemap = 0;
37 
38 typedef 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 */
50 static void function_to_string(sdlFunctionPtr function, smart_str *buf);
51 static void type_to_string(sdlTypePtr type, smart_str *buf, int level);
52 
53 static void clear_soap_fault(zval *obj TSRMLS_DC);
54 static 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);
55 static void soap_server_fault(char* code, char* string, char *actor, zval* details, char *name TSRMLS_DC);
56 static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader* hdr TSRMLS_DC);
57 
58 static sdlParamPtr get_param(sdlFunctionPtr function, char *param_name, int index, int);
59 static sdlFunctionPtr get_function(sdlPtr sdl, const char *function_name);
60 static sdlFunctionPtr get_doc_function(sdlPtr sdl, xmlNodePtr node);
61 
62 static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, char* actor, zval *function_name, int *num_params, zval **parameters[], int *version, soapHeader **headers TSRMLS_DC);
63 static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function_name,char *uri,zval *ret, soapHeader *headers, int version TSRMLS_DC);
64 static 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);
65 static xmlNodePtr serialize_parameter(sdlParamPtr param,zval *param_val,int index,char *name, int style, xmlNodePtr parent TSRMLS_DC);
66 static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName, int style, xmlNodePtr parent TSRMLS_DC);
67 
68 static void delete_service(void *service);
69 static void delete_url(void *handle);
70 static void delete_hashtable(void *hashtable);
71 
72 #ifndef ZEND_ENGINE_2
73 static void soap_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference);
74 #endif
75 
76 static 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 
180 static zend_class_entry* soap_class_entry;
181 static zend_class_entry* soap_server_class_entry;
182 static zend_class_entry* soap_fault_class_entry;
183 static zend_class_entry* soap_header_class_entry;
184 static zend_class_entry* soap_param_class_entry;
185 zend_class_entry* soap_var_class_entry;
186 
187 ZEND_DECLARE_MODULE_GLOBALS(soap)
188 
189 static 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 
213 PHP_RINIT_FUNCTION(soap);
214 PHP_MINIT_FUNCTION(soap);
215 PHP_MSHUTDOWN_FUNCTION(soap);
216 PHP_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 
zend_str_tolower_copy(char * dest,const char * source,unsigned int length)224 static 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 */
243 PHP_FUNCTION(soap_encode_to_xml);
244 PHP_FUNCTION(soap_encode_to_zval);
245 PHP_FUNCTION(use_soap_error_handler);
246 PHP_FUNCTION(is_soap_fault);
247 
248 
249 /* Server Functions */
250 PHP_METHOD(SoapServer, SoapServer);
251 PHP_METHOD(SoapServer, setClass);
252 PHP_METHOD(SoapServer, setObject);
253 PHP_METHOD(SoapServer, addFunction);
254 PHP_METHOD(SoapServer, getFunctions);
255 PHP_METHOD(SoapServer, handle);
256 PHP_METHOD(SoapServer, setPersistence);
257 PHP_METHOD(SoapServer, fault);
258 PHP_METHOD(SoapServer, addSoapHeader);
259 
260 /* Client Functions */
261 PHP_METHOD(SoapClient, SoapClient);
262 PHP_METHOD(SoapClient, __call);
263 PHP_METHOD(SoapClient, __getLastRequest);
264 PHP_METHOD(SoapClient, __getLastResponse);
265 PHP_METHOD(SoapClient, __getLastRequestHeaders);
266 PHP_METHOD(SoapClient, __getLastResponseHeaders);
267 PHP_METHOD(SoapClient, __getFunctions);
268 PHP_METHOD(SoapClient, __getTypes);
269 PHP_METHOD(SoapClient, __doRequest);
270 PHP_METHOD(SoapClient, __setCookie);
271 PHP_METHOD(SoapClient, __setLocation);
272 PHP_METHOD(SoapClient, __setSoapHeaders);
273 
274 /* SoapVar Functions */
275 PHP_METHOD(SoapVar, SoapVar);
276 
277 /* SoapFault Functions */
278 PHP_METHOD(SoapFault, SoapFault);
279 #ifdef ZEND_ENGINE_2
280 PHP_METHOD(SoapFault, __toString);
281 #endif
282 
283 /* SoapParam Functions */
284 PHP_METHOD(SoapParam, SoapParam);
285 
286 /* SoapHeader Functions */
287 PHP_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
293 ZEND_BEGIN_ARG_INFO(arginfo_soap__void, 0)
294 ZEND_END_ARG_INFO()
295 
296 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapparam_soapparam, 0, 0, 2)
297 	ZEND_ARG_INFO(0, data)
298 	ZEND_ARG_INFO(0, name)
299 ZEND_END_ARG_INFO()
300 
301 ZEND_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)
307 ZEND_END_ARG_INFO()
308 
309 ZEND_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)
316 ZEND_END_ARG_INFO()
317 
318 ZEND_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)
325 ZEND_END_ARG_INFO()
326 
327 ZEND_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)
333 ZEND_END_ARG_INFO()
334 
335 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_addsoapheader, 0, 0, 1)
336 	ZEND_ARG_INFO(0, object)
337 ZEND_END_ARG_INFO()
338 
339 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_soapserver, 0, 0, 1)
340 	ZEND_ARG_INFO(0, wsdl)
341 	ZEND_ARG_INFO(0, options)
342 ZEND_END_ARG_INFO()
343 
344 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_setpersistence, 0, 0, 1)
345 	ZEND_ARG_INFO(0, mode)
346 ZEND_END_ARG_INFO()
347 
348 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_setclass, 0, 0, 1)
349 	ZEND_ARG_INFO(0, class_name)
350 	ZEND_ARG_INFO(0, args)
351 ZEND_END_ARG_INFO()
352 
353 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_setobject, 0, 0, 1)
354 	ZEND_ARG_INFO(0, object)
355 ZEND_END_ARG_INFO()
356 
357 ZEND_BEGIN_ARG_INFO(arginfo_soapserver_getfunctions, 0)
358 ZEND_END_ARG_INFO()
359 
360 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_addfunction, 0, 0, 1)
361 	ZEND_ARG_INFO(0, functions)
362 ZEND_END_ARG_INFO()
363 
364 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_handle, 0, 0, 0)
365 	ZEND_ARG_INFO(0, soap_request)
366 ZEND_END_ARG_INFO()
367 
368 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient_soapclient, 0, 0, 1)
369 	ZEND_ARG_INFO(0, wsdl)
370 	ZEND_ARG_INFO(0, options)
371 ZEND_END_ARG_INFO()
372 
373 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___call, 0, 0, 2)
374 	ZEND_ARG_INFO(0, function_name)
375 	ZEND_ARG_INFO(0, arguments)
376 ZEND_END_ARG_INFO()
377 
378 ZEND_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)
384 ZEND_END_ARG_INFO()
385 
386 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getfunctions, 0)
387 ZEND_END_ARG_INFO()
388 
389 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___gettypes, 0)
390 ZEND_END_ARG_INFO()
391 
392 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastrequest, 0)
393 ZEND_END_ARG_INFO()
394 
395 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastresponse, 0)
396 ZEND_END_ARG_INFO()
397 
398 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastrequestheaders, 0)
399 ZEND_END_ARG_INFO()
400 
401 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastresponseheaders, 0)
402 ZEND_END_ARG_INFO()
403 
404 ZEND_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)
410 ZEND_END_ARG_INFO()
411 
412 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___setcookie, 0, 0, 1)
413 	ZEND_ARG_INFO(0, name)
414 	ZEND_ARG_INFO(0, value)
415 ZEND_END_ARG_INFO()
416 
417 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___setsoapheaders, 0, 0, 1)
418 	ZEND_ARG_INFO(0, soapheaders)
419 ZEND_END_ARG_INFO()
420 
421 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___setlocation, 0, 0, 0)
422 	ZEND_ARG_INFO(0, new_location)
423 ZEND_END_ARG_INFO()
424 
425 ZEND_BEGIN_ARG_INFO_EX(arginfo_soap_use_soap_error_handler, 0, 0, 0)
426 	ZEND_ARG_INFO(0, handler)
427 ZEND_END_ARG_INFO()
428 
429 ZEND_BEGIN_ARG_INFO_EX(arginfo_soap_is_soap_fault, 0, 0, 1)
430 	ZEND_ARG_INFO(0, object)
431 ZEND_END_ARG_INFO()
432 #else
433 unsigned char arginfo_soapclient___call[] = { 2, BYREF_NONE, BYREF_NONE };
434 unsigned 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 
471 static 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 
477 static 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 
485 static 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 
498 static 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 
515 static const zend_function_entry soap_var_functions[] = {
516 	SOAP_CTOR(SoapVar, SoapVar, arginfo_soapvar_soapvar, 0)
517 	PHP_FE_END
518 };
519 
520 static const zend_function_entry soap_param_functions[] = {
521 	SOAP_CTOR(SoapParam, SoapParam, arginfo_soapparam_soapparam, 0)
522 	PHP_FE_END
523 };
524 
525 static const zend_function_entry soap_header_functions[] = {
526 	SOAP_CTOR(SoapHeader, SoapHeader, arginfo_soapheader_soapheader, 0)
527 	PHP_FE_END
528 };
529 
530 zend_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
548 ZEND_GET_MODULE(soap)
549 #endif
550 
551 #ifndef ZEND_ENGINE_2
552 # define OnUpdateLong OnUpdateInt
553 #endif
554 
ZEND_INI_MH(OnUpdateCacheMode)555 ZEND_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 
PHP_INI_MH(OnUpdateCacheDir)571 static 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 
605 PHP_INI_BEGIN()
606 STD_PHP_INI_ENTRY("soap.wsdl_cache_enabled",     "1", PHP_INI_ALL, OnUpdateBool,
607                   cache_enabled, zend_soap_globals, soap_globals)
608 STD_PHP_INI_ENTRY("soap.wsdl_cache_dir",         "/tmp", PHP_INI_ALL, OnUpdateCacheDir,
609                   cache_dir, zend_soap_globals, soap_globals)
610 STD_PHP_INI_ENTRY("soap.wsdl_cache_ttl",         "86400", PHP_INI_ALL, OnUpdateLong,
611                   cache_ttl, zend_soap_globals, soap_globals)
612 STD_PHP_INI_ENTRY("soap.wsdl_cache",             "1", PHP_INI_ALL, OnUpdateCacheMode,
613                   cache_mode, zend_soap_globals, soap_globals)
614 STD_PHP_INI_ENTRY("soap.wsdl_cache_limit",       "5", PHP_INI_ALL, OnUpdateLong,
615                   cache_limit, zend_soap_globals, soap_globals)
616 PHP_INI_END()
617 
618 static HashTable defEnc, defEncIndex, defEncNs;
619 
php_soap_prepare_globals()620 static 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 
php_soap_init_globals(zend_soap_globals * soap_globals TSRMLS_DC)660 static 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 
PHP_MSHUTDOWN_FUNCTION(soap)675 PHP_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 
PHP_RINIT_FUNCTION(soap)689 PHP_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 
PHP_MINIT_FUNCTION(soap)704 PHP_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 
PHP_MINFO_FUNCTION(soap)873 PHP_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 */
PHP_METHOD(SoapParam,SoapParam)885 PHP_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 */
PHP_METHOD(SoapHeader,SoapHeader)910 PHP_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 */
PHP_METHOD(SoapFault,SoapFault)953 PHP_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 */
PHP_METHOD(SoapFault,__toString)1009 PHP_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 */
PHP_METHOD(SoapVar,SoapVar)1053 PHP_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 
soap_create_typemap(sdlPtr sdl,HashTable * ht TSRMLS_DC)1097 static 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 */
PHP_METHOD(SoapServer,SoapServer)1216 PHP_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 */
PHP_METHOD(SoapServer,setPersistence)1344 PHP_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 */
PHP_METHOD(SoapServer,setClass)1375 PHP_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 */
PHP_METHOD(SoapServer,setObject)1435 PHP_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 */
PHP_METHOD(SoapServer,getFunctions)1460 PHP_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 */
PHP_METHOD(SoapServer,addFunction)1509 PHP_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 */
PHP_METHOD(SoapServer,handle)1607 PHP_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 
2114 fail:
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 */
2158 PHP_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 
2184 PHP_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 
2216 static 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 
2291 static 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 
2303 static 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 
2485 PHP_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 
2495 PHP_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 */
2511 PHP_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 
2727 static 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 
2796 static 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 
3001 static 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 */
3018 PHP_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 */
3127 PHP_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 */
3157 PHP_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 */
3189 PHP_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 */
3207 PHP_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 */
3225 PHP_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 */
3243 PHP_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() */
3261 PHP_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. */
3295 PHP_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. */
3333 PHP_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. */
3374 PHP_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
3399 static 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 
3433 static 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 
3440 zval* 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 
3452 static 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 
3507 static 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 
3603 static 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 
3632 static 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 			}
3874 ignore_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 
3894 static 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 
3997 static 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 
4351 static 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 
4572 static 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 
4607 static 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 
4636 static 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 
4677 static 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 
4697 static 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 
4753 static 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 
4819 static 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 
4853 static 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);
5013 					}
5014 				}
5015 				smart_str_appendl(buf, spaces.c, spaces.len);
5016 				smart_str_appendc(buf, '}');
5017 			}
5018 			break;
5019 		default:
5020 			break;
5021 	}
5022 	smart_str_free(&spaces);
5023 	smart_str_0(buf);
5024 }
5025 
5026 static void delete_url(void *handle)
5027 {
5028 	php_url_free((php_url*)handle);
5029 }
5030 
5031 static void delete_service(void *data)
5032 {
5033 	soapServicePtr service = (soapServicePtr)data;
5034 
5035 	if (service->soap_functions.ft) {
5036 		zend_hash_destroy(service->soap_functions.ft);
5037 		efree(service->soap_functions.ft);
5038 	}
5039 
5040 	if (service->typemap) {
5041 		zend_hash_destroy(service->typemap);
5042 		efree(service->typemap);
5043 	}
5044 
5045 	if (service->soap_class.argc) {
5046 		int i;
5047 		for (i = 0; i < service->soap_class.argc;i++) {
5048 			zval_ptr_dtor(&service->soap_class.argv[i]);
5049 		}
5050 		efree(service->soap_class.argv);
5051 	}
5052 
5053 	if (service->actor) {
5054 		efree(service->actor);
5055 	}
5056 	if (service->uri) {
5057 		efree(service->uri);
5058 	}
5059 	if (service->sdl) {
5060 		delete_sdl(service->sdl);
5061 	}
5062 	if (service->encoding) {
5063 		xmlCharEncCloseFunc(service->encoding);
5064 	}
5065 	if (service->class_map) {
5066 		zend_hash_destroy(service->class_map);
5067 		FREE_HASHTABLE(service->class_map);
5068 	}
5069 	if (service->soap_object) {
5070 		zval_ptr_dtor(&service->soap_object);
5071 	}
5072 	efree(service);
5073 }
5074 
5075 static void delete_hashtable(void *data)
5076 {
5077 	HashTable *ht = (HashTable*)data;
5078 	zend_hash_destroy(ht);
5079 	efree(ht);
5080 }
5081