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