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