1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 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@php.net>                              |
18   +----------------------------------------------------------------------+
19 */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include "php_soap.h"
25 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
26 #include "ext/session/php_session.h"
27 #endif
28 #include "zend_exceptions.h"
29 
30 
31 static int le_sdl = 0;
32 int le_url = 0;
33 static int le_service = 0;
34 static int le_typemap = 0;
35 
36 typedef struct _soapHeader {
37 	sdlFunctionPtr                    function;
38 	zval                              function_name;
39 	int                               mustUnderstand;
40 	int                               num_params;
41 	zval                             *parameters;
42 	zval                              retval;
43 	sdlSoapBindingFunctionHeaderPtr   hdr;
44 	struct _soapHeader               *next;
45 } soapHeader;
46 
47 /* Local functions */
48 static void function_to_string(sdlFunctionPtr function, smart_str *buf);
49 static void type_to_string(sdlTypePtr type, smart_str *buf, int level);
50 
51 static void clear_soap_fault(zval *obj);
52 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);
53 static void add_soap_fault_ex(zval *fault, zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail);
54 static ZEND_NORETURN void soap_server_fault(char* code, char* string, char *actor, zval* details, char *name);
55 static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader* hdr);
56 
57 static sdlParamPtr get_param(sdlFunctionPtr function, char *param_name, int index, int);
58 static sdlFunctionPtr get_function(sdlPtr sdl, const char *function_name);
59 static sdlFunctionPtr get_doc_function(sdlPtr sdl, xmlNodePtr node);
60 
61 static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, char* actor, zval *function_name, int *num_params, zval **parameters, int *version, soapHeader **headers);
62 static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function_name,char *uri,zval *ret, soapHeader *headers, int version);
63 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);
64 static xmlNodePtr serialize_parameter(sdlParamPtr param,zval *param_val,int index,char *name, int style, xmlNodePtr parent);
65 static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName, int style, xmlNodePtr parent);
66 
67 static void delete_service(void *service);
68 static void delete_url(void *handle);
69 static void delete_hashtable(void *hashtable);
70 
71 static void soap_error_handler(int error_num, const char *error_filename, const uint32_t error_lineno, const char *format, va_list args);
72 
73 #define SOAP_SERVER_BEGIN_CODE() \
74 	zend_bool _old_handler = SOAP_GLOBAL(use_soap_error_handler);\
75 	char* _old_error_code = SOAP_GLOBAL(error_code);\
76 	zend_object* _old_error_object = Z_OBJ(SOAP_GLOBAL(error_object));\
77 	int _old_soap_version = SOAP_GLOBAL(soap_version);\
78 	SOAP_GLOBAL(use_soap_error_handler) = 1;\
79 	SOAP_GLOBAL(error_code) = "Server";\
80 	Z_OBJ(SOAP_GLOBAL(error_object)) = Z_OBJ_P(ZEND_THIS);
81 
82 #define SOAP_SERVER_END_CODE() \
83 	SOAP_GLOBAL(use_soap_error_handler) = _old_handler;\
84 	SOAP_GLOBAL(error_code) = _old_error_code;\
85 	Z_OBJ(SOAP_GLOBAL(error_object)) = _old_error_object;\
86 	SOAP_GLOBAL(soap_version) = _old_soap_version;
87 
88 #define SOAP_CLIENT_BEGIN_CODE() \
89 	zend_bool _old_handler = SOAP_GLOBAL(use_soap_error_handler);\
90 	char* _old_error_code = SOAP_GLOBAL(error_code);\
91 	zend_object* _old_error_object = Z_OBJ(SOAP_GLOBAL(error_object));\
92 	int _old_soap_version = SOAP_GLOBAL(soap_version);\
93 	zend_bool _old_in_compilation = CG(in_compilation); \
94 	zend_execute_data *_old_current_execute_data = EG(current_execute_data); \
95 	zval *_old_stack_top = EG(vm_stack_top); \
96 	int _bailout = 0;\
97 	SOAP_GLOBAL(use_soap_error_handler) = 1;\
98 	SOAP_GLOBAL(error_code) = "Client";\
99 	Z_OBJ(SOAP_GLOBAL(error_object)) = Z_OBJ_P(ZEND_THIS);\
100 	zend_try {
101 
102 #define SOAP_CLIENT_END_CODE() \
103 	} zend_catch {\
104 		CG(in_compilation) = _old_in_compilation; \
105 		EG(current_execute_data) = _old_current_execute_data; \
106 		if (EG(exception) == NULL || \
107 		    !instanceof_function(EG(exception)->ce, soap_fault_class_entry)) {\
108 			_bailout = 1;\
109 		}\
110 		if (_old_stack_top != EG(vm_stack_top)) { \
111 			while (EG(vm_stack)->prev != NULL && \
112 			       ((char*)_old_stack_top < (char*)EG(vm_stack) || \
113 			        (char*) _old_stack_top > (char*)EG(vm_stack)->end)) { \
114 				zend_vm_stack tmp = EG(vm_stack)->prev; \
115 				efree(EG(vm_stack)); \
116 				EG(vm_stack) = tmp; \
117 				EG(vm_stack_end) = tmp->end; \
118 			} \
119 			EG(vm_stack)->top = _old_stack_top; \
120 		} \
121 	} zend_end_try();\
122 	SOAP_GLOBAL(use_soap_error_handler) = _old_handler;\
123 	SOAP_GLOBAL(error_code) = _old_error_code;\
124 	Z_OBJ(SOAP_GLOBAL(error_object)) = _old_error_object;\
125 	SOAP_GLOBAL(soap_version) = _old_soap_version;\
126 	if (_bailout) {\
127 		zend_bailout();\
128 	}
129 
130 #define FETCH_THIS_SDL(ss) \
131 	{ \
132 		zval *__tmp; \
133 		if(FIND_SDL_PROPERTY(ZEND_THIS, __tmp) != NULL) { \
134 			FETCH_SDL_RES(ss,__tmp); \
135 		} else { \
136 			ss = NULL; \
137 		} \
138 	}
139 
140 #define FIND_SDL_PROPERTY(ss,tmp) (tmp = zend_hash_str_find(Z_OBJPROP_P(ss), "sdl", sizeof("sdl")-1))
141 #define FETCH_SDL_RES(ss,tmp) ss = (sdlPtr) zend_fetch_resource_ex(tmp, "sdl", le_sdl)
142 
143 #define FIND_TYPEMAP_PROPERTY(ss,tmp) (tmp = zend_hash_str_find(Z_OBJPROP_P(ss), "typemap", sizeof("typemap")-1))
144 #define FETCH_TYPEMAP_RES(ss,tmp) ss = (HashTable*) zend_fetch_resource_ex(tmp, "typemap", le_typemap)
145 
146 #define FETCH_THIS_SERVICE(ss) \
147 	{ \
148 		zval *tmp; \
149 		if ((tmp = zend_hash_str_find(Z_OBJPROP_P(ZEND_THIS),"service", sizeof("service")-1)) != NULL) { \
150 			ss = (soapServicePtr)zend_fetch_resource_ex(tmp, "service", le_service); \
151 		} else { \
152 	                php_error_docref(NULL, E_WARNING, "Can not fetch service object"); \
153 			SOAP_SERVER_END_CODE(); \
154 			return; \
155 		} \
156 	}
157 
158 static zend_class_entry* soap_class_entry;
159 static zend_class_entry* soap_server_class_entry;
160 static zend_class_entry* soap_fault_class_entry;
161 static zend_class_entry* soap_header_class_entry;
162 static zend_class_entry* soap_param_class_entry;
163 zend_class_entry* soap_var_class_entry;
164 
165 ZEND_DECLARE_MODULE_GLOBALS(soap)
166 
167 static void (*old_error_handler)(int, const char *, const uint32_t, const char*, va_list);
168 
169 #define call_old_error_handler(error_num, error_filename, error_lineno, format, args) \
170 { \
171 	va_list copy; \
172 	va_copy(copy, args); \
173 	old_error_handler(error_num, error_filename, error_lineno, format, copy); \
174 	va_end(copy); \
175 }
176 
177 #define PHP_SOAP_SERVER_CLASSNAME "SoapServer"
178 #define PHP_SOAP_CLIENT_CLASSNAME "SoapClient"
179 #define PHP_SOAP_VAR_CLASSNAME    "SoapVar"
180 #define PHP_SOAP_FAULT_CLASSNAME  "SoapFault"
181 #define PHP_SOAP_PARAM_CLASSNAME  "SoapParam"
182 #define PHP_SOAP_HEADER_CLASSNAME "SoapHeader"
183 
184 PHP_RINIT_FUNCTION(soap);
185 PHP_MINIT_FUNCTION(soap);
186 PHP_MSHUTDOWN_FUNCTION(soap);
187 PHP_MINFO_FUNCTION(soap);
188 
189 /*
190   Registry Functions
191   TODO: this!
192 */
193 PHP_FUNCTION(soap_encode_to_xml);
194 PHP_FUNCTION(soap_encode_to_zval);
195 PHP_FUNCTION(use_soap_error_handler);
196 PHP_FUNCTION(is_soap_fault);
197 
198 
199 /* Server Functions */
200 PHP_METHOD(SoapServer, SoapServer);
201 PHP_METHOD(SoapServer, setClass);
202 PHP_METHOD(SoapServer, setObject);
203 PHP_METHOD(SoapServer, addFunction);
204 PHP_METHOD(SoapServer, getFunctions);
205 PHP_METHOD(SoapServer, handle);
206 PHP_METHOD(SoapServer, setPersistence);
207 PHP_METHOD(SoapServer, fault);
208 PHP_METHOD(SoapServer, addSoapHeader);
209 
210 /* Client Functions */
211 PHP_METHOD(SoapClient, SoapClient);
212 PHP_METHOD(SoapClient, __call);
213 PHP_METHOD(SoapClient, __getLastRequest);
214 PHP_METHOD(SoapClient, __getLastResponse);
215 PHP_METHOD(SoapClient, __getLastRequestHeaders);
216 PHP_METHOD(SoapClient, __getLastResponseHeaders);
217 PHP_METHOD(SoapClient, __getFunctions);
218 PHP_METHOD(SoapClient, __getTypes);
219 PHP_METHOD(SoapClient, __doRequest);
220 PHP_METHOD(SoapClient, __setCookie);
221 PHP_METHOD(SoapClient, __getCookies);
222 PHP_METHOD(SoapClient, __setLocation);
223 PHP_METHOD(SoapClient, __setSoapHeaders);
224 
225 /* SoapVar Functions */
226 PHP_METHOD(SoapVar, SoapVar);
227 
228 /* SoapFault Functions */
229 PHP_METHOD(SoapFault, SoapFault);
230 PHP_METHOD(SoapFault, __toString);
231 
232 /* SoapParam Functions */
233 PHP_METHOD(SoapParam, SoapParam);
234 
235 /* SoapHeader Functions */
236 PHP_METHOD(SoapHeader, SoapHeader);
237 
238 #define SOAP_CTOR(class_name, func_name, arginfo, flags) PHP_ME(class_name, func_name, arginfo, flags)
239 
240 /* {{{ arginfo */
241 ZEND_BEGIN_ARG_INFO(arginfo_soap__void, 0)
242 ZEND_END_ARG_INFO()
243 
244 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapparam_soapparam, 0, 0, 2)
245 	ZEND_ARG_INFO(0, data)
246 	ZEND_ARG_INFO(0, name)
247 ZEND_END_ARG_INFO()
248 
249 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapheader_soapheader, 0, 0, 2)
250 	ZEND_ARG_INFO(0, namespace)
251 	ZEND_ARG_INFO(0, name)
252 	ZEND_ARG_INFO(0, data)
253 	ZEND_ARG_INFO(0, mustunderstand)
254 	ZEND_ARG_INFO(0, actor)
255 ZEND_END_ARG_INFO()
256 
257 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapfault_soapfault, 0, 0, 2)
258 	ZEND_ARG_INFO(0, faultcode)
259 	ZEND_ARG_INFO(0, faultstring)
260 	ZEND_ARG_INFO(0, faultactor)
261 	ZEND_ARG_INFO(0, detail)
262 	ZEND_ARG_INFO(0, faultname)
263 	ZEND_ARG_INFO(0, headerfault)
264 ZEND_END_ARG_INFO()
265 
266 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapvar_soapvar, 0, 0, 2)
267 	ZEND_ARG_INFO(0, data)
268 	ZEND_ARG_INFO(0, encoding)
269 	ZEND_ARG_INFO(0, type_name)
270 	ZEND_ARG_INFO(0, type_namespace)
271 	ZEND_ARG_INFO(0, node_name)
272 	ZEND_ARG_INFO(0, node_namespace)
273 ZEND_END_ARG_INFO()
274 
275 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_fault, 0, 0, 2)
276 	ZEND_ARG_INFO(0, code)
277 	ZEND_ARG_INFO(0, string)
278 	ZEND_ARG_INFO(0, actor)
279 	ZEND_ARG_INFO(0, details)
280 	ZEND_ARG_INFO(0, name)
281 ZEND_END_ARG_INFO()
282 
283 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_addsoapheader, 0, 0, 1)
284 	ZEND_ARG_INFO(0, object)
285 ZEND_END_ARG_INFO()
286 
287 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_soapserver, 0, 0, 1)
288 	ZEND_ARG_INFO(0, wsdl)
289 	ZEND_ARG_INFO(0, options)
290 ZEND_END_ARG_INFO()
291 
292 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_setpersistence, 0, 0, 1)
293 	ZEND_ARG_INFO(0, mode)
294 ZEND_END_ARG_INFO()
295 
296 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_setclass, 0, 0, 1)
297 	ZEND_ARG_INFO(0, class_name)
298 	ZEND_ARG_VARIADIC_INFO(0, args)
299 ZEND_END_ARG_INFO()
300 
301 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_setobject, 0, 0, 1)
302 	ZEND_ARG_INFO(0, object)
303 ZEND_END_ARG_INFO()
304 
305 ZEND_BEGIN_ARG_INFO(arginfo_soapserver_getfunctions, 0)
306 ZEND_END_ARG_INFO()
307 
308 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_addfunction, 0, 0, 1)
309 	ZEND_ARG_INFO(0, functions)
310 ZEND_END_ARG_INFO()
311 
312 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_handle, 0, 0, 0)
313 	ZEND_ARG_INFO(0, soap_request)
314 ZEND_END_ARG_INFO()
315 
316 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient_soapclient, 0, 0, 1)
317 	ZEND_ARG_INFO(0, wsdl)
318 	ZEND_ARG_INFO(0, options)
319 ZEND_END_ARG_INFO()
320 
321 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___call, 0, 0, 2)
322 	ZEND_ARG_INFO(0, function_name)
323 	ZEND_ARG_INFO(0, arguments)
324 ZEND_END_ARG_INFO()
325 
326 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___soapcall, 0, 0, 2)
327 	ZEND_ARG_INFO(0, function_name)
328 	ZEND_ARG_INFO(0, arguments)
329 	ZEND_ARG_INFO(0, options)
330 	ZEND_ARG_INFO(0, input_headers)
331 	ZEND_ARG_INFO(1, output_headers)
332 ZEND_END_ARG_INFO()
333 
334 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getfunctions, 0)
335 ZEND_END_ARG_INFO()
336 
337 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___gettypes, 0)
338 ZEND_END_ARG_INFO()
339 
340 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastrequest, 0)
341 ZEND_END_ARG_INFO()
342 
343 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastresponse, 0)
344 ZEND_END_ARG_INFO()
345 
346 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastrequestheaders, 0)
347 ZEND_END_ARG_INFO()
348 
349 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastresponseheaders, 0)
350 ZEND_END_ARG_INFO()
351 
352 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___dorequest, 0, 0, 4)
353 	ZEND_ARG_INFO(0, request)
354 	ZEND_ARG_INFO(0, location)
355 	ZEND_ARG_INFO(0, action)
356 	ZEND_ARG_INFO(0, version)
357 	ZEND_ARG_INFO(0, one_way)
358 ZEND_END_ARG_INFO()
359 
360 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___setcookie, 0, 0, 1)
361 	ZEND_ARG_INFO(0, name)
362 	ZEND_ARG_INFO(0, value)
363 ZEND_END_ARG_INFO()
364 
365 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getcookies, 0)
366 ZEND_END_ARG_INFO()
367 
368 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___setsoapheaders, 0, 0, 0)
369 	ZEND_ARG_INFO(0, soapheaders)
370 ZEND_END_ARG_INFO()
371 
372 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___setlocation, 0, 0, 0)
373 	ZEND_ARG_INFO(0, new_location)
374 ZEND_END_ARG_INFO()
375 
376 ZEND_BEGIN_ARG_INFO_EX(arginfo_soap_use_soap_error_handler, 0, 0, 0)
377 	ZEND_ARG_INFO(0, handler)
378 ZEND_END_ARG_INFO()
379 
380 ZEND_BEGIN_ARG_INFO_EX(arginfo_soap_is_soap_fault, 0, 0, 1)
381 	ZEND_ARG_INFO(0, object)
382 ZEND_END_ARG_INFO()
383 /* }}} */
384 
385 static const zend_function_entry soap_functions[] = {
386 	PHP_FE(use_soap_error_handler, 	arginfo_soap_use_soap_error_handler)
387 	PHP_FE(is_soap_fault, 			arginfo_soap_is_soap_fault)
388 	PHP_FE_END
389 };
390 
391 static const zend_function_entry soap_fault_functions[] = {
392 	SOAP_CTOR(SoapFault, SoapFault, arginfo_soapfault_soapfault, 0)
393 	PHP_ME(SoapFault, __toString, arginfo_soap__void, 0)
394 	PHP_FE_END
395 };
396 
397 static const zend_function_entry soap_server_functions[] = {
398 	SOAP_CTOR(SoapServer, SoapServer, 	arginfo_soapserver_soapserver, 0)
399 	PHP_ME(SoapServer, setPersistence, 	arginfo_soapserver_setpersistence, 0)
400 	PHP_ME(SoapServer, setClass, 		arginfo_soapserver_setclass, 0)
401 	PHP_ME(SoapServer, setObject, 		arginfo_soapserver_setobject, 0)
402 	PHP_ME(SoapServer, addFunction, 	arginfo_soapserver_addfunction, 0)
403 	PHP_ME(SoapServer, getFunctions, 	arginfo_soapserver_getfunctions, 0)
404 	PHP_ME(SoapServer, handle, 			arginfo_soapserver_handle, 0)
405 	PHP_ME(SoapServer, fault, 			arginfo_soapserver_fault, 0)
406 	PHP_ME(SoapServer, addSoapHeader, 	arginfo_soapserver_addsoapheader, 0)
407 	PHP_FE_END
408 };
409 
410 static const zend_function_entry soap_client_functions[] = {
411 	SOAP_CTOR(SoapClient, SoapClient, arginfo_soapclient_soapclient, 0)
412 	PHP_ME(SoapClient, __call, 						arginfo_soapclient___call, 0)
413 	ZEND_NAMED_ME(__soapCall, ZEND_MN(SoapClient___call), arginfo_soapclient___soapcall, 0)
414 	PHP_ME(SoapClient, __getLastRequest, 			arginfo_soapclient___getlastrequest, 0)
415 	PHP_ME(SoapClient, __getLastResponse, 			arginfo_soapclient___getlastresponse, 0)
416 	PHP_ME(SoapClient, __getLastRequestHeaders, 	arginfo_soapclient___getlastrequestheaders, 0)
417 	PHP_ME(SoapClient, __getLastResponseHeaders, 	arginfo_soapclient___getlastresponseheaders, 0)
418 	PHP_ME(SoapClient, __getFunctions, 				arginfo_soapclient___getfunctions, 0)
419 	PHP_ME(SoapClient, __getTypes, 					arginfo_soapclient___gettypes, 0)
420 	PHP_ME(SoapClient, __doRequest, 				arginfo_soapclient___dorequest, 0)
421 	PHP_ME(SoapClient, __setCookie, 				arginfo_soapclient___setcookie, 0)
422 	PHP_ME(SoapClient, __getCookies, 				arginfo_soapclient___getcookies, 0)
423 	PHP_ME(SoapClient, __setLocation, 				arginfo_soapclient___setlocation, 0)
424 	PHP_ME(SoapClient, __setSoapHeaders, 			arginfo_soapclient___setsoapheaders, 0)
425 	PHP_FE_END
426 };
427 
428 static const zend_function_entry soap_var_functions[] = {
429 	SOAP_CTOR(SoapVar, SoapVar, arginfo_soapvar_soapvar, 0)
430 	PHP_FE_END
431 };
432 
433 static const zend_function_entry soap_param_functions[] = {
434 	SOAP_CTOR(SoapParam, SoapParam, arginfo_soapparam_soapparam, 0)
435 	PHP_FE_END
436 };
437 
438 static const zend_function_entry soap_header_functions[] = {
439 	SOAP_CTOR(SoapHeader, SoapHeader, arginfo_soapheader_soapheader, 0)
440 	PHP_FE_END
441 };
442 
443 zend_module_entry soap_module_entry = {
444 #ifdef STANDARD_MODULE_HEADER
445   STANDARD_MODULE_HEADER,
446 #endif
447   "soap",
448   soap_functions,
449   PHP_MINIT(soap),
450   PHP_MSHUTDOWN(soap),
451   PHP_RINIT(soap),
452   NULL,
453   PHP_MINFO(soap),
454 #ifdef STANDARD_MODULE_HEADER
455   PHP_SOAP_VERSION,
456 #endif
457   STANDARD_MODULE_PROPERTIES,
458 };
459 
460 #ifdef COMPILE_DL_SOAP
461 #ifdef ZTS
462 ZEND_TSRMLS_CACHE_DEFINE()
463 #endif
ZEND_GET_MODULEnull464 ZEND_GET_MODULE(soap)
465 #endif
466 
467 ZEND_INI_MH(OnUpdateCacheMode)
468 {
469 	char *p;
470 #ifndef ZTS
471 	char *base = (char *) mh_arg2;
472 #else
473 	char *base = (char *) ts_resource(*((int *) mh_arg2));
474 #endif
475 
476 	p = (char*) (base+(size_t) mh_arg1);
477 
478 	*p = (char)atoi(ZSTR_VAL(new_value));
479 
480 	return SUCCESS;
481 }
482 
PHP_INI_MHnull483 static PHP_INI_MH(OnUpdateCacheDir)
484 {
485 	/* Only do the open_basedir check at runtime */
486 	if (stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) {
487 		char *p;
488 
489 		if (memchr(ZSTR_VAL(new_value), '\0', ZSTR_LEN(new_value)) != NULL) {
490 			return FAILURE;
491 		}
492 
493 		/* we do not use zend_memrchr() since path can contain ; itself */
494 		if ((p = strchr(ZSTR_VAL(new_value), ';'))) {
495 			char *p2;
496 			p++;
497 			if ((p2 = strchr(p, ';'))) {
498 				p = p2 + 1;
499 			}
500 		} else {
501 			p = ZSTR_VAL(new_value);
502 		}
503 
504 		if (PG(open_basedir) && *p && php_check_open_basedir(p)) {
505 			return FAILURE;
506 		}
507 	}
508 
509 	OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
510 	return SUCCESS;
511 }
512 
513 PHP_INI_BEGIN()
514 STD_PHP_INI_ENTRY("soap.wsdl_cache_enabled",     "1", PHP_INI_ALL, OnUpdateBool,
515                   cache_enabled, zend_soap_globals, soap_globals)
516 STD_PHP_INI_ENTRY("soap.wsdl_cache_dir",         "/tmp", PHP_INI_ALL, OnUpdateCacheDir,
517                   cache_dir, zend_soap_globals, soap_globals)
518 STD_PHP_INI_ENTRY("soap.wsdl_cache_ttl",         "86400", PHP_INI_ALL, OnUpdateLong,
519                   cache_ttl, zend_soap_globals, soap_globals)
520 STD_PHP_INI_ENTRY("soap.wsdl_cache",             "1", PHP_INI_ALL, OnUpdateCacheMode,
521                   cache_mode, zend_soap_globals, soap_globals)
522 STD_PHP_INI_ENTRY("soap.wsdl_cache_limit",       "5", PHP_INI_ALL, OnUpdateLong,
523                   cache_limit, zend_soap_globals, soap_globals)
524 PHP_INI_END()
525 
526 static HashTable defEnc, defEncIndex, defEncNs;
527 
php_soap_prepare_globalsnull528 static void php_soap_prepare_globals()
529 {
530 	int i;
531 	const encode* enc;
532 
533 	zend_hash_init(&defEnc, 0, NULL, NULL, 1);
534 	zend_hash_init(&defEncIndex, 0, NULL, NULL, 1);
535 	zend_hash_init(&defEncNs, 0, NULL, NULL, 1);
536 
537 	i = 0;
538 	do {
539 		enc = &defaultEncoding[i];
540 
541 		/* If has a ns and a str_type then index it */
542 		if (defaultEncoding[i].details.type_str) {
543 			if (defaultEncoding[i].details.ns != NULL) {
544 				char *ns_type;
545 				spprintf(&ns_type, 0, "%s:%s", defaultEncoding[i].details.ns, defaultEncoding[i].details.type_str);
546 				zend_hash_str_add_ptr(&defEnc, ns_type, strlen(ns_type), (void*)enc);
547 				efree(ns_type);
548 			} else {
549 				zend_hash_str_add_ptr(&defEnc, defaultEncoding[i].details.type_str, strlen(defaultEncoding[i].details.type_str), (void*)enc);
550 			}
551 		}
552 		/* Index everything by number */
553 		zend_hash_index_add_ptr(&defEncIndex, defaultEncoding[i].details.type, (void*)enc);
554 		i++;
555 	} while (defaultEncoding[i].details.type != END_KNOWN_TYPES);
556 
557 	/* hash by namespace */
558 	zend_hash_str_add_ptr(&defEncNs, XSD_1999_NAMESPACE, sizeof(XSD_1999_NAMESPACE)-1, XSD_NS_PREFIX);
559 	zend_hash_str_add_ptr(&defEncNs, XSD_NAMESPACE, sizeof(XSD_NAMESPACE)-1, XSD_NS_PREFIX);
560 	zend_hash_str_add_ptr(&defEncNs, XSI_NAMESPACE, sizeof(XSI_NAMESPACE)-1, XSI_NS_PREFIX);
561 	zend_hash_str_add_ptr(&defEncNs, XML_NAMESPACE, sizeof(XML_NAMESPACE)-1, XML_NS_PREFIX);
562 	zend_hash_str_add_ptr(&defEncNs, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)-1, SOAP_1_1_ENC_NS_PREFIX);
563 	zend_hash_str_add_ptr(&defEncNs, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)-1, SOAP_1_2_ENC_NS_PREFIX);
564 }
565 
php_soap_init_globals(zend_soap_globals *soap_globals)566 static void php_soap_init_globals(zend_soap_globals *soap_globals)
567 {
568 #if defined(COMPILE_DL_SOAP) && defined(ZTS)
569 	ZEND_TSRMLS_CACHE_UPDATE();
570 #endif
571 	soap_globals->defEnc = defEnc;
572 	soap_globals->defEncIndex = defEncIndex;
573 	soap_globals->defEncNs = defEncNs;
574 	soap_globals->typemap = NULL;
575 	soap_globals->use_soap_error_handler = 0;
576 	soap_globals->error_code = NULL;
577 	ZVAL_OBJ(&soap_globals->error_object, NULL);
578 	soap_globals->sdl = NULL;
579 	soap_globals->soap_version = SOAP_1_1;
580 	soap_globals->mem_cache = NULL;
581 	soap_globals->ref_map = NULL;
582 }
583 
PHP_MSHUTDOWN_FUNCTIONnull584 PHP_MSHUTDOWN_FUNCTION(soap)
585 {
586 	zend_error_cb = old_error_handler;
587 	zend_hash_destroy(&SOAP_GLOBAL(defEnc));
588 	zend_hash_destroy(&SOAP_GLOBAL(defEncIndex));
589 	zend_hash_destroy(&SOAP_GLOBAL(defEncNs));
590 	if (SOAP_GLOBAL(mem_cache)) {
591 		zend_hash_destroy(SOAP_GLOBAL(mem_cache));
592 		free(SOAP_GLOBAL(mem_cache));
593 	}
594 	UNREGISTER_INI_ENTRIES();
595 	return SUCCESS;
596 }
597 
PHP_RINIT_FUNCTIONnull598 PHP_RINIT_FUNCTION(soap)
599 {
600 	SOAP_GLOBAL(typemap) = NULL;
601 	SOAP_GLOBAL(use_soap_error_handler) = 0;
602 	SOAP_GLOBAL(error_code) = NULL;
603 	ZVAL_OBJ(&SOAP_GLOBAL(error_object), NULL);
604 	SOAP_GLOBAL(sdl) = NULL;
605 	SOAP_GLOBAL(soap_version) = SOAP_1_1;
606 	SOAP_GLOBAL(encoding) = NULL;
607 	SOAP_GLOBAL(class_map) = NULL;
608 	SOAP_GLOBAL(features) = 0;
609 	SOAP_GLOBAL(ref_map) = NULL;
610 	return SUCCESS;
611 }
612 
delete_sdl_res(zend_resource *res)613 static void delete_sdl_res(zend_resource *res)
614 {
615 	delete_sdl(res->ptr);
616 }
617 
delete_url_res(zend_resource *res)618 static void delete_url_res(zend_resource *res)
619 {
620 	delete_url(res->ptr);
621 }
622 
delete_service_res(zend_resource *res)623 static void delete_service_res(zend_resource *res)
624 {
625 	delete_service(res->ptr);
626 }
627 
delete_hashtable_res(zend_resource *res)628 static void delete_hashtable_res(zend_resource *res)
629 {
630 	delete_hashtable(res->ptr);
631 }
632 
PHP_MINIT_FUNCTIONnull633 PHP_MINIT_FUNCTION(soap)
634 {
635 	zend_class_entry ce;
636 
637 	/* TODO: add ini entry for always use soap errors */
638 	php_soap_prepare_globals();
639 	ZEND_INIT_MODULE_GLOBALS(soap, php_soap_init_globals, NULL);
640 	REGISTER_INI_ENTRIES();
641 
642 	/* Register SoapClient class */
643 	/* BIG NOTE : THIS EMITS AN COMPILATION WARNING UNDER ZE2 - handle_function_call deprecated.
644 		soap_call_function_handler should be of type zend_function, not (*handle_function_call).
645 	*/
646 	{
647 		INIT_CLASS_ENTRY(ce, PHP_SOAP_CLIENT_CLASSNAME, soap_client_functions);
648 		soap_class_entry = zend_register_internal_class(&ce);
649 	}
650 	/* Register SoapVar class */
651 	INIT_CLASS_ENTRY(ce, PHP_SOAP_VAR_CLASSNAME, soap_var_functions);
652 	soap_var_class_entry = zend_register_internal_class(&ce);
653 
654 	/* Register SoapServer class */
655 	INIT_CLASS_ENTRY(ce, PHP_SOAP_SERVER_CLASSNAME, soap_server_functions);
656 	soap_server_class_entry = zend_register_internal_class(&ce);
657 
658 	/* Register SoapFault class */
659 	INIT_CLASS_ENTRY(ce, PHP_SOAP_FAULT_CLASSNAME, soap_fault_functions);
660 	soap_fault_class_entry = zend_register_internal_class_ex(&ce, zend_ce_exception);
661 
662 	/* Register SoapParam class */
663 	INIT_CLASS_ENTRY(ce, PHP_SOAP_PARAM_CLASSNAME, soap_param_functions);
664 	soap_param_class_entry = zend_register_internal_class(&ce);
665 
666 	INIT_CLASS_ENTRY(ce, PHP_SOAP_HEADER_CLASSNAME, soap_header_functions);
667 	soap_header_class_entry = zend_register_internal_class(&ce);
668 
669 	le_sdl = zend_register_list_destructors_ex(delete_sdl_res, NULL, "SOAP SDL", module_number);
670 	le_url = zend_register_list_destructors_ex(delete_url_res, NULL, "SOAP URL", module_number);
671 	le_service = zend_register_list_destructors_ex(delete_service_res, NULL, "SOAP service", module_number);
672 	le_typemap = zend_register_list_destructors_ex(delete_hashtable_res, NULL, "SOAP table", module_number);
673 
674 	REGISTER_LONG_CONSTANT("SOAP_1_1", SOAP_1_1, CONST_CS | CONST_PERSISTENT);
675 	REGISTER_LONG_CONSTANT("SOAP_1_2", SOAP_1_2, CONST_CS | CONST_PERSISTENT);
676 
677 	REGISTER_LONG_CONSTANT("SOAP_PERSISTENCE_SESSION", SOAP_PERSISTENCE_SESSION, CONST_CS | CONST_PERSISTENT);
678 	REGISTER_LONG_CONSTANT("SOAP_PERSISTENCE_REQUEST", SOAP_PERSISTENCE_REQUEST, CONST_CS | CONST_PERSISTENT);
679 	REGISTER_LONG_CONSTANT("SOAP_FUNCTIONS_ALL", SOAP_FUNCTIONS_ALL, CONST_CS | CONST_PERSISTENT);
680 
681 	REGISTER_LONG_CONSTANT("SOAP_ENCODED", SOAP_ENCODED, CONST_CS | CONST_PERSISTENT);
682 	REGISTER_LONG_CONSTANT("SOAP_LITERAL", SOAP_LITERAL, CONST_CS | CONST_PERSISTENT);
683 
684 	REGISTER_LONG_CONSTANT("SOAP_RPC", SOAP_RPC, CONST_CS | CONST_PERSISTENT);
685 	REGISTER_LONG_CONSTANT("SOAP_DOCUMENT", SOAP_DOCUMENT, CONST_CS | CONST_PERSISTENT);
686 
687 	REGISTER_LONG_CONSTANT("SOAP_ACTOR_NEXT", SOAP_ACTOR_NEXT, CONST_CS | CONST_PERSISTENT);
688 	REGISTER_LONG_CONSTANT("SOAP_ACTOR_NONE", SOAP_ACTOR_NONE, CONST_CS | CONST_PERSISTENT);
689 	REGISTER_LONG_CONSTANT("SOAP_ACTOR_UNLIMATERECEIVER", SOAP_ACTOR_UNLIMATERECEIVER, CONST_CS | CONST_PERSISTENT);
690 
691 	REGISTER_LONG_CONSTANT("SOAP_COMPRESSION_ACCEPT", SOAP_COMPRESSION_ACCEPT, CONST_CS | CONST_PERSISTENT);
692 	REGISTER_LONG_CONSTANT("SOAP_COMPRESSION_GZIP", SOAP_COMPRESSION_GZIP, CONST_CS | CONST_PERSISTENT);
693 	REGISTER_LONG_CONSTANT("SOAP_COMPRESSION_DEFLATE", SOAP_COMPRESSION_DEFLATE, CONST_CS | CONST_PERSISTENT);
694 
695 	REGISTER_LONG_CONSTANT("SOAP_AUTHENTICATION_BASIC", SOAP_AUTHENTICATION_BASIC, CONST_CS | CONST_PERSISTENT);
696 	REGISTER_LONG_CONSTANT("SOAP_AUTHENTICATION_DIGEST", SOAP_AUTHENTICATION_DIGEST, CONST_CS | CONST_PERSISTENT);
697 
698 	REGISTER_LONG_CONSTANT("UNKNOWN_TYPE", UNKNOWN_TYPE, CONST_CS | CONST_PERSISTENT);
699 
700 	REGISTER_LONG_CONSTANT("XSD_STRING", XSD_STRING, CONST_CS | CONST_PERSISTENT);
701 	REGISTER_LONG_CONSTANT("XSD_BOOLEAN", XSD_BOOLEAN, CONST_CS | CONST_PERSISTENT);
702 	REGISTER_LONG_CONSTANT("XSD_DECIMAL", XSD_DECIMAL, CONST_CS | CONST_PERSISTENT);
703 	REGISTER_LONG_CONSTANT("XSD_FLOAT", XSD_FLOAT, CONST_CS | CONST_PERSISTENT);
704 	REGISTER_LONG_CONSTANT("XSD_DOUBLE", XSD_DOUBLE, CONST_CS | CONST_PERSISTENT);
705 	REGISTER_LONG_CONSTANT("XSD_DURATION", XSD_DURATION, CONST_CS | CONST_PERSISTENT);
706 	REGISTER_LONG_CONSTANT("XSD_DATETIME", XSD_DATETIME, CONST_CS | CONST_PERSISTENT);
707 	REGISTER_LONG_CONSTANT("XSD_TIME", XSD_TIME, CONST_CS | CONST_PERSISTENT);
708 	REGISTER_LONG_CONSTANT("XSD_DATE", XSD_DATE, CONST_CS | CONST_PERSISTENT);
709 	REGISTER_LONG_CONSTANT("XSD_GYEARMONTH", XSD_GYEARMONTH, CONST_CS | CONST_PERSISTENT);
710 	REGISTER_LONG_CONSTANT("XSD_GYEAR", XSD_GYEAR, CONST_CS | CONST_PERSISTENT);
711 	REGISTER_LONG_CONSTANT("XSD_GMONTHDAY", XSD_GMONTHDAY, CONST_CS | CONST_PERSISTENT);
712 	REGISTER_LONG_CONSTANT("XSD_GDAY", XSD_GDAY, CONST_CS | CONST_PERSISTENT);
713 	REGISTER_LONG_CONSTANT("XSD_GMONTH", XSD_GMONTH, CONST_CS | CONST_PERSISTENT);
714 	REGISTER_LONG_CONSTANT("XSD_HEXBINARY", XSD_HEXBINARY, CONST_CS | CONST_PERSISTENT);
715 	REGISTER_LONG_CONSTANT("XSD_BASE64BINARY", XSD_BASE64BINARY, CONST_CS | CONST_PERSISTENT);
716 	REGISTER_LONG_CONSTANT("XSD_ANYURI", XSD_ANYURI, CONST_CS | CONST_PERSISTENT);
717 	REGISTER_LONG_CONSTANT("XSD_QNAME", XSD_QNAME, CONST_CS | CONST_PERSISTENT);
718 	REGISTER_LONG_CONSTANT("XSD_NOTATION", XSD_NOTATION, CONST_CS | CONST_PERSISTENT);
719 	REGISTER_LONG_CONSTANT("XSD_NORMALIZEDSTRING", XSD_NORMALIZEDSTRING, CONST_CS | CONST_PERSISTENT);
720 	REGISTER_LONG_CONSTANT("XSD_TOKEN", XSD_TOKEN, CONST_CS | CONST_PERSISTENT);
721 	REGISTER_LONG_CONSTANT("XSD_LANGUAGE", XSD_LANGUAGE, CONST_CS | CONST_PERSISTENT);
722 	REGISTER_LONG_CONSTANT("XSD_NMTOKEN", XSD_NMTOKEN, CONST_CS | CONST_PERSISTENT);
723 	REGISTER_LONG_CONSTANT("XSD_NAME", XSD_NAME, CONST_CS | CONST_PERSISTENT);
724 	REGISTER_LONG_CONSTANT("XSD_NCNAME", XSD_NCNAME, CONST_CS | CONST_PERSISTENT);
725 	REGISTER_LONG_CONSTANT("XSD_ID", XSD_ID, CONST_CS | CONST_PERSISTENT);
726 	REGISTER_LONG_CONSTANT("XSD_IDREF", XSD_IDREF, CONST_CS | CONST_PERSISTENT);
727 	REGISTER_LONG_CONSTANT("XSD_IDREFS", XSD_IDREFS, CONST_CS | CONST_PERSISTENT);
728 	REGISTER_LONG_CONSTANT("XSD_ENTITY", XSD_ENTITY, CONST_CS | CONST_PERSISTENT);
729 	REGISTER_LONG_CONSTANT("XSD_ENTITIES", XSD_ENTITIES, CONST_CS | CONST_PERSISTENT);
730 	REGISTER_LONG_CONSTANT("XSD_INTEGER", XSD_INTEGER, CONST_CS | CONST_PERSISTENT);
731 	REGISTER_LONG_CONSTANT("XSD_NONPOSITIVEINTEGER", XSD_NONPOSITIVEINTEGER, CONST_CS | CONST_PERSISTENT);
732 	REGISTER_LONG_CONSTANT("XSD_NEGATIVEINTEGER", XSD_NEGATIVEINTEGER, CONST_CS | CONST_PERSISTENT);
733 	REGISTER_LONG_CONSTANT("XSD_LONG", XSD_LONG, CONST_CS | CONST_PERSISTENT);
734 	REGISTER_LONG_CONSTANT("XSD_INT", XSD_INT, CONST_CS | CONST_PERSISTENT);
735 	REGISTER_LONG_CONSTANT("XSD_SHORT", XSD_SHORT, CONST_CS | CONST_PERSISTENT);
736 	REGISTER_LONG_CONSTANT("XSD_BYTE", XSD_BYTE, CONST_CS | CONST_PERSISTENT);
737 	REGISTER_LONG_CONSTANT("XSD_NONNEGATIVEINTEGER", XSD_NONNEGATIVEINTEGER, CONST_CS | CONST_PERSISTENT);
738 	REGISTER_LONG_CONSTANT("XSD_UNSIGNEDLONG", XSD_UNSIGNEDLONG, CONST_CS | CONST_PERSISTENT);
739 	REGISTER_LONG_CONSTANT("XSD_UNSIGNEDINT", XSD_UNSIGNEDINT, CONST_CS | CONST_PERSISTENT);
740 	REGISTER_LONG_CONSTANT("XSD_UNSIGNEDSHORT", XSD_UNSIGNEDSHORT, CONST_CS | CONST_PERSISTENT);
741 	REGISTER_LONG_CONSTANT("XSD_UNSIGNEDBYTE", XSD_UNSIGNEDBYTE, CONST_CS | CONST_PERSISTENT);
742 	REGISTER_LONG_CONSTANT("XSD_POSITIVEINTEGER", XSD_POSITIVEINTEGER, CONST_CS | CONST_PERSISTENT);
743 	REGISTER_LONG_CONSTANT("XSD_NMTOKENS", XSD_NMTOKENS, CONST_CS | CONST_PERSISTENT);
744 	REGISTER_LONG_CONSTANT("XSD_ANYTYPE", XSD_ANYTYPE, CONST_CS | CONST_PERSISTENT);
745 	REGISTER_LONG_CONSTANT("XSD_ANYXML", XSD_ANYXML, CONST_CS | CONST_PERSISTENT);
746 
747 	REGISTER_LONG_CONSTANT("APACHE_MAP", APACHE_MAP, CONST_CS | CONST_PERSISTENT);
748 
749 	REGISTER_LONG_CONSTANT("SOAP_ENC_OBJECT", SOAP_ENC_OBJECT, CONST_CS | CONST_PERSISTENT);
750 	REGISTER_LONG_CONSTANT("SOAP_ENC_ARRAY", SOAP_ENC_ARRAY, CONST_CS | CONST_PERSISTENT);
751 
752 	REGISTER_LONG_CONSTANT("XSD_1999_TIMEINSTANT", XSD_1999_TIMEINSTANT, CONST_CS | CONST_PERSISTENT);
753 
754 	REGISTER_STRING_CONSTANT("XSD_NAMESPACE", XSD_NAMESPACE, CONST_CS | CONST_PERSISTENT);
755 	REGISTER_STRING_CONSTANT("XSD_1999_NAMESPACE", XSD_1999_NAMESPACE,  CONST_CS | CONST_PERSISTENT);
756 
757 	REGISTER_LONG_CONSTANT("SOAP_SINGLE_ELEMENT_ARRAYS", SOAP_SINGLE_ELEMENT_ARRAYS, CONST_CS | CONST_PERSISTENT);
758 	REGISTER_LONG_CONSTANT("SOAP_WAIT_ONE_WAY_CALLS", SOAP_WAIT_ONE_WAY_CALLS, CONST_CS | CONST_PERSISTENT);
759 	REGISTER_LONG_CONSTANT("SOAP_USE_XSI_ARRAY_TYPE", SOAP_USE_XSI_ARRAY_TYPE, CONST_CS | CONST_PERSISTENT);
760 
761 	REGISTER_LONG_CONSTANT("WSDL_CACHE_NONE",   WSDL_CACHE_NONE,   CONST_CS | CONST_PERSISTENT);
762 	REGISTER_LONG_CONSTANT("WSDL_CACHE_DISK",   WSDL_CACHE_DISK,   CONST_CS | CONST_PERSISTENT);
763 	REGISTER_LONG_CONSTANT("WSDL_CACHE_MEMORY", WSDL_CACHE_MEMORY, CONST_CS | CONST_PERSISTENT);
764 	REGISTER_LONG_CONSTANT("WSDL_CACHE_BOTH",   WSDL_CACHE_BOTH,   CONST_CS | CONST_PERSISTENT);
765 
766 	/* New SOAP SSL Method Constants */
767 	REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_TLS",    SOAP_SSL_METHOD_TLS,    CONST_CS | CONST_PERSISTENT);
768 	REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv2",  SOAP_SSL_METHOD_SSLv2,  CONST_CS | CONST_PERSISTENT);
769 	REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv3",  SOAP_SSL_METHOD_SSLv3,  CONST_CS | CONST_PERSISTENT);
770 	REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv23", SOAP_SSL_METHOD_SSLv23, CONST_CS | CONST_PERSISTENT);
771 
772 	old_error_handler = zend_error_cb;
773 	zend_error_cb = soap_error_handler;
774 
775 	return SUCCESS;
776 }
777 
PHP_MINFO_FUNCTIONnull778 PHP_MINFO_FUNCTION(soap)
779 {
780 	php_info_print_table_start();
781 	php_info_print_table_row(2, "Soap Client", "enabled");
782 	php_info_print_table_row(2, "Soap Server", "enabled");
783 	php_info_print_table_end();
784 	DISPLAY_INI_ENTRIES();
785 }
786 
787 
788 /* {{{ proto object SoapParam::SoapParam(mixed data, string name)
789    SoapParam constructor */
PHP_METHODnull790 PHP_METHOD(SoapParam, SoapParam)
791 {
792 	zval *data;
793 	char *name;
794 	size_t name_length;
795 	zval *this_ptr;
796 
797 	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zs", &data, &name, &name_length) == FAILURE) {
798 		return;
799 	}
800 	if (name_length == 0) {
801 		php_error_docref(NULL, E_WARNING, "Invalid parameter name");
802 		return;
803 	}
804 
805 	this_ptr = ZEND_THIS;
806 	add_property_stringl(this_ptr, "param_name", name, name_length);
807 	add_property_zval(this_ptr, "param_data", data);
808 }
809 /* }}} */
810 
811 
812 /* {{{ proto object SoapHeader::SoapHeader(string namespace, string name [, mixed data [, bool mustUnderstand [, mixed actor]]])
813    SoapHeader constructor */
PHP_METHODnull814 PHP_METHOD(SoapHeader, SoapHeader)
815 {
816 	zval *data = NULL, *actor = NULL;
817 	char *name, *ns;
818 	size_t name_len, ns_len;
819 	zend_bool must_understand = 0;
820 	zval *this_ptr;
821 
822 	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss|zbz", &ns, &ns_len, &name, &name_len, &data, &must_understand, &actor) == FAILURE) {
823 		return;
824 	}
825 	if (ns_len == 0) {
826 		php_error_docref(NULL, E_WARNING, "Invalid namespace");
827 		return;
828 	}
829 	if (name_len == 0) {
830 		php_error_docref(NULL, E_WARNING, "Invalid header name");
831 		return;
832 	}
833 
834 	this_ptr = ZEND_THIS;
835 	add_property_stringl(this_ptr, "namespace", ns, ns_len);
836 	add_property_stringl(this_ptr, "name", name, name_len);
837 	if (data) {
838 		add_property_zval(this_ptr, "data", data);
839 	}
840 	add_property_bool(this_ptr, "mustUnderstand", must_understand);
841 	if (actor == NULL) {
842 	} else if (Z_TYPE_P(actor) == IS_LONG &&
843 	  (Z_LVAL_P(actor) == SOAP_ACTOR_NEXT ||
844 	   Z_LVAL_P(actor) == SOAP_ACTOR_NONE ||
845 	   Z_LVAL_P(actor) == SOAP_ACTOR_UNLIMATERECEIVER)) {
846 		add_property_long(this_ptr, "actor", Z_LVAL_P(actor));
847 	} else if (Z_TYPE_P(actor) == IS_STRING && Z_STRLEN_P(actor) > 0) {
848 		add_property_stringl(this_ptr, "actor", Z_STRVAL_P(actor), Z_STRLEN_P(actor));
849 	} else {
850 		php_error_docref(NULL, E_WARNING, "Invalid actor");
851 	}
852 }
853 /* }}} */
854 
855 /* {{{ proto object SoapFault::SoapFault(string faultcode, string faultstring [, string faultactor [, mixed detail [, string faultname [, mixed headerfault]]]])
856    SoapFault constructor */
PHP_METHODnull857 PHP_METHOD(SoapFault, SoapFault)
858 {
859 	char *fault_string = NULL, *fault_code = NULL, *fault_actor = NULL, *name = NULL, *fault_code_ns = NULL;
860 	size_t fault_string_len, fault_actor_len = 0, name_len = 0, fault_code_len = 0;
861 	zval *code = NULL, *details = NULL, *headerfault = NULL, *this_ptr;
862 
863 	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zs|s!z!s!z",
864 		&code,
865 		&fault_string, &fault_string_len,
866 		&fault_actor, &fault_actor_len,
867 		&details, &name, &name_len, &headerfault) == FAILURE) {
868 		return;
869 	}
870 
871 	if (Z_TYPE_P(code) == IS_NULL) {
872 	} else if (Z_TYPE_P(code) == IS_STRING) {
873 		fault_code = Z_STRVAL_P(code);
874 		fault_code_len = Z_STRLEN_P(code);
875 	} else if (Z_TYPE_P(code) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(code)) == 2) {
876 		zval *t_ns = zend_hash_index_find(Z_ARRVAL_P(code), 0);
877 		zval *t_code = zend_hash_index_find(Z_ARRVAL_P(code), 1);
878 		if (t_ns && t_code && Z_TYPE_P(t_ns) == IS_STRING && Z_TYPE_P(t_code) == IS_STRING) {
879 			fault_code_ns = Z_STRVAL_P(t_ns);
880 			fault_code = Z_STRVAL_P(t_code);
881 			fault_code_len = Z_STRLEN_P(t_code);
882 		} else {
883 			php_error_docref(NULL, E_WARNING, "Invalid fault code");
884 			return;
885 		}
886 	} else  {
887 		php_error_docref(NULL, E_WARNING, "Invalid fault code");
888 		return;
889 	}
890 	if (fault_code != NULL && fault_code_len == 0) {
891 		php_error_docref(NULL, E_WARNING, "Invalid fault code");
892 		return;
893 	}
894 	if (name != NULL && name_len == 0) {
895 		name = NULL;
896 	}
897 
898 	this_ptr = ZEND_THIS;
899 	set_soap_fault(this_ptr, fault_code_ns, fault_code, fault_string, fault_actor, details, name);
900 	if (headerfault != NULL) {
901 		add_property_zval(this_ptr, "headerfault", headerfault);
902 	}
903 }
904 /* }}} */
905 
906 /* {{{ proto object SoapFault::SoapFault(string faultcode, string faultstring [, string faultactor [, mixed detail [, string faultname [, mixed headerfault]]]])
907    SoapFault constructor */
PHP_METHODnull908 PHP_METHOD(SoapFault, __toString)
909 {
910 	zval *faultcode, *faultstring, *file, *line, trace, rv1, rv2, rv3, rv4;
911 	zend_string *str;
912 	zend_fcall_info fci;
913 	zval *this_ptr;
914 	zend_string *faultcode_val, *faultstring_val, *file_val;
915 	zend_long line_val;
916 
917 	if (zend_parse_parameters_none() == FAILURE) {
918 		return;
919 	}
920 
921 	this_ptr = ZEND_THIS;
922 	faultcode   = zend_read_property(soap_fault_class_entry, this_ptr, "faultcode", sizeof("faultcode")-1, 1, &rv1);
923 	faultstring = zend_read_property(soap_fault_class_entry, this_ptr, "faultstring", sizeof("faultstring")-1, 1, &rv2);
924 	file = zend_read_property(soap_fault_class_entry, this_ptr, "file", sizeof("file")-1, 1, &rv3);
925 	line = zend_read_property(soap_fault_class_entry, this_ptr, "line", sizeof("line")-1, 1, &rv4);
926 
927 	fci.size = sizeof(fci);
928 	ZVAL_STRINGL(&fci.function_name, "gettraceasstring", sizeof("gettraceasstring")-1);
929 	fci.object = Z_OBJ_P(ZEND_THIS);
930 	fci.retval = &trace;
931 	fci.param_count = 0;
932 	fci.params = NULL;
933 	fci.no_separation = 1;
934 
935 	zend_call_function(&fci, NULL);
936 
937 	zval_ptr_dtor(&fci.function_name);
938 
939 	faultcode_val = zval_get_string(faultcode);
940 	faultstring_val = zval_get_string(faultstring);
941 	file_val = zval_get_string(file);
942 	line_val = zval_get_long(line);
943 	convert_to_string(&trace);
944 
945 	str = strpprintf(0, "SoapFault exception: [%s] %s in %s:" ZEND_LONG_FMT "\nStack trace:\n%s",
946 	               ZSTR_VAL(faultcode_val), ZSTR_VAL(faultstring_val), ZSTR_VAL(file_val), line_val,
947 	               Z_STRLEN(trace) ? Z_STRVAL(trace) : "#0 {main}\n");
948 
949 	zend_string_release_ex(file_val, 0);
950 	zend_string_release_ex(faultstring_val, 0);
951 	zend_string_release_ex(faultcode_val, 0);
952 	zval_ptr_dtor(&trace);
953 
954 	RETVAL_STR(str);
955 }
956 /* }}} */
957 
958 /* {{{ proto object SoapVar::SoapVar(mixed data, int encoding [, string type_name [, string type_namespace [, string node_name [, string node_namespace]]]])
959    SoapVar constructor */
PHP_METHODnull960 PHP_METHOD(SoapVar, SoapVar)
961 {
962 	zval *data, *type, *this_ptr;
963 	char *stype = NULL, *ns = NULL, *name = NULL, *namens = NULL;
964 	size_t stype_len = 0, ns_len = 0, name_len = 0, namens_len = 0;
965 
966 	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "z!z|ssss", &data, &type, &stype, &stype_len, &ns, &ns_len, &name, &name_len, &namens, &namens_len) == FAILURE) {
967 		return;
968 	}
969 
970 	this_ptr = ZEND_THIS;
971 	if (Z_TYPE_P(type) == IS_NULL) {
972 		add_property_long(this_ptr, "enc_type", UNKNOWN_TYPE);
973 	} else {
974 		if (zend_hash_index_exists(&SOAP_GLOBAL(defEncIndex), Z_LVAL_P(type))) {
975 			add_property_long(this_ptr, "enc_type", Z_LVAL_P(type));
976 		} else {
977 			php_error_docref(NULL, E_WARNING, "Invalid type ID");
978 			return;
979 		}
980 	}
981 
982 	if (data) {
983 		add_property_zval(this_ptr, "enc_value", data);
984 	}
985 
986 	if (stype && stype_len > 0) {
987 		add_property_stringl(this_ptr, "enc_stype", stype, stype_len);
988 	}
989 	if (ns && ns_len > 0) {
990 		add_property_stringl(this_ptr, "enc_ns", ns, ns_len);
991 	}
992 	if (name && name_len > 0) {
993 		add_property_stringl(this_ptr, "enc_name", name, name_len);
994 	}
995 	if (namens && namens_len > 0) {
996 		add_property_stringl(this_ptr, "enc_namens", namens, namens_len);
997 	}
998 }
999 /* }}} */
1000 
soap_create_typemap(sdlPtr sdl, HashTable *ht)1001 static HashTable* soap_create_typemap(sdlPtr sdl, HashTable *ht) /* {{{ */
1002 {
1003 	zval *tmp;
1004 	HashTable *ht2;
1005 	HashTable *typemap = NULL;
1006 
1007 	ZEND_HASH_FOREACH_VAL(ht, tmp) {
1008 		char *type_name = NULL;
1009 		char *type_ns = NULL;
1010 		zval *to_xml = NULL;
1011 		zval *to_zval = NULL;
1012 		encodePtr enc, new_enc;
1013 		zend_string *name;
1014 
1015 		if (Z_TYPE_P(tmp) != IS_ARRAY) {
1016 			php_error_docref(NULL, E_WARNING, "Wrong 'typemap' option");
1017 			return NULL;
1018 		}
1019 		ht2 = Z_ARRVAL_P(tmp);
1020 
1021 		ZEND_HASH_FOREACH_STR_KEY_VAL(ht2, name, tmp) {
1022 			if (name) {
1023 				if (ZSTR_LEN(name) == sizeof("type_name")-1 &&
1024 				    strncmp(ZSTR_VAL(name), "type_name", sizeof("type_name")-1) == 0) {
1025 					if (Z_TYPE_P(tmp) == IS_STRING) {
1026 						type_name = Z_STRVAL_P(tmp);
1027 					} else if (Z_TYPE_P(tmp) != IS_NULL) {
1028 					}
1029 				} else if (ZSTR_LEN(name) == sizeof("type_ns")-1 &&
1030 				    strncmp(ZSTR_VAL(name), "type_ns", sizeof("type_ns")-1) == 0) {
1031 					if (Z_TYPE_P(tmp) == IS_STRING) {
1032 						type_ns = Z_STRVAL_P(tmp);
1033 					} else if (Z_TYPE_P(tmp) != IS_NULL) {
1034 					}
1035 				} else if (ZSTR_LEN(name) == sizeof("to_xml")-1 &&
1036 				    strncmp(ZSTR_VAL(name), "to_xml", sizeof("to_xml")-1) == 0) {
1037 					to_xml = tmp;
1038 				} else if (ZSTR_LEN(name) == sizeof("from_xml")-1 &&
1039 				    strncmp(ZSTR_VAL(name), "from_xml", sizeof("from_xml")-1) == 0) {
1040 					to_zval = tmp;
1041 				}
1042 			}
1043 		} ZEND_HASH_FOREACH_END();
1044 
1045 		if (type_name) {
1046 			smart_str nscat = {0};
1047 
1048 			if (type_ns) {
1049 				enc = get_encoder(sdl, type_ns, type_name);
1050 			} else {
1051 				enc = get_encoder_ex(sdl, type_name, strlen(type_name));
1052 			}
1053 
1054 			new_enc = emalloc(sizeof(encode));
1055 			memset(new_enc, 0, sizeof(encode));
1056 
1057 			if (enc) {
1058 				new_enc->details.type = enc->details.type;
1059 				new_enc->details.ns = estrdup(enc->details.ns);
1060 				new_enc->details.type_str = estrdup(enc->details.type_str);
1061 				new_enc->details.sdl_type = enc->details.sdl_type;
1062 			} else {
1063 				enc = get_conversion(UNKNOWN_TYPE);
1064 				new_enc->details.type = enc->details.type;
1065 				if (type_ns) {
1066 					new_enc->details.ns = estrdup(type_ns);
1067 				}
1068 				new_enc->details.type_str = estrdup(type_name);
1069 			}
1070 			new_enc->to_xml = enc->to_xml;
1071 			new_enc->to_zval = enc->to_zval;
1072 			new_enc->details.map = emalloc(sizeof(soapMapping));
1073 			memset(new_enc->details.map, 0, sizeof(soapMapping));
1074 			if (to_xml) {
1075 				ZVAL_COPY(&new_enc->details.map->to_xml, to_xml);
1076 				new_enc->to_xml = to_xml_user;
1077 			} else if (enc->details.map && Z_TYPE(enc->details.map->to_xml) != IS_UNDEF) {
1078 				ZVAL_COPY(&new_enc->details.map->to_xml, &enc->details.map->to_xml);
1079 			}
1080 			if (to_zval) {
1081 				ZVAL_COPY(&new_enc->details.map->to_zval, to_zval);
1082 				new_enc->to_zval = to_zval_user;
1083 			} else if (enc->details.map && Z_TYPE(enc->details.map->to_zval) != IS_UNDEF) {
1084 				ZVAL_COPY(&new_enc->details.map->to_zval, &enc->details.map->to_zval);
1085 			}
1086 			if (!typemap) {
1087 				typemap = emalloc(sizeof(HashTable));
1088 				zend_hash_init(typemap, 0, NULL, delete_encoder, 0);
1089 			}
1090 
1091 			if (type_ns) {
1092 				smart_str_appends(&nscat, type_ns);
1093 				smart_str_appendc(&nscat, ':');
1094 			}
1095 			smart_str_appends(&nscat, type_name);
1096 			smart_str_0(&nscat);
1097 			zend_hash_update_ptr(typemap, nscat.s, new_enc);
1098 			smart_str_free(&nscat);
1099 		}
1100 	} ZEND_HASH_FOREACH_END();
1101 	return typemap;
1102 }
1103 /* }}} */
1104 
1105 /* {{{ proto object SoapServer::SoapServer(mixed wsdl [, array options])
1106    SoapServer constructor */
PHP_METHODnull1107 PHP_METHOD(SoapServer, SoapServer)
1108 {
1109 	soapServicePtr service;
1110 	zval *wsdl = NULL, *options = NULL;
1111 	zend_resource *res;
1112 	int version = SOAP_1_1;
1113 	zend_long cache_wsdl;
1114 	HashTable *typemap_ht = NULL;
1115 
1116 	SOAP_SERVER_BEGIN_CODE();
1117 
1118 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|a", &wsdl, &options) == FAILURE) {
1119 		php_error_docref(NULL, E_ERROR, "Invalid parameters");
1120 	}
1121 
1122 	if (Z_TYPE_P(wsdl) != IS_STRING && Z_TYPE_P(wsdl) != IS_NULL) {
1123 		php_error_docref(NULL, E_ERROR, "Invalid parameters");
1124 	}
1125 
1126 	service = emalloc(sizeof(soapService));
1127 	memset(service, 0, sizeof(soapService));
1128 	service->send_errors = 1;
1129 
1130 	cache_wsdl = SOAP_GLOBAL(cache_enabled) ? SOAP_GLOBAL(cache_mode) : 0;
1131 
1132 	if (options != NULL) {
1133 		HashTable *ht = Z_ARRVAL_P(options);
1134 		zval *tmp;
1135 
1136 		if ((tmp = zend_hash_str_find(ht, "soap_version", sizeof("soap_version")-1)) != NULL) {
1137 			if (Z_TYPE_P(tmp) == IS_LONG &&
1138 			    (Z_LVAL_P(tmp) == SOAP_1_1 || Z_LVAL_P(tmp) == SOAP_1_2)) {
1139 				version = Z_LVAL_P(tmp);
1140 			} else {
1141 				php_error_docref(NULL, E_ERROR, "'soap_version' option must be SOAP_1_1 or SOAP_1_2");
1142 			}
1143 		}
1144 
1145 		if ((tmp = zend_hash_str_find(ht, "uri", sizeof("uri")-1)) != NULL &&
1146 		    Z_TYPE_P(tmp) == IS_STRING) {
1147 			service->uri = estrndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
1148 		} else if (Z_TYPE_P(wsdl) == IS_NULL) {
1149 			php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
1150 		}
1151 
1152 		if ((tmp = zend_hash_str_find(ht, "actor", sizeof("actor")-1)) != NULL &&
1153 		    Z_TYPE_P(tmp) == IS_STRING) {
1154 			service->actor = estrndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
1155 		}
1156 
1157 		if ((tmp = zend_hash_str_find(ht, "encoding", sizeof("encoding")-1)) != NULL &&
1158 		    Z_TYPE_P(tmp) == IS_STRING) {
1159 			xmlCharEncodingHandlerPtr encoding;
1160 
1161 			encoding = xmlFindCharEncodingHandler(Z_STRVAL_P(tmp));
1162 			if (encoding == NULL) {
1163 				php_error_docref(NULL, E_ERROR, "Invalid 'encoding' option - '%s'", Z_STRVAL_P(tmp));
1164 			} else {
1165 			  service->encoding = encoding;
1166 			}
1167 		}
1168 
1169 		if ((tmp = zend_hash_str_find(ht, "classmap", sizeof("classmap")-1)) != NULL &&
1170 			Z_TYPE_P(tmp) == IS_ARRAY) {
1171 			service->class_map = zend_array_dup(Z_ARRVAL_P(tmp));
1172 		}
1173 
1174 		if ((tmp = zend_hash_str_find(ht, "typemap", sizeof("typemap")-1)) != NULL &&
1175 			Z_TYPE_P(tmp) == IS_ARRAY &&
1176 			zend_hash_num_elements(Z_ARRVAL_P(tmp)) > 0) {
1177 			typemap_ht = Z_ARRVAL_P(tmp);
1178 		}
1179 
1180 		if ((tmp = zend_hash_str_find(ht, "features", sizeof("features")-1)) != NULL &&
1181 			Z_TYPE_P(tmp) == IS_LONG) {
1182 			service->features = Z_LVAL_P(tmp);
1183 		}
1184 
1185 		if ((tmp = zend_hash_str_find(ht, "cache_wsdl", sizeof("cache_wsdl")-1)) != NULL &&
1186 		    Z_TYPE_P(tmp) == IS_LONG) {
1187 			cache_wsdl = Z_LVAL_P(tmp);
1188 		}
1189 
1190 		if ((tmp = zend_hash_str_find(ht, "send_errors", sizeof("send_errors")-1)) != NULL) {
1191 			if (Z_TYPE_P(tmp) == IS_FALSE) {
1192 				service->send_errors = 0;
1193 			} else if (Z_TYPE_P(tmp) == IS_TRUE) {
1194 				service->send_errors = 1;
1195 			} else if (Z_TYPE_P(tmp) == IS_LONG) {
1196 				service->send_errors = Z_LVAL_P(tmp);
1197 			}
1198 		}
1199 
1200 	} else if (Z_TYPE_P(wsdl) == IS_NULL) {
1201 		php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
1202 	}
1203 
1204 	service->version = version;
1205 	service->type = SOAP_FUNCTIONS;
1206 	service->soap_functions.functions_all = FALSE;
1207 	service->soap_functions.ft = zend_new_array(0);
1208 
1209 	if (Z_TYPE_P(wsdl) != IS_NULL) {
1210 		service->sdl = get_sdl(ZEND_THIS, Z_STRVAL_P(wsdl), cache_wsdl);
1211 		if (service->uri == NULL) {
1212 			if (service->sdl->target_ns) {
1213 				service->uri = estrdup(service->sdl->target_ns);
1214 			} else {
1215 				/*FIXME*/
1216 				service->uri = estrdup("http://unknown-uri/");
1217 			}
1218 		}
1219 	}
1220 
1221 	if (typemap_ht) {
1222 		service->typemap = soap_create_typemap(service->sdl, typemap_ht);
1223 	}
1224 
1225 	res = zend_register_resource(service, le_service);
1226 	add_property_resource(ZEND_THIS, "service", res);
1227 
1228 	SOAP_SERVER_END_CODE();
1229 }
1230 /* }}} */
1231 
1232 
1233 /* {{{ proto object SoapServer::setPersistence(int mode )
1234    Sets persistence mode of SoapServer */
PHP_METHODnull1235 PHP_METHOD(SoapServer, setPersistence)
1236 {
1237 	soapServicePtr service;
1238 	zend_long value;
1239 
1240 	SOAP_SERVER_BEGIN_CODE();
1241 
1242 	FETCH_THIS_SERVICE(service);
1243 
1244 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) != FAILURE) {
1245 		if (service->type == SOAP_CLASS) {
1246 			if (value == SOAP_PERSISTENCE_SESSION ||
1247 				value == SOAP_PERSISTENCE_REQUEST) {
1248 				service->soap_class.persistence = value;
1249 			} else {
1250 				php_error_docref(NULL, E_WARNING, "Tried to set persistence with bogus value (" ZEND_LONG_FMT ")", value);
1251 				return;
1252 			}
1253 		} else {
1254 			php_error_docref(NULL, E_WARNING, "Tried to set persistence when you are using you SOAP SERVER in function mode, no persistence needed");
1255 			return;
1256 		}
1257 	}
1258 
1259 	SOAP_SERVER_END_CODE();
1260 }
1261 /* }}} */
1262 
1263 
1264 /* {{{ proto void SoapServer::setClass(string class_name [, mixed args])
1265    Sets class which will handle SOAP requests */
PHP_METHODnull1266 PHP_METHOD(SoapServer, setClass)
1267 {
1268 	soapServicePtr service;
1269 	zend_string *classname;
1270 	zend_class_entry *ce;
1271 	int num_args = 0;
1272 	zval *argv = NULL;
1273 
1274 	SOAP_SERVER_BEGIN_CODE();
1275 
1276 	FETCH_THIS_SERVICE(service);
1277 
1278 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S*", &classname, &argv, &num_args) == FAILURE) {
1279 		return;
1280 	}
1281 
1282 	ce = zend_lookup_class(classname);
1283 
1284 	if (ce) {
1285 		service->type = SOAP_CLASS;
1286 		service->soap_class.ce = ce;
1287 
1288 		service->soap_class.persistence = SOAP_PERSISTENCE_REQUEST;
1289 		service->soap_class.argc = num_args;
1290 		if (service->soap_class.argc > 0) {
1291 			int i;
1292 			service->soap_class.argv = safe_emalloc(sizeof(zval), service->soap_class.argc, 0);
1293 			for (i = 0;i < service->soap_class.argc;i++) {
1294 				ZVAL_COPY(&service->soap_class.argv[i], &argv[i]);
1295 			}
1296 		}
1297 	} else {
1298 		php_error_docref(NULL, E_WARNING, "Tried to set a non existent class (%s)", ZSTR_VAL(classname));
1299 		return;
1300 	}
1301 
1302 	SOAP_SERVER_END_CODE();
1303 }
1304 /* }}} */
1305 
1306 
1307 /* {{{ proto void SoapServer::setObject(object obj)
1308    Sets object which will handle SOAP requests */
PHP_METHODnull1309 PHP_METHOD(SoapServer, setObject)
1310 {
1311 	soapServicePtr service;
1312 	zval *obj;
1313 
1314 	SOAP_SERVER_BEGIN_CODE();
1315 
1316 	FETCH_THIS_SERVICE(service);
1317 
1318 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &obj) == FAILURE) {
1319 		return;
1320 	}
1321 
1322 	service->type = SOAP_OBJECT;
1323 
1324 	Z_ADDREF_P(obj);
1325 	ZVAL_OBJ(&service->soap_object, Z_OBJ_P(obj));
1326 
1327 	SOAP_SERVER_END_CODE();
1328 }
1329 /* }}} */
1330 
1331 
1332 /* {{{ proto array SoapServer::getFunctions(void)
1333    Returns list of defined functions */
PHP_METHODnull1334 PHP_METHOD(SoapServer, getFunctions)
1335 {
1336 	soapServicePtr  service;
1337 	HashTable      *ft = NULL;
1338 
1339 	SOAP_SERVER_BEGIN_CODE();
1340 
1341 	if (zend_parse_parameters_none() == FAILURE) {
1342 		return;
1343 	}
1344 
1345 	FETCH_THIS_SERVICE(service);
1346 
1347 	array_init(return_value);
1348 	if (service->type == SOAP_OBJECT) {
1349 		ft = &(Z_OBJCE(service->soap_object)->function_table);
1350 	} else if (service->type == SOAP_CLASS) {
1351 		ft = &service->soap_class.ce->function_table;
1352 	} else if (service->soap_functions.functions_all == TRUE) {
1353 		ft = EG(function_table);
1354 	} else if (service->soap_functions.ft != NULL) {
1355 		zval *name;
1356 
1357 		ZEND_HASH_FOREACH_VAL(service->soap_functions.ft, name) {
1358 			add_next_index_str(return_value, zend_string_copy(Z_STR_P(name)));
1359 		} ZEND_HASH_FOREACH_END();
1360 	}
1361 	if (ft != NULL) {
1362 		zend_function *f;
1363 
1364 		ZEND_HASH_FOREACH_PTR(ft, f) {
1365 			if ((service->type != SOAP_OBJECT && service->type != SOAP_CLASS) || (f->common.fn_flags & ZEND_ACC_PUBLIC)) {
1366 				add_next_index_str(return_value, zend_string_copy(f->common.function_name));
1367 			}
1368 		} ZEND_HASH_FOREACH_END();
1369 	}
1370 
1371 	SOAP_SERVER_END_CODE();
1372 }
1373 /* }}} */
1374 
1375 
1376 /* {{{ proto void SoapServer::addFunction(mixed functions)
1377    Adds one or several functions those will handle SOAP requests */
PHP_METHODnull1378 PHP_METHOD(SoapServer, addFunction)
1379 {
1380 	soapServicePtr service;
1381 	zval *function_name, function_copy;
1382 
1383 	SOAP_SERVER_BEGIN_CODE();
1384 
1385 	FETCH_THIS_SERVICE(service);
1386 
1387 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &function_name) == FAILURE) {
1388 		return;
1389 	}
1390 
1391 	/* TODO: could use zend_is_callable here */
1392 
1393 	if (Z_TYPE_P(function_name) == IS_ARRAY) {
1394 		if (service->type == SOAP_FUNCTIONS) {
1395 			zval *tmp_function;
1396 
1397 			if (service->soap_functions.ft == NULL) {
1398 				service->soap_functions.functions_all = FALSE;
1399 				service->soap_functions.ft = zend_new_array(zend_hash_num_elements(Z_ARRVAL_P(function_name)));
1400 			}
1401 
1402 			ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(function_name), tmp_function) {
1403 				zend_string *key;
1404 				zend_function *f;
1405 
1406 				if (Z_TYPE_P(tmp_function) != IS_STRING) {
1407 					php_error_docref(NULL, E_WARNING, "Tried to add a function that isn't a string");
1408 					return;
1409 				}
1410 
1411 				key = zend_string_tolower(Z_STR_P(tmp_function));
1412 
1413 				if ((f = zend_hash_find_ptr(EG(function_table), key)) == NULL) {
1414 					php_error_docref(NULL, E_WARNING, "Tried to add a non existent function '%s'", Z_STRVAL_P(tmp_function));
1415 					return;
1416 				}
1417 
1418 				ZVAL_STR_COPY(&function_copy, f->common.function_name);
1419 				zend_hash_update(service->soap_functions.ft, key, &function_copy);
1420 
1421 				zend_string_release_ex(key, 0);
1422 			} ZEND_HASH_FOREACH_END();
1423 		}
1424 	} else if (Z_TYPE_P(function_name) == IS_STRING) {
1425 		zend_string *key;
1426 		zend_function *f;
1427 
1428 		key = zend_string_tolower(Z_STR_P(function_name));
1429 
1430 		if ((f = zend_hash_find_ptr(EG(function_table), key)) == NULL) {
1431 			php_error_docref(NULL, E_WARNING, "Tried to add a non existent function '%s'", Z_STRVAL_P(function_name));
1432 			return;
1433 		}
1434 		if (service->soap_functions.ft == NULL) {
1435 			service->soap_functions.functions_all = FALSE;
1436 			service->soap_functions.ft = zend_new_array(0);
1437 		}
1438 
1439 		ZVAL_STR_COPY(&function_copy, f->common.function_name);
1440 		zend_hash_update(service->soap_functions.ft, key, &function_copy);
1441 		zend_string_release_ex(key, 0);
1442 	} else if (Z_TYPE_P(function_name) == IS_LONG) {
1443 		if (Z_LVAL_P(function_name) == SOAP_FUNCTIONS_ALL) {
1444 			if (service->soap_functions.ft != NULL) {
1445 				zend_hash_destroy(service->soap_functions.ft);
1446 				efree(service->soap_functions.ft);
1447 				service->soap_functions.ft = NULL;
1448 			}
1449 			service->soap_functions.functions_all = TRUE;
1450 		} else {
1451 			php_error_docref(NULL, E_WARNING, "Invalid value passed");
1452 			return;
1453 		}
1454 	}
1455 
1456 	SOAP_SERVER_END_CODE();
1457 }
1458 /* }}} */
1459 
_soap_server_exception(soapServicePtr service, sdlFunctionPtr function, zval *this_ptr)1460 static void _soap_server_exception(soapServicePtr service, sdlFunctionPtr function, zval *this_ptr) /* {{{ */
1461 {
1462 	zval exception_object;
1463 
1464 	ZVAL_OBJ(&exception_object, EG(exception));
1465 	if (instanceof_function(Z_OBJCE(exception_object), soap_fault_class_entry)) {
1466 		soap_server_fault_ex(function, &exception_object, NULL);
1467 	} else if (instanceof_function(Z_OBJCE(exception_object), zend_ce_error)) {
1468 		if (service->send_errors) {
1469 			zval rv;
1470 			zend_string *msg = zval_get_string(zend_read_property(zend_ce_error, &exception_object, "message", sizeof("message")-1, 0, &rv));
1471 			add_soap_fault_ex(&exception_object, this_ptr, "Server", ZSTR_VAL(msg), NULL, NULL);
1472 			zend_string_release_ex(msg, 0);
1473 		} else {
1474 			add_soap_fault_ex(&exception_object, this_ptr, "Server", "Internal Error", NULL, NULL);
1475 		}
1476 		soap_server_fault_ex(function, &exception_object, NULL);
1477 	}
1478 }
1479 /* }}} */
1480 
1481 /* {{{ proto void SoapServer::handle([string soap_request])
1482    Handles a SOAP request */
PHP_METHODnull1483 PHP_METHOD(SoapServer, handle)
1484 {
1485 	int soap_version, old_soap_version;
1486 	sdlPtr old_sdl = NULL;
1487 	soapServicePtr service;
1488 	xmlDocPtr doc_request = NULL, doc_return = NULL;
1489 	zval function_name, *params, *soap_obj, retval;
1490 	char *fn_name, cont_len[30];
1491 	int num_params = 0, size, i, call_status = 0;
1492 	xmlChar *buf;
1493 	HashTable *function_table;
1494 	soapHeader *soap_headers = NULL;
1495 	sdlFunctionPtr function;
1496 	char *arg = NULL;
1497 	size_t arg_len = 0;
1498 	xmlCharEncodingHandlerPtr old_encoding;
1499 	HashTable *old_class_map, *old_typemap;
1500 	int old_features;
1501 	zval tmp_soap;
1502 
1503 	SOAP_SERVER_BEGIN_CODE();
1504 
1505 	FETCH_THIS_SERVICE(service);
1506 	SOAP_GLOBAL(soap_version) = service->version;
1507 
1508 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &arg, &arg_len) == FAILURE) {
1509 		return;
1510 	}
1511 
1512 	if (ZEND_NUM_ARGS() > 0 && ZEND_SIZE_T_INT_OVFL(arg_len)) {
1513 		soap_server_fault("Server", "Input string is too long", NULL, NULL, NULL);
1514 		return;
1515 	}
1516 
1517 	if (SG(request_info).request_method &&
1518 	    strcmp(SG(request_info).request_method, "GET") == 0 &&
1519 	    SG(request_info).query_string &&
1520 	    stricmp(SG(request_info).query_string, "wsdl") == 0) {
1521 
1522 		if (service->sdl) {
1523 /*
1524 			char *hdr = emalloc(sizeof("Location: ")+strlen(service->sdl->source));
1525 			strcpy(hdr,"Location: ");
1526 			strcat(hdr,service->sdl->source);
1527 			sapi_add_header(hdr, sizeof("Location: ")+strlen(service->sdl->source)-1, 1);
1528 			efree(hdr);
1529 */
1530 			zval readfile, readfile_ret, param;
1531 
1532 			sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
1533 			ZVAL_STRING(&param, service->sdl->source);
1534 			ZVAL_STRING(&readfile, "readfile");
1535 			if (call_user_function(EG(function_table), NULL, &readfile, &readfile_ret, 1, &param ) == FAILURE) {
1536 				soap_server_fault("Server", "Couldn't find WSDL", NULL, NULL, NULL);
1537 			}
1538 
1539 			zval_ptr_dtor(&param);
1540 			zval_ptr_dtor_str(&readfile);
1541 			zval_ptr_dtor(&readfile_ret);
1542 
1543 			SOAP_SERVER_END_CODE();
1544 			return;
1545 		} else {
1546 			soap_server_fault("Server", "WSDL generation is not supported yet", NULL, NULL, NULL);
1547 /*
1548 			sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8"), 1);
1549 			PUTS("<?xml version=\"1.0\" ?>\n<definitions\n");
1550 			PUTS("    xmlns=\"http://schemas.xmlsoap.org/wsdl/\"\n");
1551 			PUTS("    targetNamespace=\"");
1552 			PUTS(service->uri);
1553 			PUTS("\">\n");
1554 			PUTS("</definitions>");
1555 */
1556 			SOAP_SERVER_END_CODE();
1557 			return;
1558 		}
1559 	}
1560 
1561 	ZVAL_NULL(&retval);
1562 
1563 	if (php_output_start_default() != SUCCESS) {
1564 		php_error_docref(NULL, E_ERROR,"ob_start failed");
1565 	}
1566 
1567 	if (ZEND_NUM_ARGS() == 0) {
1568 		if (SG(request_info).request_body && 0 == php_stream_rewind(SG(request_info).request_body)) {
1569 			zval *server_vars, *encoding;
1570 			php_stream_filter *zf = NULL;
1571 			zend_string *server = zend_string_init("_SERVER", sizeof("_SERVER") - 1, 0);
1572 
1573 			zend_is_auto_global(server);
1574 			if ((server_vars = zend_hash_find(&EG(symbol_table), server)) != NULL &&
1575 			    Z_TYPE_P(server_vars) == IS_ARRAY &&
1576 			    (encoding = zend_hash_str_find(Z_ARRVAL_P(server_vars), "HTTP_CONTENT_ENCODING", sizeof("HTTP_CONTENT_ENCODING")-1)) != NULL &&
1577 			    Z_TYPE_P(encoding) == IS_STRING) {
1578 
1579 				if (strcmp(Z_STRVAL_P(encoding),"gzip") == 0
1580 				||  strcmp(Z_STRVAL_P(encoding),"x-gzip") == 0
1581 				||  strcmp(Z_STRVAL_P(encoding),"deflate") == 0
1582 				) {
1583 					zval filter_params;
1584 
1585 					array_init_size(&filter_params, 1);
1586 					add_assoc_long_ex(&filter_params, "window", sizeof("window")-1, 0x2f); /* ANY WBITS */
1587 
1588 					zf = php_stream_filter_create("zlib.inflate", &filter_params, 0);
1589 					zend_array_destroy(Z_ARR(filter_params));
1590 
1591 					if (zf) {
1592 						php_stream_filter_append(&SG(request_info).request_body->readfilters, zf);
1593 					} else {
1594 						php_error_docref(NULL, E_WARNING,"Can't uncompress compressed request");
1595 						zend_string_release_ex(server, 0);
1596 						return;
1597 					}
1598 				} else {
1599 					php_error_docref(NULL, E_WARNING,"Request is compressed with unknown compression '%s'",Z_STRVAL_P(encoding));
1600 					zend_string_release_ex(server, 0);
1601 					return;
1602 				}
1603 			}
1604 			zend_string_release_ex(server, 0);
1605 
1606 			doc_request = soap_xmlParseFile("php://input");
1607 
1608 			if (zf) {
1609 				php_stream_filter_remove(zf, 1);
1610 			}
1611 		} else {
1612 			zval_ptr_dtor(&retval);
1613 			return;
1614 		}
1615 	} else {
1616 		doc_request = soap_xmlParseMemory(arg,arg_len);
1617 	}
1618 
1619 	if (doc_request == NULL) {
1620 		soap_server_fault("Client", "Bad Request", NULL, NULL, NULL);
1621 	}
1622 	if (xmlGetIntSubset(doc_request) != NULL) {
1623 		xmlNodePtr env = get_node(doc_request->children,"Envelope");
1624 		if (env && env->ns) {
1625 			if (strcmp((char*)env->ns->href, SOAP_1_1_ENV_NAMESPACE) == 0) {
1626 				SOAP_GLOBAL(soap_version) = SOAP_1_1;
1627 			} else if (strcmp((char*)env->ns->href,SOAP_1_2_ENV_NAMESPACE) == 0) {
1628 				SOAP_GLOBAL(soap_version) = SOAP_1_2;
1629 			}
1630 		}
1631 		xmlFreeDoc(doc_request);
1632 		soap_server_fault("Server", "DTD are not supported by SOAP", NULL, NULL, NULL);
1633 	}
1634 
1635 	old_sdl = SOAP_GLOBAL(sdl);
1636 	SOAP_GLOBAL(sdl) = service->sdl;
1637 	old_encoding = SOAP_GLOBAL(encoding);
1638 	SOAP_GLOBAL(encoding) = service->encoding;
1639 	old_class_map = SOAP_GLOBAL(class_map);
1640 	SOAP_GLOBAL(class_map) = service->class_map;
1641 	old_typemap = SOAP_GLOBAL(typemap);
1642 	SOAP_GLOBAL(typemap) = service->typemap;
1643 	old_features = SOAP_GLOBAL(features);
1644 	SOAP_GLOBAL(features) = service->features;
1645 	old_soap_version = SOAP_GLOBAL(soap_version);
1646 
1647 	zend_try {
1648 		function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, &params, &soap_version, &soap_headers);
1649 	} zend_catch {
1650 		/* Avoid leaking persistent memory */
1651 		xmlFreeDoc(doc_request);
1652 		zend_bailout();
1653 	} zend_end_try();
1654 
1655 	xmlFreeDoc(doc_request);
1656 
1657 	if (EG(exception)) {
1658 		php_output_discard();
1659 		_soap_server_exception(service, function, ZEND_THIS);
1660 		goto fail;
1661 	}
1662 
1663 	service->soap_headers_ptr = &soap_headers;
1664 
1665 	soap_obj = NULL;
1666 	if (service->type == SOAP_OBJECT) {
1667 		soap_obj = &service->soap_object;
1668 		function_table = &((Z_OBJCE_P(soap_obj))->function_table);
1669 	} else if (service->type == SOAP_CLASS) {
1670 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
1671 		/* If persistent then set soap_obj from from the previous created session (if available) */
1672 		if (service->soap_class.persistence == SOAP_PERSISTENCE_SESSION) {
1673 			zval *session_vars, *tmp_soap_p;
1674 
1675 			if (PS(session_status) != php_session_active &&
1676 			    PS(session_status) != php_session_disabled) {
1677 				php_session_start();
1678 			}
1679 
1680 			/* Find the soap object and assign */
1681 			session_vars = &PS(http_session_vars);
1682 			ZVAL_DEREF(session_vars);
1683 			if (Z_TYPE_P(session_vars) == IS_ARRAY &&
1684 			    (tmp_soap_p = zend_hash_str_find(Z_ARRVAL_P(session_vars), "_bogus_session_name", sizeof("_bogus_session_name")-1)) != NULL &&
1685 			    Z_TYPE_P(tmp_soap_p) == IS_OBJECT &&
1686 			    Z_OBJCE_P(tmp_soap_p) == service->soap_class.ce) {
1687 				soap_obj = tmp_soap_p;
1688 			}
1689 		}
1690 #endif
1691 		/* If new session or something weird happned */
1692 		if (soap_obj == NULL) {
1693 
1694 			object_init_ex(&tmp_soap, service->soap_class.ce);
1695 
1696 			/* Call constructor */
1697 			if (zend_hash_str_exists(&Z_OBJCE(tmp_soap)->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1)) {
1698 				zval c_ret, constructor;
1699 
1700 				ZVAL_STRING(&constructor, ZEND_CONSTRUCTOR_FUNC_NAME);
1701 				if (call_user_function(NULL, &tmp_soap, &constructor, &c_ret, service->soap_class.argc, service->soap_class.argv) == FAILURE) {
1702 					php_error_docref(NULL, E_ERROR, "Error calling constructor");
1703 				}
1704 				if (EG(exception)) {
1705 					php_output_discard();
1706 					_soap_server_exception(service, function, ZEND_THIS);
1707 					zval_ptr_dtor_str(&constructor);
1708 					zval_ptr_dtor(&c_ret);
1709 					zval_ptr_dtor(&tmp_soap);
1710 					goto fail;
1711 				}
1712 				zval_ptr_dtor_str(&constructor);
1713 				zval_ptr_dtor(&c_ret);
1714 			} else {
1715 				int class_name_len = ZSTR_LEN(service->soap_class.ce->name);
1716 				char *class_name = emalloc(class_name_len+1);
1717 
1718 				memcpy(class_name, ZSTR_VAL(service->soap_class.ce->name), class_name_len+1);
1719 				if (zend_hash_str_exists(&Z_OBJCE(tmp_soap)->function_table, php_strtolower(class_name, class_name_len), class_name_len)) {
1720 					zval c_ret, constructor;
1721 
1722 					ZVAL_STR_COPY(&constructor, service->soap_class.ce->name);
1723 					if (call_user_function(NULL, &tmp_soap, &constructor, &c_ret, service->soap_class.argc, service->soap_class.argv) == FAILURE) {
1724 						php_error_docref(NULL, E_ERROR, "Error calling constructor");
1725 					}
1726 
1727 					if (EG(exception)) {
1728 						php_output_discard();
1729 						_soap_server_exception(service, function, ZEND_THIS);
1730 						zval_ptr_dtor_str(&constructor);
1731 						zval_ptr_dtor(&c_ret);
1732 						efree(class_name);
1733 						zval_ptr_dtor(&tmp_soap);
1734 						goto fail;
1735 					}
1736 
1737 					zval_ptr_dtor_str(&constructor);
1738 					zval_ptr_dtor(&c_ret);
1739 				}
1740 				efree(class_name);
1741 			}
1742 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
1743 			/* If session then update session hash with new object */
1744 			if (service->soap_class.persistence == SOAP_PERSISTENCE_SESSION) {
1745 				zval *session_vars = &PS(http_session_vars), *tmp_soap_p;
1746 
1747 				ZVAL_DEREF(session_vars);
1748 				if (Z_TYPE_P(session_vars) == IS_ARRAY &&
1749 				    (tmp_soap_p = zend_hash_str_update(Z_ARRVAL_P(session_vars), "_bogus_session_name", sizeof("_bogus_session_name")-1, &tmp_soap)) != NULL) {
1750 					soap_obj = tmp_soap_p;
1751 				} else {
1752 					soap_obj = &tmp_soap;
1753 				}
1754 			} else {
1755 				soap_obj = &tmp_soap;
1756 			}
1757 #else
1758 			soap_obj = &tmp_soap;
1759 #endif
1760 
1761 		}
1762 		function_table = &((Z_OBJCE_P(soap_obj))->function_table);
1763 	} else {
1764 		if (service->soap_functions.functions_all == TRUE) {
1765 			function_table = EG(function_table);
1766 		} else {
1767 			function_table = service->soap_functions.ft;
1768 		}
1769 	}
1770 
1771 	/* Process soap headers */
1772 	if (soap_headers != NULL) {
1773 		soapHeader *header = soap_headers;
1774 		while (header != NULL) {
1775 			soapHeader *h = header;
1776 
1777 			header = header->next;
1778 #if 0
1779 			if (service->sdl && !h->function && !h->hdr) {
1780 				if (h->mustUnderstand) {
1781 					soap_server_fault("MustUnderstand","Header not understood", NULL, NULL, NULL);
1782 				} else {
1783 					continue;
1784 				}
1785 			}
1786 #endif
1787 			fn_name = estrndup(Z_STRVAL(h->function_name),Z_STRLEN(h->function_name));
1788 			if (zend_hash_str_exists(function_table, php_strtolower(fn_name, Z_STRLEN(h->function_name)), Z_STRLEN(h->function_name)) ||
1789 			    ((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) &&
1790 			     zend_hash_str_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1791 				if (service->type == SOAP_CLASS || service->type == SOAP_OBJECT) {
1792 					call_status = call_user_function(NULL, soap_obj, &h->function_name, &h->retval, h->num_params, h->parameters);
1793 				} else {
1794 					call_status = call_user_function(EG(function_table), NULL, &h->function_name, &h->retval, h->num_params, h->parameters);
1795 				}
1796 				if (call_status != SUCCESS) {
1797 					php_error_docref(NULL, E_WARNING, "Function '%s' call failed", Z_STRVAL(h->function_name));
1798 					return;
1799 				}
1800 				if (Z_TYPE(h->retval) == IS_OBJECT &&
1801 				    instanceof_function(Z_OBJCE(h->retval), soap_fault_class_entry)) {
1802 					zval *tmp;
1803 
1804 					if ((tmp = zend_hash_str_find(Z_OBJPROP(h->retval), "headerfault", sizeof("headerfault")-1)) != NULL &&
1805 					    Z_TYPE_P(tmp) != IS_NULL) {
1806 					}
1807 					php_output_discard();
1808 					soap_server_fault_ex(function, &h->retval, h);
1809 					efree(fn_name);
1810 					if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
1811 					goto fail;
1812 				} else if (EG(exception)) {
1813 					php_output_discard();
1814 					_soap_server_exception(service, function, ZEND_THIS);
1815 					efree(fn_name);
1816 					if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
1817 					goto fail;
1818 				}
1819 			} else if (h->mustUnderstand) {
1820 				soap_server_fault("MustUnderstand","Header not understood", NULL, NULL, NULL);
1821 			}
1822 			efree(fn_name);
1823 		}
1824 	}
1825 
1826 	fn_name = estrndup(Z_STRVAL(function_name),Z_STRLEN(function_name));
1827 	if (zend_hash_str_exists(function_table, php_strtolower(fn_name, Z_STRLEN(function_name)), Z_STRLEN(function_name)) ||
1828 	    ((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) &&
1829 	     zend_hash_str_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1830 		if (service->type == SOAP_CLASS || service->type == SOAP_OBJECT) {
1831 			call_status = call_user_function(NULL, soap_obj, &function_name, &retval, num_params, params);
1832 			if (service->type == SOAP_CLASS) {
1833 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
1834 				if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1835 					zval_ptr_dtor(soap_obj);
1836 					soap_obj = NULL;
1837 				}
1838 #else
1839 				zval_ptr_dtor(soap_obj);
1840 				soap_obj = NULL;
1841 #endif
1842 			}
1843 		} else {
1844 			call_status = call_user_function(EG(function_table), NULL, &function_name, &retval, num_params, params);
1845 		}
1846 	} else {
1847 		php_error(E_ERROR, "Function '%s' doesn't exist", Z_STRVAL(function_name));
1848 	}
1849 	efree(fn_name);
1850 
1851 	if (EG(exception)) {
1852 		php_output_discard();
1853 		_soap_server_exception(service, function, ZEND_THIS);
1854 		if (service->type == SOAP_CLASS) {
1855 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
1856 			if (soap_obj && service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1857 #else
1858 			if (soap_obj) {
1859 #endif
1860 				zval_ptr_dtor(soap_obj);
1861 			}
1862 		}
1863 		goto fail;
1864 	}
1865 
1866 	if (call_status == SUCCESS) {
1867 		char *response_name;
1868 
1869 		if (Z_TYPE(retval) == IS_OBJECT &&
1870 		    instanceof_function(Z_OBJCE(retval), soap_fault_class_entry)) {
1871 			php_output_discard();
1872 			soap_server_fault_ex(function, &retval, NULL);
1873 			goto fail;
1874 		}
1875 
1876 		if (function && function->responseName) {
1877 			response_name = estrdup(function->responseName);
1878 		} else {
1879 			response_name = emalloc(Z_STRLEN(function_name) + sizeof("Response"));
1880 			memcpy(response_name,Z_STRVAL(function_name),Z_STRLEN(function_name));
1881 			memcpy(response_name+Z_STRLEN(function_name),"Response",sizeof("Response"));
1882 		}
1883 		doc_return = serialize_response_call(function, response_name, service->uri, &retval, soap_headers, soap_version);
1884 		efree(response_name);
1885 	} else {
1886 		php_error_docref(NULL, E_WARNING, "Function '%s' call failed", Z_STRVAL(function_name));
1887 		return;
1888 	}
1889 
1890 	if (EG(exception)) {
1891 		php_output_discard();
1892 		_soap_server_exception(service, function, ZEND_THIS);
1893 		if (service->type == SOAP_CLASS) {
1894 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
1895 			if (soap_obj && service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
1896 #else
1897 			if (soap_obj) {
1898 #endif
1899 				zval_ptr_dtor(soap_obj);
1900 			}
1901 		}
1902 		goto fail;
1903 	}
1904 
1905 	/* Flush buffer */
1906 	php_output_discard();
1907 
1908 	if (doc_return) {
1909 		/* xmlDocDumpMemoryEnc(doc_return, &buf, &size, XML_CHAR_ENCODING_UTF8); */
1910 		xmlDocDumpMemory(doc_return, &buf, &size);
1911 
1912 		if (size == 0) {
1913 			php_error_docref(NULL, E_ERROR, "Dump memory failed");
1914 		}
1915 
1916 		if (soap_version == SOAP_1_2) {
1917 			sapi_add_header("Content-Type: application/soap+xml; charset=utf-8", sizeof("Content-Type: application/soap+xml; charset=utf-8")-1, 1);
1918 		} else {
1919 			sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
1920 		}
1921 
1922 		if (zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0)) {
1923 			sapi_add_header("Connection: close", sizeof("Connection: close")-1, 1);
1924 		} else {
1925 			snprintf(cont_len, sizeof(cont_len), "Content-Length: %d", size);
1926 			sapi_add_header(cont_len, strlen(cont_len), 1);
1927 		}
1928 		php_write(buf, size);
1929 		xmlFree(buf);
1930 	} else {
1931 		sapi_add_header("HTTP/1.1 202 Accepted", sizeof("HTTP/1.1 202 Accepted")-1, 1);
1932 		sapi_add_header("Content-Length: 0", sizeof("Content-Length: 0")-1, 1);
1933 	}
1934 
1935 fail:
1936 	SOAP_GLOBAL(soap_version) = old_soap_version;
1937 	SOAP_GLOBAL(encoding) = old_encoding;
1938 	SOAP_GLOBAL(sdl) = old_sdl;
1939 	SOAP_GLOBAL(class_map) = old_class_map;
1940 	SOAP_GLOBAL(typemap) = old_typemap;
1941 	SOAP_GLOBAL(features) = old_features;
1942 
1943 	if (doc_return) {
1944 		xmlFreeDoc(doc_return);
1945 	}
1946 
1947 	/* Free soap headers */
1948 	zval_ptr_dtor(&retval);
1949 	while (soap_headers != NULL) {
1950 		soapHeader *h = soap_headers;
1951 		int i;
1952 
1953 		soap_headers = soap_headers->next;
1954 		if (h->parameters) {
1955 			i = h->num_params;
1956 			while (i > 0) {
1957 				zval_ptr_dtor(&h->parameters[--i]);
1958 			}
1959 			efree(h->parameters);
1960 		}
1961 		zval_ptr_dtor_str(&h->function_name);
1962 		zval_ptr_dtor(&h->retval);
1963 		efree(h);
1964 	}
1965 	service->soap_headers_ptr = NULL;
1966 
1967 	/* Free Memory */
1968 	if (num_params > 0) {
1969 		for (i = 0; i < num_params;i++) {
1970 			zval_ptr_dtor(&params[i]);
1971 		}
1972 		efree(params);
1973 	}
1974 	zval_ptr_dtor_str(&function_name);
1975 
1976 	SOAP_SERVER_END_CODE();
1977 }
1978 /* }}} */
1979 
1980 /* {{{ proto SoapServer::fault ( staring code, string string [, string actor [, mixed details [, string name]]] )
1981    Issue SoapFault indicating an error */
1982 PHP_METHOD(SoapServer, fault)
1983 {
1984 	char *code, *string, *actor=NULL, *name=NULL;
1985 	size_t code_len, string_len, actor_len = 0, name_len = 0;
1986 	zval* details = NULL;
1987 	soapServicePtr service;
1988 	xmlCharEncodingHandlerPtr old_encoding;
1989 
1990 	SOAP_SERVER_BEGIN_CODE();
1991 	FETCH_THIS_SERVICE(service);
1992 	old_encoding = SOAP_GLOBAL(encoding);
1993 	SOAP_GLOBAL(encoding) = service->encoding;
1994 
1995 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|szs",
1996 	    &code, &code_len, &string, &string_len, &actor, &actor_len, &details,
1997 	    &name, &name_len) == FAILURE) {
1998 		return;
1999 	}
2000 
2001 	soap_server_fault(code, string, actor, details, name);
2002 
2003 	SOAP_GLOBAL(encoding) = old_encoding;
2004 	SOAP_SERVER_END_CODE();
2005 }
2006 /* }}} */
2007 
2008 /* {{{ proto SoapServer::addSoapHeader(SoapHeader $object) */
2009 PHP_METHOD(SoapServer, addSoapHeader)
2010 {
2011 	soapServicePtr service;
2012 	zval *fault;
2013 	soapHeader **p;
2014 
2015 	SOAP_SERVER_BEGIN_CODE();
2016 
2017 	FETCH_THIS_SERVICE(service);
2018 
2019 	if (!service || !service->soap_headers_ptr) {
2020 		php_error_docref(NULL, E_WARNING, "The SoapServer::addSoapHeader function may be called only during SOAP request processing");
2021 		return;
2022 	}
2023 
2024 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &fault, soap_header_class_entry) == FAILURE) {
2025 		return;
2026 	}
2027 
2028 	p = service->soap_headers_ptr;
2029 	while (*p != NULL) {
2030 		p = &(*p)->next;
2031 	}
2032 	*p = emalloc(sizeof(soapHeader));
2033 	memset(*p, 0, sizeof(soapHeader));
2034 	ZVAL_NULL(&(*p)->function_name);
2035 	Z_ADDREF_P(fault);
2036 	ZVAL_OBJ(&(*p)->retval, Z_OBJ_P(fault));
2037 
2038 	SOAP_SERVER_END_CODE();
2039 }
2040 /* }}} */
2041 
2042 static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader *hdr) /* {{{ */
2043 {
2044 	int soap_version;
2045 	xmlChar *buf;
2046 	char cont_len[30];
2047 	int size;
2048 	xmlDocPtr doc_return;
2049 	zval *agent_name;
2050 	int use_http_error_status = 1;
2051 
2052 	soap_version = SOAP_GLOBAL(soap_version);
2053 
2054 	doc_return = serialize_response_call(function, NULL, NULL, fault, hdr, soap_version);
2055 
2056 	xmlDocDumpMemory(doc_return, &buf, &size);
2057 
2058 	if ((Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY || zend_is_auto_global_str(ZEND_STRL("_SERVER"))) &&
2059 		(agent_name = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_USER_AGENT", sizeof("HTTP_USER_AGENT")-1)) != NULL &&
2060 		Z_TYPE_P(agent_name) == IS_STRING) {
2061 		if (strncmp(Z_STRVAL_P(agent_name), "Shockwave Flash", sizeof("Shockwave Flash")-1) == 0) {
2062 			use_http_error_status = 0;
2063 		}
2064 	}
2065 	/*
2066 	   Want to return HTTP 500 but apache wants to over write
2067 	   our fault code with their own handling... Figure this out later
2068 	*/
2069 	if (use_http_error_status) {
2070 		sapi_add_header("HTTP/1.1 500 Internal Service Error", sizeof("HTTP/1.1 500 Internal Service Error")-1, 1);
2071 	}
2072 	if (zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0)) {
2073 		sapi_add_header("Connection: close", sizeof("Connection: close")-1, 1);
2074 	} else {
2075 		snprintf(cont_len, sizeof(cont_len), "Content-Length: %d", size);
2076 		sapi_add_header(cont_len, strlen(cont_len), 1);
2077 	}
2078 	if (soap_version == SOAP_1_2) {
2079 		sapi_add_header("Content-Type: application/soap+xml; charset=utf-8", sizeof("Content-Type: application/soap+xml; charset=utf-8")-1, 1);
2080 	} else {
2081 		sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
2082 	}
2083 
2084 	php_write(buf, size);
2085 
2086 	xmlFreeDoc(doc_return);
2087 	xmlFree(buf);
2088 	zend_clear_exception();
2089 }
2090 /* }}} */
2091 
2092 static ZEND_NORETURN void soap_server_fault(char* code, char* string, char *actor, zval* details, char* name) /* {{{ */
2093 {
2094 	zval ret;
2095 
2096 	ZVAL_NULL(&ret);
2097 	set_soap_fault(&ret, NULL, code, string, actor, details, name);
2098 	/* TODO: Which function */
2099 	soap_server_fault_ex(NULL, &ret, NULL);
2100 	zend_bailout();
2101 }
2102 /* }}} */
2103 
2104 static zend_never_inline ZEND_COLD void soap_real_error_handler(int error_num, const char *error_filename, const uint32_t error_lineno, const char *format, va_list args) /* {{{ */
2105 {
2106 	zend_bool _old_in_compilation;
2107 	zend_execute_data *_old_current_execute_data;
2108 	int _old_http_response_code;
2109 	char *_old_http_status_line;
2110 
2111 	_old_in_compilation = CG(in_compilation);
2112 	_old_current_execute_data = EG(current_execute_data);
2113 	_old_http_response_code = SG(sapi_headers).http_response_code;
2114 	_old_http_status_line = SG(sapi_headers).http_status_line;
2115 
2116 	if (Z_OBJ(SOAP_GLOBAL(error_object)) &&
2117 	    instanceof_function(Z_OBJCE(SOAP_GLOBAL(error_object)), soap_class_entry)) {
2118 		zval *tmp;
2119 		int use_exceptions = 0;
2120 
2121 		if ((tmp = zend_hash_str_find(Z_OBJPROP(SOAP_GLOBAL(error_object)), "_exceptions", sizeof("_exceptions")-1)) == NULL ||
2122 		     Z_TYPE_P(tmp) != IS_FALSE) {
2123 		     use_exceptions = 1;
2124 		}
2125 
2126 		if ((error_num == E_USER_ERROR ||
2127 		     error_num == E_COMPILE_ERROR ||
2128 		     error_num == E_CORE_ERROR ||
2129 		     error_num == E_ERROR ||
2130 		     error_num == E_PARSE) &&
2131 		    use_exceptions) {
2132 			zval fault;
2133 			char* code = SOAP_GLOBAL(error_code);
2134 			char buffer[1024];
2135 			size_t buffer_len;
2136 			va_list argcopy;
2137 
2138 			va_copy(argcopy, args);
2139 			buffer_len = vslprintf(buffer, sizeof(buffer)-1, format, argcopy);
2140 			va_end(argcopy);
2141 
2142 			buffer[sizeof(buffer)-1]=0;
2143 			if (buffer_len > sizeof(buffer) - 1 || buffer_len == (size_t)-1) {
2144 				buffer_len = sizeof(buffer) - 1;
2145 			}
2146 
2147 			if (code == NULL) {
2148 				code = "Client";
2149 			}
2150 			add_soap_fault_ex(&fault, &SOAP_GLOBAL(error_object), code, buffer, NULL, NULL);
2151 			Z_ADDREF(fault);
2152 			zend_throw_exception_object(&fault);
2153 			zend_bailout();
2154 		} else if (!use_exceptions ||
2155 		           !SOAP_GLOBAL(error_code) ||
2156 		           strcmp(SOAP_GLOBAL(error_code),"WSDL") != 0) {
2157 			/* Ignore libxml warnings during WSDL parsing */
2158 			call_old_error_handler(error_num, error_filename, error_lineno, format, args);
2159 		}
2160 	} else {
2161 		int old = PG(display_errors);
2162 		int fault = 0;
2163 		zval fault_obj;
2164 		va_list argcopy;
2165 
2166 		if (error_num == E_USER_ERROR ||
2167 		    error_num == E_COMPILE_ERROR ||
2168 		    error_num == E_CORE_ERROR ||
2169 		    error_num == E_ERROR ||
2170 		    error_num == E_PARSE) {
2171 
2172 			char* code = SOAP_GLOBAL(error_code);
2173 			char buffer[1024];
2174 			zval outbuf;
2175 			zval *tmp;
2176 			soapServicePtr service;
2177 
2178 			ZVAL_UNDEF(&outbuf);
2179 			if (code == NULL) {
2180 				code = "Server";
2181 			}
2182 			if (Z_OBJ(SOAP_GLOBAL(error_object)) &&
2183 			    instanceof_function(Z_OBJCE(SOAP_GLOBAL(error_object)), soap_server_class_entry) &&
2184 		        (tmp = zend_hash_str_find(Z_OBJPROP(SOAP_GLOBAL(error_object)), "service", sizeof("service")-1)) != NULL &&
2185 				(service = (soapServicePtr)zend_fetch_resource_ex(tmp, "service", le_service)) &&
2186 				!service->send_errors) {
2187 				strcpy(buffer, "Internal Error");
2188 			} else {
2189 				size_t buffer_len;
2190 				zval outbuflen;
2191 
2192 				va_copy(argcopy, args);
2193 				buffer_len = vslprintf(buffer, sizeof(buffer)-1, format, argcopy);
2194 				va_end(argcopy);
2195 
2196 				buffer[sizeof(buffer)-1]=0;
2197 				if (buffer_len > sizeof(buffer) - 1 || buffer_len == (size_t)-1) {
2198 					buffer_len = sizeof(buffer) - 1;
2199 				}
2200 
2201 				/* Get output buffer and send as fault detials */
2202 				if (php_output_get_length(&outbuflen) != FAILURE && Z_LVAL(outbuflen) != 0) {
2203 					php_output_get_contents(&outbuf);
2204 				}
2205 				php_output_discard();
2206 
2207 			}
2208 			ZVAL_NULL(&fault_obj);
2209 			set_soap_fault(&fault_obj, NULL, code, buffer, NULL, &outbuf, NULL);
2210 			fault = 1;
2211 		}
2212 
2213 		PG(display_errors) = 0;
2214 		SG(sapi_headers).http_status_line = NULL;
2215 		zend_try {
2216 			call_old_error_handler(error_num, error_filename, error_lineno, format, args);
2217 		} zend_catch {
2218 			CG(in_compilation) = _old_in_compilation;
2219 			EG(current_execute_data) = _old_current_execute_data;
2220 			if (SG(sapi_headers).http_status_line) {
2221 				efree(SG(sapi_headers).http_status_line);
2222 			}
2223 			SG(sapi_headers).http_status_line = _old_http_status_line;
2224 			SG(sapi_headers).http_response_code = _old_http_response_code;
2225 		} zend_end_try();
2226 		PG(display_errors) = old;
2227 
2228 		if (fault) {
2229 			soap_server_fault_ex(NULL, &fault_obj, NULL);
2230 			zend_bailout();
2231 		}
2232 	}
2233 }
2234 /* }}} */
2235 
2236 static void soap_error_handler(int error_num, const char *error_filename, const uint32_t error_lineno, const char *format, va_list args) /* {{{ */
2237 {
2238 	if (EXPECTED(!SOAP_GLOBAL(use_soap_error_handler))) {
2239 		call_old_error_handler(error_num, error_filename, error_lineno, format, args);
2240 	} else {
2241 		soap_real_error_handler(error_num, error_filename, error_lineno, format, args);
2242 	}
2243 }
2244 /* }}} */
2245 
2246 /* {{{ proto use_soap_error_handler([bool $handler = TRUE]) */
2247 PHP_FUNCTION(use_soap_error_handler)
2248 {
2249 	zend_bool handler = 1;
2250 
2251 	ZVAL_BOOL(return_value, SOAP_GLOBAL(use_soap_error_handler));
2252 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &handler) == SUCCESS) {
2253 		SOAP_GLOBAL(use_soap_error_handler) = handler;
2254 	}
2255 }
2256 /* }}} */
2257 
2258 /* {{{ proto is_soap_fault(mixed $object) */
2259 PHP_FUNCTION(is_soap_fault)
2260 {
2261 	zval *fault;
2262 
2263 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &fault) == SUCCESS &&
2264 	    Z_TYPE_P(fault) == IS_OBJECT &&
2265 	    instanceof_function(Z_OBJCE_P(fault), soap_fault_class_entry)) {
2266 		RETURN_TRUE;
2267 	}
2268 	RETURN_FALSE
2269 }
2270 /* }}} */
2271 
2272 /* SoapClient functions */
2273 
2274 /* {{{ proto object SoapClient::SoapClient(mixed wsdl [, array options])
2275    SoapClient constructor */
2276 PHP_METHOD(SoapClient, SoapClient)
2277 {
2278 
2279 	zval *wsdl, *options = NULL;
2280 	int  soap_version = SOAP_1_1;
2281 	php_stream_context *context = NULL;
2282 	zend_long cache_wsdl;
2283 	sdlPtr sdl = NULL;
2284 	HashTable *typemap_ht = NULL;
2285 	zval *this_ptr = ZEND_THIS;
2286 
2287 	SOAP_CLIENT_BEGIN_CODE();
2288 
2289 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|a", &wsdl, &options) == FAILURE) {
2290 		php_error_docref(NULL, E_ERROR, "Invalid parameters");
2291 	}
2292 
2293 	if (Z_TYPE_P(wsdl) != IS_STRING && Z_TYPE_P(wsdl) != IS_NULL) {
2294 		php_error_docref(NULL, E_ERROR, "$wsdl must be string or null");
2295 	}
2296 
2297 	cache_wsdl = SOAP_GLOBAL(cache_enabled) ? SOAP_GLOBAL(cache_mode) : 0;
2298 
2299 	if (options != NULL) {
2300 		HashTable *ht = Z_ARRVAL_P(options);
2301 		zval *tmp, tmp2;
2302 
2303 		if (Z_TYPE_P(wsdl) == IS_NULL) {
2304 			/* Fetching non-WSDL mode options */
2305 			if ((tmp = zend_hash_str_find(ht, "uri", sizeof("uri")-1)) != NULL &&
2306 			    Z_TYPE_P(tmp) == IS_STRING) {
2307 				add_property_str(this_ptr, "uri", zend_string_copy(Z_STR_P(tmp)));
2308 			} else {
2309 				php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
2310 			}
2311 
2312 			if ((tmp = zend_hash_str_find(ht, "style", sizeof("style")-1)) != NULL &&
2313 					Z_TYPE_P(tmp) == IS_LONG &&
2314 					(Z_LVAL_P(tmp) == SOAP_RPC || Z_LVAL_P(tmp) == SOAP_DOCUMENT)) {
2315 				add_property_long(this_ptr, "style", Z_LVAL_P(tmp));
2316 			}
2317 
2318 			if ((tmp = zend_hash_str_find(ht, "use", sizeof("use")-1)) != NULL &&
2319 					Z_TYPE_P(tmp) == IS_LONG &&
2320 					(Z_LVAL_P(tmp) == SOAP_LITERAL || Z_LVAL_P(tmp) == SOAP_ENCODED)) {
2321 				add_property_long(this_ptr, "use", Z_LVAL_P(tmp));
2322 			}
2323 		}
2324 
2325 		if ((tmp = zend_hash_str_find(ht, "stream_context", sizeof("stream_context")-1)) != NULL &&
2326 				Z_TYPE_P(tmp) == IS_RESOURCE) {
2327 			context = php_stream_context_from_zval(tmp, 1);
2328 			Z_ADDREF_P(tmp);
2329 		} else {
2330 			context = php_stream_context_alloc();
2331 		}
2332 
2333 		if ((tmp = zend_hash_str_find(ht, "location", sizeof("location")-1)) != NULL &&
2334 		    Z_TYPE_P(tmp) == IS_STRING) {
2335 			add_property_str(this_ptr, "location", zend_string_copy(Z_STR_P(tmp)));
2336 		} else if (Z_TYPE_P(wsdl) == IS_NULL) {
2337 			php_error_docref(NULL, E_ERROR, "'location' option is required in nonWSDL mode");
2338 		}
2339 
2340 		if ((tmp = zend_hash_str_find(ht, "soap_version", sizeof("soap_version")-1)) != NULL) {
2341 			if (Z_TYPE_P(tmp) == IS_LONG ||
2342 			    (Z_LVAL_P(tmp) == SOAP_1_1 && Z_LVAL_P(tmp) == SOAP_1_2)) {
2343 				soap_version = Z_LVAL_P(tmp);
2344 			}
2345 		}
2346 		if ((tmp = zend_hash_str_find(ht, "login", sizeof("login")-1)) != NULL &&
2347 		    Z_TYPE_P(tmp) == IS_STRING) {
2348 			add_property_str(this_ptr, "_login", zend_string_copy(Z_STR_P(tmp)));
2349 			if ((tmp = zend_hash_str_find(ht, "password", sizeof("password")-1)) != NULL &&
2350 			    Z_TYPE_P(tmp) == IS_STRING) {
2351 				add_property_str(this_ptr, "_password", zend_string_copy(Z_STR_P(tmp)));
2352 			}
2353 			if ((tmp = zend_hash_str_find(ht, "authentication", sizeof("authentication")-1)) != NULL &&
2354 			    Z_TYPE_P(tmp) == IS_LONG &&
2355 			    Z_LVAL_P(tmp) == SOAP_AUTHENTICATION_DIGEST) {
2356 				add_property_null(this_ptr, "_digest");
2357 			}
2358 		}
2359 		if ((tmp = zend_hash_str_find(ht, "proxy_host", sizeof("proxy_host")-1)) != NULL &&
2360 		    Z_TYPE_P(tmp) == IS_STRING) {
2361 			add_property_str(this_ptr, "_proxy_host", zend_string_copy(Z_STR_P(tmp)));
2362 			if ((tmp = zend_hash_str_find(ht, "proxy_port", sizeof("proxy_port")-1)) != NULL) {
2363 				if (Z_TYPE_P(tmp) != IS_LONG) {
2364 					ZVAL_LONG(&tmp2, zval_get_long(tmp));
2365 					tmp = &tmp2;
2366 				}
2367 				add_property_long(this_ptr, "_proxy_port", Z_LVAL_P(tmp));
2368 			}
2369 			if ((tmp = zend_hash_str_find(ht, "proxy_login", sizeof("proxy_login")-1)) != NULL &&
2370 			    Z_TYPE_P(tmp) == IS_STRING) {
2371 				add_property_str(this_ptr, "_proxy_login", zend_string_copy(Z_STR_P(tmp)));
2372 				if ((tmp = zend_hash_str_find(ht, "proxy_password", sizeof("proxy_password")-1)) != NULL &&
2373 				    Z_TYPE_P(tmp) == IS_STRING) {
2374 					add_property_str(this_ptr, "_proxy_password", zend_string_copy(Z_STR_P(tmp)));
2375 				}
2376 			}
2377 		}
2378 		if ((tmp = zend_hash_str_find(ht, "local_cert", sizeof("local_cert")-1)) != NULL &&
2379 		    Z_TYPE_P(tmp) == IS_STRING) {
2380 		  if (!context) {
2381   			context = php_stream_context_alloc();
2382 		  }
2383  			php_stream_context_set_option(context, "ssl", "local_cert", tmp);
2384 			if ((tmp = zend_hash_str_find(ht, "passphrase", sizeof("passphrase")-1)) != NULL &&
2385 			    Z_TYPE_P(tmp) == IS_STRING) {
2386 				php_stream_context_set_option(context, "ssl", "passphrase", tmp);
2387 			}
2388 		}
2389 		if ((tmp = zend_hash_str_find(ht, "trace", sizeof("trace")-1)) != NULL &&
2390 		    (Z_TYPE_P(tmp) == IS_TRUE ||
2391 		     (Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 1))) {
2392 			add_property_long(this_ptr, "trace", 1);
2393 		}
2394 
2395 		if ((tmp = zend_hash_str_find(ht, "exceptions", sizeof("exceptions")-1)) != NULL &&
2396 		    (Z_TYPE_P(tmp) == IS_FALSE ||
2397 		     (Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 0))) {
2398 			add_property_bool(this_ptr, "_exceptions", 0);
2399 		}
2400 
2401 		if ((tmp = zend_hash_str_find(ht, "compression", sizeof("compression")-1)) != NULL &&
2402 		    Z_TYPE_P(tmp) == IS_LONG &&
2403 	      zend_hash_str_exists(EG(function_table), "gzinflate", sizeof("gzinflate")-1) &&
2404 	      zend_hash_str_exists(EG(function_table), "gzdeflate", sizeof("gzdeflate")-1) &&
2405 	      zend_hash_str_exists(EG(function_table), "gzuncompress", sizeof("gzuncompress")-1) &&
2406 	      zend_hash_str_exists(EG(function_table), "gzcompress", sizeof("gzcompress")-1) &&
2407 	      zend_hash_str_exists(EG(function_table), "gzencode", sizeof("gzencode")-1)) {
2408 			add_property_long(this_ptr, "compression", Z_LVAL_P(tmp));
2409 		}
2410 		if ((tmp = zend_hash_str_find(ht, "encoding", sizeof("encoding")-1)) != NULL &&
2411 		    Z_TYPE_P(tmp) == IS_STRING) {
2412 			xmlCharEncodingHandlerPtr encoding;
2413 
2414 			encoding = xmlFindCharEncodingHandler(Z_STRVAL_P(tmp));
2415 			if (encoding == NULL) {
2416 				php_error_docref(NULL, E_ERROR, "Invalid 'encoding' option - '%s'", Z_STRVAL_P(tmp));
2417 			} else {
2418 				xmlCharEncCloseFunc(encoding);
2419 				add_property_str(this_ptr, "_encoding", zend_string_copy(Z_STR_P(tmp)));
2420 			}
2421 		}
2422 		if ((tmp = zend_hash_str_find(ht, "classmap", sizeof("classmap")-1)) != NULL &&
2423 			Z_TYPE_P(tmp) == IS_ARRAY) {
2424 			add_property_zval(this_ptr, "_classmap", tmp);
2425 		}
2426 
2427 		if ((tmp = zend_hash_str_find(ht, "typemap", sizeof("typemap")-1)) != NULL &&
2428 			Z_TYPE_P(tmp) == IS_ARRAY &&
2429 			zend_hash_num_elements(Z_ARRVAL_P(tmp)) > 0) {
2430 			typemap_ht = Z_ARRVAL_P(tmp);
2431 		}
2432 
2433 		if ((tmp = zend_hash_str_find(ht, "features", sizeof("features")-1)) != NULL &&
2434 			Z_TYPE_P(tmp) == IS_LONG) {
2435 			add_property_long(this_ptr, "_features", Z_LVAL_P(tmp));
2436 	    }
2437 
2438 		if ((tmp = zend_hash_str_find(ht, "connection_timeout", sizeof("connection_timeout")-1)) != NULL) {
2439 			if (Z_TYPE_P(tmp) != IS_LONG) {
2440 				ZVAL_LONG(&tmp2, zval_get_long(tmp));
2441 				tmp = &tmp2;
2442 			}
2443 			if (Z_LVAL_P(tmp) > 0) {
2444 				add_property_long(this_ptr, "_connection_timeout", Z_LVAL_P(tmp));
2445 			}
2446 		}
2447 
2448 		if (context) {
2449 			add_property_resource(this_ptr, "_stream_context", context->res);
2450 		}
2451 
2452 		if ((tmp = zend_hash_str_find(ht, "cache_wsdl", sizeof("cache_wsdl")-1)) != NULL &&
2453 		    Z_TYPE_P(tmp) == IS_LONG) {
2454 			cache_wsdl = Z_LVAL_P(tmp);
2455 		}
2456 
2457 		if ((tmp = zend_hash_str_find(ht, "user_agent", sizeof("user_agent")-1)) != NULL &&
2458 		    Z_TYPE_P(tmp) == IS_STRING) {
2459 			add_property_str(this_ptr, "_user_agent", zend_string_copy(Z_STR_P(tmp)));
2460 		}
2461 
2462 		if ((tmp = zend_hash_str_find(ht, "keep_alive", sizeof("keep_alive")-1)) != NULL &&
2463 				(Z_TYPE_P(tmp) == IS_FALSE ||
2464 				 (Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 0))) {
2465 			add_property_long(this_ptr, "_keep_alive", 0);
2466 		}
2467 
2468 		if ((tmp = zend_hash_str_find(ht, "ssl_method", sizeof("ssl_method")-1)) != NULL &&
2469 			Z_TYPE_P(tmp) == IS_LONG) {
2470 			add_property_long(this_ptr, "_ssl_method", Z_LVAL_P(tmp));
2471 		}
2472 	} else if (Z_TYPE_P(wsdl) == IS_NULL) {
2473 		php_error_docref(NULL, E_ERROR, "'location' and 'uri' options are required in nonWSDL mode");
2474 	}
2475 
2476 	add_property_long(this_ptr, "_soap_version", soap_version);
2477 
2478 	if (Z_TYPE_P(wsdl) != IS_NULL) {
2479 		int    old_soap_version;
2480 		zend_resource *res;
2481 
2482 		old_soap_version = SOAP_GLOBAL(soap_version);
2483 		SOAP_GLOBAL(soap_version) = soap_version;
2484 
2485 		sdl = get_sdl(this_ptr, Z_STRVAL_P(wsdl), cache_wsdl);
2486 		res = zend_register_resource(sdl, le_sdl);
2487 
2488 		add_property_resource(this_ptr, "sdl", res);
2489 
2490 		SOAP_GLOBAL(soap_version) = old_soap_version;
2491 	}
2492 
2493 	if (typemap_ht) {
2494 		HashTable *typemap = soap_create_typemap(sdl, typemap_ht);
2495 		if (typemap) {
2496 			zend_resource *res;
2497 
2498 			res = zend_register_resource(typemap, le_typemap);
2499 			add_property_resource(this_ptr, "typemap", res);
2500 		}
2501 	}
2502 	SOAP_CLIENT_END_CODE();
2503 }
2504 /* }}} */
2505 
2506 static int do_request(zval *this_ptr, xmlDoc *request, char *location, char *action, int version, int one_way, zval *response) /* {{{ */
2507 {
2508 	int    ret = TRUE;
2509 	char  *buf;
2510 	int    buf_size;
2511 	zval   func;
2512 	zval  params[5];
2513 	zval  *trace;
2514 	zval  *fault;
2515 	int    _bailout = 0;
2516 
2517 	ZVAL_NULL(response);
2518 
2519 	xmlDocDumpMemory(request, (xmlChar**)&buf, &buf_size);
2520 	if (!buf) {
2521 		add_soap_fault(this_ptr, "HTTP", "Error build soap request", NULL, NULL);
2522 		return FALSE;
2523 	}
2524 
2525 	zend_try {
2526 		if ((trace = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace")-1)) != NULL &&
2527 		    (Z_TYPE_P(trace) == IS_TRUE || (Z_TYPE_P(trace) == IS_LONG && Z_LVAL_P(trace) != 0))) {
2528 			add_property_stringl(this_ptr, "__last_request", buf, buf_size);
2529 		}
2530 
2531 		ZVAL_STRINGL(&func,"__doRequest",sizeof("__doRequest")-1);
2532 		ZVAL_STRINGL(&params[0], buf, buf_size);
2533 		if (location == NULL) {
2534 			ZVAL_NULL(&params[1]);
2535 		} else {
2536 			ZVAL_STRING(&params[1], location);
2537 		}
2538 		if (action == NULL) {
2539 			ZVAL_NULL(&params[2]);
2540 		} else {
2541 			ZVAL_STRING(&params[2], action);
2542 		}
2543 		ZVAL_LONG(&params[3], version);
2544 		ZVAL_LONG(&params[4], one_way);
2545 
2546 		if (call_user_function(NULL, this_ptr, &func, response, 5, params) != SUCCESS) {
2547 			add_soap_fault(this_ptr, "Client", "SoapClient::__doRequest() failed", NULL, NULL);
2548 			ret = FALSE;
2549 		} else if (Z_TYPE_P(response) != IS_STRING) {
2550 			if (EG(exception) && instanceof_function(EG(exception)->ce, zend_ce_error)) {
2551 				zval rv;
2552 				zend_string *msg;
2553 				zval exception_object;
2554 
2555 				ZVAL_OBJ(&exception_object, EG(exception));
2556 				msg = zval_get_string(zend_read_property(zend_ce_error, &exception_object, "message", sizeof("message")-1, 0, &rv));
2557 				/* change class */
2558 				EG(exception)->ce = soap_fault_class_entry;
2559 				set_soap_fault(&exception_object, NULL, "Client", ZSTR_VAL(msg), NULL, NULL, NULL);
2560 				zend_string_release_ex(msg, 0);
2561 			} else if ((fault = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault")-1)) == NULL) {
2562 				add_soap_fault(this_ptr, "Client", "SoapClient::__doRequest() returned non string value", NULL, NULL);
2563 			}
2564 			ret = FALSE;
2565 		} else if ((trace = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace")-1)) != NULL &&
2566 		    (Z_TYPE_P(trace) == IS_TRUE || (Z_TYPE_P(trace) == IS_LONG && Z_LVAL_P(trace) != 0))) {
2567 			add_property_str(this_ptr, "__last_response", zend_string_copy(Z_STR_P(response)));
2568 		}
2569 	} zend_catch {
2570 		_bailout = 1;
2571 	} zend_end_try();
2572 	zval_ptr_dtor(&func);
2573 	zval_ptr_dtor(&params[2]);
2574 	zval_ptr_dtor(&params[1]);
2575 	zval_ptr_dtor(&params[0]);
2576 	xmlFree(buf);
2577 	if (_bailout) {
2578 		zend_bailout();
2579 	}
2580 	if (ret && (fault = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault")-1)) != NULL) {
2581 		ret = FALSE;
2582 	}
2583 	return ret;
2584 }
2585 /* }}} */
2586 
2587 static void do_soap_call(zend_execute_data *execute_data,
2588                          zval* this_ptr,
2589                          char* function,
2590                          size_t function_len,
2591                          int arg_count,
2592                          zval* real_args,
2593                          zval* return_value,
2594                          char* location,
2595                          char* soap_action,
2596                          char* call_uri,
2597                          HashTable* soap_headers,
2598                          zval* output_headers
2599                         ) /* {{{ */
2600 {
2601 	zval *tmp;
2602 	zval *trace;
2603  	sdlPtr sdl = NULL;
2604  	sdlPtr old_sdl = NULL;
2605  	sdlFunctionPtr fn;
2606 	xmlDocPtr request = NULL;
2607 	int ret = FALSE;
2608 	int soap_version;
2609 	zval response;
2610 	xmlCharEncodingHandlerPtr old_encoding;
2611 	HashTable *old_class_map;
2612 	int old_features;
2613 	HashTable *old_typemap, *typemap = NULL;
2614 	smart_str action = {0};
2615 	int bailout = 0;
2616 
2617 	SOAP_CLIENT_BEGIN_CODE();
2618 
2619 	if ((trace = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace")-1)) != NULL &&
2620 		(Z_TYPE_P(trace) == IS_TRUE || (Z_TYPE_P(trace) == IS_LONG && Z_LVAL_P(trace) != 0))) {
2621 		zend_hash_str_del(Z_OBJPROP_P(this_ptr), "__last_request", sizeof("__last_request")-1);
2622 		zend_hash_str_del(Z_OBJPROP_P(this_ptr), "__last_response", sizeof("__last_response")-1);
2623 	}
2624 	if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_soap_version", sizeof("_soap_version")-1)) != NULL &&
2625 		Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == SOAP_1_2) {
2626 		soap_version = SOAP_1_2;
2627 	} else {
2628 		soap_version = SOAP_1_1;
2629 	}
2630 
2631 	if (location == NULL) {
2632 		if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "location", sizeof("location")-1)) != NULL &&
2633 		    Z_TYPE_P(tmp) == IS_STRING) {
2634 		  location = Z_STRVAL_P(tmp);
2635 		}
2636 	}
2637 
2638 	if (FIND_SDL_PROPERTY(this_ptr,tmp) != NULL) {
2639 		FETCH_SDL_RES(sdl,tmp);
2640 	}
2641 	if (FIND_TYPEMAP_PROPERTY(this_ptr,tmp) != NULL) {
2642 		FETCH_TYPEMAP_RES(typemap,tmp);
2643 	}
2644 
2645  	clear_soap_fault(this_ptr);
2646 
2647 	SOAP_GLOBAL(soap_version) = soap_version;
2648 	old_sdl = SOAP_GLOBAL(sdl);
2649 	SOAP_GLOBAL(sdl) = sdl;
2650 	old_encoding = SOAP_GLOBAL(encoding);
2651 	if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_encoding", sizeof("_encoding")-1)) != NULL &&
2652 	    Z_TYPE_P(tmp) == IS_STRING) {
2653 		SOAP_GLOBAL(encoding) = xmlFindCharEncodingHandler(Z_STRVAL_P(tmp));
2654 	} else {
2655 		SOAP_GLOBAL(encoding) = NULL;
2656 	}
2657 	old_class_map = SOAP_GLOBAL(class_map);
2658 	if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_classmap", sizeof("_classmap")-1)) != NULL &&
2659 	    Z_TYPE_P(tmp) == IS_ARRAY) {
2660 		SOAP_GLOBAL(class_map) = Z_ARRVAL_P(tmp);
2661 	} else {
2662 		SOAP_GLOBAL(class_map) = NULL;
2663 	}
2664 	old_typemap = SOAP_GLOBAL(typemap);
2665 	SOAP_GLOBAL(typemap) = typemap;
2666 	old_features = SOAP_GLOBAL(features);
2667 	if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_features", sizeof("_features")-1)) != NULL &&
2668 	    Z_TYPE_P(tmp) == IS_LONG) {
2669 		SOAP_GLOBAL(features) = Z_LVAL_P(tmp);
2670 	} else {
2671 		SOAP_GLOBAL(features) = 0;
2672 	}
2673 
2674 	zend_try {
2675 	 	if (sdl != NULL) {
2676  			fn = get_function(sdl, function);
2677  			if (fn != NULL) {
2678 				sdlBindingPtr binding = fn->binding;
2679 				int one_way = 0;
2680 
2681 				if (fn->responseName == NULL &&
2682 				    fn->responseParameters == NULL &&
2683 				    soap_headers == NULL) {
2684 					one_way = 1;
2685 				}
2686 
2687 				if (location == NULL) {
2688 					location = binding->location;
2689 				}
2690 				if (binding->bindingType == BINDING_SOAP) {
2691 					sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes;
2692  					request = serialize_function_call(this_ptr, fn, NULL, fnb->input.ns, real_args, arg_count, soap_version, soap_headers);
2693 	 				ret = do_request(this_ptr, request, location, fnb->soapAction, soap_version, one_way, &response);
2694  				} else {
2695 	 				request = serialize_function_call(this_ptr, fn, NULL, sdl->target_ns, real_args, arg_count, soap_version, soap_headers);
2696 	 				ret = do_request(this_ptr, request, location, NULL, soap_version, one_way, &response);
2697  				}
2698 
2699 				xmlFreeDoc(request);
2700 				request = NULL;
2701 
2702 				if (ret && Z_TYPE(response) == IS_STRING) {
2703 					encode_reset_ns();
2704 					ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), fn, NULL, return_value, output_headers);
2705 					encode_finish();
2706 				}
2707 
2708 				zval_ptr_dtor(&response);
2709 
2710 	 		} else {
2711 	 			smart_str error = {0};
2712 	 			smart_str_appends(&error,"Function (\"");
2713 	 			smart_str_appends(&error,function);
2714 	 			smart_str_appends(&error,"\") is not a valid method for this service");
2715 	 			smart_str_0(&error);
2716 				add_soap_fault(this_ptr, "Client", ZSTR_VAL(error.s), NULL, NULL);
2717 				smart_str_free(&error);
2718 			}
2719 		} else {
2720 			zval *uri;
2721 
2722 			if ((uri = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "uri", sizeof("uri")-1)) == NULL || Z_TYPE_P(uri) != IS_STRING) {
2723 				add_soap_fault(this_ptr, "Client", "Error finding \"uri\" property", NULL,