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