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