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