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