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