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