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