1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2008 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Brad Lafountain <rodif_bl@yahoo.com> |
16 | Shane Caraveo <shane@caraveo.com> |
17 | Dmitry Stogov <dmitry@zend.com> |
18 +----------------------------------------------------------------------+
19 */
20 /* $Id: soap.c,v 1.247 2008/07/22 01:46:43 felipe Exp $ */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include "php_soap.h"
26 #if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
27 #include "ext/session/php_session.h"
28 #endif
29 #include "zend_exceptions.h"
30 #include "ext/libxml/php_libxml.h"
31
32 typedef struct _soapHeader {
33 sdlFunctionPtr function;
34 zval function_name;
35 int mustUnderstand;
36 int num_params;
37 zval **parameters;
38 zval retval;
39 sdlSoapBindingFunctionHeaderPtr hdr;
40 struct _soapHeader *next;
41 } soapHeader;
42
43 /* Local functions */
44 static void function_to_string(sdlFunctionPtr function, smart_str *buf);
45 static void type_to_string(sdlTypePtr type, smart_str *buf, int level);
46
47 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 TSRMLS_DC);
48 static void soap_server_fault(char* code, char* string, char *actor, zval* details, char *name TSRMLS_DC);
49 static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader* hdr TSRMLS_DC);
50
51 static sdlParamPtr get_param(sdlFunctionPtr function, char *param_name, int index, int);
52 static sdlFunctionPtr get_function(sdlPtr sdl, const char *function_name);
53 static sdlFunctionPtr get_doc_function(sdlPtr sdl, xmlNodePtr node);
54
55 static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, char* actor, zval *function_name, int *num_params, zval **parameters[], int *version, soapHeader **headers TSRMLS_DC);
56 static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function_name,char *uri,zval *ret, soapHeader *headers, int version TSRMLS_DC);
57 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 TSRMLS_DC);
58 static xmlNodePtr serialize_parameter(sdlParamPtr param,zval *param_val,int index,char *name, int style, xmlNodePtr parent TSRMLS_DC);
59 static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName, int style, xmlNodePtr parent TSRMLS_DC);
60
61 static void soap_error_handler(int error_num, const char *error_filename, const uint error_lineno, const char *format, va_list args);
62
63 #define SOAP_SERVER_BEGIN_CODE() \
64 zend_bool _old_handler = SOAP_GLOBAL(use_soap_error_handler);\
65 char* _old_error_code = SOAP_GLOBAL(error_code);\
66 zval* _old_error_object = SOAP_GLOBAL(error_object);\
67 int _old_soap_version = SOAP_GLOBAL(soap_version);\
68 SOAP_GLOBAL(use_soap_error_handler) = 1;\
69 SOAP_GLOBAL(error_code) = "Server";\
70 SOAP_GLOBAL(error_object) = this_ptr;
71
72 #define SOAP_SERVER_END_CODE() \
73 SOAP_GLOBAL(use_soap_error_handler) = _old_handler;\
74 SOAP_GLOBAL(error_code) = _old_error_code;\
75 SOAP_GLOBAL(error_object) = _old_error_object;\
76 SOAP_GLOBAL(soap_version) = _old_soap_version;
77
78 #define SOAP_CLIENT_BEGIN_CODE() \
79 zend_bool _old_handler = SOAP_GLOBAL(use_soap_error_handler);\
80 char* _old_error_code = SOAP_GLOBAL(error_code);\
81 zval* _old_error_object = SOAP_GLOBAL(error_object);\
82 int _old_soap_version = SOAP_GLOBAL(soap_version);\
83 zend_bool _old_in_compilation = CG(in_compilation); \
84 zend_bool _old_in_execution = EG(in_execution); \
85 zend_execute_data *_old_current_execute_data = EG(current_execute_data); \
86 int _bailout = 0;\
87 SOAP_GLOBAL(use_soap_error_handler) = 1;\
88 SOAP_GLOBAL(error_code) = "Client";\
89 SOAP_GLOBAL(error_object) = this_ptr;\
90 zend_try {
91
92 #define SOAP_CLIENT_END_CODE() \
93 } zend_catch {\
94 CG(in_compilation) = _old_in_compilation; \
95 EG(in_execution) = _old_in_execution; \
96 EG(current_execute_data) = _old_current_execute_data; \
97 if (EG(exception) == NULL || \
98 Z_TYPE_P(EG(exception)) != IS_OBJECT || \
99 !instanceof_function(Z_OBJCE_P(EG(exception)), soap_fault_class_entry TSRMLS_CC)) {\
100 _bailout = 1;\
101 }\
102 } zend_end_try();\
103 SOAP_GLOBAL(use_soap_error_handler) = _old_handler;\
104 SOAP_GLOBAL(error_code) = _old_error_code;\
105 SOAP_GLOBAL(error_object) = _old_error_object;\
106 SOAP_GLOBAL(soap_version) = _old_soap_version;\
107 if (_bailout) {\
108 zend_bailout();\
109 }
110
111 #define HTTP_RAW_POST_DATA "HTTP_RAW_POST_DATA"
112
113 #define ZERO_PARAM() \
114 if (zend_parse_parameters_none() == FAILURE) \
115 return;
116
117 static zend_class_entry* soap_client_class_entry;
118 static zend_class_entry* soap_server_class_entry;
119 static zend_class_entry* soap_fault_class_entry;
120 static zend_class_entry* soap_header_class_entry;
121 static zend_class_entry* soap_param_class_entry;
122 zend_class_entry* soap_var_class_entry;
123
124 ZEND_DECLARE_MODULE_GLOBALS(soap)
125
126 static void (*old_error_handler)(int, const char *, const uint, const char*, va_list);
127
128 #ifdef va_copy
129 #define call_old_error_handler(error_num, error_filename, error_lineno, format, args) \
130 { \
131 va_list copy; \
132 va_copy(copy, args); \
133 old_error_handler(error_num, error_filename, error_lineno, format, copy); \
134 va_end(copy); \
135 }
136 #else
137 #define call_old_error_handler(error_num, error_filename, error_lineno, format, args) \
138 { \
139 old_error_handler(error_num, error_filename, error_lineno, format, args); \
140 }
141 #endif
142
143 #define PHP_SOAP_SERVER_CLASSNAME "SoapServer"
144 #define PHP_SOAP_CLIENT_CLASSNAME "SoapClient"
145 #define PHP_SOAP_VAR_CLASSNAME "SoapVar"
146 #define PHP_SOAP_FAULT_CLASSNAME "SoapFault"
147 #define PHP_SOAP_PARAM_CLASSNAME "SoapParam"
148 #define PHP_SOAP_HEADER_CLASSNAME "SoapHeader"
149
150 PHP_RINIT_FUNCTION(soap);
151 PHP_MINIT_FUNCTION(soap);
152 PHP_MSHUTDOWN_FUNCTION(soap);
153 PHP_MINFO_FUNCTION(soap);
154
155 /*
156 Registry Functions
157 TODO: this!
158 */
159 PHP_FUNCTION(soap_encode_to_xml);
160 PHP_FUNCTION(soap_encode_to_zval);
161 PHP_FUNCTION(use_soap_error_handler);
162 PHP_FUNCTION(is_soap_fault);
163
164
165 /* Server Functions */
166 PHP_METHOD(SoapServer, SoapServer);
167 PHP_METHOD(SoapServer, setClass);
168 PHP_METHOD(SoapServer, setObject);
169 PHP_METHOD(SoapServer, addFunction);
170 PHP_METHOD(SoapServer, getFunctions);
171 PHP_METHOD(SoapServer, handle);
172 PHP_METHOD(SoapServer, setPersistence);
173 PHP_METHOD(SoapServer, fault);
174 PHP_METHOD(SoapServer, addSoapHeader);
175
176 /* Client Functions */
177 PHP_METHOD(SoapClient, SoapClient);
178 PHP_METHOD(SoapClient, __call);
179 PHP_METHOD(SoapClient, __getLastRequest);
180 PHP_METHOD(SoapClient, __getLastResponse);
181 PHP_METHOD(SoapClient, __getLastRequestHeaders);
182 PHP_METHOD(SoapClient, __getLastResponseHeaders);
183 PHP_METHOD(SoapClient, __getFunctions);
184 PHP_METHOD(SoapClient, __getTypes);
185 PHP_METHOD(SoapClient, __doRequest);
186 PHP_METHOD(SoapClient, __setCookie);
187 PHP_METHOD(SoapClient, __getCookies);
188 PHP_METHOD(SoapClient, __setLocation);
189 PHP_METHOD(SoapClient, __setSoapHeaders);
190
191 /* SoapVar Functions */
192 PHP_METHOD(SoapVar, SoapVar);
193
194 /* SoapFault Functions */
195 PHP_METHOD(SoapFault, SoapFault);
196 PHP_METHOD(SoapFault, __toString);
197
198 /* SoapParam Functions */
199 PHP_METHOD(SoapParam, SoapParam);
200
201 /* SoapHeader Functions */
202 PHP_METHOD(SoapHeader, SoapHeader);
203
204 #define SOAP_CTOR(class_name, func_name, arginfo, flags) ZEND_FENTRY(__construct, ZEND_MN(class_name##_##func_name), arginfo, flags)
205
206 /* {{{ arginfo */
207 static
208 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapparam_soapparam, 0, 0, 2)
209 ZEND_ARG_INFO(0, data)
210 ZEND_ARG_INFO(0, name)
211 ZEND_END_ARG_INFO()
212
213 static
214 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapheader_soapheader, 0, 0, 2)
215 ZEND_ARG_INFO(0, namespace)
216 ZEND_ARG_INFO(0, name)
217 ZEND_ARG_INFO(0, data)
218 ZEND_ARG_INFO(0, mustunderstand)
219 ZEND_ARG_INFO(0, actor)
220 ZEND_END_ARG_INFO()
221
222 static
223 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapfault_soapfault, 0, 0, 2)
224 ZEND_ARG_INFO(0, faultcode)
225 ZEND_ARG_INFO(0, faultstring)
226 ZEND_ARG_INFO(0, faultactor)
227 ZEND_ARG_INFO(0, detail)
228 ZEND_ARG_INFO(0, faultname)
229 ZEND_ARG_INFO(0, headerfault)
230 ZEND_END_ARG_INFO()
231
232 static
233 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapvar_soapvar, 0, 0, 2)
234 ZEND_ARG_INFO(0, data)
235 ZEND_ARG_INFO(0, encoding)
236 ZEND_ARG_INFO(0, type_name)
237 ZEND_ARG_INFO(0, type_namespace)
238 ZEND_ARG_INFO(0, node_name)
239 ZEND_ARG_INFO(0, node_namespace)
240 ZEND_END_ARG_INFO()
241
242 static
243 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_fault, 0, 0, 2)
244 ZEND_ARG_INFO(0, code)
245 ZEND_ARG_INFO(0, string)
246 ZEND_ARG_INFO(0, actor)
247 ZEND_ARG_INFO(0, details)
248 ZEND_ARG_INFO(0, name)
249 ZEND_END_ARG_INFO()
250
251 static
252 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_addsoapheader, 0, 0, 1)
253 ZEND_ARG_INFO(0, object)
254 ZEND_END_ARG_INFO()
255
256 static
257 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_soapserver, 0, 0, 1)
258 ZEND_ARG_INFO(0, wsdl)
259 ZEND_ARG_INFO(0, options)
260 ZEND_END_ARG_INFO()
261
262 static
263 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_setpersistence, 0, 0, 1)
264 ZEND_ARG_INFO(0, mode)
265 ZEND_END_ARG_INFO()
266
267 static
268 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_setclass, 0, 0, 1)
269 ZEND_ARG_INFO(0, class_name)
270 ZEND_ARG_INFO(0, args)
271 ZEND_END_ARG_INFO()
272
273 static
274 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_setobject, 0, 0, 1)
275 ZEND_ARG_INFO(0, object)
276 ZEND_END_ARG_INFO()
277
278 static
279 ZEND_BEGIN_ARG_INFO(arginfo_soapserver_getfunctions, 0)
280 ZEND_END_ARG_INFO()
281
282 static
283 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_addfunction, 0, 0, 1)
284 ZEND_ARG_INFO(0, functions)
285 ZEND_END_ARG_INFO()
286
287 static
288 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_handle, 0, 0, 0)
289 ZEND_ARG_INFO(0, soap_request)
290 ZEND_END_ARG_INFO()
291
292 static
293 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient_soapclient, 0, 0, 1)
294 ZEND_ARG_INFO(0, wsdl)
295 ZEND_ARG_INFO(0, options)
296 ZEND_END_ARG_INFO()
297
298 static
299 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___call, 0, 0, 2)
300 ZEND_ARG_INFO(0, function_name)
301 ZEND_ARG_INFO(0, arguments)
302 ZEND_END_ARG_INFO()
303
304 static
305 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___soapcall, 0, 0, 2)
306 ZEND_ARG_INFO(0, function_name)
307 ZEND_ARG_INFO(0, arguments)
308 ZEND_ARG_INFO(0, options)
309 ZEND_ARG_INFO(0, input_headers)
310 ZEND_ARG_INFO(1, output_headers)
311 ZEND_END_ARG_INFO()
312
313 static
314 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getfunctions, 0)
315 ZEND_END_ARG_INFO()
316
317 static
318 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___gettypes, 0)
319 ZEND_END_ARG_INFO()
320
321 static
322 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastrequest, 0)
323 ZEND_END_ARG_INFO()
324
325 static
326 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastresponse, 0)
327 ZEND_END_ARG_INFO()
328
329 static
330 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastrequestheaders, 0)
331 ZEND_END_ARG_INFO()
332
333 static
334 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastresponseheaders, 0)
335 ZEND_END_ARG_INFO()
336
337 static
338 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___dorequest, 0, 0, 4)
339 ZEND_ARG_INFO(0, request)
340 ZEND_ARG_INFO(0, location)
341 ZEND_ARG_INFO(0, action)
342 ZEND_ARG_INFO(0, version)
343 ZEND_ARG_INFO(0, one_way)
344 ZEND_END_ARG_INFO()
345
346 static
347 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___setcookie, 0, 0, 1)
348 ZEND_ARG_INFO(0, name)
349 ZEND_ARG_INFO(0, value)
350 ZEND_END_ARG_INFO()
351
352 static
353 ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getcookie, 0)
354 ZEND_END_ARG_INFO()
355
356 static
357 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___setsoapheaders, 0, 0, 1)
358 ZEND_ARG_INFO(0, soapheaders)
359 ZEND_END_ARG_INFO()
360
361 static
362 ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___setlocation, 0, 0, 0)
363 ZEND_ARG_INFO(0, new_location)
364 ZEND_END_ARG_INFO()
365
366 static
367 ZEND_BEGIN_ARG_INFO_EX(arginfo_soap_use_soap_error_handler, 0, 0, 0)
368 ZEND_ARG_INFO(0, handler)
369 ZEND_END_ARG_INFO()
370
371 static
372 ZEND_BEGIN_ARG_INFO_EX(arginfo_soap_is_soap_fault, 0, 0, 1)
373 ZEND_ARG_INFO(0, object)
374 ZEND_END_ARG_INFO()
375 /* }}} */
376
377 static const zend_function_entry soap_functions[] = {
378 PHP_FE(use_soap_error_handler, arginfo_soap_use_soap_error_handler)
379 PHP_FE(is_soap_fault, arginfo_soap_is_soap_fault)
380 {NULL, NULL, NULL}
381 };
382
383 static const zend_function_entry soap_fault_functions[] = {
384 SOAP_CTOR(SoapFault, SoapFault, arginfo_soapfault_soapfault, 0)
385 PHP_ME(SoapFault, __toString, NULL, 0)
386 {NULL, NULL, NULL}
387 };
388
389 static const zend_function_entry soap_server_functions[] = {
390 SOAP_CTOR(SoapServer, SoapServer, arginfo_soapserver_soapserver, 0)
391 PHP_ME(SoapServer, setPersistence, arginfo_soapserver_setpersistence, 0)
392 PHP_ME(SoapServer, setClass, arginfo_soapserver_setclass, 0)
393 PHP_ME(SoapServer, setObject, arginfo_soapserver_setobject, 0)
394 PHP_ME(SoapServer, addFunction, arginfo_soapserver_addfunction, 0)
395 PHP_ME(SoapServer, getFunctions, arginfo_soapserver_getfunctions, 0)
396 PHP_ME(SoapServer, handle, arginfo_soapserver_handle, 0)
397 PHP_ME(SoapServer, fault, arginfo_soapserver_fault, 0)
398 PHP_ME(SoapServer, addSoapHeader, arginfo_soapserver_addsoapheader, 0)
399 {NULL, NULL, NULL}
400 };
401
402 static const zend_function_entry soap_client_functions[] = {
403 SOAP_CTOR(SoapClient, SoapClient, arginfo_soapclient_soapclient, 0)
404 PHP_ME(SoapClient, __call, arginfo_soapclient___call, 0)
405 ZEND_FENTRY(__soapCall, ZEND_MN(SoapClient___call), arginfo_soapclient___soapcall, 0)
406 PHP_ME(SoapClient, __getLastRequest, arginfo_soapclient___getlastrequest, 0)
407 PHP_ME(SoapClient, __getLastResponse, arginfo_soapclient___getlastresponse, 0)
408 PHP_ME(SoapClient, __getLastRequestHeaders, arginfo_soapclient___getlastrequestheaders, 0)
409 PHP_ME(SoapClient, __getLastResponseHeaders, arginfo_soapclient___getlastresponseheaders, 0)
410 PHP_ME(SoapClient, __getFunctions, arginfo_soapclient___getfunctions, 0)
411 PHP_ME(SoapClient, __getTypes, arginfo_soapclient___gettypes, 0)
412 PHP_ME(SoapClient, __doRequest, arginfo_soapclient___dorequest, 0)
413 PHP_ME(SoapClient, __setCookie, arginfo_soapclient___setcookie, 0)
414 PHP_ME(SoapClient, __getCookies, arginfo_soapclient___getcookie, 0)
415 PHP_ME(SoapClient, __setLocation, arginfo_soapclient___setlocation, 0)
416 PHP_ME(SoapClient, __setSoapHeaders, arginfo_soapclient___setsoapheaders, 0)
417 {NULL, NULL, NULL}
418 };
419
420 static const zend_function_entry soap_var_functions[] = {
421 SOAP_CTOR(SoapVar, SoapVar, arginfo_soapvar_soapvar, 0)
422 {NULL, NULL, NULL}
423 };
424
425 static const zend_function_entry soap_param_functions[] = {
426 SOAP_CTOR(SoapParam, SoapParam, arginfo_soapparam_soapparam, 0)
427 {NULL, NULL, NULL}
428 };
429
430 static const zend_function_entry soap_header_functions[] = {
431 SOAP_CTOR(SoapHeader, SoapHeader, arginfo_soapheader_soapheader, 0)
432 {NULL, NULL, NULL}
433 };
434
435 zend_module_entry soap_module_entry = {
436 #ifdef STANDARD_MODULE_HEADER
437 STANDARD_MODULE_HEADER,
438 #endif
439 "soap",
440 soap_functions,
441 PHP_MINIT(soap),
442 PHP_MSHUTDOWN(soap),
443 PHP_RINIT(soap),
444 NULL,
445 PHP_MINFO(soap),
446 #ifdef STANDARD_MODULE_HEADER
447 NO_VERSION_YET,
448 #endif
449 STANDARD_MODULE_PROPERTIES,
450 };
451
452 #ifdef COMPILE_DL_SOAP
453 ZEND_GET_MODULE(soap)
454 #endif
455
456 char* soap_unicode_to_string(UChar *ustr, int ustr_len TSRMLS_DC)
457 {
458 int dummy;
459
460 return php_libxml_unicode_to_string(ustr, ustr_len, &dummy TSRMLS_CC);
461 }
462
463 void soap_decode_string(zval *ret, char* str TSRMLS_DC)
464 {
465 if (UG(unicode)) {
466 /* TODO: unicode support */
467 ZVAL_STRING(ret, str, 1);
468 zval_string_to_unicode_ex(ret, UG(utf8_conv) TSRMLS_CC);
469 } else if (SOAP_GLOBAL(encoding) != NULL) {
470 xmlBufferPtr in = xmlBufferCreateStatic(str, strlen(str));
471 xmlBufferPtr out = xmlBufferCreate();
472 int n = xmlCharEncOutFunc(SOAP_GLOBAL(encoding), out, in);
473
474 if (n >= 0) {
475 ZVAL_STRING(ret, (char*)xmlBufferContent(out), 1);
476 } else {
477 ZVAL_STRING(ret, str, 1);
478 }
479 xmlBufferFree(out);
480 xmlBufferFree(in);
481 } else {
482 ZVAL_STRING(ret, str, 1);
483 }
484 }
485
486 char* soap_encode_string_ex(zend_uchar type, zstr data, int len TSRMLS_DC)
487 {
488 char *str;
489 int new_len;
490
491 if (type == IS_UNICODE) {
492 str = soap_unicode_to_string(data.u, len TSRMLS_CC);
493 } else {
494 str = estrndup(data.s, len);
495 new_len = len;
496
497 if (SOAP_GLOBAL(encoding) != NULL) {
498 xmlBufferPtr in = xmlBufferCreateStatic(str, new_len);
499 xmlBufferPtr out = xmlBufferCreate();
500 int n = xmlCharEncInFunc(SOAP_GLOBAL(encoding), out, in);
501
502 if (n >= 0) {
503 efree(str);
504 str = estrdup((char*)xmlBufferContent(out));
505 }
506 xmlBufferFree(out);
507 xmlBufferFree(in);
508 }
509 if (!php_libxml_xmlCheckUTF8(BAD_CAST(str))) {
510 char *err = emalloc(new_len + 8);
511 char c;
512 int i;
513
514 memcpy(err, str, new_len+1);
515 for (i = 0; (c = err[i++]);) {
516 if ((c & 0x80) == 0) {
517 } else if ((c & 0xe0) == 0xc0) {
518 if ((err[i] & 0xc0) != 0x80) {
519 break;
520 }
521 i++;
522 } else if ((c & 0xf0) == 0xe0) {
523 if ((err[i] & 0xc0) != 0x80 || (err[i+1] & 0xc0) != 0x80) {
524 break;
525 }
526 i += 2;
527 } else if ((c & 0xf8) == 0xf0) {
528 if ((err[i] & 0xc0) != 0x80 || (err[i+1] & 0xc0) != 0x80 || (err[i+2] & 0xc0) != 0x80) {
529 break;
530 }
531 i += 3;
532 } else {
533 break;
534 }
535 }
536 if (c) {
537 err[i-1] = '\\';
538 err[i++] = 'x';
539 err[i++] = ((unsigned char)c >> 4) + ((((unsigned char)c >> 4) > 9) ? ('a' - 10) : '');
540 err[i++] = (c & 15) + (((c & 15) > 9) ? ('a' - 10) : '');
541 err[i++] = '.';
542 err[i++] = '.';
543 err[i++] = '.';
544 err[i++] = 0;
545 }
546
547 soap_error1(E_ERROR, "Encoding: string '%s' is not a valid utf-8 string", err);
548 }
549 }
550 return str;
551 }
552
553 char* soap_encode_string(zval *data, int* len TSRMLS_DC)
554 {
555 char *str;
556 int new_len;
557
558 if (Z_TYPE_P(data) == IS_UNICODE) {
559 str = soap_unicode_to_string(Z_USTRVAL_P(data), Z_USTRLEN_P(data) TSRMLS_CC);
560 new_len = strlen(str);
561 } else {
562 if (Z_TYPE_P(data) == IS_STRING) {
563 str = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data));
564 new_len = Z_STRLEN_P(data);
565 } else {
566 zval tmp = *data;
567
568 zval_copy_ctor(&tmp);
569 convert_to_string(&tmp);
570 str = estrndup(Z_STRVAL(tmp), Z_STRLEN(tmp));
571 new_len = Z_STRLEN(tmp);
572 zval_dtor(&tmp);
573 }
574
575 if (SOAP_GLOBAL(encoding) != NULL) {
576 xmlBufferPtr in = xmlBufferCreateStatic(str, new_len);
577 xmlBufferPtr out = xmlBufferCreate();
578 int n = xmlCharEncInFunc(SOAP_GLOBAL(encoding), out, in);
579
580 if (n >= 0) {
581 efree(str);
582 str = estrdup((char*)xmlBufferContent(out));
583 new_len = n;
584 }
585 xmlBufferFree(out);
586 xmlBufferFree(in);
587 }
588 if (!php_libxml_xmlCheckUTF8(BAD_CAST(str))) {
589 char *err = emalloc(new_len + 8);
590 char c;
591 int i;
592
593 memcpy(err, str, new_len+1);
594 for (i = 0; (c = err[i++]);) {
595 if ((c & 0x80) == 0) {
596 } else if ((c & 0xe0) == 0xc0) {
597 if ((err[i] & 0xc0) != 0x80) {
598 break;
599 }
600 i++;
601 } else if ((c & 0xf0) == 0xe0) {
602 if ((err[i] & 0xc0) != 0x80 || (err[i+1] & 0xc0) != 0x80) {
603 break;
604 }
605 i += 2;
606 } else if ((c & 0xf8) == 0xf0) {
607 if ((err[i] & 0xc0) != 0x80 || (err[i+1] & 0xc0) != 0x80 || (err[i+2] & 0xc0) != 0x80) {
608 break;
609 }
610 i += 3;
611 } else {
612 break;
613 }
614 }
615 if (c) {
616 err[i-1] = '\\';
617 err[i++] = 'x';
618 err[i++] = ((unsigned char)c >> 4) + ((((unsigned char)c >> 4) > 9) ? ('a' - 10) : '');
619 err[i++] = (c & 15) + (((c & 15) > 9) ? ('a' - 10) : '');
620 err[i++] = '.';
621 err[i++] = '.';
622 err[i++] = '.';
623 err[i++] = 0;
624 }
625
626 soap_error1(E_ERROR, "Encoding: string '%s' is not a valid utf-8 string", err);
627 }
628 }
629 if (len) {
630 *len = new_len;
631 }
632 return str;
633 }
634
635 ZEND_INI_MH(OnUpdateCacheEnabled)
636 {
637 if (OnUpdateBool(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC) == FAILURE) {
638 return FAILURE;
639 }
640 if (SOAP_GLOBAL(cache_enabled)) {
641 SOAP_GLOBAL(cache) = SOAP_GLOBAL(cache_mode);
642 } else {
643 SOAP_GLOBAL(cache) = 0;
644 }
645 return SUCCESS;
646 }
647
648 ZEND_INI_MH(OnUpdateCacheMode)
649 {
650 char *p;
651 #ifndef ZTS
652 char *base = (char *) mh_arg2;
653 #else
654 char *base = (char *) ts_resource(*((int *) mh_arg2));
655 #endif
656
657 p = (char*) (base+(size_t) mh_arg1);
658
659 *p = (char)atoi(new_value);
660
661 if (SOAP_GLOBAL(cache_enabled)) {
662 SOAP_GLOBAL(cache) = SOAP_GLOBAL(cache_mode);
663 } else {
664 SOAP_GLOBAL(cache) = 0;
665 }
666 return SUCCESS;
667 }
668
669 PHP_INI_BEGIN()
670 STD_PHP_INI_ENTRY("soap.wsdl_cache_enabled", "1", PHP_INI_ALL, OnUpdateCacheEnabled,
671 cache_enabled, zend_soap_globals, soap_globals)
672 STD_PHP_INI_ENTRY("soap.wsdl_cache_dir", "/tmp", PHP_INI_ALL, OnUpdateString,
673 cache_dir, zend_soap_globals, soap_globals)
674 STD_PHP_INI_ENTRY("soap.wsdl_cache_ttl", "86400", PHP_INI_ALL, OnUpdateLong,
675 cache_ttl, zend_soap_globals, soap_globals)
676 STD_PHP_INI_ENTRY("soap.wsdl_cache", "1", PHP_INI_ALL, OnUpdateCacheMode,
677 cache_mode, zend_soap_globals, soap_globals)
678 STD_PHP_INI_ENTRY("soap.wsdl_cache_limit", "5", PHP_INI_ALL, OnUpdateLong,
679 cache_limit, zend_soap_globals, soap_globals)
680 PHP_INI_END()
681
682 static HashTable defEnc, defEncIndex, defEncNs;
683
684 static void php_soap_prepare_globals()
685 {
686 int i;
687 encodePtr enc;
688
689 zend_hash_init(&defEnc, 0, NULL, NULL, 1);
690 zend_hash_init(&defEncIndex, 0, NULL, NULL, 1);
691 zend_hash_init(&defEncNs, 0, NULL, NULL, 1);
692
693 i = 0;
694 do {
695 enc = &defaultEncoding[i];
696
697 /* If has a ns and a str_type then index it */
698 if (defaultEncoding[i].details.type_str) {
699 if (defaultEncoding[i].details.ns != NULL) {
700 char *ns_type;
701 spprintf(&ns_type, 0, "%s:%s", defaultEncoding[i].details.ns, defaultEncoding[i].details.type_str);
702 zend_hash_add(&defEnc, ns_type, strlen(ns_type) + 1, &enc, sizeof(encodePtr), NULL);
703 efree(ns_type);
704 } else {
705 zend_hash_add(&defEnc, defaultEncoding[i].details.type_str, strlen(defaultEncoding[i].details.type_str) + 1, &enc, sizeof(encodePtr), NULL);
706 }
707 }
708 /* Index everything by number */
709 if (!zend_hash_index_exists(&defEncIndex, defaultEncoding[i].details.type)) {
710 zend_hash_index_update(&defEncIndex, defaultEncoding[i].details.type, &enc, sizeof(encodePtr), NULL);
711 }
712 i++;
713 } while (defaultEncoding[i].details.type != END_KNOWN_TYPES);
714
715 /* hash by namespace */
716 zend_hash_add(&defEncNs, XSD_1999_NAMESPACE, sizeof(XSD_1999_NAMESPACE), XSD_NS_PREFIX, sizeof(XSD_NS_PREFIX), NULL);
717 zend_hash_add(&defEncNs, XSD_NAMESPACE, sizeof(XSD_NAMESPACE), XSD_NS_PREFIX, sizeof(XSD_NS_PREFIX), NULL);
718 zend_hash_add(&defEncNs, XSI_NAMESPACE, sizeof(XSI_NAMESPACE), XSI_NS_PREFIX, sizeof(XSI_NS_PREFIX), NULL);
719 zend_hash_add(&defEncNs, XML_NAMESPACE, sizeof(XML_NAMESPACE), XML_NS_PREFIX, sizeof(XML_NS_PREFIX), NULL);
720 zend_hash_add(&defEncNs, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE), SOAP_1_1_ENC_NS_PREFIX, sizeof(SOAP_1_1_ENC_NS_PREFIX), NULL);
721 zend_hash_add(&defEncNs, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE), SOAP_1_2_ENC_NS_PREFIX, sizeof(SOAP_1_2_ENC_NS_PREFIX), NULL);
722 }
723
724 static void php_soap_init_globals(zend_soap_globals *soap_globals TSRMLS_DC)
725 {
726 soap_globals->defEnc = defEnc;
727 soap_globals->defEncIndex = defEncIndex;
728 soap_globals->defEncNs = defEncNs;
729 soap_globals->typemap = NULL;
730 soap_globals->use_soap_error_handler = 0;
731 soap_globals->error_code = NULL;
732 soap_globals->error_object = NULL;
733 soap_globals->sdl = NULL;
734 soap_globals->soap_version = SOAP_1_1;
735 soap_globals->mem_cache = NULL;
736 soap_globals->ref_map = NULL;
737 }
738
739 PHP_MSHUTDOWN_FUNCTION(soap)
740 {
741 zend_error_cb = old_error_handler;
742 zend_hash_destroy(&SOAP_GLOBAL(defEnc));
743 zend_hash_destroy(&SOAP_GLOBAL(defEncIndex));
744 zend_hash_destroy(&SOAP_GLOBAL(defEncNs));
745 if (SOAP_GLOBAL(mem_cache)) {
746 zend_hash_destroy(SOAP_GLOBAL(mem_cache));
747 free(SOAP_GLOBAL(mem_cache));
748 }
749 UNREGISTER_INI_ENTRIES();
750 return SUCCESS;
751 }
752
753 PHP_RINIT_FUNCTION(soap)
754 {
755 SOAP_GLOBAL(typemap) = NULL;
756 SOAP_GLOBAL(use_soap_error_handler) = 0;
757 SOAP_GLOBAL(error_code) = NULL;
758 SOAP_GLOBAL(error_object) = NULL;
759 SOAP_GLOBAL(sdl) = NULL;
760 SOAP_GLOBAL(soap_version) = SOAP_1_1;
761 SOAP_GLOBAL(encoding) = NULL;
762 SOAP_GLOBAL(class_map) = NULL;
763 SOAP_GLOBAL(features) = 0;
764 SOAP_GLOBAL(ref_map) = NULL;
765 return SUCCESS;
766 }
767
768 static void soap_server_dtor(void *object, zend_object_handle handle TSRMLS_DC)
769 {
770 soap_server_object *service = (soap_server_object*)object;
771
772 if (service->soap_functions.ft) {
773 zend_hash_destroy(service->soap_functions.ft);
774 efree(service->soap_functions.ft);
775 }
776
777 if (service->typemap) {
778 zend_hash_destroy(service->typemap);
779 efree(service->typemap);
780 }
781
782 if (service->soap_class.argc) {
783 int i;
784 for (i = 0; i < service->soap_class.argc;i++) {
785 zval_ptr_dtor(&service->soap_class.argv[i]);
786 }
787 efree(service->soap_class.argv);
788 }
789
790 if (service->actor) {
791 efree(service->actor);
792 }
793 if (service->uri) {
794 efree(service->uri);
795 }
796 if (service->sdl) {
797 delete_sdl(service->sdl);
798 }
799 if (service->encoding) {
800 xmlCharEncCloseFunc(service->encoding);
801 }
802 if (service->class_map) {
803 zend_hash_destroy(service->class_map);
804 FREE_HASHTABLE(service->class_map);
805 }
806 if (service->soap_object) {
807 zval_ptr_dtor(&service->soap_object);
808 }
809 zend_object_std_dtor(object TSRMLS_CC);
810 efree(object);
811 }
812
813 static zend_object_value soap_server_ctor(zend_class_entry *ce TSRMLS_DC)
814 {
815 zend_object_value new_value;
816 soap_server_object *obj = (soap_server_object*)emalloc(sizeof(soap_server_object));
817
818 memset(obj, 0, sizeof(soap_server_object));
819
820 zend_object_std_init(&obj->zo, ce TSRMLS_CC);
821
822 obj->sdl = NULL;
823 obj->uri = NULL;
824 obj->typemap = NULL;
825 obj->version = SOAP_1_1;
826 obj->class_map = NULL;
827 obj->features = 0;
828 obj->encoding = NULL;
829
830 obj->soap_functions.ft = NULL;
831 obj->soap_functions.functions_all = 1;
832
833 obj->soap_class.ce = NULL;
834 obj->soap_class.argv = NULL;
835 obj->soap_class.argc = 0;
836 obj->soap_class.persistance = SOAP_PERSISTENCE_REQUEST;
837
838 obj->type = SOAP_MAP_FUNCTION;
839 obj->actor = NULL;
840 obj->soap_headers_ptr = NULL;
841
842 new_value.handle = zend_objects_store_put(obj, soap_server_dtor, NULL, NULL TSRMLS_CC);
843 new_value.handlers = zend_get_std_object_handlers();
844
845 return new_value;
846 }
847
848 static void soap_client_dtor(void *object, zend_object_handle handle TSRMLS_DC)
849 {
850 soap_client_object *client = (soap_client_object*)object;
851
852 if (client->typemap) {
853 zend_hash_destroy(client->typemap);
854 efree(client->typemap);
855 }
856 if (client->uri) {
857 efree(client->uri);
858 }
859 if (client->sdl) {
860 delete_sdl(client->sdl);
861 }
862 if (client->encoding) {
863 xmlCharEncCloseFunc(client->encoding);
864 }
865 if (client->class_map) {
866 zend_hash_destroy(client->class_map);
867 FREE_HASHTABLE(client->class_map);
868 }
869 if (client->location) {
870 efree(client->location);
871 }
872 if (client->login) {
873 efree(client->login);
874 }
875 if (client->password) {
876 efree(client->password);
877 }
878 if (client->digest_realm) {
879 efree(client->digest_realm);
880 }
881 if (client->digest_algorithm) {
882 efree(client->digest_algorithm);
883