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