php-src/ext/soap/soap.c
Peter Kokot 92ac598aab Remove local variables
This patch removes the so called local variables defined per
file basis for certain editors to properly show tab width, and
similar settings. These are mainly used by Vim and Emacs editors
yet with recent changes the once working definitions don't work
anymore in Vim without custom plugins or additional configuration.
Neither are these settings synced across the PHP code base.

A simpler and better approach is EditorConfig and fixing code
using some code style fixing tools in the future instead.

This patch also removes the so called modelines for Vim. Modelines
allow Vim editor specifically to set some editor configuration such as
syntax highlighting, indentation style and tab width to be set in the
first line or the last 5 lines per file basis. Since the php test
files have syntax highlighting already set in most editors properly and
EditorConfig takes care of the indentation settings, this patch removes
these as well for the Vim 6.0 and newer versions.

With the removal of local variables for certain editors such as
Emacs and Vim, the footer is also probably not needed anymore when
creating extensions using ext_skel.php script.

Additionally, Vim modelines for setting php syntax and some editor
settings has been removed from some *.phpt files.  All these are
mostly not relevant for phpt files neither work properly in the
middle of the file.
2019-02-03 21:03:00 +01:00

4866 lines
157 KiB
C

/*
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Brad Lafountain <rodif_bl@yahoo.com> |
| Shane Caraveo <shane@caraveo.com> |
| Dmitry Stogov <dmitry@php.net> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_soap.h"
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
#include "ext/session/php_session.h"
#endif
#include "zend_exceptions.h"
static int le_sdl = 0;
int le_url = 0;
static int le_service = 0;
static int le_typemap = 0;
typedef struct _soapHeader {
sdlFunctionPtr function;
zval function_name;
int mustUnderstand;
int num_params;
zval *parameters;
zval retval;
sdlSoapBindingFunctionHeaderPtr hdr;
struct _soapHeader *next;
} soapHeader;
/* Local functions */
static void function_to_string(sdlFunctionPtr function, smart_str *buf);
static void type_to_string(sdlTypePtr type, smart_str *buf, int level);
static void clear_soap_fault(zval *obj);
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);
static void add_soap_fault_ex(zval *fault, zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail);
static void soap_server_fault(char* code, char* string, char *actor, zval* details, char *name);
static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader* hdr);
static sdlParamPtr get_param(sdlFunctionPtr function, char *param_name, int index, int);
static sdlFunctionPtr get_function(sdlPtr sdl, const char *function_name);
static sdlFunctionPtr get_doc_function(sdlPtr sdl, xmlNodePtr node);
static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, char* actor, zval *function_name, int *num_params, zval **parameters, int *version, soapHeader **headers);
static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function_name,char *uri,zval *ret, soapHeader *headers, int version);
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);
static xmlNodePtr serialize_parameter(sdlParamPtr param,zval *param_val,int index,char *name, int style, xmlNodePtr parent);
static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName, int style, xmlNodePtr parent);
static void delete_service(void *service);
static void delete_url(void *handle);
static void delete_hashtable(void *hashtable);
static void soap_error_handler(int error_num, const char *error_filename, const uint32_t error_lineno, const char *format, va_list args);
#define SOAP_SERVER_BEGIN_CODE() \
zend_bool _old_handler = SOAP_GLOBAL(use_soap_error_handler);\
char* _old_error_code = SOAP_GLOBAL(error_code);\
zend_object* _old_error_object = Z_OBJ(SOAP_GLOBAL(error_object));\
int _old_soap_version = SOAP_GLOBAL(soap_version);\
SOAP_GLOBAL(use_soap_error_handler) = 1;\
SOAP_GLOBAL(error_code) = "Server";\
Z_OBJ(SOAP_GLOBAL(error_object)) = Z_OBJ_P(ZEND_THIS);
#define SOAP_SERVER_END_CODE() \
SOAP_GLOBAL(use_soap_error_handler) = _old_handler;\
SOAP_GLOBAL(error_code) = _old_error_code;\
Z_OBJ(SOAP_GLOBAL(error_object)) = _old_error_object;\
SOAP_GLOBAL(soap_version) = _old_soap_version;
#define SOAP_CLIENT_BEGIN_CODE() \
zend_bool _old_handler = SOAP_GLOBAL(use_soap_error_handler);\
char* _old_error_code = SOAP_GLOBAL(error_code);\
zend_object* _old_error_object = Z_OBJ(SOAP_GLOBAL(error_object));\
int _old_soap_version = SOAP_GLOBAL(soap_version);\
zend_bool _old_in_compilation = CG(in_compilation); \
zend_execute_data *_old_current_execute_data = EG(current_execute_data); \
zval *_old_stack_top = EG(vm_stack_top); \
int _bailout = 0;\
SOAP_GLOBAL(use_soap_error_handler) = 1;\
SOAP_GLOBAL(error_code) = "Client";\
Z_OBJ(SOAP_GLOBAL(error_object)) = Z_OBJ_P(ZEND_THIS);\
zend_try {
#define SOAP_CLIENT_END_CODE() \
} zend_catch {\
CG(in_compilation) = _old_in_compilation; \
EG(current_execute_data) = _old_current_execute_data; \
if (EG(exception) == NULL || \
!instanceof_function(EG(exception)->ce, soap_fault_class_entry)) {\
_bailout = 1;\
}\
if (_old_stack_top != EG(vm_stack_top)) { \
while (EG(vm_stack)->prev != NULL && \
((char*)_old_stack_top < (char*)EG(vm_stack) || \
(char*) _old_stack_top > (char*)EG(vm_stack)->end)) { \
zend_vm_stack tmp = EG(vm_stack)->prev; \
efree(EG(vm_stack)); \
EG(vm_stack) = tmp; \
EG(vm_stack_end) = tmp->end; \
} \
EG(vm_stack)->top = _old_stack_top; \
} \
} zend_end_try();\
SOAP_GLOBAL(use_soap_error_handler) = _old_handler;\
SOAP_GLOBAL(error_code) = _old_error_code;\
Z_OBJ(SOAP_GLOBAL(error_object)) = _old_error_object;\
SOAP_GLOBAL(soap_version) = _old_soap_version;\
if (_bailout) {\
zend_bailout();\
}
#define FETCH_THIS_SDL(ss) \
{ \
zval *__tmp; \
if(FIND_SDL_PROPERTY(ZEND_THIS, __tmp) != NULL) { \
FETCH_SDL_RES(ss,__tmp); \
} else { \
ss = NULL; \
} \
}
#define FIND_SDL_PROPERTY(ss,tmp) (tmp = zend_hash_str_find(Z_OBJPROP_P(ss), "sdl", sizeof("sdl")-1))
#define FETCH_SDL_RES(ss,tmp) ss = (sdlPtr) zend_fetch_resource_ex(tmp, "sdl", le_sdl)
#define FIND_TYPEMAP_PROPERTY(ss,tmp) (tmp = zend_hash_str_find(Z_OBJPROP_P(ss), "typemap", sizeof("typemap")-1))
#define FETCH_TYPEMAP_RES(ss,tmp) ss = (HashTable*) zend_fetch_resource_ex(tmp, "typemap", le_typemap)
#define FETCH_THIS_SERVICE(ss) \
{ \
zval *tmp; \
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(ZEND_THIS),"service", sizeof("service")-1)) != NULL) { \
ss = (soapServicePtr)zend_fetch_resource_ex(tmp, "service", le_service); \
} else { \
php_error_docref(NULL, E_WARNING, "Can not fetch service object"); \
SOAP_SERVER_END_CODE(); \
return; \
} \
}
static zend_class_entry* soap_class_entry;
static zend_class_entry* soap_server_class_entry;
static zend_class_entry* soap_fault_class_entry;
static zend_class_entry* soap_header_class_entry;
static zend_class_entry* soap_param_class_entry;
zend_class_entry* soap_var_class_entry;
ZEND_DECLARE_MODULE_GLOBALS(soap)
static void (*old_error_handler)(int, const char *, const uint32_t, const char*, va_list);
#define call_old_error_handler(error_num, error_filename, error_lineno, format, args) \
{ \
va_list copy; \
va_copy(copy, args); \
old_error_handler(error_num, error_filename, error_lineno, format, copy); \
va_end(copy); \
}
#define PHP_SOAP_SERVER_CLASSNAME "SoapServer"
#define PHP_SOAP_CLIENT_CLASSNAME "SoapClient"
#define PHP_SOAP_VAR_CLASSNAME "SoapVar"
#define PHP_SOAP_FAULT_CLASSNAME "SoapFault"
#define PHP_SOAP_PARAM_CLASSNAME "SoapParam"
#define PHP_SOAP_HEADER_CLASSNAME "SoapHeader"
PHP_RINIT_FUNCTION(soap);
PHP_MINIT_FUNCTION(soap);
PHP_MSHUTDOWN_FUNCTION(soap);
PHP_MINFO_FUNCTION(soap);
/*
Registry Functions
TODO: this!
*/
PHP_FUNCTION(soap_encode_to_xml);
PHP_FUNCTION(soap_encode_to_zval);
PHP_FUNCTION(use_soap_error_handler);
PHP_FUNCTION(is_soap_fault);
/* Server Functions */
PHP_METHOD(SoapServer, SoapServer);
PHP_METHOD(SoapServer, setClass);
PHP_METHOD(SoapServer, setObject);
PHP_METHOD(SoapServer, addFunction);
PHP_METHOD(SoapServer, getFunctions);
PHP_METHOD(SoapServer, handle);
PHP_METHOD(SoapServer, setPersistence);
PHP_METHOD(SoapServer, fault);
PHP_METHOD(SoapServer, addSoapHeader);
/* Client Functions */
PHP_METHOD(SoapClient, SoapClient);
PHP_METHOD(SoapClient, __call);
PHP_METHOD(SoapClient, __getLastRequest);
PHP_METHOD(SoapClient, __getLastResponse);
PHP_METHOD(SoapClient, __getLastRequestHeaders);
PHP_METHOD(SoapClient, __getLastResponseHeaders);
PHP_METHOD(SoapClient, __getFunctions);
PHP_METHOD(SoapClient, __getTypes);
PHP_METHOD(SoapClient, __doRequest);
PHP_METHOD(SoapClient, __setCookie);
PHP_METHOD(SoapClient, __getCookies);
PHP_METHOD(SoapClient, __setLocation);
PHP_METHOD(SoapClient, __setSoapHeaders);
/* SoapVar Functions */
PHP_METHOD(SoapVar, SoapVar);
/* SoapFault Functions */
PHP_METHOD(SoapFault, SoapFault);
PHP_METHOD(SoapFault, __toString);
/* SoapParam Functions */
PHP_METHOD(SoapParam, SoapParam);
/* SoapHeader Functions */
PHP_METHOD(SoapHeader, SoapHeader);
#define SOAP_CTOR(class_name, func_name, arginfo, flags) PHP_ME(class_name, func_name, arginfo, flags)
/* {{{ arginfo */
ZEND_BEGIN_ARG_INFO(arginfo_soap__void, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapparam_soapparam, 0, 0, 2)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapheader_soapheader, 0, 0, 2)
ZEND_ARG_INFO(0, namespace)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(0, mustunderstand)
ZEND_ARG_INFO(0, actor)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapfault_soapfault, 0, 0, 2)
ZEND_ARG_INFO(0, faultcode)
ZEND_ARG_INFO(0, faultstring)
ZEND_ARG_INFO(0, faultactor)
ZEND_ARG_INFO(0, detail)
ZEND_ARG_INFO(0, faultname)
ZEND_ARG_INFO(0, headerfault)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapvar_soapvar, 0, 0, 2)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(0, encoding)
ZEND_ARG_INFO(0, type_name)
ZEND_ARG_INFO(0, type_namespace)
ZEND_ARG_INFO(0, node_name)
ZEND_ARG_INFO(0, node_namespace)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_fault, 0, 0, 2)
ZEND_ARG_INFO(0, code)
ZEND_ARG_INFO(0, string)
ZEND_ARG_INFO(0, actor)
ZEND_ARG_INFO(0, details)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_addsoapheader, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_soapserver, 0, 0, 1)
ZEND_ARG_INFO(0, wsdl)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_setpersistence, 0, 0, 1)
ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_setclass, 0, 0, 1)
ZEND_ARG_INFO(0, class_name)
ZEND_ARG_VARIADIC_INFO(0, args)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_setobject, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_soapserver_getfunctions, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_addfunction, 0, 0, 1)
ZEND_ARG_INFO(0, functions)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapserver_handle, 0, 0, 0)
ZEND_ARG_INFO(0, soap_request)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient_soapclient, 0, 0, 1)
ZEND_ARG_INFO(0, wsdl)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___call, 0, 0, 2)
ZEND_ARG_INFO(0, function_name)
ZEND_ARG_INFO(0, arguments)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___soapcall, 0, 0, 2)
ZEND_ARG_INFO(0, function_name)
ZEND_ARG_INFO(0, arguments)
ZEND_ARG_INFO(0, options)
ZEND_ARG_INFO(0, input_headers)
ZEND_ARG_INFO(1, output_headers)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getfunctions, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_soapclient___gettypes, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastrequest, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastresponse, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastrequestheaders, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getlastresponseheaders, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___dorequest, 0, 0, 4)
ZEND_ARG_INFO(0, request)
ZEND_ARG_INFO(0, location)
ZEND_ARG_INFO(0, action)
ZEND_ARG_INFO(0, version)
ZEND_ARG_INFO(0, one_way)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___setcookie, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_soapclient___getcookies, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___setsoapheaders, 0, 0, 0)
ZEND_ARG_INFO(0, soapheaders)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soapclient___setlocation, 0, 0, 0)
ZEND_ARG_INFO(0, new_location)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soap_use_soap_error_handler, 0, 0, 0)
ZEND_ARG_INFO(0, handler)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_soap_is_soap_fault, 0, 0, 1)
ZEND_ARG_INFO(0, object)
ZEND_END_ARG_INFO()
/* }}} */
static const zend_function_entry soap_functions[] = {
PHP_FE(use_soap_error_handler, arginfo_soap_use_soap_error_handler)
PHP_FE(is_soap_fault, arginfo_soap_is_soap_fault)
PHP_FE_END
};
static const zend_function_entry soap_fault_functions[] = {
SOAP_CTOR(SoapFault, SoapFault, arginfo_soapfault_soapfault, 0)
PHP_ME(SoapFault, __toString, arginfo_soap__void, 0)
PHP_FE_END
};
static const zend_function_entry soap_server_functions[] = {
SOAP_CTOR(SoapServer, SoapServer, arginfo_soapserver_soapserver, 0)
PHP_ME(SoapServer, setPersistence, arginfo_soapserver_setpersistence, 0)
PHP_ME(SoapServer, setClass, arginfo_soapserver_setclass, 0)
PHP_ME(SoapServer, setObject, arginfo_soapserver_setobject, 0)
PHP_ME(SoapServer, addFunction, arginfo_soapserver_addfunction, 0)
PHP_ME(SoapServer, getFunctions, arginfo_soapserver_getfunctions, 0)
PHP_ME(SoapServer, handle, arginfo_soapserver_handle, 0)
PHP_ME(SoapServer, fault, arginfo_soapserver_fault, 0)
PHP_ME(SoapServer, addSoapHeader, arginfo_soapserver_addsoapheader, 0)
PHP_FE_END
};
static const zend_function_entry soap_client_functions[] = {
SOAP_CTOR(SoapClient, SoapClient, arginfo_soapclient_soapclient, 0)
PHP_ME(SoapClient, __call, arginfo_soapclient___call, 0)
ZEND_NAMED_ME(__soapCall, ZEND_MN(SoapClient___call), arginfo_soapclient___soapcall, 0)
PHP_ME(SoapClient, __getLastRequest, arginfo_soapclient___getlastrequest, 0)
PHP_ME(SoapClient, __getLastResponse, arginfo_soapclient___getlastresponse, 0)
PHP_ME(SoapClient, __getLastRequestHeaders, arginfo_soapclient___getlastrequestheaders, 0)
PHP_ME(SoapClient, __getLastResponseHeaders, arginfo_soapclient___getlastresponseheaders, 0)
PHP_ME(SoapClient, __getFunctions, arginfo_soapclient___getfunctions, 0)
PHP_ME(SoapClient, __getTypes, arginfo_soapclient___gettypes, 0)
PHP_ME(SoapClient, __doRequest, arginfo_soapclient___dorequest, 0)
PHP_ME(SoapClient, __setCookie, arginfo_soapclient___setcookie, 0)
PHP_ME(SoapClient, __getCookies, arginfo_soapclient___getcookies, 0)
PHP_ME(SoapClient, __setLocation, arginfo_soapclient___setlocation, 0)
PHP_ME(SoapClient, __setSoapHeaders, arginfo_soapclient___setsoapheaders, 0)
PHP_FE_END
};
static const zend_function_entry soap_var_functions[] = {
SOAP_CTOR(SoapVar, SoapVar, arginfo_soapvar_soapvar, 0)
PHP_FE_END
};
static const zend_function_entry soap_param_functions[] = {
SOAP_CTOR(SoapParam, SoapParam, arginfo_soapparam_soapparam, 0)
PHP_FE_END
};
static const zend_function_entry soap_header_functions[] = {
SOAP_CTOR(SoapHeader, SoapHeader, arginfo_soapheader_soapheader, 0)
PHP_FE_END
};
zend_module_entry soap_module_entry = {
#ifdef STANDARD_MODULE_HEADER
STANDARD_MODULE_HEADER,
#endif
"soap",
soap_functions,
PHP_MINIT(soap),
PHP_MSHUTDOWN(soap),
PHP_RINIT(soap),
NULL,
PHP_MINFO(soap),
#ifdef STANDARD_MODULE_HEADER
PHP_SOAP_VERSION,
#endif
STANDARD_MODULE_PROPERTIES,
};
#ifdef COMPILE_DL_SOAP
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
ZEND_GET_MODULE(soap)
#endif
ZEND_INI_MH(OnUpdateCacheMode)
{
char *p;
#ifndef ZTS
char *base = (char *) mh_arg2;
#else
char *base = (char *) ts_resource(*((int *) mh_arg2));
#endif
p = (char*) (base+(size_t) mh_arg1);
*p = (char)atoi(ZSTR_VAL(new_value));
return SUCCESS;
}
static PHP_INI_MH(OnUpdateCacheDir)
{
/* Only do the open_basedir check at runtime */
if (stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) {
char *p;
if (memchr(ZSTR_VAL(new_value), '\0', ZSTR_LEN(new_value)) != NULL) {
return FAILURE;
}
/* we do not use zend_memrchr() since path can contain ; itself */
if ((p = strchr(ZSTR_VAL(new_value), ';'))) {
char *p2;
p++;
if ((p2 = strchr(p, ';'))) {
p = p2 + 1;
}
} else {
p = ZSTR_VAL(new_value);
}
if (PG(open_basedir) && *p && php_check_open_basedir(p)) {
return FAILURE;
}
}
OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
return SUCCESS;
}
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("soap.wsdl_cache_enabled", "1", PHP_INI_ALL, OnUpdateBool,
cache_enabled, zend_soap_globals, soap_globals)
STD_PHP_INI_ENTRY("soap.wsdl_cache_dir", "/tmp", PHP_INI_ALL, OnUpdateCacheDir,
cache_dir, zend_soap_globals, soap_globals)
STD_PHP_INI_ENTRY("soap.wsdl_cache_ttl", "86400", PHP_INI_ALL, OnUpdateLong,
cache_ttl, zend_soap_globals, soap_globals)
STD_PHP_INI_ENTRY("soap.wsdl_cache", "1", PHP_INI_ALL, OnUpdateCacheMode,
cache_mode, zend_soap_globals, soap_globals)
STD_PHP_INI_ENTRY("soap.wsdl_cache_limit", "5", PHP_INI_ALL, OnUpdateLong,
cache_limit, zend_soap_globals, soap_globals)
PHP_INI_END()
static HashTable defEnc, defEncIndex, defEncNs;
static void php_soap_prepare_globals()
{
int i;
const encode* enc;
zend_hash_init(&defEnc, 0, NULL, NULL, 1);
zend_hash_init(&defEncIndex, 0, NULL, NULL, 1);
zend_hash_init(&defEncNs, 0, NULL, NULL, 1);
i = 0;
do {
enc = &defaultEncoding[i];
/* If has a ns and a str_type then index it */
if (defaultEncoding[i].details.type_str) {
if (defaultEncoding[i].details.ns != NULL) {
char *ns_type;
spprintf(&ns_type, 0, "%s:%s", defaultEncoding[i].details.ns, defaultEncoding[i].details.type_str);
zend_hash_str_add_ptr(&defEnc, ns_type, strlen(ns_type), (void*)enc);
efree(ns_type);
} else {
zend_hash_str_add_ptr(&defEnc, defaultEncoding[i].details.type_str, strlen(defaultEncoding[i].details.type_str), (void*)enc);
}
}
/* Index everything by number */
zend_hash_index_add_ptr(&defEncIndex, defaultEncoding[i].details.type, (void*)enc);
i++;
} while (defaultEncoding[i].details.type != END_KNOWN_TYPES);
/* hash by namespace */
zend_hash_str_add_ptr(&defEncNs, XSD_1999_NAMESPACE, sizeof(XSD_1999_NAMESPACE)-1, XSD_NS_PREFIX);
zend_hash_str_add_ptr(&defEncNs, XSD_NAMESPACE, sizeof(XSD_NAMESPACE)-1, XSD_NS_PREFIX);
zend_hash_str_add_ptr(&defEncNs, XSI_NAMESPACE, sizeof(XSI_NAMESPACE)-1, XSI_NS_PREFIX);
zend_hash_str_add_ptr(&defEncNs, XML_NAMESPACE, sizeof(XML_NAMESPACE)-1, XML_NS_PREFIX);
zend_hash_str_add_ptr(&defEncNs, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)-1, SOAP_1_1_ENC_NS_PREFIX);
zend_hash_str_add_ptr(&defEncNs, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)-1, SOAP_1_2_ENC_NS_PREFIX);
}
static void php_soap_init_globals(zend_soap_globals *soap_globals)
{
#if defined(COMPILE_DL_SOAP) && defined(ZTS)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
soap_globals->defEnc = defEnc;
soap_globals->defEncIndex = defEncIndex;
soap_globals->defEncNs = defEncNs;
soap_globals->typemap = NULL;
soap_globals->use_soap_error_handler = 0;
soap_globals->error_code = NULL;
ZVAL_OBJ(&soap_globals->error_object, NULL);
soap_globals->sdl = NULL;
soap_globals->soap_version = SOAP_1_1;
soap_globals->mem_cache = NULL;
soap_globals->ref_map = NULL;
}
PHP_MSHUTDOWN_FUNCTION(soap)
{
zend_error_cb = old_error_handler;
zend_hash_destroy(&SOAP_GLOBAL(defEnc));
zend_hash_destroy(&SOAP_GLOBAL(defEncIndex));
zend_hash_destroy(&SOAP_GLOBAL(defEncNs));
if (SOAP_GLOBAL(mem_cache)) {
zend_hash_destroy(SOAP_GLOBAL(mem_cache));
free(SOAP_GLOBAL(mem_cache));
}
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
PHP_RINIT_FUNCTION(soap)
{
SOAP_GLOBAL(typemap) = NULL;
SOAP_GLOBAL(use_soap_error_handler) = 0;
SOAP_GLOBAL(error_code) = NULL;
ZVAL_OBJ(&SOAP_GLOBAL(error_object), NULL);
SOAP_GLOBAL(sdl) = NULL;
SOAP_GLOBAL(soap_version) = SOAP_1_1;
SOAP_GLOBAL(encoding) = NULL;
SOAP_GLOBAL(class_map) = NULL;
SOAP_GLOBAL(features) = 0;
SOAP_GLOBAL(ref_map) = NULL;
return SUCCESS;
}
static void delete_sdl_res(zend_resource *res)
{
delete_sdl(res->ptr);
}
static void delete_url_res(zend_resource *res)
{
delete_url(res->ptr);
}
static void delete_service_res(zend_resource *res)
{
delete_service(res->ptr);
}
static void delete_hashtable_res(zend_resource *res)
{
delete_hashtable(res->ptr);
}
PHP_MINIT_FUNCTION(soap)
{
zend_class_entry ce;
/* TODO: add ini entry for always use soap errors */
php_soap_prepare_globals();
ZEND_INIT_MODULE_GLOBALS(soap, php_soap_init_globals, NULL);
REGISTER_INI_ENTRIES();
/* Register SoapClient class */
/* BIG NOTE : THIS EMITS AN COMPILATION WARNING UNDER ZE2 - handle_function_call deprecated.
soap_call_function_handler should be of type zend_function, not (*handle_function_call).
*/
{
INIT_CLASS_ENTRY(ce, PHP_SOAP_CLIENT_CLASSNAME, soap_client_functions);
soap_class_entry = zend_register_internal_class(&ce);
}
/* Register SoapVar class */
INIT_CLASS_ENTRY(ce, PHP_SOAP_VAR_CLASSNAME, soap_var_functions);
soap_var_class_entry = zend_register_internal_class(&ce);
/* Register SoapServer class */
INIT_CLASS_ENTRY(ce, PHP_SOAP_SERVER_CLASSNAME, soap_server_functions);
soap_server_class_entry = zend_register_internal_class(&ce);
/* Register SoapFault class */
INIT_CLASS_ENTRY(ce, PHP_SOAP_FAULT_CLASSNAME, soap_fault_functions);
soap_fault_class_entry = zend_register_internal_class_ex(&ce, zend_ce_exception);
/* Register SoapParam class */
INIT_CLASS_ENTRY(ce, PHP_SOAP_PARAM_CLASSNAME, soap_param_functions);
soap_param_class_entry = zend_register_internal_class(&ce);
INIT_CLASS_ENTRY(ce, PHP_SOAP_HEADER_CLASSNAME, soap_header_functions);
soap_header_class_entry = zend_register_internal_class(&ce);
le_sdl = zend_register_list_destructors_ex(delete_sdl_res, NULL, "SOAP SDL", module_number);
le_url = zend_register_list_destructors_ex(delete_url_res, NULL, "SOAP URL", module_number);
le_service = zend_register_list_destructors_ex(delete_service_res, NULL, "SOAP service", module_number);
le_typemap = zend_register_list_destructors_ex(delete_hashtable_res, NULL, "SOAP table", module_number);
REGISTER_LONG_CONSTANT("SOAP_1_1", SOAP_1_1, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_1_2", SOAP_1_2, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_PERSISTENCE_SESSION", SOAP_PERSISTENCE_SESSION, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_PERSISTENCE_REQUEST", SOAP_PERSISTENCE_REQUEST, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_FUNCTIONS_ALL", SOAP_FUNCTIONS_ALL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_ENCODED", SOAP_ENCODED, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_LITERAL", SOAP_LITERAL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_RPC", SOAP_RPC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_DOCUMENT", SOAP_DOCUMENT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_ACTOR_NEXT", SOAP_ACTOR_NEXT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_ACTOR_NONE", SOAP_ACTOR_NONE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_ACTOR_UNLIMATERECEIVER", SOAP_ACTOR_UNLIMATERECEIVER, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_COMPRESSION_ACCEPT", SOAP_COMPRESSION_ACCEPT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_COMPRESSION_GZIP", SOAP_COMPRESSION_GZIP, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_COMPRESSION_DEFLATE", SOAP_COMPRESSION_DEFLATE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_AUTHENTICATION_BASIC", SOAP_AUTHENTICATION_BASIC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_AUTHENTICATION_DIGEST", SOAP_AUTHENTICATION_DIGEST, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("UNKNOWN_TYPE", UNKNOWN_TYPE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_STRING", XSD_STRING, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_BOOLEAN", XSD_BOOLEAN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_DECIMAL", XSD_DECIMAL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_FLOAT", XSD_FLOAT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_DOUBLE", XSD_DOUBLE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_DURATION", XSD_DURATION, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_DATETIME", XSD_DATETIME, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_TIME", XSD_TIME, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_DATE", XSD_DATE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_GYEARMONTH", XSD_GYEARMONTH, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_GYEAR", XSD_GYEAR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_GMONTHDAY", XSD_GMONTHDAY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_GDAY", XSD_GDAY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_GMONTH", XSD_GMONTH, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_HEXBINARY", XSD_HEXBINARY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_BASE64BINARY", XSD_BASE64BINARY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_ANYURI", XSD_ANYURI, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_QNAME", XSD_QNAME, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_NOTATION", XSD_NOTATION, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_NORMALIZEDSTRING", XSD_NORMALIZEDSTRING, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_TOKEN", XSD_TOKEN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_LANGUAGE", XSD_LANGUAGE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_NMTOKEN", XSD_NMTOKEN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_NAME", XSD_NAME, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_NCNAME", XSD_NCNAME, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_ID", XSD_ID, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_IDREF", XSD_IDREF, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_IDREFS", XSD_IDREFS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_ENTITY", XSD_ENTITY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_ENTITIES", XSD_ENTITIES, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_INTEGER", XSD_INTEGER, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_NONPOSITIVEINTEGER", XSD_NONPOSITIVEINTEGER, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_NEGATIVEINTEGER", XSD_NEGATIVEINTEGER, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_LONG", XSD_LONG, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_INT", XSD_INT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_SHORT", XSD_SHORT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_BYTE", XSD_BYTE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_NONNEGATIVEINTEGER", XSD_NONNEGATIVEINTEGER, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_UNSIGNEDLONG", XSD_UNSIGNEDLONG, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_UNSIGNEDINT", XSD_UNSIGNEDINT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_UNSIGNEDSHORT", XSD_UNSIGNEDSHORT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_UNSIGNEDBYTE", XSD_UNSIGNEDBYTE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_POSITIVEINTEGER", XSD_POSITIVEINTEGER, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_NMTOKENS", XSD_NMTOKENS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_ANYTYPE", XSD_ANYTYPE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_ANYXML", XSD_ANYXML, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("APACHE_MAP", APACHE_MAP, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_ENC_OBJECT", SOAP_ENC_OBJECT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_ENC_ARRAY", SOAP_ENC_ARRAY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XSD_1999_TIMEINSTANT", XSD_1999_TIMEINSTANT, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("XSD_NAMESPACE", XSD_NAMESPACE, CONST_CS | CONST_PERSISTENT);
REGISTER_STRING_CONSTANT("XSD_1999_NAMESPACE", XSD_1999_NAMESPACE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_SINGLE_ELEMENT_ARRAYS", SOAP_SINGLE_ELEMENT_ARRAYS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_WAIT_ONE_WAY_CALLS", SOAP_WAIT_ONE_WAY_CALLS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_USE_XSI_ARRAY_TYPE", SOAP_USE_XSI_ARRAY_TYPE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("WSDL_CACHE_NONE", WSDL_CACHE_NONE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("WSDL_CACHE_DISK", WSDL_CACHE_DISK, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("WSDL_CACHE_MEMORY", WSDL_CACHE_MEMORY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("WSDL_CACHE_BOTH", WSDL_CACHE_BOTH, CONST_CS | CONST_PERSISTENT);
/* New SOAP SSL Method Constants */
REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_TLS", SOAP_SSL_METHOD_TLS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv2", SOAP_SSL_METHOD_SSLv2, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv3", SOAP_SSL_METHOD_SSLv3, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOAP_SSL_METHOD_SSLv23", SOAP_SSL_METHOD_SSLv23, CONST_CS | CONST_PERSISTENT);
old_error_handler = zend_error_cb;
zend_error_cb = soap_error_handler;
return SUCCESS;
}
PHP_MINFO_FUNCTION(soap)
{
php_info_print_table_start();
php_info_print_table_row(2, "Soap Client", "enabled");
php_info_print_table_row(2, "Soap Server", "enabled");
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/* {{{ proto object SoapParam::SoapParam(mixed data, string name)
SoapParam constructor */
PHP_METHOD(SoapParam, SoapParam)
{
zval *data;
char *name;
size_t name_length;
zval *this_ptr;
if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zs", &data, &name, &name_length) == FAILURE) {
return;
}
if (name_length == 0) {
php_error_docref(NULL, E_WARNING, "Invalid parameter name");
return;
}
this_ptr = ZEND_THIS;
add_property_stringl(this_ptr, "param_name", name, name_length);
add_property_zval(this_ptr, "param_data", data);
}
/* }}} */
/* {{{ proto object SoapHeader::SoapHeader(string namespace, string name [, mixed data [, bool mustUnderstand [, mixed actor]]])
SoapHeader constructor */
PHP_METHOD(SoapHeader, SoapHeader)
{
zval *data = NULL, *actor = NULL;
char *name, *ns;
size_t name_len, ns_len;
zend_bool must_understand = 0;
zval *this_ptr;
if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ss|zbz", &ns, &ns_len, &name, &name_len, &data, &must_understand, &actor) == FAILURE) {
return;
}
if (ns_len == 0) {
php_error_docref(NULL, E_WARNING, "Invalid namespace");
return;
}
if (name_len == 0) {
php_error_docref(NULL, E_WARNING, "Invalid header name");
return;
}
this_ptr = ZEND_THIS;
add_property_stringl(this_ptr, "namespace", ns, ns_len);
add_property_stringl(this_ptr, "name", name, name_len);
if (data) {
add_property_zval(this_ptr, "data", data);
}
add_property_bool(this_ptr, "mustUnderstand", must_understand);
if (actor == NULL) {
} else if (Z_TYPE_P(actor) == IS_LONG &&
(Z_LVAL_P(actor) == SOAP_ACTOR_NEXT ||
Z_LVAL_P(actor) == SOAP_ACTOR_NONE ||
Z_LVAL_P(actor) == SOAP_ACTOR_UNLIMATERECEIVER)) {
add_property_long(this_ptr, "actor", Z_LVAL_P(actor));
} else if (Z_TYPE_P(actor) == IS_STRING && Z_STRLEN_P(actor) > 0) {
add_property_stringl(this_ptr, "actor", Z_STRVAL_P(actor), Z_STRLEN_P(actor));
} else {
php_error_docref(NULL, E_WARNING, "Invalid actor");
}
}
/* }}} */
/* {{{ proto object SoapFault::SoapFault(string faultcode, string faultstring [, string faultactor [, mixed detail [, string faultname [, mixed headerfault]]]])
SoapFault constructor */
PHP_METHOD(SoapFault, SoapFault)
{
char *fault_string = NULL, *fault_code = NULL, *fault_actor = NULL, *name = NULL, *fault_code_ns = NULL;
size_t fault_string_len, fault_actor_len = 0, name_len = 0, fault_code_len = 0;
zval *code = NULL, *details = NULL, *headerfault = NULL, *this_ptr;
if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zs|s!z!s!z",
&code,
&fault_string, &fault_string_len,
&fault_actor, &fault_actor_len,
&details, &name, &name_len, &headerfault) == FAILURE) {
return;
}
if (Z_TYPE_P(code) == IS_NULL) {
} else if (Z_TYPE_P(code) == IS_STRING) {
fault_code = Z_STRVAL_P(code);
fault_code_len = Z_STRLEN_P(code);
} else if (Z_TYPE_P(code) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(code)) == 2) {
zval *t_ns = zend_hash_index_find(Z_ARRVAL_P(code), 0);
zval *t_code = zend_hash_index_find(Z_ARRVAL_P(code), 1);
if (t_ns && t_code && Z_TYPE_P(t_ns) == IS_STRING && Z_TYPE_P(t_code) == IS_STRING) {
fault_code_ns = Z_STRVAL_P(t_ns);
fault_code = Z_STRVAL_P(t_code);
fault_code_len = Z_STRLEN_P(t_code);
} else {
php_error_docref(NULL, E_WARNING, "Invalid fault code");
return;
}
} else {
php_error_docref(NULL, E_WARNING, "Invalid fault code");
return;
}
if (fault_code != NULL && fault_code_len == 0) {
php_error_docref(NULL, E_WARNING, "Invalid fault code");
return;
}
if (name != NULL && name_len == 0) {
name = NULL;
}
this_ptr = ZEND_THIS;
set_soap_fault(this_ptr, fault_code_ns, fault_code, fault_string, fault_actor, details, name);
if (headerfault != NULL) {
add_property_zval(this_ptr, "headerfault", headerfault);
}
}
/* }}} */
/* {{{ proto object SoapFault::SoapFault(string faultcode, string faultstring [, string faultactor [, mixed detail [, string faultname [, mixed headerfault]]]])
SoapFault constructor */
PHP_METHOD(SoapFault, __toString)
{
zval *faultcode, *faultstring, *file, *line, trace, rv1, rv2, rv3, rv4;
zend_string *str;
zend_fcall_info fci;
zval *this_ptr;
zend_string *faultcode_val, *faultstring_val, *file_val;
zend_long line_val;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
this_ptr = ZEND_THIS;
faultcode = zend_read_property(soap_fault_class_entry, this_ptr, "faultcode", sizeof("faultcode")-1, 1, &rv1);
faultstring = zend_read_property(soap_fault_class_entry, this_ptr, "faultstring", sizeof("faultstring")-1, 1, &rv2);
file = zend_read_property(soap_fault_class_entry, this_ptr, "file", sizeof("file")-1, 1, &rv3);
line = zend_read_property(soap_fault_class_entry, this_ptr, "line", sizeof("line")-1, 1, &rv4);
fci.size = sizeof(fci);
ZVAL_STRINGL(&fci.function_name, "gettraceasstring", sizeof("gettraceasstring")-1);
fci.object = Z_OBJ_P(ZEND_THIS);
fci.retval = &trace;
fci.param_count = 0;
fci.params = NULL;
fci.no_separation = 1;
zend_call_function(&fci, NULL);
zval_ptr_dtor(&fci.function_name);
faultcode_val = zval_get_string(faultcode);
faultstring_val = zval_get_string(faultstring);
file_val = zval_get_string(file);
line_val = zval_get_long(line);
convert_to_string(&trace);
str = strpprintf(0, "SoapFault exception: [%s] %s in %s:" ZEND_LONG_FMT "\nStack trace:\n%s",
ZSTR_VAL(faultcode_val), ZSTR_VAL(faultstring_val), ZSTR_VAL(file_val), line_val,
Z_STRLEN(trace) ? Z_STRVAL(trace) : "#0 {main}\n");
zend_string_release_ex(file_val, 0);
zend_string_release_ex(faultstring_val, 0);
zend_string_release_ex(faultcode_val, 0);
zval_ptr_dtor(&trace);
RETVAL_STR(str);
}
/* }}} */
/* {{{ proto object SoapVar::SoapVar(mixed data, int encoding [, string type_name [, string type_namespace [, string node_name [, string node_namespace]]]])
SoapVar constructor */
PHP_METHOD(SoapVar, SoapVar)
{
zval *data, *type, *this_ptr;
char *stype = NULL, *ns = NULL, *name = NULL, *namens = NULL;
size_t stype_len = 0, ns_len = 0, name_len = 0, namens_len = 0;
if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "z!z|ssss", &data, &type, &stype, &stype_len, &ns, &ns_len, &name, &name_len, &namens, &namens_len) == FAILURE) {
return;
}
this_ptr = ZEND_THIS;
if (Z_TYPE_P(type) == IS_NULL) {
add_property_long(this_ptr, "enc_type", UNKNOWN_TYPE);
} else {
if (zend_hash_index_exists(&SOAP_GLOBAL(defEncIndex), Z_LVAL_P(type))) {
add_property_long(this_ptr, "enc_type", Z_LVAL_P(type));
} else {
php_error_docref(NULL, E_WARNING, "Invalid type ID");
return;
}
}
if (data) {
add_property_zval(this_ptr, "enc_value", data);
}
if (stype && stype_len > 0) {
add_property_stringl(this_ptr, "enc_stype", stype, stype_len);
}
if (ns && ns_len > 0) {
add_property_stringl(this_ptr, "enc_ns", ns, ns_len);
}
if (name && name_len > 0) {
add_property_stringl(this_ptr, "enc_name", name, name_len);
}
if (namens && namens_len > 0) {
add_property_stringl(this_ptr, "enc_namens", namens, namens_len);
}
}
/* }}} */
static HashTable* soap_create_typemap(sdlPtr sdl, HashTable *ht) /* {{{ */
{
zval *tmp;
HashTable *ht2;
HashTable *typemap = NULL;
ZEND_HASH_FOREACH_VAL(ht, tmp) {
char *type_name = NULL;
char *type_ns = NULL;
zval *to_xml = NULL;
zval *to_zval = NULL;
encodePtr enc, new_enc;
zend_string *name;
if (Z_TYPE_P(tmp) != IS_ARRAY) {
php_error_docref(NULL, E_WARNING, "Wrong 'typemap' option");
return NULL;
}
ht2 = Z_ARRVAL_P(tmp);
ZEND_HASH_FOREACH_STR_KEY_VAL(ht2, name, tmp) {
if (name) {
if (ZSTR_LEN(name) == sizeof("type_name")-1 &&
strncmp(ZSTR_VAL(name), "type_name", sizeof("type_name")-1) == 0) {
if (Z_TYPE_P(tmp) == IS_STRING) {
type_name = Z_STRVAL_P(tmp);
} else if (Z_TYPE_P(tmp) != IS_NULL) {
}
} else if (ZSTR_LEN(name) == sizeof("type_ns")-1 &&
strncmp(ZSTR_VAL(name), "type_ns", sizeof("type_ns")-1) == 0) {
if (Z_TYPE_P(tmp) == IS_STRING) {
type_ns = Z_STRVAL_P(tmp);
} else if (Z_TYPE_P(tmp) != IS_NULL) {
}
} else if (ZSTR_LEN(name) == sizeof("to_xml")-1 &&
strncmp(ZSTR_VAL(name), "to_xml", sizeof("to_xml")-1) == 0) {
to_xml = tmp;
} else if (ZSTR_LEN(name) == sizeof("from_xml")-1 &&
strncmp(ZSTR_VAL(name), "from_xml", sizeof("from_xml")-1) == 0) {
to_zval = tmp;
}
}
} ZEND_HASH_FOREACH_END();
if (type_name) {
smart_str nscat = {0};
if (type_ns) {
enc = get_encoder(sdl, type_ns, type_name);
} else {
enc = get_encoder_ex(sdl, type_name, strlen(type_name));
}
new_enc = emalloc(sizeof(encode));
memset(new_enc, 0, sizeof(encode));
if (enc) {
new_enc->details.type = enc->details.type;
new_enc->details.ns = estrdup(enc->details.ns);
new_enc->details.type_str = estrdup(enc->details.type_str);
new_enc->details.sdl_type = enc->details.sdl_type;
} else {
enc = get_conversion(UNKNOWN_TYPE);
new_enc->details.type = enc->details.type;
if (type_ns) {
new_enc->details.ns = estrdup(type_ns);
}
new_enc->details.type_str = estrdup(type_name);
}
new_enc->to_xml = enc->to_xml;
new_enc->to_zval = enc->to_zval;
new_enc->details.map = emalloc(sizeof(soapMapping));
memset(new_enc->details.map, 0, sizeof(soapMapping));
if (to_xml) {
ZVAL_COPY(&new_enc->details.map->to_xml, to_xml);
new_enc->to_xml = to_xml_user;
} else if (enc->details.map && Z_TYPE(enc->details.map->to_xml) != IS_UNDEF) {
ZVAL_COPY(&new_enc->details.map->to_xml, &enc->details.map->to_xml);
}
if (to_zval) {
ZVAL_COPY(&new_enc->details.map->to_zval, to_zval);
new_enc->to_zval = to_zval_user;
} else if (enc->details.map && Z_TYPE(enc->details.map->to_zval) != IS_UNDEF) {
ZVAL_COPY(&new_enc->details.map->to_zval, &enc->details.map->to_zval);
}
if (!typemap) {
typemap = emalloc(sizeof(HashTable));
zend_hash_init(typemap, 0, NULL, delete_encoder, 0);
}
if (type_ns) {
smart_str_appends(&nscat, type_ns);
smart_str_appendc(&nscat, ':');
}
smart_str_appends(&nscat, type_name);
smart_str_0(&nscat);
zend_hash_update_ptr(typemap, nscat.s, new_enc);
smart_str_free(&nscat);
}
} ZEND_HASH_FOREACH_END();
return typemap;
}
/* }}} */
/* {{{ proto object SoapServer::SoapServer(mixed wsdl [, array options])
SoapServer constructor */
PHP_METHOD(SoapServer, SoapServer)
{
soapServicePtr service;
zval *wsdl = NULL, *options = NULL;
zend_resource *res;
int version = SOAP_1_1;
zend_long cache_wsdl;
HashTable *typemap_ht = NULL;
SOAP_SERVER_BEGIN_CODE();
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|a", &wsdl, &options) == FAILURE) {
php_error_docref(NULL, E_ERROR, "Invalid parameters");
}
if (Z_TYPE_P(wsdl) != IS_STRING && Z_TYPE_P(wsdl) != IS_NULL) {
php_error_docref(NULL, E_ERROR, "Invalid parameters");
}
service = emalloc(sizeof(soapService));
memset(service, 0, sizeof(soapService));
service->send_errors = 1;
cache_wsdl = SOAP_GLOBAL(cache_enabled) ? SOAP_GLOBAL(cache_mode) : 0;
if (options != NULL) {
HashTable *ht = Z_ARRVAL_P(options);
zval *tmp;
if ((tmp = zend_hash_str_find(ht, "soap_version", sizeof("soap_version")-1)) != NULL) {
if (Z_TYPE_P(tmp) == IS_LONG &&
(Z_LVAL_P(tmp) == SOAP_1_1 || Z_LVAL_P(tmp) == SOAP_1_2)) {
version = Z_LVAL_P(tmp);
} else {
php_error_docref(NULL, E_ERROR, "'soap_version' option must be SOAP_1_1 or SOAP_1_2");
}
}
if ((tmp = zend_hash_str_find(ht, "uri", sizeof("uri")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
service->uri = estrndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
} else if (Z_TYPE_P(wsdl) == IS_NULL) {
php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
}
if ((tmp = zend_hash_str_find(ht, "actor", sizeof("actor")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
service->actor = estrndup(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
}
if ((tmp = zend_hash_str_find(ht, "encoding", sizeof("encoding")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
xmlCharEncodingHandlerPtr encoding;
encoding = xmlFindCharEncodingHandler(Z_STRVAL_P(tmp));
if (encoding == NULL) {
php_error_docref(NULL, E_ERROR, "Invalid 'encoding' option - '%s'", Z_STRVAL_P(tmp));
} else {
service->encoding = encoding;
}
}
if ((tmp = zend_hash_str_find(ht, "classmap", sizeof("classmap")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_ARRAY) {
service->class_map = zend_array_dup(Z_ARRVAL_P(tmp));
}
if ((tmp = zend_hash_str_find(ht, "typemap", sizeof("typemap")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_ARRAY &&
zend_hash_num_elements(Z_ARRVAL_P(tmp)) > 0) {
typemap_ht = Z_ARRVAL_P(tmp);
}
if ((tmp = zend_hash_str_find(ht, "features", sizeof("features")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_LONG) {
service->features = Z_LVAL_P(tmp);
}
if ((tmp = zend_hash_str_find(ht, "cache_wsdl", sizeof("cache_wsdl")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_LONG) {
cache_wsdl = Z_LVAL_P(tmp);
}
if ((tmp = zend_hash_str_find(ht, "send_errors", sizeof("send_errors")-1)) != NULL) {
if (Z_TYPE_P(tmp) == IS_FALSE) {
service->send_errors = 0;
} else if (Z_TYPE_P(tmp) == IS_TRUE) {
service->send_errors = 1;
} else if (Z_TYPE_P(tmp) == IS_LONG) {
service->send_errors = Z_LVAL_P(tmp);
}
}
} else if (Z_TYPE_P(wsdl) == IS_NULL) {
php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
}
service->version = version;
service->type = SOAP_FUNCTIONS;
service->soap_functions.functions_all = FALSE;
service->soap_functions.ft = zend_new_array(0);
if (Z_TYPE_P(wsdl) != IS_NULL) {
service->sdl = get_sdl(ZEND_THIS, Z_STRVAL_P(wsdl), cache_wsdl);
if (service->uri == NULL) {
if (service->sdl->target_ns) {
service->uri = estrdup(service->sdl->target_ns);
} else {
/*FIXME*/
service->uri = estrdup("http://unknown-uri/");
}
}
}
if (typemap_ht) {
service->typemap = soap_create_typemap(service->sdl, typemap_ht);
}
res = zend_register_resource(service, le_service);
add_property_resource(ZEND_THIS, "service", res);
SOAP_SERVER_END_CODE();
}
/* }}} */
/* {{{ proto object SoapServer::setPersistence(int mode )
Sets persistence mode of SoapServer */
PHP_METHOD(SoapServer, setPersistence)
{
soapServicePtr service;
zend_long value;
SOAP_SERVER_BEGIN_CODE();
FETCH_THIS_SERVICE(service);
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) != FAILURE) {
if (service->type == SOAP_CLASS) {
if (value == SOAP_PERSISTENCE_SESSION ||
value == SOAP_PERSISTENCE_REQUEST) {
service->soap_class.persistence = value;
} else {
php_error_docref(NULL, E_WARNING, "Tried to set persistence with bogus value (" ZEND_LONG_FMT ")", value);
return;
}
} else {
php_error_docref(NULL, E_WARNING, "Tried to set persistence when you are using you SOAP SERVER in function mode, no persistence needed");
return;
}
}
SOAP_SERVER_END_CODE();
}
/* }}} */
/* {{{ proto void SoapServer::setClass(string class_name [, mixed args])
Sets class which will handle SOAP requests */
PHP_METHOD(SoapServer, setClass)
{
soapServicePtr service;
zend_string *classname;
zend_class_entry *ce;
int num_args = 0;
zval *argv = NULL;
SOAP_SERVER_BEGIN_CODE();
FETCH_THIS_SERVICE(service);
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S*", &classname, &argv, &num_args) == FAILURE) {
return;
}
ce = zend_lookup_class(classname);
if (ce) {
service->type = SOAP_CLASS;
service->soap_class.ce = ce;
service->soap_class.persistence = SOAP_PERSISTENCE_REQUEST;
service->soap_class.argc = num_args;
if (service->soap_class.argc > 0) {
int i;
service->soap_class.argv = safe_emalloc(sizeof(zval), service->soap_class.argc, 0);
for (i = 0;i < service->soap_class.argc;i++) {
ZVAL_COPY(&service->soap_class.argv[i], &argv[i]);
}
}
} else {
php_error_docref(NULL, E_WARNING, "Tried to set a non existent class (%s)", ZSTR_VAL(classname));
return;
}
SOAP_SERVER_END_CODE();
}
/* }}} */
/* {{{ proto void SoapServer::setObject(object obj)
Sets object which will handle SOAP requests */
PHP_METHOD(SoapServer, setObject)
{
soapServicePtr service;
zval *obj;
SOAP_SERVER_BEGIN_CODE();
FETCH_THIS_SERVICE(service);
if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &obj) == FAILURE) {
return;
}
service->type = SOAP_OBJECT;
ZVAL_COPY(&service->soap_object, obj);
SOAP_SERVER_END_CODE();
}
/* }}} */
/* {{{ proto array SoapServer::getFunctions(void)
Returns list of defined functions */
PHP_METHOD(SoapServer, getFunctions)
{
soapServicePtr service;
HashTable *ft = NULL;
SOAP_SERVER_BEGIN_CODE();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
FETCH_THIS_SERVICE(service);
array_init(return_value);
if (service->type == SOAP_OBJECT) {
ft = &(Z_OBJCE(service->soap_object)->function_table);
} else if (service->type == SOAP_CLASS) {
ft = &service->soap_class.ce->function_table;
} else if (service->soap_functions.functions_all == TRUE) {
ft = EG(function_table);
} else if (service->soap_functions.ft != NULL) {
zval *name;
ZEND_HASH_FOREACH_VAL(service->soap_functions.ft, name) {
add_next_index_str(return_value, zend_string_copy(Z_STR_P(name)));
} ZEND_HASH_FOREACH_END();
}
if (ft != NULL) {
zend_function *f;
ZEND_HASH_FOREACH_PTR(ft, f) {
if ((service->type != SOAP_OBJECT && service->type != SOAP_CLASS) || (f->common.fn_flags & ZEND_ACC_PUBLIC)) {
add_next_index_str(return_value, zend_string_copy(f->common.function_name));
}
} ZEND_HASH_FOREACH_END();
}
SOAP_SERVER_END_CODE();
}
/* }}} */
/* {{{ proto void SoapServer::addFunction(mixed functions)
Adds one or several functions those will handle SOAP requests */
PHP_METHOD(SoapServer, addFunction)
{
soapServicePtr service;
zval *function_name, function_copy;
SOAP_SERVER_BEGIN_CODE();
FETCH_THIS_SERVICE(service);
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &function_name) == FAILURE) {
return;
}
/* TODO: could use zend_is_callable here */
if (Z_TYPE_P(function_name) == IS_ARRAY) {
if (service->type == SOAP_FUNCTIONS) {
zval *tmp_function;
if (service->soap_functions.ft == NULL) {
service->soap_functions.functions_all = FALSE;
service->soap_functions.ft = zend_new_array(zend_hash_num_elements(Z_ARRVAL_P(function_name)));
}
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(function_name), tmp_function) {
zend_string *key;
zend_function *f;
if (Z_TYPE_P(tmp_function) != IS_STRING) {
php_error_docref(NULL, E_WARNING, "Tried to add a function that isn't a string");
return;
}
key = zend_string_tolower(Z_STR_P(tmp_function));
if ((f = zend_hash_find_ptr(EG(function_table), key)) == NULL) {
php_error_docref(NULL, E_WARNING, "Tried to add a non existent function '%s'", Z_STRVAL_P(tmp_function));
return;
}
ZVAL_STR_COPY(&function_copy, f->common.function_name);
zend_hash_update(service->soap_functions.ft, key, &function_copy);
zend_string_release_ex(key, 0);
} ZEND_HASH_FOREACH_END();
}
} else if (Z_TYPE_P(function_name) == IS_STRING) {
zend_string *key;
zend_function *f;
key = zend_string_tolower(Z_STR_P(function_name));
if ((f = zend_hash_find_ptr(EG(function_table), key)) == NULL) {
php_error_docref(NULL, E_WARNING, "Tried to add a non existent function '%s'", Z_STRVAL_P(function_name));
return;
}
if (service->soap_functions.ft == NULL) {
service->soap_functions.functions_all = FALSE;
service->soap_functions.ft = zend_new_array(0);
}
ZVAL_STR_COPY(&function_copy, f->common.function_name);
zend_hash_update(service->soap_functions.ft, key, &function_copy);
zend_string_release_ex(key, 0);
} else if (Z_TYPE_P(function_name) == IS_LONG) {
if (Z_LVAL_P(function_name) == SOAP_FUNCTIONS_ALL) {
if (service->soap_functions.ft != NULL) {
zend_hash_destroy(service->soap_functions.ft);
efree(service->soap_functions.ft);
service->soap_functions.ft = NULL;
}
service->soap_functions.functions_all = TRUE;
} else {
php_error_docref(NULL, E_WARNING, "Invalid value passed");
return;
}
}
SOAP_SERVER_END_CODE();
}
/* }}} */
static void _soap_server_exception(soapServicePtr service, sdlFunctionPtr function, zval *this_ptr) /* {{{ */
{
zval exception_object;
ZVAL_OBJ(&exception_object, EG(exception));
if (instanceof_function(Z_OBJCE(exception_object), soap_fault_class_entry)) {
soap_server_fault_ex(function, &exception_object, NULL);
} else if (instanceof_function(Z_OBJCE(exception_object), zend_ce_error)) {
if (service->send_errors) {
zval rv;
zend_string *msg = zval_get_string(zend_read_property(zend_ce_error, &exception_object, "message", sizeof("message")-1, 0, &rv));
add_soap_fault_ex(&exception_object, this_ptr, "Server", ZSTR_VAL(msg), NULL, NULL);
zend_string_release_ex(msg, 0);
} else {
add_soap_fault_ex(&exception_object, this_ptr, "Server", "Internal Error", NULL, NULL);
}
soap_server_fault_ex(function, &exception_object, NULL);
}
}
/* }}} */
/* {{{ proto void SoapServer::handle([string soap_request])
Handles a SOAP request */
PHP_METHOD(SoapServer, handle)
{
int soap_version, old_soap_version;
sdlPtr old_sdl = NULL;
soapServicePtr service;
xmlDocPtr doc_request=NULL, doc_return;
zval function_name, *params, *soap_obj, retval;
char *fn_name, cont_len[30];
int num_params = 0, size, i, call_status = 0;
xmlChar *buf;
HashTable *function_table;
soapHeader *soap_headers = NULL;
sdlFunctionPtr function;
char *arg = NULL;
size_t arg_len = 0;
xmlCharEncodingHandlerPtr old_encoding;
HashTable *old_class_map, *old_typemap;
int old_features;
zval tmp_soap;
SOAP_SERVER_BEGIN_CODE();
FETCH_THIS_SERVICE(service);
SOAP_GLOBAL(soap_version) = service->version;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &arg, &arg_len) == FAILURE) {
return;
}
if (ZEND_NUM_ARGS() > 0 && ZEND_SIZE_T_INT_OVFL(arg_len)) {
soap_server_fault("Server", "Input string is too long", NULL, NULL, NULL);
return;
}
if (SG(request_info).request_method &&
strcmp(SG(request_info).request_method, "GET") == 0 &&
SG(request_info).query_string &&
stricmp(SG(request_info).query_string, "wsdl") == 0) {
if (service->sdl) {
/*
char *hdr = emalloc(sizeof("Location: ")+strlen(service->sdl->source));
strcpy(hdr,"Location: ");
strcat(hdr,service->sdl->source);
sapi_add_header(hdr, sizeof("Location: ")+strlen(service->sdl->source)-1, 1);
efree(hdr);
*/
zval readfile, readfile_ret, param;
sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
ZVAL_STRING(&param, service->sdl->source);
ZVAL_STRING(&readfile, "readfile");
if (call_user_function(EG(function_table), NULL, &readfile, &readfile_ret, 1, &param ) == FAILURE) {
soap_server_fault("Server", "Couldn't find WSDL", NULL, NULL, NULL);
}
zval_ptr_dtor(&param);
zval_ptr_dtor_str(&readfile);
zval_ptr_dtor(&readfile_ret);
SOAP_SERVER_END_CODE();
return;
} else {
soap_server_fault("Server", "WSDL generation is not supported yet", NULL, NULL, NULL);
/*
sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8"), 1);
PUTS("<?xml version=\"1.0\" ?>\n<definitions\n");
PUTS(" xmlns=\"http://schemas.xmlsoap.org/wsdl/\"\n");
PUTS(" targetNamespace=\"");
PUTS(service->uri);
PUTS("\">\n");
PUTS("</definitions>");
*/
SOAP_SERVER_END_CODE();
return;
}
}
ZVAL_NULL(&retval);
if (php_output_start_default() != SUCCESS) {
php_error_docref(NULL, E_ERROR,"ob_start failed");
}
if (ZEND_NUM_ARGS() == 0) {
if (SG(request_info).request_body && 0 == php_stream_rewind(SG(request_info).request_body)) {
zval *server_vars, *encoding;
php_stream_filter *zf = NULL;
zend_string *server = zend_string_init("_SERVER", sizeof("_SERVER") - 1, 0);
zend_is_auto_global(server);
if ((server_vars = zend_hash_find(&EG(symbol_table), server)) != NULL &&
Z_TYPE_P(server_vars) == IS_ARRAY &&
(encoding = zend_hash_str_find(Z_ARRVAL_P(server_vars), "HTTP_CONTENT_ENCODING", sizeof("HTTP_CONTENT_ENCODING")-1)) != NULL &&
Z_TYPE_P(encoding) == IS_STRING) {
if (strcmp(Z_STRVAL_P(encoding),"gzip") == 0
|| strcmp(Z_STRVAL_P(encoding),"x-gzip") == 0
|| strcmp(Z_STRVAL_P(encoding),"deflate") == 0
) {
zval filter_params;
array_init_size(&filter_params, 1);
add_assoc_long_ex(&filter_params, "window", sizeof("window")-1, 0x2f); /* ANY WBITS */
zf = php_stream_filter_create("zlib.inflate", &filter_params, 0);
zend_array_destroy(Z_ARR(filter_params));
if (zf) {
php_stream_filter_append(&SG(request_info).request_body->readfilters, zf);
} else {
php_error_docref(NULL, E_WARNING,"Can't uncompress compressed request");
zend_string_release_ex(server, 0);
return;
}
} else {
php_error_docref(NULL, E_WARNING,"Request is compressed with unknown compression '%s'",Z_STRVAL_P(encoding));
zend_string_release_ex(server, 0);
return;
}
}
zend_string_release_ex(server, 0);
doc_request = soap_xmlParseFile("php://input");
if (zf) {
php_stream_filter_remove(zf, 1);
}
} else {
zval_ptr_dtor(&retval);
return;
}
} else {
doc_request = soap_xmlParseMemory(arg,arg_len);
}
if (doc_request == NULL) {
soap_server_fault("Client", "Bad Request", NULL, NULL, NULL);
}
if (xmlGetIntSubset(doc_request) != NULL) {
xmlNodePtr env = get_node(doc_request->children,"Envelope");
if (env && env->ns) {
if (strcmp((char*)env->ns->href, SOAP_1_1_ENV_NAMESPACE) == 0) {
SOAP_GLOBAL(soap_version) = SOAP_1_1;
} else if (strcmp((char*)env->ns->href,SOAP_1_2_ENV_NAMESPACE) == 0) {
SOAP_GLOBAL(soap_version) = SOAP_1_2;
}
}
xmlFreeDoc(doc_request);
soap_server_fault("Server", "DTD are not supported by SOAP", NULL, NULL, NULL);
}
old_sdl = SOAP_GLOBAL(sdl);
SOAP_GLOBAL(sdl) = service->sdl;
old_encoding = SOAP_GLOBAL(encoding);
SOAP_GLOBAL(encoding) = service->encoding;
old_class_map = SOAP_GLOBAL(class_map);
SOAP_GLOBAL(class_map) = service->class_map;
old_typemap = SOAP_GLOBAL(typemap);
SOAP_GLOBAL(typemap) = service->typemap;
old_features = SOAP_GLOBAL(features);
SOAP_GLOBAL(features) = service->features;
old_soap_version = SOAP_GLOBAL(soap_version);
function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, &params, &soap_version, &soap_headers);
xmlFreeDoc(doc_request);
if (EG(exception)) {
php_output_discard();
_soap_server_exception(service, function, ZEND_THIS);
goto fail;
}
service->soap_headers_ptr = &soap_headers;
soap_obj = NULL;
if (service->type == SOAP_OBJECT) {
soap_obj = &service->soap_object;
function_table = &((Z_OBJCE_P(soap_obj))->function_table);
} else if (service->type == SOAP_CLASS) {
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
/* If persistent then set soap_obj from from the previous created session (if available) */
if (service->soap_class.persistence == SOAP_PERSISTENCE_SESSION) {
zval *session_vars, *tmp_soap_p;
if (PS(session_status) != php_session_active &&
PS(session_status) != php_session_disabled) {
php_session_start();
}
/* Find the soap object and assign */
session_vars = &PS(http_session_vars);
ZVAL_DEREF(session_vars);
if (Z_TYPE_P(session_vars) == IS_ARRAY &&
(tmp_soap_p = zend_hash_str_find(Z_ARRVAL_P(session_vars), "_bogus_session_name", sizeof("_bogus_session_name")-1)) != NULL &&
Z_TYPE_P(tmp_soap_p) == IS_OBJECT &&
Z_OBJCE_P(tmp_soap_p) == service->soap_class.ce) {
soap_obj = tmp_soap_p;
}
}
#endif
/* If new session or something weird happned */
if (soap_obj == NULL) {
object_init_ex(&tmp_soap, service->soap_class.ce);
/* Call constructor */
if (zend_hash_str_exists(&Z_OBJCE(tmp_soap)->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1)) {
zval c_ret, constructor;
ZVAL_STRING(&constructor, ZEND_CONSTRUCTOR_FUNC_NAME);
if (call_user_function(NULL, &tmp_soap, &constructor, &c_ret, service->soap_class.argc, service->soap_class.argv) == FAILURE) {
php_error_docref(NULL, E_ERROR, "Error calling constructor");
}
if (EG(exception)) {
php_output_discard();
_soap_server_exception(service, function, ZEND_THIS);
zval_ptr_dtor_str(&constructor);
zval_ptr_dtor(&c_ret);
zval_ptr_dtor(&tmp_soap);
goto fail;
}
zval_ptr_dtor_str(&constructor);
zval_ptr_dtor(&c_ret);
} else {
int class_name_len = ZSTR_LEN(service->soap_class.ce->name);
char *class_name = emalloc(class_name_len+1);
memcpy(class_name, ZSTR_VAL(service->soap_class.ce->name), class_name_len+1);
if (zend_hash_str_exists(&Z_OBJCE(tmp_soap)->function_table, php_strtolower(class_name, class_name_len), class_name_len)) {
zval c_ret, constructor;
ZVAL_STR_COPY(&constructor, service->soap_class.ce->name);
if (call_user_function(NULL, &tmp_soap, &constructor, &c_ret, service->soap_class.argc, service->soap_class.argv) == FAILURE) {
php_error_docref(NULL, E_ERROR, "Error calling constructor");
}
if (EG(exception)) {
php_output_discard();
_soap_server_exception(service, function, ZEND_THIS);
zval_ptr_dtor_str(&constructor);
zval_ptr_dtor(&c_ret);
efree(class_name);
zval_ptr_dtor(&tmp_soap);
goto fail;
}
zval_ptr_dtor_str(&constructor);
zval_ptr_dtor(&c_ret);
}
efree(class_name);
}
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
/* If session then update session hash with new object */
if (service->soap_class.persistence == SOAP_PERSISTENCE_SESSION) {
zval *session_vars = &PS(http_session_vars), *tmp_soap_p;
ZVAL_DEREF(session_vars);
if (Z_TYPE_P(session_vars) == IS_ARRAY &&
(tmp_soap_p = zend_hash_str_update(Z_ARRVAL_P(session_vars), "_bogus_session_name", sizeof("_bogus_session_name")-1, &tmp_soap)) != NULL) {
soap_obj = tmp_soap_p;
} else {
soap_obj = &tmp_soap;
}
} else {
soap_obj = &tmp_soap;
}
#else
soap_obj = &tmp_soap;
#endif
}
function_table = &((Z_OBJCE_P(soap_obj))->function_table);
} else {
if (service->soap_functions.functions_all == TRUE) {
function_table = EG(function_table);
} else {
function_table = service->soap_functions.ft;
}
}
doc_return = NULL;
/* Process soap headers */
if (soap_headers != NULL) {
soapHeader *header = soap_headers;
while (header != NULL) {
soapHeader *h = header;
header = header->next;
#if 0
if (service->sdl && !h->function && !h->hdr) {
if (h->mustUnderstand) {
soap_server_fault("MustUnderstand","Header not understood", NULL, NULL, NULL);
} else {
continue;
}
}
#endif
fn_name = estrndup(Z_STRVAL(h->function_name),Z_STRLEN(h->function_name));
if (zend_hash_str_exists(function_table, php_strtolower(fn_name, Z_STRLEN(h->function_name)), Z_STRLEN(h->function_name)) ||
((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) &&
zend_hash_str_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
if (service->type == SOAP_CLASS || service->type == SOAP_OBJECT) {
call_status = call_user_function(NULL, soap_obj, &h->function_name, &h->retval, h->num_params, h->parameters);
} else {
call_status = call_user_function(EG(function_table), NULL, &h->function_name, &h->retval, h->num_params, h->parameters);
}
if (call_status != SUCCESS) {
php_error_docref(NULL, E_WARNING, "Function '%s' call failed", Z_STRVAL(h->function_name));
return;
}
if (Z_TYPE(h->retval) == IS_OBJECT &&
instanceof_function(Z_OBJCE(h->retval), soap_fault_class_entry)) {
zval *tmp;
if ((tmp = zend_hash_str_find(Z_OBJPROP(h->retval), "headerfault", sizeof("headerfault")-1)) != NULL &&
Z_TYPE_P(tmp) != IS_NULL) {
}
php_output_discard();
soap_server_fault_ex(function, &h->retval, h);
efree(fn_name);
if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
goto fail;
} else if (EG(exception)) {
php_output_discard();
_soap_server_exception(service, function, ZEND_THIS);
efree(fn_name);
if (service->type == SOAP_CLASS && soap_obj) {zval_ptr_dtor(soap_obj);}
goto fail;
}
} else if (h->mustUnderstand) {
soap_server_fault("MustUnderstand","Header not understood", NULL, NULL, NULL);
}
efree(fn_name);
}
}
fn_name = estrndup(Z_STRVAL(function_name),Z_STRLEN(function_name));
if (zend_hash_str_exists(function_table, php_strtolower(fn_name, Z_STRLEN(function_name)), Z_STRLEN(function_name)) ||
((service->type == SOAP_CLASS || service->type == SOAP_OBJECT) &&
zend_hash_str_exists(function_table, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
if (service->type == SOAP_CLASS || service->type == SOAP_OBJECT) {
call_status = call_user_function(NULL, soap_obj, &function_name, &retval, num_params, params);
if (service->type == SOAP_CLASS) {
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
if (service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
zval_ptr_dtor(soap_obj);
soap_obj = NULL;
}
#else
zval_ptr_dtor(soap_obj);
soap_obj = NULL;
#endif
}
} else {
call_status = call_user_function(EG(function_table), NULL, &function_name, &retval, num_params, params);
}
} else {
php_error(E_ERROR, "Function '%s' doesn't exist", Z_STRVAL(function_name));
}
efree(fn_name);
if (EG(exception)) {
php_output_discard();
_soap_server_exception(service, function, ZEND_THIS);
if (service->type == SOAP_CLASS) {
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
if (soap_obj && service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
#else
if (soap_obj) {
#endif
zval_ptr_dtor(soap_obj);
}
}
goto fail;
}
if (call_status == SUCCESS) {
char *response_name;
if (Z_TYPE(retval) == IS_OBJECT &&
instanceof_function(Z_OBJCE(retval), soap_fault_class_entry)) {
php_output_discard();
soap_server_fault_ex(function, &retval, NULL);
goto fail;
}
if (function && function->responseName) {
response_name = estrdup(function->responseName);
} else {
response_name = emalloc(Z_STRLEN(function_name) + sizeof("Response"));
memcpy(response_name,Z_STRVAL(function_name),Z_STRLEN(function_name));
memcpy(response_name+Z_STRLEN(function_name),"Response",sizeof("Response"));
}
doc_return = serialize_response_call(function, response_name, service->uri, &retval, soap_headers, soap_version);
efree(response_name);
} else {
php_error_docref(NULL, E_WARNING, "Function '%s' call failed", Z_STRVAL(function_name));
return;
}
if (EG(exception)) {
php_output_discard();
_soap_server_exception(service, function, ZEND_THIS);
if (service->type == SOAP_CLASS) {
#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
if (soap_obj && service->soap_class.persistence != SOAP_PERSISTENCE_SESSION) {
#else
if (soap_obj) {
#endif
zval_ptr_dtor(soap_obj);
}
}
goto fail;
}
/* Flush buffer */
php_output_discard();
if (doc_return) {
/* xmlDocDumpMemoryEnc(doc_return, &buf, &size, XML_CHAR_ENCODING_UTF8); */
xmlDocDumpMemory(doc_return, &buf, &size);
if (size == 0) {
php_error_docref(NULL, E_ERROR, "Dump memory failed");
}
if (soap_version == SOAP_1_2) {
sapi_add_header("Content-Type: application/soap+xml; charset=utf-8", sizeof("Content-Type: application/soap+xml; charset=utf-8")-1, 1);
} else {
sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
}
xmlFreeDoc(doc_return);
if (zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0)) {
sapi_add_header("Connection: close", sizeof("Connection: close")-1, 1);
} else {
snprintf(cont_len, sizeof(cont_len), "Content-Length: %d", size);
sapi_add_header(cont_len, strlen(cont_len), 1);
}
php_write(buf, size);
xmlFree(buf);
} else {
sapi_add_header("HTTP/1.1 202 Accepted", sizeof("HTTP/1.1 202 Accepted")-1, 1);
sapi_add_header("Content-Length: 0", sizeof("Content-Length: 0")-1, 1);
}
fail:
SOAP_GLOBAL(soap_version) = old_soap_version;
SOAP_GLOBAL(encoding) = old_encoding;
SOAP_GLOBAL(sdl) = old_sdl;
SOAP_GLOBAL(class_map) = old_class_map;
SOAP_GLOBAL(typemap) = old_typemap;
SOAP_GLOBAL(features) = old_features;
/* Free soap headers */
zval_ptr_dtor(&retval);
while (soap_headers != NULL) {
soapHeader *h = soap_headers;
int i;
soap_headers = soap_headers->next;
if (h->parameters) {
i = h->num_params;
while (i > 0) {
zval_ptr_dtor(&h->parameters[--i]);
}
efree(h->parameters);
}
zval_ptr_dtor_str(&h->function_name);
zval_ptr_dtor(&h->retval);
efree(h);
}
service->soap_headers_ptr = NULL;
/* Free Memory */
if (num_params > 0) {
for (i = 0; i < num_params;i++) {
zval_ptr_dtor(&params[i]);
}
efree(params);
}
zval_ptr_dtor_str(&function_name);
SOAP_SERVER_END_CODE();
}
/* }}} */
/* {{{ proto SoapServer::fault ( staring code, string string [, string actor [, mixed details [, string name]]] )
Issue SoapFault indicating an error */
PHP_METHOD(SoapServer, fault)
{
char *code, *string, *actor=NULL, *name=NULL;
size_t code_len, string_len, actor_len = 0, name_len = 0;
zval* details = NULL;
soapServicePtr service;
xmlCharEncodingHandlerPtr old_encoding;
SOAP_SERVER_BEGIN_CODE();
FETCH_THIS_SERVICE(service);
old_encoding = SOAP_GLOBAL(encoding);
SOAP_GLOBAL(encoding) = service->encoding;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|szs",
&code, &code_len, &string, &string_len, &actor, &actor_len, &details,
&name, &name_len) == FAILURE) {
return;
}
soap_server_fault(code, string, actor, details, name);
SOAP_GLOBAL(encoding) = old_encoding;
SOAP_SERVER_END_CODE();
}
/* }}} */
/* {{{ proto SoapServer::addSoapHeader(SoapHeader $object) */
PHP_METHOD(SoapServer, addSoapHeader)
{
soapServicePtr service;
zval *fault;
soapHeader **p;
SOAP_SERVER_BEGIN_CODE();
FETCH_THIS_SERVICE(service);
if (!service || !service->soap_headers_ptr) {
php_error_docref(NULL, E_WARNING, "The SoapServer::addSoapHeader function may be called only during SOAP request processing");
return;
}
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &fault, soap_header_class_entry) == FAILURE) {
return;
}
p = service->soap_headers_ptr;
while (*p != NULL) {
p = &(*p)->next;
}
*p = emalloc(sizeof(soapHeader));
memset(*p, 0, sizeof(soapHeader));
ZVAL_NULL(&(*p)->function_name);
ZVAL_COPY(&(*p)->retval, fault);
SOAP_SERVER_END_CODE();
}
/* }}} */
static void soap_server_fault_ex(sdlFunctionPtr function, zval* fault, soapHeader *hdr) /* {{{ */
{
int soap_version;
xmlChar *buf;
char cont_len[30];
int size;
xmlDocPtr doc_return;
zval *agent_name;
int use_http_error_status = 1;
soap_version = SOAP_GLOBAL(soap_version);
doc_return = serialize_response_call(function, NULL, NULL, fault, hdr, soap_version);
xmlDocDumpMemory(doc_return, &buf, &size);
if ((Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY || zend_is_auto_global_str(ZEND_STRL("_SERVER"))) &&
(agent_name = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_USER_AGENT", sizeof("HTTP_USER_AGENT")-1)) != NULL &&
Z_TYPE_P(agent_name) == IS_STRING) {
if (strncmp(Z_STRVAL_P(agent_name), "Shockwave Flash", sizeof("Shockwave Flash")-1) == 0) {
use_http_error_status = 0;
}
}
/*
Want to return HTTP 500 but apache wants to over write
our fault code with their own handling... Figure this out later
*/
if (use_http_error_status) {
sapi_add_header("HTTP/1.1 500 Internal Service Error", sizeof("HTTP/1.1 500 Internal Service Error")-1, 1);
}
if (zend_ini_long("zlib.output_compression", sizeof("zlib.output_compression"), 0)) {
sapi_add_header("Connection: close", sizeof("Connection: close")-1, 1);
} else {
snprintf(cont_len, sizeof(cont_len), "Content-Length: %d", size);
sapi_add_header(cont_len, strlen(cont_len), 1);
}
if (soap_version == SOAP_1_2) {
sapi_add_header("Content-Type: application/soap+xml; charset=utf-8", sizeof("Content-Type: application/soap+xml; charset=utf-8")-1, 1);
} else {
sapi_add_header("Content-Type: text/xml; charset=utf-8", sizeof("Content-Type: text/xml; charset=utf-8")-1, 1);
}
php_write(buf, size);
xmlFreeDoc(doc_return);
xmlFree(buf);
zend_clear_exception();
}
/* }}} */
static void soap_server_fault(char* code, char* string, char *actor, zval* details, char* name) /* {{{ */
{
zval ret;
ZVAL_NULL(&ret);
set_soap_fault(&ret, NULL, code, string, actor, details, name);
/* TODO: Which function */
soap_server_fault_ex(NULL, &ret, NULL);
zend_bailout();
}
/* }}} */
static void soap_error_handler(int error_num, const char *error_filename, const uint32_t error_lineno, const char *format, va_list args) /* {{{ */
{
zend_bool _old_in_compilation;
zend_execute_data *_old_current_execute_data;
int _old_http_response_code;
char *_old_http_status_line;
_old_in_compilation = CG(in_compilation);
_old_current_execute_data = EG(current_execute_data);
_old_http_response_code = SG(sapi_headers).http_response_code;
_old_http_status_line = SG(sapi_headers).http_status_line;
if (!PG(modules_activated) || !SOAP_GLOBAL(use_soap_error_handler) || !EG(objects_store).object_buckets) {
call_old_error_handler(error_num, error_filename, error_lineno, format, args);
return;
}
if (Z_OBJ(SOAP_GLOBAL(error_object)) &&
instanceof_function(Z_OBJCE(SOAP_GLOBAL(error_object)), soap_class_entry)) {
zval *tmp;
int use_exceptions = 0;
if ((tmp = zend_hash_str_find(Z_OBJPROP(SOAP_GLOBAL(error_object)), "_exceptions", sizeof("_exceptions")-1)) == NULL ||
Z_TYPE_P(tmp) != IS_FALSE) {
use_exceptions = 1;
}
if ((error_num == E_USER_ERROR ||
error_num == E_COMPILE_ERROR ||
error_num == E_CORE_ERROR ||
error_num == E_ERROR ||
error_num == E_PARSE) &&
use_exceptions) {
zval fault;
char* code = SOAP_GLOBAL(error_code);
char buffer[1024];
size_t buffer_len;
va_list argcopy;
va_copy(argcopy, args);
buffer_len = vslprintf(buffer, sizeof(buffer)-1, format, argcopy);
va_end(argcopy);
buffer[sizeof(buffer)-1]=0;
if (buffer_len > sizeof(buffer) - 1 || buffer_len == (size_t)-1) {
buffer_len = sizeof(buffer) - 1;
}
if (code == NULL) {
code = "Client";
}
add_soap_fault_ex(&fault, &SOAP_GLOBAL(error_object), code, buffer, NULL, NULL);
Z_ADDREF(fault);
zend_throw_exception_object(&fault);
zend_bailout();
} else if (!use_exceptions ||
!SOAP_GLOBAL(error_code) ||
strcmp(SOAP_GLOBAL(error_code),"WSDL") != 0) {
/* Ignore libxml warnings during WSDL parsing */
call_old_error_handler(error_num, error_filename, error_lineno, format, args);
}
} else {
int old = PG(display_errors);
int fault = 0;
zval fault_obj;
va_list argcopy;
if (error_num == E_USER_ERROR ||
error_num == E_COMPILE_ERROR ||
error_num == E_CORE_ERROR ||
error_num == E_ERROR ||
error_num == E_PARSE) {
char* code = SOAP_GLOBAL(error_code);
char buffer[1024];
zval outbuf;
zval *tmp;
soapServicePtr service;
ZVAL_UNDEF(&outbuf);
if (code == NULL) {
code = "Server";
}
if (Z_OBJ(SOAP_GLOBAL(error_object)) &&
instanceof_function(Z_OBJCE(SOAP_GLOBAL(error_object)), soap_server_class_entry) &&
(tmp = zend_hash_str_find(Z_OBJPROP(SOAP_GLOBAL(error_object)), "service", sizeof("service")-1)) != NULL &&
(service = (soapServicePtr)zend_fetch_resource_ex(tmp, "service", le_service)) &&
!service->send_errors) {
strcpy(buffer, "Internal Error");
} else {
size_t buffer_len;
zval outbuflen;
va_copy(argcopy, args);
buffer_len = vslprintf(buffer, sizeof(buffer)-1, format, argcopy);
va_end(argcopy);
buffer[sizeof(buffer)-1]=0;
if (buffer_len > sizeof(buffer) - 1 || buffer_len == (size_t)-1) {
buffer_len = sizeof(buffer) - 1;
}
/* Get output buffer and send as fault detials */
if (php_output_get_length(&outbuflen) != FAILURE && Z_LVAL(outbuflen) != 0) {
php_output_get_contents(&outbuf);
}
php_output_discard();
}
ZVAL_NULL(&fault_obj);
set_soap_fault(&fault_obj, NULL, code, buffer, NULL, &outbuf, NULL);
fault = 1;
}
PG(display_errors) = 0;
SG(sapi_headers).http_status_line = NULL;
zend_try {
call_old_error_handler(error_num, error_filename, error_lineno, format, args);
} zend_catch {
CG(in_compilation) = _old_in_compilation;
EG(current_execute_data) = _old_current_execute_data;
if (SG(sapi_headers).http_status_line) {
efree(SG(sapi_headers).http_status_line);
}
SG(sapi_headers).http_status_line = _old_http_status_line;
SG(sapi_headers).http_response_code = _old_http_response_code;
} zend_end_try();
PG(display_errors) = old;
if (fault) {
soap_server_fault_ex(NULL, &fault_obj, NULL);
zend_bailout();
}
}
}
/* }}} */
/* {{{ proto use_soap_error_handler([bool $handler = TRUE]) */
PHP_FUNCTION(use_soap_error_handler)
{
zend_bool handler = 1;
ZVAL_BOOL(return_value, SOAP_GLOBAL(use_soap_error_handler));
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &handler) == SUCCESS) {
SOAP_GLOBAL(use_soap_error_handler) = handler;
}
}
/* }}} */
/* {{{ proto is_soap_fault(mixed $object) */
PHP_FUNCTION(is_soap_fault)
{
zval *fault;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &fault) == SUCCESS &&
Z_TYPE_P(fault) == IS_OBJECT &&
instanceof_function(Z_OBJCE_P(fault), soap_fault_class_entry)) {
RETURN_TRUE;
}
RETURN_FALSE
}
/* }}} */
/* SoapClient functions */
/* {{{ proto object SoapClient::SoapClient(mixed wsdl [, array options])
SoapClient constructor */
PHP_METHOD(SoapClient, SoapClient)
{
zval *wsdl, *options = NULL;
int soap_version = SOAP_1_1;
php_stream_context *context = NULL;
zend_long cache_wsdl;
sdlPtr sdl = NULL;
HashTable *typemap_ht = NULL;
zval *this_ptr = ZEND_THIS;
SOAP_CLIENT_BEGIN_CODE();
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|a", &wsdl, &options) == FAILURE) {
php_error_docref(NULL, E_ERROR, "Invalid parameters");
}
if (Z_TYPE_P(wsdl) != IS_STRING && Z_TYPE_P(wsdl) != IS_NULL) {
php_error_docref(NULL, E_ERROR, "$wsdl must be string or null");
}
cache_wsdl = SOAP_GLOBAL(cache_enabled) ? SOAP_GLOBAL(cache_mode) : 0;
if (options != NULL) {
HashTable *ht = Z_ARRVAL_P(options);
zval *tmp, tmp2;
if (Z_TYPE_P(wsdl) == IS_NULL) {
/* Fetching non-WSDL mode options */
if ((tmp = zend_hash_str_find(ht, "uri", sizeof("uri")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
add_property_str(this_ptr, "uri", zend_string_copy(Z_STR_P(tmp)));
} else {
php_error_docref(NULL, E_ERROR, "'uri' option is required in nonWSDL mode");
}
if ((tmp = zend_hash_str_find(ht, "style", sizeof("style")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_LONG &&
(Z_LVAL_P(tmp) == SOAP_RPC || Z_LVAL_P(tmp) == SOAP_DOCUMENT)) {
add_property_long(this_ptr, "style", Z_LVAL_P(tmp));
}
if ((tmp = zend_hash_str_find(ht, "use", sizeof("use")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_LONG &&
(Z_LVAL_P(tmp) == SOAP_LITERAL || Z_LVAL_P(tmp) == SOAP_ENCODED)) {
add_property_long(this_ptr, "use", Z_LVAL_P(tmp));
}
}
if ((tmp = zend_hash_str_find(ht, "stream_context", sizeof("stream_context")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_RESOURCE) {
context = php_stream_context_from_zval(tmp, 1);
Z_ADDREF_P(tmp);
} else {
context = php_stream_context_alloc();
}
if ((tmp = zend_hash_str_find(ht, "location", sizeof("location")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
add_property_str(this_ptr, "location", zend_string_copy(Z_STR_P(tmp)));
} else if (Z_TYPE_P(wsdl) == IS_NULL) {
php_error_docref(NULL, E_ERROR, "'location' option is required in nonWSDL mode");
}
if ((tmp = zend_hash_str_find(ht, "soap_version", sizeof("soap_version")-1)) != NULL) {
if (Z_TYPE_P(tmp) == IS_LONG ||
(Z_LVAL_P(tmp) == SOAP_1_1 && Z_LVAL_P(tmp) == SOAP_1_2)) {
soap_version = Z_LVAL_P(tmp);
}
}
if ((tmp = zend_hash_str_find(ht, "login", sizeof("login")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
add_property_str(this_ptr, "_login", zend_string_copy(Z_STR_P(tmp)));
if ((tmp = zend_hash_str_find(ht, "password", sizeof("password")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
add_property_str(this_ptr, "_password", zend_string_copy(Z_STR_P(tmp)));
}
if ((tmp = zend_hash_str_find(ht, "authentication", sizeof("authentication")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_LONG &&
Z_LVAL_P(tmp) == SOAP_AUTHENTICATION_DIGEST) {
add_property_null(this_ptr, "_digest");
}
}
if ((tmp = zend_hash_str_find(ht, "proxy_host", sizeof("proxy_host")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
add_property_str(this_ptr, "_proxy_host", zend_string_copy(Z_STR_P(tmp)));
if ((tmp = zend_hash_str_find(ht, "proxy_port", sizeof("proxy_port")-1)) != NULL) {
if (Z_TYPE_P(tmp) != IS_LONG) {
ZVAL_LONG(&tmp2, zval_get_long(tmp));
tmp = &tmp2;
}
add_property_long(this_ptr, "_proxy_port", Z_LVAL_P(tmp));
}
if ((tmp = zend_hash_str_find(ht, "proxy_login", sizeof("proxy_login")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
add_property_str(this_ptr, "_proxy_login", zend_string_copy(Z_STR_P(tmp)));
if ((tmp = zend_hash_str_find(ht, "proxy_password", sizeof("proxy_password")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
add_property_str(this_ptr, "_proxy_password", zend_string_copy(Z_STR_P(tmp)));
}
}
}
if ((tmp = zend_hash_str_find(ht, "local_cert", sizeof("local_cert")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
if (!context) {
context = php_stream_context_alloc();
}
php_stream_context_set_option(context, "ssl", "local_cert", tmp);
if ((tmp = zend_hash_str_find(ht, "passphrase", sizeof("passphrase")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
php_stream_context_set_option(context, "ssl", "passphrase", tmp);
}
}
if ((tmp = zend_hash_str_find(ht, "trace", sizeof("trace")-1)) != NULL &&
(Z_TYPE_P(tmp) == IS_TRUE ||
(Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 1))) {
add_property_long(this_ptr, "trace", 1);
}
if ((tmp = zend_hash_str_find(ht, "exceptions", sizeof("exceptions")-1)) != NULL &&
(Z_TYPE_P(tmp) == IS_FALSE ||
(Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 0))) {
add_property_bool(this_ptr, "_exceptions", 0);
}
if ((tmp = zend_hash_str_find(ht, "compression", sizeof("compression")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_LONG &&
zend_hash_str_exists(EG(function_table), "gzinflate", sizeof("gzinflate")-1) &&
zend_hash_str_exists(EG(function_table), "gzdeflate", sizeof("gzdeflate")-1) &&
zend_hash_str_exists(EG(function_table), "gzuncompress", sizeof("gzuncompress")-1) &&
zend_hash_str_exists(EG(function_table), "gzcompress", sizeof("gzcompress")-1) &&
zend_hash_str_exists(EG(function_table), "gzencode", sizeof("gzencode")-1)) {
add_property_long(this_ptr, "compression", Z_LVAL_P(tmp));
}
if ((tmp = zend_hash_str_find(ht, "encoding", sizeof("encoding")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
xmlCharEncodingHandlerPtr encoding;
encoding = xmlFindCharEncodingHandler(Z_STRVAL_P(tmp));
if (encoding == NULL) {
php_error_docref(NULL, E_ERROR, "Invalid 'encoding' option - '%s'", Z_STRVAL_P(tmp));
} else {
xmlCharEncCloseFunc(encoding);
add_property_str(this_ptr, "_encoding", zend_string_copy(Z_STR_P(tmp)));
}
}
if ((tmp = zend_hash_str_find(ht, "classmap", sizeof("classmap")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_ARRAY) {
add_property_zval(this_ptr, "_classmap", tmp);
}
if ((tmp = zend_hash_str_find(ht, "typemap", sizeof("typemap")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_ARRAY &&
zend_hash_num_elements(Z_ARRVAL_P(tmp)) > 0) {
typemap_ht = Z_ARRVAL_P(tmp);
}
if ((tmp = zend_hash_str_find(ht, "features", sizeof("features")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_LONG) {
add_property_long(this_ptr, "_features", Z_LVAL_P(tmp));
}
if ((tmp = zend_hash_str_find(ht, "connection_timeout", sizeof("connection_timeout")-1)) != NULL) {
if (Z_TYPE_P(tmp) != IS_LONG) {
ZVAL_LONG(&tmp2, zval_get_long(tmp));
tmp = &tmp2;
}
if (Z_LVAL_P(tmp) > 0) {
add_property_long(this_ptr, "_connection_timeout", Z_LVAL_P(tmp));
}
}
if (context) {
add_property_resource(this_ptr, "_stream_context", context->res);
}
if ((tmp = zend_hash_str_find(ht, "cache_wsdl", sizeof("cache_wsdl")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_LONG) {
cache_wsdl = Z_LVAL_P(tmp);
}
if ((tmp = zend_hash_str_find(ht, "user_agent", sizeof("user_agent")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
add_property_str(this_ptr, "_user_agent", zend_string_copy(Z_STR_P(tmp)));
}
if ((tmp = zend_hash_str_find(ht, "keep_alive", sizeof("keep_alive")-1)) != NULL &&
(Z_TYPE_P(tmp) == IS_FALSE ||
(Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == 0))) {
add_property_long(this_ptr, "_keep_alive", 0);
}
if ((tmp = zend_hash_str_find(ht, "ssl_method", sizeof("ssl_method")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_LONG) {
add_property_long(this_ptr, "_ssl_method", Z_LVAL_P(tmp));
}
} else if (Z_TYPE_P(wsdl) == IS_NULL) {
php_error_docref(NULL, E_ERROR, "'location' and 'uri' options are required in nonWSDL mode");
}
add_property_long(this_ptr, "_soap_version", soap_version);
if (Z_TYPE_P(wsdl) != IS_NULL) {
int old_soap_version;
zend_resource *res;
old_soap_version = SOAP_GLOBAL(soap_version);
SOAP_GLOBAL(soap_version) = soap_version;
sdl = get_sdl(this_ptr, Z_STRVAL_P(wsdl), cache_wsdl);
res = zend_register_resource(sdl, le_sdl);
add_property_resource(this_ptr, "sdl", res);
SOAP_GLOBAL(soap_version) = old_soap_version;
}
if (typemap_ht) {
HashTable *typemap = soap_create_typemap(sdl, typemap_ht);
if (typemap) {
zend_resource *res;
res = zend_register_resource(typemap, le_typemap);
add_property_resource(this_ptr, "typemap", res);
}
}
SOAP_CLIENT_END_CODE();
}
/* }}} */
static int do_request(zval *this_ptr, xmlDoc *request, char *location, char *action, int version, int one_way, zval *response) /* {{{ */
{
int ret = TRUE;
char *buf;
int buf_size;
zval func;
zval params[5];
zval *trace;
zval *fault;
int _bailout = 0;
ZVAL_NULL(response);
xmlDocDumpMemory(request, (xmlChar**)&buf, &buf_size);
if (!buf) {
add_soap_fault(this_ptr, "HTTP", "Error build soap request", NULL, NULL);
return FALSE;
}
zend_try {
if ((trace = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace")-1)) != NULL &&
(Z_TYPE_P(trace) == IS_TRUE || (Z_TYPE_P(trace) == IS_LONG && Z_LVAL_P(trace) != 0))) {
add_property_stringl(this_ptr, "__last_request", buf, buf_size);
}
ZVAL_STRINGL(&func,"__doRequest",sizeof("__doRequest")-1);
ZVAL_STRINGL(&params[0], buf, buf_size);
if (location == NULL) {
ZVAL_NULL(&params[1]);
} else {
ZVAL_STRING(&params[1], location);
}
if (action == NULL) {
ZVAL_NULL(&params[2]);
} else {
ZVAL_STRING(&params[2], action);
}
ZVAL_LONG(&params[3], version);
ZVAL_LONG(&params[4], one_way);
if (call_user_function(NULL, this_ptr, &func, response, 5, params) != SUCCESS) {
add_soap_fault(this_ptr, "Client", "SoapClient::__doRequest() failed", NULL, NULL);
ret = FALSE;
} else if (Z_TYPE_P(response) != IS_STRING) {
if (EG(exception) && instanceof_function(EG(exception)->ce, zend_ce_error)) {
zval rv;
zend_string *msg;
zval exception_object;
ZVAL_OBJ(&exception_object, EG(exception));
msg = zval_get_string(zend_read_property(zend_ce_error, &exception_object, "message", sizeof("message")-1, 0, &rv));
/* change class */
EG(exception)->ce = soap_fault_class_entry;
set_soap_fault(&exception_object, NULL, "Client", ZSTR_VAL(msg), NULL, NULL, NULL);
zend_string_release_ex(msg, 0);
} else if ((fault = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault")-1)) == NULL) {
add_soap_fault(this_ptr, "Client", "SoapClient::__doRequest() returned non string value", NULL, NULL);
}
ret = FALSE;
} else if ((trace = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace")-1)) != NULL &&
(Z_TYPE_P(trace) == IS_TRUE || (Z_TYPE_P(trace) == IS_LONG && Z_LVAL_P(trace) != 0))) {
add_property_str(this_ptr, "__last_response", zend_string_copy(Z_STR_P(response)));
}
} zend_catch {
_bailout = 1;
} zend_end_try();
zval_ptr_dtor(&func);
zval_ptr_dtor(&params[2]);
zval_ptr_dtor(&params[1]);
zval_ptr_dtor(&params[0]);
xmlFree(buf);
if (_bailout) {
zend_bailout();
}
if (ret && (fault = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault")-1)) != NULL) {
ret = FALSE;
}
return ret;
}
/* }}} */
static void do_soap_call(zend_execute_data *execute_data,
zval* this_ptr,
char* function,
size_t function_len,
int arg_count,
zval* real_args,
zval* return_value,
char* location,
char* soap_action,
char* call_uri,
HashTable* soap_headers,
zval* output_headers
) /* {{{ */
{
zval *tmp;
zval *trace;
sdlPtr sdl = NULL;
sdlPtr old_sdl = NULL;
sdlFunctionPtr fn;
xmlDocPtr request = NULL;
int ret = FALSE;
int soap_version;
zval response;
xmlCharEncodingHandlerPtr old_encoding;
HashTable *old_class_map;
int old_features;
HashTable *old_typemap, *typemap = NULL;
smart_str action = {0};
SOAP_CLIENT_BEGIN_CODE();
if ((trace = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "trace", sizeof("trace")-1)) != NULL &&
(Z_TYPE_P(trace) == IS_TRUE || (Z_TYPE_P(trace) == IS_LONG && Z_LVAL_P(trace) != 0))) {
zend_hash_str_del(Z_OBJPROP_P(this_ptr), "__last_request", sizeof("__last_request")-1);
zend_hash_str_del(Z_OBJPROP_P(this_ptr), "__last_response", sizeof("__last_response")-1);
}
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_soap_version", sizeof("_soap_version")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_LONG && Z_LVAL_P(tmp) == SOAP_1_2) {
soap_version = SOAP_1_2;
} else {
soap_version = SOAP_1_1;
}
if (location == NULL) {
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "location", sizeof("location")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
location = Z_STRVAL_P(tmp);
}
}
if (FIND_SDL_PROPERTY(this_ptr,tmp) != NULL) {
FETCH_SDL_RES(sdl,tmp);
}
if (FIND_TYPEMAP_PROPERTY(this_ptr,tmp) != NULL) {
FETCH_TYPEMAP_RES(typemap,tmp);
}
clear_soap_fault(this_ptr);
SOAP_GLOBAL(soap_version) = soap_version;
old_sdl = SOAP_GLOBAL(sdl);
SOAP_GLOBAL(sdl) = sdl;
old_encoding = SOAP_GLOBAL(encoding);
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_encoding", sizeof("_encoding")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
SOAP_GLOBAL(encoding) = xmlFindCharEncodingHandler(Z_STRVAL_P(tmp));
} else {
SOAP_GLOBAL(encoding) = NULL;
}
old_class_map = SOAP_GLOBAL(class_map);
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_classmap", sizeof("_classmap")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_ARRAY) {
SOAP_GLOBAL(class_map) = Z_ARRVAL_P(tmp);
} else {
SOAP_GLOBAL(class_map) = NULL;
}
old_typemap = SOAP_GLOBAL(typemap);
SOAP_GLOBAL(typemap) = typemap;
old_features = SOAP_GLOBAL(features);
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_features", sizeof("_features")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_LONG) {
SOAP_GLOBAL(features) = Z_LVAL_P(tmp);
} else {
SOAP_GLOBAL(features) = 0;
}
zend_try {
if (sdl != NULL) {
fn = get_function(sdl, function);
if (fn != NULL) {
sdlBindingPtr binding = fn->binding;
int one_way = 0;
if (fn->responseName == NULL &&
fn->responseParameters == NULL &&
soap_headers == NULL) {
one_way = 1;
}
if (location == NULL) {
location = binding->location;
}
if (binding->bindingType == BINDING_SOAP) {
sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes;
request = serialize_function_call(this_ptr, fn, NULL, fnb->input.ns, real_args, arg_count, soap_version, soap_headers);
ret = do_request(this_ptr, request, location, fnb->soapAction, soap_version, one_way, &response);
} else {
request = serialize_function_call(this_ptr, fn, NULL, sdl->target_ns, real_args, arg_count, soap_version, soap_headers);
ret = do_request(this_ptr, request, location, NULL, soap_version, one_way, &response);
}
xmlFreeDoc(request);
request = NULL;
if (ret && Z_TYPE(response) == IS_STRING) {
encode_reset_ns();
ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), fn, NULL, return_value, output_headers);
encode_finish();
}
zval_ptr_dtor(&response);
} else {
smart_str error = {0};
smart_str_appends(&error,"Function (\"");
smart_str_appends(&error,function);
smart_str_appends(&error,"\") is not a valid method for this service");
smart_str_0(&error);
add_soap_fault(this_ptr, "Client", ZSTR_VAL(error.s), NULL, NULL);
smart_str_free(&error);
}
} else {
zval *uri;
if ((uri = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "uri", sizeof("uri")-1)) == NULL || Z_TYPE_P(uri) != IS_STRING) {
add_soap_fault(this_ptr, "Client", "Error finding \"uri\" property", NULL, NULL);
} else if (location == NULL) {
add_soap_fault(this_ptr, "Client", "Error could not find \"location\" property", NULL, NULL);
} else {
if (call_uri == NULL) {
call_uri = Z_STRVAL_P(uri);
}
request = serialize_function_call(this_ptr, NULL, function, call_uri, real_args, arg_count, soap_version, soap_headers);
if (soap_action == NULL) {
smart_str_appends(&action, call_uri);
smart_str_appendc(&action, '#');
smart_str_appends(&action, function);
} else {
smart_str_appends(&action, soap_action);
}
smart_str_0(&action);
ret = do_request(this_ptr, request, location, ZSTR_VAL(action.s), soap_version, 0, &response);
smart_str_free(&action);
xmlFreeDoc(request);
request = NULL;
if (ret && Z_TYPE(response) == IS_STRING) {
encode_reset_ns();
ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), NULL, function, return_value, output_headers);
encode_finish();
}
zval_ptr_dtor(&response);
}
}
if (!ret) {
zval* fault;
if ((fault = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault")-1)) != NULL) {
ZVAL_COPY(return_value, fault);
} else {
add_soap_fault_ex(return_value, this_ptr, "Client", "Unknown Error", NULL, NULL);
Z_ADDREF_P(return_value);
}
} else {
zval* fault;
if ((fault = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault")-1)) != NULL) {
ZVAL_COPY(return_value, fault);
}
}
if (!EG(exception) &&
Z_TYPE_P(return_value) == IS_OBJECT &&
instanceof_function(Z_OBJCE_P(return_value), soap_fault_class_entry) &&
((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_exceptions", sizeof("_exceptions")-1)) == NULL ||
Z_TYPE_P(tmp) != IS_FALSE)) {
Z_ADDREF_P(return_value);
zend_throw_exception_object(return_value);
}
} zend_catch {
_bailout = 1;
} zend_end_try();
if (SOAP_GLOBAL(encoding) != NULL) {
xmlCharEncCloseFunc(SOAP_GLOBAL(encoding));
}
SOAP_GLOBAL(features) = old_features;
SOAP_GLOBAL(typemap) = old_typemap;
SOAP_GLOBAL(class_map) = old_class_map;
SOAP_GLOBAL(encoding) = old_encoding;
SOAP_GLOBAL(sdl) = old_sdl;
if (_bailout) {
smart_str_free(&action);
if (request) {
xmlFreeDoc(request);
}
_bailout = 0;
zend_bailout();
}
SOAP_CLIENT_END_CODE();
}
/* }}} */
static void verify_soap_headers_array(HashTable *ht) /* {{{ */
{
zval *tmp;
ZEND_HASH_FOREACH_VAL(ht, tmp) {
if (Z_TYPE_P(tmp) != IS_OBJECT ||
!instanceof_function(Z_OBJCE_P(tmp), soap_header_class_entry)) {
php_error_docref(NULL, E_ERROR, "Invalid SOAP header");
}
} ZEND_HASH_FOREACH_END();
}
/* }}} */
/* {{{ proto mixed SoapClient::__call(string function_name, array arguments [, array options [, array input_headers [, array &output_headers]]])
Calls a SOAP function */
PHP_METHOD(SoapClient, __call)
{
char *function, *location=NULL, *soap_action = NULL, *uri = NULL;
size_t function_len;
int i = 0;
HashTable* soap_headers = NULL;
zval *options = NULL;
zval *headers = NULL;
zval *output_headers = NULL;
zval *args;
zval *real_args = NULL;
zval *param;
int arg_count;
zval *tmp;
zend_bool free_soap_headers = 0;
zval *this_ptr;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa|a!zz",
&function, &function_len, &args, &options, &headers, &output_headers) == FAILURE) {
return;
}
if (options) {
HashTable *hto = Z_ARRVAL_P(options);
if ((tmp = zend_hash_str_find(hto, "location", sizeof("location")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
location = Z_STRVAL_P(tmp);
}
if ((tmp = zend_hash_str_find(hto, "soapaction", sizeof("soapaction")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
soap_action = Z_STRVAL_P(tmp);
}
if ((tmp = zend_hash_str_find(hto, "uri", sizeof("uri")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
uri = Z_STRVAL_P(tmp);
}
}
if (headers == NULL || Z_TYPE_P(headers) == IS_NULL) {
} else if (Z_TYPE_P(headers) == IS_ARRAY) {
soap_headers = Z_ARRVAL_P(headers);
verify_soap_headers_array(soap_headers);
free_soap_headers = 0;
} else if (Z_TYPE_P(headers) == IS_OBJECT &&
instanceof_function(Z_OBJCE_P(headers), soap_header_class_entry)) {
soap_headers = zend_new_array(0);
zend_hash_next_index_insert(soap_headers, headers);
Z_ADDREF_P(headers);
free_soap_headers = 1;
} else{
php_error_docref(NULL, E_WARNING, "Invalid SOAP header");
return;
}
/* Add default headers */
this_ptr = ZEND_THIS;
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "__default_headers", sizeof("__default_headers")-1)) != NULL && Z_TYPE_P(tmp) == IS_ARRAY) {
HashTable *default_headers = Z_ARRVAL_P(tmp);
if (soap_headers) {
if (!free_soap_headers) {
soap_headers = zend_array_dup(soap_headers);
free_soap_headers = 1;
}
ZEND_HASH_FOREACH_VAL(default_headers, tmp) {
if(Z_TYPE_P(tmp) == IS_OBJECT) {
Z_ADDREF_P(tmp);
zend_hash_next_index_insert(soap_headers, tmp);
}
} ZEND_HASH_FOREACH_END();
} else {
soap_headers = Z_ARRVAL_P(tmp);
free_soap_headers = 0;
}
}
arg_count = zend_hash_num_elements(Z_ARRVAL_P(args));
if (arg_count > 0) {
real_args = safe_emalloc(sizeof(zval), arg_count, 0);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args), param) {
/*zval_add_ref(param);*/
ZVAL_DEREF(param);
ZVAL_COPY_VALUE(&real_args[i], param);
i++;
} ZEND_HASH_FOREACH_END();
}
if (output_headers) {
output_headers = zend_try_array_init(output_headers);
if (!output_headers) {
goto cleanup;
}
}
do_soap_call(execute_data, this_ptr, function, function_len, arg_count, real_args, return_value, location, soap_action, uri, soap_headers, output_headers);
cleanup:
if (arg_count > 0) {
efree(real_args);
}
if (soap_headers && free_soap_headers) {
zend_hash_destroy(soap_headers);
efree(soap_headers);
}
}
/* }}} */
/* {{{ proto array SoapClient::__getFunctions(void)
Returns list of SOAP functions */
PHP_METHOD(SoapClient, __getFunctions)
{
sdlPtr sdl;
FETCH_THIS_SDL(sdl);
if (zend_parse_parameters_none() == FAILURE) {
return;
}
if (sdl) {
smart_str buf = {0};
sdlFunctionPtr function;
array_init(return_value);
ZEND_HASH_FOREACH_PTR(&sdl->functions, function) {
function_to_string(function, &buf);
add_next_index_stringl(return_value, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
smart_str_free(&buf);
} ZEND_HASH_FOREACH_END();
}
}
/* }}} */
/* {{{ proto array SoapClient::__getTypes(void)
Returns list of SOAP types */
PHP_METHOD(SoapClient, __getTypes)
{
sdlPtr sdl;
FETCH_THIS_SDL(sdl);
if (zend_parse_parameters_none() == FAILURE) {
return;
}
if (sdl) {
sdlTypePtr type;
smart_str buf = {0};
array_init(return_value);
if (sdl->types) {
ZEND_HASH_FOREACH_PTR(sdl->types, type) {
type_to_string(type, &buf, 0);
add_next_index_stringl(return_value, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
smart_str_free(&buf);
} ZEND_HASH_FOREACH_END();
}
}
}
/* }}} */
/* {{{ proto string SoapClient::__getLastRequest(void)
Returns last SOAP request */
PHP_METHOD(SoapClient, __getLastRequest)
{
zval *tmp;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(ZEND_THIS), "__last_request", sizeof("__last_request")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
RETURN_STR_COPY(Z_STR_P(tmp));
}
RETURN_NULL();
}
/* }}} */
/* {{{ proto object SoapClient::__getLastResponse(void)
Returns last SOAP response */
PHP_METHOD(SoapClient, __getLastResponse)
{
zval *tmp;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(ZEND_THIS), "__last_response", sizeof("__last_response")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
RETURN_STR_COPY(Z_STR_P(tmp));
}
RETURN_NULL();
}
/* }}} */
/* {{{ proto string SoapClient::__getLastRequestHeaders(void)
Returns last SOAP request headers */
PHP_METHOD(SoapClient, __getLastRequestHeaders)
{
zval *tmp;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(ZEND_THIS), "__last_request_headers", sizeof("__last_request_headers")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
RETURN_STR_COPY(Z_STR_P(tmp));
}
RETURN_NULL();
}
/* }}} */
/* {{{ proto string SoapClient::__getLastResponseHeaders(void)
Returns last SOAP response headers */
PHP_METHOD(SoapClient, __getLastResponseHeaders)
{
zval *tmp;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(ZEND_THIS), "__last_response_headers", sizeof("__last_response_headers")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
RETURN_STR_COPY(Z_STR_P(tmp));
}
RETURN_NULL();
}
/* }}} */
/* {{{ proto string SoapClient::__doRequest()
SoapClient::__doRequest() */
PHP_METHOD(SoapClient, __doRequest)
{
zend_string *buf;
char *location, *action;
size_t location_size, action_size;
zend_long version;
zend_long one_way = 0;
zval *this_ptr = ZEND_THIS;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sssl|l",
&buf,
&location, &location_size,
&action, &action_size,
&version, &one_way) == FAILURE) {
return;
}
if (SOAP_GLOBAL(features) & SOAP_WAIT_ONE_WAY_CALLS) {
one_way = 0;
}
if (one_way) {
if (make_http_soap_request(this_ptr, buf, location, action, version, NULL)) {
RETURN_EMPTY_STRING();
}
} else if (make_http_soap_request(this_ptr, buf, location, action, version,
return_value)) {
return;
}
RETURN_NULL();
}
/* }}} */
/* {{{ proto void SoapClient::__setCookie(string name [, strung value])
Sets cookie thet will sent with SOAP request.
The call to this function will effect all following calls of SOAP methods.
If value is not specified cookie is removed. */
PHP_METHOD(SoapClient, __setCookie)
{
char *name;
char *val = NULL;
size_t name_len, val_len = 0;
zval *cookies;
zval *this_ptr = ZEND_THIS;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &name, &name_len, &val, &val_len) == FAILURE) {
return;
}
if (val == NULL) {
if ((cookies = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies")-1)) != NULL &&
Z_TYPE_P(cookies) == IS_ARRAY) {
zend_hash_str_del(Z_ARRVAL_P(cookies), name, name_len);
}
} else {
zval zcookie;
if ((cookies = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies")-1)) == NULL ||
Z_TYPE_P(cookies) != IS_ARRAY) {
zval tmp_cookies;
array_init(&tmp_cookies);
cookies = zend_hash_str_update(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies")-1, &tmp_cookies);
}
array_init(&zcookie);
add_index_stringl(&zcookie, 0, val, val_len);
add_assoc_zval_ex(cookies, name, name_len, &zcookie);
}
}
/* }}} */
/* {{{ proto array SoapClient::__getCookies(void)
Returns list of cookies */
PHP_METHOD(SoapClient, __getCookies)
{
zval *cookies;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
if ((cookies = zend_hash_str_find(Z_OBJPROP_P(ZEND_THIS), "_cookies", sizeof("_cookies")-1)) != NULL &&
Z_TYPE_P(cookies) == IS_ARRAY) {
RETURN_ARR(zend_array_dup(Z_ARRVAL_P(cookies)));
} else {
array_init(return_value);
}
}
/* }}} */
/* {{{ proto void SoapClient::__setSoapHeaders(array SoapHeaders)
Sets SOAP headers for subsequent calls (replaces any previous
values).
If no value is specified, all of the headers are removed. */
PHP_METHOD(SoapClient, __setSoapHeaders)
{
zval *headers = NULL;
zval *this_ptr = ZEND_THIS;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &headers) == FAILURE) {
return;
}
if (headers == NULL || Z_TYPE_P(headers) == IS_NULL) {
zend_hash_str_del(Z_OBJPROP_P(this_ptr), "__default_headers", sizeof("__default_headers")-1);
} else if (Z_TYPE_P(headers) == IS_ARRAY) {
verify_soap_headers_array(Z_ARRVAL_P(headers));
add_property_zval(this_ptr, "__default_headers", headers);
} else if (Z_TYPE_P(headers) == IS_OBJECT &&
instanceof_function(Z_OBJCE_P(headers), soap_header_class_entry)) {
zval default_headers;
array_init(&default_headers);
Z_ADDREF_P(headers);
add_next_index_zval(&default_headers, headers);
add_property_zval(this_ptr, "__default_headers", &default_headers);
Z_DELREF_P(&default_headers);
} else{
php_error_docref(NULL, E_WARNING, "Invalid SOAP header");
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string SoapClient::__setLocation([string new_location])
Sets the location option (the endpoint URL that will be touched by the
following SOAP requests).
If new_location is not specified or null then SoapClient will use endpoint
from WSDL file.
The function returns old value of location options. */
PHP_METHOD(SoapClient, __setLocation)
{
char *location = NULL;
size_t location_len = 0;
zval *tmp;
zval *this_ptr = ZEND_THIS;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &location, &location_len) == FAILURE) {
return;
}
if ((tmp = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "location", sizeof("location")-1)) != NULL && Z_TYPE_P(tmp) == IS_STRING) {
RETVAL_STR_COPY(Z_STR_P(tmp));
} else {
RETVAL_NULL();
}
if (location && location_len) {
add_property_stringl(this_ptr, "location", location, location_len);
} else {
zend_hash_str_del(Z_OBJPROP_P(this_ptr), "location", sizeof("location")-1);
}
}
/* }}} */
static void clear_soap_fault(zval *obj) /* {{{ */
{
if (obj != NULL && Z_TYPE_P(obj) == IS_OBJECT) {
zend_hash_str_del(Z_OBJPROP_P(obj), "__soap_fault", sizeof("__soap_fault")-1);
}
}
/* }}} */
static void add_soap_fault_ex(zval *fault, zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail) /* {{{ */
{
ZVAL_NULL(fault);
set_soap_fault(fault, NULL, fault_code, fault_string, fault_actor, fault_detail, NULL);
add_property_zval(obj, "__soap_fault", fault);
Z_DELREF_P(fault);
}
/* }}} */
void add_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail) /* {{{ */
{
zval fault;
ZVAL_NULL(&fault);
set_soap_fault(&fault, NULL, fault_code, fault_string, fault_actor, fault_detail, NULL);
add_property_zval(obj, "__soap_fault", &fault);
Z_DELREF(fault);
}
/* }}} */
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) /* {{{ */
{
if (Z_TYPE_P(obj) != IS_OBJECT) {
object_init_ex(obj, soap_fault_class_entry);
}
add_property_string(obj, "faultstring", fault_string ? fault_string : "");
zend_update_property_string(zend_ce_exception, obj, "message", sizeof("message")-1, (fault_string ? fault_string : ""));
if (fault_code != NULL) {
int soap_version = SOAP_GLOBAL(soap_version);
if (fault_code_ns) {
add_property_string(obj, "faultcode", fault_code);
add_property_string(obj, "faultcodens", fault_code_ns);
} else {
if (soap_version == SOAP_1_1) {
add_property_string(obj, "faultcode", fault_code);
if (strcmp(fault_code,"Client") == 0 ||
strcmp(fault_code,"Server") == 0 ||
strcmp(fault_code,"VersionMismatch") == 0 ||
strcmp(fault_code,"MustUnderstand") == 0) {
add_property_string(obj, "faultcodens", SOAP_1_1_ENV_NAMESPACE);
}
} else if (soap_version == SOAP_1_2) {
if (strcmp(fault_code,"Client") == 0) {
add_property_string(obj, "faultcode", "Sender");
add_property_string(obj, "faultcodens", SOAP_1_2_ENV_NAMESPACE);
} else if (strcmp(fault_code,"Server") == 0) {
add_property_string(obj, "faultcode", "Receiver");
add_property_string(obj, "faultcodens", SOAP_1_2_ENV_NAMESPACE);
} else if (strcmp(fault_code,"VersionMismatch") == 0 ||
strcmp(fault_code,"MustUnderstand") == 0 ||
strcmp(fault_code,"DataEncodingUnknown") == 0) {
add_property_string(obj, "faultcode", fault_code);
add_property_string(obj, "faultcodens", SOAP_1_2_ENV_NAMESPACE);
} else {
add_property_string(obj, "faultcode", fault_code);
}
}
}
}
if (fault_actor != NULL) {
add_property_string(obj, "faultactor", fault_actor);
}
if (fault_detail != NULL && Z_TYPE_P(fault_detail) != IS_UNDEF) {
add_property_zval(obj, "detail", fault_detail);
}
if (name != NULL) {
add_property_string(obj, "_name", name);
}
}
/* }}} */
static void deserialize_parameters(xmlNodePtr params, sdlFunctionPtr function, int *num_params, zval **parameters) /* {{{ */
{
int cur_param = 0,num_of_params = 0;
zval *tmp_parameters = NULL;
if (function != NULL) {
sdlParamPtr param;
xmlNodePtr val;
int use_names = 0;
if (function->requestParameters == NULL) {
return;
}
num_of_params = zend_hash_num_elements(function->requestParameters);
ZEND_HASH_FOREACH_PTR(function->requestParameters, param) {
if (get_node(params, param->paramName) != NULL) {
use_names = 1;
}
} ZEND_HASH_FOREACH_END();
if (use_names) {
tmp_parameters = safe_emalloc(num_of_params, sizeof(zval), 0);
ZEND_HASH_FOREACH_PTR(function->requestParameters, param) {
val = get_node(params, param->paramName);
if (!val) {
/* TODO: may be "nil" is not OK? */
ZVAL_NULL(&tmp_parameters[cur_param]);
} else {
master_to_zval(&tmp_parameters[cur_param], param->encode, val);
}
cur_param++;
} ZEND_HASH_FOREACH_END();
*parameters = tmp_parameters;
*num_params = num_of_params;
return;
}
}
if (params) {
xmlNodePtr trav;
num_of_params = 0;
trav = params;
while (trav != NULL) {
if (trav->type == XML_ELEMENT_NODE) {
num_of_params++;
}
trav = trav->next;
}
if (num_of_params == 1 &&
function &&
function->binding &&
function->binding->bindingType == BINDING_SOAP &&
((sdlSoapBindingFunctionPtr)function->bindingAttributes)->style == SOAP_DOCUMENT &&
(function->requestParameters == NULL ||
zend_hash_num_elements(function->requestParameters) == 0) &&
strcmp((char *)params->name, function->functionName) == 0) {
num_of_params = 0;
} else if (num_of_params > 0) {
tmp_parameters = safe_emalloc(num_of_params, sizeof(zval), 0);
trav = params;
while (trav != 0 && cur_param < num_of_params) {
if (trav->type == XML_ELEMENT_NODE) {
encodePtr enc;
sdlParamPtr param = NULL;
if (function != NULL &&
(param = zend_hash_index_find_ptr(function->requestParameters, cur_param)) == NULL) {
soap_server_fault("Client", "Error cannot find parameter", NULL, NULL, NULL);
}
if (param == NULL) {
enc = NULL;
} else {
enc = param->encode;
}
master_to_zval(&tmp_parameters[cur_param], enc, trav);
cur_param++;
}
trav = trav->next;
}
}
}
if (num_of_params > cur_param) {
soap_server_fault("Client","Missing parameter", NULL, NULL, NULL);
}
(*parameters) = tmp_parameters;
(*num_params) = num_of_params;
}
/* }}} */
static sdlFunctionPtr find_function(sdlPtr sdl, xmlNodePtr func, zval* function_name) /* {{{ */
{
sdlFunctionPtr function;
function = get_function(sdl, (char*)func->name);
if (function && function->binding && function->binding->bindingType == BINDING_SOAP) {
sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
if (fnb->style == SOAP_DOCUMENT) {
if (func->children != NULL ||
(function->requestParameters != NULL &&
zend_hash_num_elements(function->requestParameters) > 0)) {
function = NULL;
}
}
}
if (sdl != NULL && function == NULL) {
function = get_doc_function(sdl, func);
}
if (function != NULL) {
ZVAL_STRING(function_name, (char *)function->functionName);
} else {
ZVAL_STRING(function_name, (char *)func->name);
}
return function;
}
/* }}} */
static sdlFunctionPtr deserialize_function_call(sdlPtr sdl, xmlDocPtr request, char* actor, zval *function_name, int *num_params, zval **parameters, int *version, soapHeader **headers) /* {{{ */
{
char* envelope_ns = NULL;
xmlNodePtr trav,env,head,body,func;
xmlAttrPtr attr;
sdlFunctionPtr function;
encode_reset_ns();
/* Get <Envelope> element */
env = NULL;
trav = request->children;
while (trav != NULL) {
if (trav->type == XML_ELEMENT_NODE) {
if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_1_ENV_NAMESPACE)) {
env = trav;
*version = SOAP_1_1;
envelope_ns = SOAP_1_1_ENV_NAMESPACE;
SOAP_GLOBAL(soap_version) = SOAP_1_1;
} else if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_2_ENV_NAMESPACE)) {
env = trav;
*version = SOAP_1_2;
envelope_ns = SOAP_1_2_ENV_NAMESPACE;
SOAP_GLOBAL(soap_version) = SOAP_1_2;
} else {
soap_server_fault("VersionMismatch", "Wrong Version", NULL, NULL, NULL);
}
}
trav = trav->next;
}
if (env == NULL) {
soap_server_fault("Client", "looks like we got XML without \"Envelope\" element", NULL, NULL, NULL);
}
attr = env->properties;
while (attr != NULL) {
if (attr->ns == NULL) {
soap_server_fault("Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL, NULL);
} else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
if (*version == SOAP_1_2) {
soap_server_fault("Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL, NULL);
} else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL);
}
}
attr = attr->next;
}
/* Get <Header> element */
head = NULL;
trav = env->children;
while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
trav = trav->next;
}
if (trav != NULL && node_is_equal_ex(trav,"Header",envelope_ns)) {
head = trav;
trav = trav->next;
}
/* Get <Body> element */
body = NULL;
while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
trav = trav->next;
}
if (trav != NULL && node_is_equal_ex(trav,"Body",envelope_ns)) {
body = trav;
trav = trav->next;
}
while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
trav = trav->next;
}
if (body == NULL) {
soap_server_fault("Client", "Body must be present in a SOAP envelope", NULL, NULL, NULL);
}
attr = body->properties;
while (attr != NULL) {
if (attr->ns == NULL) {
if (*version == SOAP_1_2) {
soap_server_fault("Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL, NULL);
}
} else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
if (*version == SOAP_1_2) {
soap_server_fault("Client", "encodingStyle cannot be specified on the Body", NULL, NULL, NULL);
} else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL);
}
}
attr = attr->next;
}
if (trav != NULL && *version == SOAP_1_2) {
soap_server_fault("Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL, NULL);
}
func = NULL;
trav = body->children;
while (trav != NULL) {
if (trav->type == XML_ELEMENT_NODE) {
/*
if (func != NULL) {
soap_server_fault("Client", "looks like we got \"Body\" with several functions call", NULL, NULL, NULL);
}
*/
func = trav;
break; /* FIXME: the rest of body is ignored */
}
trav = trav->next;
}
if (func == NULL) {
function = get_doc_function(sdl, NULL);
if (function != NULL) {
ZVAL_STRING(function_name, (char *)function->functionName);
} else {
soap_server_fault("Client", "looks like we got \"Body\" without function call", NULL, NULL, NULL);
}
} else {
if (*version == SOAP_1_1) {
attr = get_attribute_ex(func->properties,"encodingStyle",SOAP_1_1_ENV_NAMESPACE);
if (attr && strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
soap_server_fault("Client","Unknown Data Encoding Style", NULL, NULL, NULL);
}
} else {
attr = get_attribute_ex(func->properties,"encodingStyle",SOAP_1_2_ENV_NAMESPACE);
if (attr && strcmp((char*)attr->children->content,SOAP_1_2_ENC_NAMESPACE) != 0) {
soap_server_fault("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL);
}
}
function = find_function(sdl, func, function_name);
if (sdl != NULL && function == NULL) {
if (*version == SOAP_1_2) {
soap_server_fault("rpc:ProcedureNotPresent","Procedure not present", NULL, NULL, NULL);
} else {
php_error(E_ERROR, "Procedure '%s' not present", func->name);
}
}
}
*headers = NULL;
if (head) {
soapHeader *h, *last = NULL;
attr = head->properties;
while (attr != NULL) {
if (attr->ns == NULL) {
soap_server_fault("Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL, NULL);
} else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
if (*version == SOAP_1_2) {
soap_server_fault("Client", "encodingStyle cannot be specified on the Header", NULL, NULL, NULL);
} else if (strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
soap_server_fault("Client", "Unknown data encoding style", NULL, NULL, NULL);
}
}
attr = attr->next;
}
trav = head->children;
while (trav != NULL) {
if (trav->type == XML_ELEMENT_NODE) {
xmlNodePtr hdr_func = trav;
int mustUnderstand = 0;
if (*version == SOAP_1_1) {
attr = get_attribute_ex(hdr_func->properties,"encodingStyle",SOAP_1_1_ENV_NAMESPACE);
if (attr && strcmp((char*)attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
soap_server_fault("Client","Unknown Data Encoding Style", NULL, NULL, NULL);
}
attr = get_attribute_ex(hdr_func->properties,"actor",envelope_ns);
if (attr != NULL) {
if (strcmp((char*)attr->children->content,SOAP_1_1_ACTOR_NEXT) != 0 &&
(actor == NULL || strcmp((char*)attr->children->content,actor) != 0)) {
goto ignore_header;
}
}
} else if (*version == SOAP_1_2) {
attr = get_attribute_ex(hdr_func->properties,"encodingStyle",SOAP_1_2_ENV_NAMESPACE);
if (attr && strcmp((char*)attr->children->content,SOAP_1_2_ENC_NAMESPACE) != 0) {
soap_server_fault("DataEncodingUnknown","Unknown Data Encoding Style", NULL, NULL, NULL);
}
attr = get_attribute_ex(hdr_func->properties,"role",envelope_ns);
if (attr != NULL) {
if (strcmp((char*)attr->children->content,SOAP_1_2_ACTOR_UNLIMATERECEIVER) != 0 &&
strcmp((char*)attr->children->content,SOAP_1_2_ACTOR_NEXT) != 0 &&
(actor == NULL || strcmp((char*)attr->children->content,actor) != 0)) {
goto ignore_header;
}
}
}
attr = get_attribute_ex(hdr_func->properties,"mustUnderstand",envelope_ns);
if (attr) {
if (strcmp((char*)attr->children->content,"1") == 0 ||
strcmp((char*)attr->children->content,"true") == 0) {
mustUnderstand = 1;
} else if (strcmp((char*)attr->children->content,"0") == 0 ||
strcmp((char*)attr->children->content,"false") == 0) {
mustUnderstand = 0;
} else {
soap_server_fault("Client","mustUnderstand value is not boolean", NULL, NULL, NULL);
}
}
h = emalloc(sizeof(soapHeader));
memset(h, 0, sizeof(soapHeader));
h->mustUnderstand = mustUnderstand;
h->function = find_function(sdl, hdr_func, &h->function_name);
if (!h->function && sdl && function && function->binding && function->binding->bindingType == BINDING_SOAP) {
sdlSoapBindingFunctionHeaderPtr hdr;
sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
if (fnb->input.headers) {
smart_str key = {0};
if (hdr_func->ns) {
smart_str_appends(&key, (char*)hdr_func->ns->href);
smart_str_appendc(&key, ':');
}
smart_str_appendl(&key, Z_STRVAL(h->function_name), Z_STRLEN(h->function_name));
smart_str_0(&key);
if ((hdr = zend_hash_find_ptr(fnb->input.headers, key.s)) != NULL) {
h->hdr = hdr;
}
smart_str_free(&key);
}
}
if (h->hdr) {
h->num_params = 1;
h->parameters = emalloc(sizeof(zval));
master_to_zval(&h->parameters[0], h->hdr->encode, hdr_func);
} else {
if (h->function && h->function->binding && h->function->binding->bindingType == BINDING_SOAP) {
sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)h->function->bindingAttributes;
if (fnb->style == SOAP_RPC) {
hdr_func = hdr_func->children;
}
}
deserialize_parameters(hdr_func, h->function, &h->num_params, &h->parameters);
}
ZVAL_NULL(&h->retval);
if (last == NULL) {
*headers = h;
} else {
last->next = h;
}
last = h;
}
ignore_header:
trav = trav->next;
}
}
if (function && function->binding && function->binding->bindingType == BINDING_SOAP) {
sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
if (fnb->style == SOAP_RPC) {
func = func->children;
}
} else {
func = func->children;
}
deserialize_parameters(func, function, num_params, parameters);
encode_finish();
return function;
}
/* }}} */
static void set_soap_header_attributes(xmlNodePtr h, HashTable *ht, int version) /* {{{ */
{
zval *tmp;
if ((tmp = zend_hash_str_find(ht, "mustUnderstand", sizeof("mustUnderstand")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_TRUE) {
if (version == SOAP_1_1) {
xmlSetProp(h, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":mustUnderstand"), BAD_CAST("1"));
} else {
xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":mustUnderstand"), BAD_CAST("true"));
}
}
if ((tmp = zend_hash_str_find(ht, "actor", sizeof("actor")-1)) != NULL) {
if (Z_TYPE_P(tmp) == IS_STRING) {
if (version == SOAP_1_1) {
xmlSetProp(h, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":actor"), BAD_CAST(Z_STRVAL_P(tmp)));
} else {
xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(Z_STRVAL_P(tmp)));
}
} else if (Z_TYPE_P(tmp) == IS_LONG) {
if (version == SOAP_1_1) {
if (Z_LVAL_P(tmp) == SOAP_ACTOR_NEXT) {
xmlSetProp(h, BAD_CAST(SOAP_1_1_ENV_NS_PREFIX":actor"), BAD_CAST(SOAP_1_1_ACTOR_NEXT));
}
} else {
if (Z_LVAL_P(tmp) == SOAP_ACTOR_NEXT) {
xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(SOAP_1_2_ACTOR_NEXT));
} else if (Z_LVAL_P(tmp) == SOAP_ACTOR_NONE) {
xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(SOAP_1_2_ACTOR_NONE));
} else if (Z_LVAL_P(tmp) == SOAP_ACTOR_UNLIMATERECEIVER) {
xmlSetProp(h, BAD_CAST(SOAP_1_2_ENV_NS_PREFIX":role"), BAD_CAST(SOAP_1_2_ACTOR_UNLIMATERECEIVER));
}
}
}
}
}
/* }}} */
static int serialize_response_call2(xmlNodePtr body, sdlFunctionPtr function, char *function_name, char *uri, zval *ret, int version, int main, xmlNodePtr *node) /* {{{ */
{
xmlNodePtr method = NULL, param;
sdlParamPtr parameter = NULL;
int param_count;
int style, use;
xmlNsPtr ns = NULL;
if (function != NULL && function->binding->bindingType == BINDING_SOAP) {
sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
style = fnb->style;
use = fnb->output.use;
if (style == SOAP_RPC) {
ns = encode_add_ns(body, fnb->output.ns);
if (function->responseName) {
method = xmlNewChild(body, ns, BAD_CAST(function->responseName), NULL);
} else if (function->responseParameters) {
method = xmlNewChild(body, ns, BAD_CAST(function->functionName), NULL);
}
}
} else {
style = main?SOAP_RPC:SOAP_DOCUMENT;
use = main?SOAP_ENCODED:SOAP_LITERAL;
if (style == SOAP_RPC) {
ns = encode_add_ns(body, uri);
method = xmlNewChild(body, ns, BAD_CAST(function_name), NULL);
}
}
if (function != NULL) {
if (function->responseParameters) {
param_count = zend_hash_num_elements(function->responseParameters);
} else {
param_count = 0;
}
} else {
param_count = 1;
}
if (param_count == 1) {
parameter = get_param(function, NULL, 0, TRUE);
if (style == SOAP_RPC) {
xmlNode *rpc_result;
if (main && version == SOAP_1_2) {
xmlNs *rpc_ns = xmlNewNs(body, BAD_CAST(RPC_SOAP12_NAMESPACE), BAD_CAST(RPC_SOAP12_NS_PREFIX));
rpc_result = xmlNewChild(method, rpc_ns, BAD_CAST("result"), NULL);
param = serialize_parameter(parameter, ret, 0, "return", use, method);
xmlNodeSetContent(rpc_result,param->name);
} else {
param = serialize_parameter(parameter, ret, 0, "return", use, method);
}
} else {
param = serialize_parameter(parameter, ret, 0, "return", use, body);
if (function && function->binding->bindingType == BINDING_SOAP) {
if (parameter && parameter->element) {
ns = encode_add_ns(param, parameter->element->namens);
xmlNodeSetName(param, BAD_CAST(parameter->element->name));
xmlSetNs(param, ns);
}
} else if (strcmp((char*)param->name,"return") == 0) {
ns = encode_add_ns(param, uri);
xmlNodeSetName(param, BAD_CAST(function_name));
xmlSetNs(param, ns);
}
}
} else if (param_count > 1 && Z_TYPE_P(ret) == IS_ARRAY) {
zval *data;
int i = 0;
zend_string *param_name;
zend_ulong param_index = i;
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(ret), param_index, param_name, data) {
parameter = get_param(function, ZSTR_VAL(param_name), param_index, TRUE);
if (style == SOAP_RPC) {
param = serialize_parameter(parameter, data, i, ZSTR_VAL(param_name), use, method);
} else {
param = serialize_parameter(parameter, data, i, ZSTR_VAL(param_name), use, body);
if (function && function->binding->bindingType == BINDING_SOAP) {
if (parameter && parameter->element) {
ns = encode_add_ns(param, parameter->element->namens);
xmlNodeSetName(param, BAD_CAST(parameter->element->name));
xmlSetNs(param, ns);
}
}
}
i++;
param_index = i;
} ZEND_HASH_FOREACH_END();
}
if (use == SOAP_ENCODED && version == SOAP_1_2 && method != NULL) {
xmlSetNsProp(method, body->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
}
if (node) {
*node = method;
}
return use;
}
/* }}} */
static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function_name, char *uri, zval *ret, soapHeader* headers, int version) /* {{{ */
{
xmlDocPtr doc;
xmlNodePtr envelope = NULL, body, param;
xmlNsPtr ns = NULL;
int use = SOAP_LITERAL;
xmlNodePtr head = NULL;
encode_reset_ns();
doc = xmlNewDoc(BAD_CAST("1.0"));
doc->charset = XML_CHAR_ENCODING_UTF8;
doc->encoding = xmlCharStrdup("UTF-8");
if (version == SOAP_1_1) {
envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENV_NAMESPACE), BAD_CAST(SOAP_1_1_ENV_NS_PREFIX));
xmlSetNs(envelope,ns);
} else if (version == SOAP_1_2) {
envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENV_NAMESPACE), BAD_CAST(SOAP_1_2_ENV_NS_PREFIX));
xmlSetNs(envelope,ns);
} else {
soap_server_fault("Server", "Unknown SOAP version", NULL, NULL, NULL);
}
xmlDocSetRootElement(doc, envelope);
if (Z_TYPE_P(ret) == IS_OBJECT &&
instanceof_function(Z_OBJCE_P(ret), soap_fault_class_entry)) {
char *detail_name;
HashTable* prop;
zval *tmp;
sdlFaultPtr fault = NULL;
char *fault_ns = NULL;
prop = Z_OBJPROP_P(ret);
if (headers &&
(tmp = zend_hash_str_find(prop, "headerfault", sizeof("headerfault")-1)) != NULL) {
encodePtr hdr_enc = NULL;
int hdr_use = SOAP_LITERAL;
zval *hdr_ret = tmp;
char *hdr_ns = headers->hdr?headers->hdr->ns:NULL;
char *hdr_name = Z_STRVAL(headers->function_name);
head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL);
if (Z_TYPE_P(hdr_ret) == IS_OBJECT &&
instanceof_function(Z_OBJCE_P(hdr_ret), soap_header_class_entry)) {
HashTable* ht = Z_OBJPROP_P(hdr_ret);
sdlSoapBindingFunctionHeaderPtr hdr;
smart_str key = {0};
if ((tmp = zend_hash_str_find(ht, "namespace", sizeof("namespace")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
smart_str_appendl(&key, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
smart_str_appendc(&key, ':');
hdr_ns = Z_STRVAL_P(tmp);
}
if ((tmp = zend_hash_str_find(ht, "name", sizeof("name")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
smart_str_appendl(&key, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
hdr_name = Z_STRVAL_P(tmp);
}
smart_str_0(&key);
if (headers->hdr && headers->hdr->headerfaults &&
(hdr = zend_hash_find_ptr(headers->hdr->headerfaults, key.s)) != NULL) {
hdr_enc = hdr->encode;
hdr_use = hdr->use;
}
smart_str_free(&key);
if ((tmp = zend_hash_str_find(ht, "data", sizeof("data")-1)) != NULL) {
hdr_ret = tmp;
} else {
hdr_ret = NULL;
}
}
if (headers->function) {
if (serialize_response_call2(head, headers->function, Z_STRVAL(headers->function_name), uri, hdr_ret, version, 0, NULL) == SOAP_ENCODED) {
use = SOAP_ENCODED;
}
} else {
xmlNodePtr xmlHdr = master_to_xml(hdr_enc, hdr_ret, hdr_use, head);
if (hdr_name) {
xmlNodeSetName(xmlHdr, BAD_CAST(hdr_name));
}
if (hdr_ns) {
xmlNsPtr nsptr = encode_add_ns(xmlHdr, hdr_ns);
xmlSetNs(xmlHdr, nsptr);
}
}
}
body = xmlNewChild(envelope, ns, BAD_CAST("Body"), NULL);
param = xmlNewChild(body, ns, BAD_CAST("Fault"), NULL);
if ((tmp = zend_hash_str_find(prop, "faultcodens", sizeof("faultcodens")-1)) != NULL && Z_TYPE_P(tmp) == IS_STRING) {
fault_ns = Z_STRVAL_P(tmp);
}
use = SOAP_LITERAL;
if ((tmp = zend_hash_str_find(prop, "_name", sizeof("_name")-1)) != NULL && Z_TYPE_P(tmp) == IS_STRING) {
sdlFaultPtr tmp_fault;
if (function && function->faults &&
(tmp_fault = zend_hash_find_ptr(function->faults, Z_STR_P(tmp))) != NULL) {
fault = tmp_fault;
if (function->binding &&
function->binding->bindingType == BINDING_SOAP &&
fault->bindingAttributes) {
sdlSoapBindingFunctionFaultPtr fb = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
use = fb->use;
if (fault_ns == NULL) {
fault_ns = fb->ns;
}
}
}
} else if (function && function->faults &&
zend_hash_num_elements(function->faults) == 1) {
zend_hash_internal_pointer_reset(function->faults);
fault = zend_hash_get_current_data_ptr(function->faults);
if (function->binding &&
function->binding->bindingType == BINDING_SOAP &&
fault->bindingAttributes) {
sdlSoapBindingFunctionFaultPtr fb = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
use = fb->use;
if (fault_ns == NULL) {
fault_ns = fb->ns;
}
}
}
if (fault_ns == NULL &&
fault &&
fault->details &&
zend_hash_num_elements(fault->details) == 1) {
sdlParamPtr sparam;
zend_hash_internal_pointer_reset(fault->details);
sparam = zend_hash_get_current_data_ptr(fault->details);
if (sparam->element) {
fault_ns = sparam->element->namens;
}
}
if (version == SOAP_1_1) {
if ((tmp = zend_hash_str_find(prop, "faultcode", sizeof("faultcode")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
xmlNodePtr node = xmlNewNode(NULL, BAD_CAST("faultcode"));
zend_string *str = php_escape_html_entities((unsigned char*)Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 0, 0, NULL);
xmlAddChild(param, node);
if (fault_ns) {
xmlNsPtr nsptr = encode_add_ns(node, fault_ns);
xmlChar *code = xmlBuildQName(BAD_CAST(ZSTR_VAL(str)), nsptr->prefix, NULL, 0);
xmlNodeSetContent(node, code);
xmlFree(code);
} else {
xmlNodeSetContentLen(node, BAD_CAST(ZSTR_VAL(str)), (int)ZSTR_LEN(str));
}
zend_string_release_ex(str, 0);
}
if ((tmp = zend_hash_str_find(prop, "faultstring", sizeof("faultstring")-1)) != NULL) {
xmlNodePtr node = master_to_xml(get_conversion(IS_STRING), tmp, SOAP_LITERAL, param);
xmlNodeSetName(node, BAD_CAST("faultstring"));
}
if ((tmp = zend_hash_str_find(prop, "faultactor", sizeof("faultactor")-1)) != NULL) {
xmlNodePtr node = master_to_xml(get_conversion(IS_STRING), tmp, SOAP_LITERAL, param);
xmlNodeSetName(node, BAD_CAST("faultactor"));
}
detail_name = "detail";
} else {
if ((tmp = zend_hash_str_find(prop, "faultcode", sizeof("faultcode")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
xmlNodePtr node = xmlNewChild(param, ns, BAD_CAST("Code"), NULL);
zend_string *str = php_escape_html_entities((unsigned char*)Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), 0, 0, NULL);
node = xmlNewChild(node, ns, BAD_CAST("Value"), NULL);
if (fault_ns) {
xmlNsPtr nsptr = encode_add_ns(node, fault_ns);
xmlChar *code = xmlBuildQName(BAD_CAST(ZSTR_VAL(str)), nsptr->prefix, NULL, 0);
xmlNodeSetContent(node, code);
xmlFree(code);
} else {
xmlNodeSetContentLen(node, BAD_CAST(ZSTR_VAL(str)), (int)ZSTR_LEN(str));
}
zend_string_release_ex(str, 0);
}
if ((tmp = zend_hash_str_find(prop, "faultstring", sizeof("faultstring")-1)) != NULL) {
xmlNodePtr node = xmlNewChild(param, ns, BAD_CAST("Reason"), NULL);
node = master_to_xml(get_conversion(IS_STRING), tmp, SOAP_LITERAL, node);
xmlNodeSetName(node, BAD_CAST("Text"));
xmlSetNs(node, ns);
}
detail_name = SOAP_1_2_ENV_NS_PREFIX":Detail";
}
if (fault && fault->details && zend_hash_num_elements(fault->details) == 1) {
xmlNodePtr node;
zval *detail = NULL;
sdlParamPtr sparam;
xmlNodePtr x;
if ((tmp = zend_hash_str_find(prop, "detail", sizeof("detail")-1)) != NULL &&
Z_TYPE_P(tmp) != IS_NULL) {
detail = tmp;
}
node = xmlNewNode(NULL, BAD_CAST(detail_name));
xmlAddChild(param, node);
zend_hash_internal_pointer_reset(fault->details);
sparam = zend_hash_get_current_data_ptr(fault->details);
if (detail &&
Z_TYPE_P(detail) == IS_OBJECT &&
sparam->element &&
zend_hash_num_elements(Z_OBJPROP_P(detail)) == 1 &&
(tmp = zend_hash_str_find(Z_OBJPROP_P(detail), sparam->element->name, strlen(sparam->element->name))) != NULL) {
detail = tmp;
}
x = serialize_parameter(sparam, detail, 1, NULL, use, node);
if (function &&
function->binding &&
function->binding->bindingType == BINDING_SOAP &&
function->bindingAttributes) {
sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
if (fnb->style == SOAP_RPC && !sparam->element) {
if (fault->bindingAttributes) {
sdlSoapBindingFunctionFaultPtr fb = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
if (fb->ns) {
xmlNsPtr ns = encode_add_ns(x, fb->ns);
xmlSetNs(x, ns);
}
}
} else {
if (sparam->element) {
ns = encode_add_ns(x, sparam->element->namens);
xmlNodeSetName(x, BAD_CAST(sparam->element->name));
xmlSetNs(x, ns);
}
}
}
if (use == SOAP_ENCODED && version == SOAP_1_2) {
xmlSetNsProp(x, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
}
} else if ((tmp = zend_hash_str_find(prop, "detail", sizeof("detail")-1)) != NULL &&
Z_TYPE_P(tmp) != IS_NULL) {
serialize_zval(tmp, NULL, detail_name, use, param);
}
} else {
if (headers) {
soapHeader *h;
head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL);
h = headers;
while (h != NULL) {
if (Z_TYPE(h->retval) != IS_NULL) {
encodePtr hdr_enc = NULL;
int hdr_use = SOAP_LITERAL;
zval *hdr_ret = &h->retval;
char *hdr_ns = h->hdr?h->hdr->ns:NULL;
char *hdr_name = Z_STRVAL(h->function_name);
HashTable *ht = NULL;
if (Z_TYPE(h->retval) == IS_OBJECT &&
instanceof_function(Z_OBJCE(h->retval), soap_header_class_entry)) {
zval *tmp;
sdlSoapBindingFunctionHeaderPtr hdr;
smart_str key = {0};
ht = Z_OBJPROP(h->retval);
if ((tmp = zend_hash_str_find(ht, "namespace", sizeof("namespace")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
smart_str_appendl(&key, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
smart_str_appendc(&key, ':');
hdr_ns = Z_STRVAL_P(tmp);
}
if ((tmp = zend_hash_str_find(ht, "name", sizeof("name")-1)) != NULL &&
Z_TYPE_P(tmp) == IS_STRING) {
smart_str_appendl(&key, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp));
hdr_name = Z_STRVAL_P(tmp);
}
smart_str_0(&key);
if (function && function->binding && function->binding->bindingType == BINDING_SOAP) {
sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
if (fnb->output.headers &&
(hdr = zend_hash_find_ptr(fnb->output.headers, key.s)) != NULL) {
hdr_enc = hdr->encode;
hdr_use = hdr->use;
}
}
smart_str_free(&key);
if ((tmp = zend_hash_str_find(ht, "data", sizeof("data")-1)) != NULL) {
hdr_ret = tmp;
} else {
hdr_ret = NULL;
}
}
if (h->function) {
xmlNodePtr xmlHdr = NULL;
if (serialize_response_call2(head, h->function, Z_STRVAL(h->function_name), uri, hdr_ret, version, 0, &xmlHdr) == SOAP_ENCODED) {
use = SOAP_ENCODED;
}
if (ht) {
set_soap_header_attributes(xmlHdr, ht, version);
}
} else {
xmlNodePtr xmlHdr = master_to_xml(hdr_enc, hdr_ret, hdr_use, head);
if (hdr_name) {
xmlNodeSetName(xmlHdr, BAD_CAST(hdr_name));
}
if (hdr_ns) {
xmlNsPtr nsptr = encode_add_ns(xmlHdr,hdr_ns);
xmlSetNs(xmlHdr, nsptr);
}
if (ht) {
set_soap_header_attributes(xmlHdr, ht, version);
}
}
}
h = h->next;
}
if (head->children == NULL) {
xmlUnlinkNode(head);
xmlFreeNode(head);
}
}
body = xmlNewChild(envelope, ns, BAD_CAST("Body"), NULL);
if (serialize_response_call2(body, function, function_name, uri, ret, version, 1, NULL) == SOAP_ENCODED) {
use = SOAP_ENCODED;
}
}
if (use == SOAP_ENCODED) {
xmlNewNs(envelope, BAD_CAST(XSD_NAMESPACE), BAD_CAST(XSD_NS_PREFIX));
if (version == SOAP_1_1) {
xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENC_NAMESPACE), BAD_CAST(SOAP_1_1_ENC_NS_PREFIX));
xmlSetNsProp(envelope, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_1_ENC_NAMESPACE));
} else if (version == SOAP_1_2) {
xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENC_NAMESPACE), BAD_CAST(SOAP_1_2_ENC_NS_PREFIX));
}
}
encode_finish();
if (function && function->responseName == NULL &&
body->children == NULL && head == NULL) {
xmlFreeDoc(doc);
return NULL;
}
return doc;
}
/* }}} */
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) /* {{{ */
{
xmlDoc *doc;
xmlNodePtr envelope = NULL, body, method = NULL, head = NULL;
xmlNsPtr ns = NULL;
zval *zstyle, *zuse;
int i, style, use;
HashTable *hdrs = NULL;
encode_reset_ns();
doc = xmlNewDoc(BAD_CAST("1.0"));
doc->encoding = xmlCharStrdup("UTF-8");
doc->charset = XML_CHAR_ENCODING_UTF8;
if (version == SOAP_1_1) {
envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENV_NAMESPACE), BAD_CAST(SOAP_1_1_ENV_NS_PREFIX));
xmlSetNs(envelope, ns);
} else if (version == SOAP_1_2) {
envelope = xmlNewDocNode(doc, NULL, BAD_CAST("Envelope"), NULL);
ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENV_NAMESPACE), BAD_CAST(SOAP_1_2_ENV_NS_PREFIX));
xmlSetNs(envelope, ns);
} else {
soap_error0(E_ERROR, "Unknown SOAP version");
}
xmlDocSetRootElement(doc, envelope);
if (soap_headers) {
head = xmlNewChild(envelope, ns, BAD_CAST("Header"), NULL);
}
body = xmlNewChild(envelope, ns, BAD_CAST("Body"), NULL);
if (function && function->binding->bindingType == BINDING_SOAP) {
sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)function->bindingAttributes;
hdrs = fnb->input.headers;
style = fnb->style;
/*FIXME: how to pass method name if style is SOAP_DOCUMENT */
/*style = SOAP_RPC;*/
use = fnb->input.use;
if (style == SOAP_RPC) {
ns = encode_add_ns(body, fnb->input.ns);
if (function->requestName) {
method = xmlNewChild(body, ns, BAD_CAST(function->requestName), NULL);
} else {
method = xmlNewChild(body, ns, BAD_CAST(function->functionName), NULL);
}
}
} else {
if ((zstyle = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "style", sizeof("style")-1)) != NULL &&
Z_TYPE_P(zstyle) == IS_LONG) {
style = Z_LVAL_P(zstyle);
} else {
style = SOAP_RPC;
}
/*FIXME: how to pass method name if style is SOAP_DOCUMENT */
/*style = SOAP_RPC;*/
if (style == SOAP_RPC) {
ns = encode_add_ns(body, uri);
if (function_name) {
method = xmlNewChild(body, ns, BAD_CAST(function_name), NULL);
} else if (function && function->requestName) {
method = xmlNewChild(body, ns, BAD_CAST(function->requestName), NULL);
} else if (function && function->functionName) {
method = xmlNewChild(body, ns, BAD_CAST(function->functionName), NULL);
} else {
method = body;
}
} else {
method = body;
}
if ((zuse = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "use", sizeof("use")-1)) != NULL &&
Z_TYPE_P(zuse) == IS_LONG && Z_LVAL_P(zuse) == SOAP_LITERAL) {
use = SOAP_LITERAL;
} else {
use = SOAP_ENCODED;
}
}
for (i = 0;i < arg_count;i++) {
xmlNodePtr param;
sdlParamPtr parameter = get_param(function, NULL, i, FALSE);
if (style == SOAP_RPC) {
param = serialize_parameter(parameter, &arguments[i], i, NULL, use, method);
} else if (style == SOAP_DOCUMENT) {
param = serialize_parameter(parameter, &arguments[i], i, NULL, use, body);
if (function && function->binding->bindingType == BINDING_SOAP) {
if (parameter && parameter->element) {
ns = encode_add_ns(param, parameter->element->namens);
xmlNodeSetName(param, BAD_CAST(parameter->element->name));
xmlSetNs(param, ns);
}
}
}
}
if (function && function->requestParameters) {
int n = zend_hash_num_elements(function->requestParameters);
if (n > arg_count) {
for (i = arg_count; i < n; i++) {
xmlNodePtr param;
sdlParamPtr parameter = get_param(function, NULL, i, FALSE);
if (style == SOAP_RPC) {
param = serialize_parameter(parameter, NULL, i, NULL, use, method);
} else if (style == SOAP_DOCUMENT) {
param = serialize_parameter(parameter, NULL, i, NULL, use, body);
if (function && function->binding->bindingType == BINDING_SOAP) {
if (parameter && parameter->element) {
ns = encode_add_ns(param, parameter->element->namens);
xmlNodeSetName(param, BAD_CAST(parameter->element->name));
xmlSetNs(param, ns);
}
}
}
}
}
}
if (head) {
zval* header;
ZEND_HASH_FOREACH_VAL(soap_headers, header) {
HashTable *ht;
zval *name, *ns, *tmp;
if (Z_TYPE_P(header) != IS_OBJECT) {
continue;
}
ht = Z_OBJPROP_P(header);
if ((name = zend_hash_str_find(ht, "name", sizeof("name")-1)) != NULL &&
Z_TYPE_P(name) == IS_STRING &&
(ns = zend_hash_str_find(ht, "namespace", sizeof("namespace")-1)) != NULL &&
Z_TYPE_P(ns) == IS_STRING) {
xmlNodePtr h;
xmlNsPtr nsptr;
int hdr_use = SOAP_LITERAL;
encodePtr enc = NULL;
if (hdrs) {
smart_str key = {0};
sdlSoapBindingFunctionHeaderPtr hdr;
smart_str_appendl(&key, Z_STRVAL_P(ns), Z_STRLEN_P(ns));
smart_str_appendc(&key, ':');
smart_str_appendl(&key, Z_STRVAL_P(name), Z_STRLEN_P(name));
smart_str_0(&key);
if ((hdr = zend_hash_find_ptr(hdrs, key.s)) != NULL) {
hdr_use = hdr->use;
enc = hdr->encode;
if (hdr_use == SOAP_ENCODED) {
use = SOAP_ENCODED;
}
}
smart_str_free(&key);
}
if ((tmp = zend_hash_str_find(ht, "data", sizeof("data")-1)) != NULL) {
h = master_to_xml(enc, tmp, hdr_use, head);
xmlNodeSetName(h, BAD_CAST(Z_STRVAL_P(name)));
} else {
h = xmlNewNode(NULL, BAD_CAST(Z_STRVAL_P(name)));
xmlAddChild(head, h);
}
nsptr = encode_add_ns(h, Z_STRVAL_P(ns));
xmlSetNs(h, nsptr);
set_soap_header_attributes(h, ht, version);
}
} ZEND_HASH_FOREACH_END();
}
if (use == SOAP_ENCODED) {
xmlNewNs(envelope, BAD_CAST(XSD_NAMESPACE), BAD_CAST(XSD_NS_PREFIX));
if (version == SOAP_1_1) {
xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENC_NAMESPACE), BAD_CAST(SOAP_1_1_ENC_NS_PREFIX));
xmlSetNsProp(envelope, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_1_ENC_NAMESPACE));
} else if (version == SOAP_1_2) {
xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENC_NAMESPACE), BAD_CAST(SOAP_1_2_ENC_NS_PREFIX));
if (method) {
xmlSetNsProp(method, envelope->ns, BAD_CAST("encodingStyle"), BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
}
}
}
encode_finish();
return doc;
}
/* }}} */
static xmlNodePtr serialize_parameter(sdlParamPtr param, zval *param_val, int index, char *name, int style, xmlNodePtr parent) /* {{{ */
{
char *paramName;
xmlNodePtr xmlParam;
char paramNameBuf[10];
if (param_val &&
Z_TYPE_P(param_val) == IS_OBJECT &&
Z_OBJCE_P(param_val) == soap_param_class_entry) {
zval *param_name;
zval *param_data;
if ((param_name = zend_hash_str_find(Z_OBJPROP_P(param_val), "param_name", sizeof("param_name")-1)) != NULL &&
Z_TYPE_P(param_name) == IS_STRING &&
(param_data = zend_hash_str_find(Z_OBJPROP_P(param_val), "param_data", sizeof("param_data")-1)) != NULL) {
param_val = param_data;
name = Z_STRVAL_P(param_name);
}
}
if (param != NULL && param->paramName != NULL) {
paramName = param->paramName;
} else {
if (name == NULL) {
paramName = paramNameBuf;
snprintf(paramName, sizeof(paramNameBuf), "param%d",index);
} else {
paramName = name;
}
}
xmlParam = serialize_zval(param_val, param, paramName, style, parent);
return xmlParam;
}
/* }}} */
static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName, int style, xmlNodePtr parent) /* {{{ */
{
xmlNodePtr xmlParam;
encodePtr enc;
zval defval;
ZVAL_UNDEF(&defval);
if (param != NULL) {
enc = param->encode;
if (val == NULL) {
if (param->element) {
if (param->element->fixed) {
ZVAL_STRING(&defval, param->element->fixed);
val = &defval;
} else if (param->element->def && !param->element->nillable) {
ZVAL_STRING(&defval, param->element->def);
val = &defval;
}
}
}
} else {
enc = NULL;
}
xmlParam = master_to_xml(enc, val, style, parent);
zval_ptr_dtor(&defval);
if (!strcmp((char*)xmlParam->name, "BOGUS")) {
xmlNodeSetName(xmlParam, BAD_CAST(paramName));
}
return xmlParam;
}
/* }}} */
static sdlParamPtr get_param(sdlFunctionPtr function, char *param_name, int index, int response) /* {{{ */
{
sdlParamPtr tmp;
HashTable *ht;
if (function == NULL) {
return NULL;
}
if (response == FALSE) {
ht = function->requestParameters;
} else {
ht = function->responseParameters;
}
if (ht == NULL) {
return NULL;
}
if (param_name != NULL) {
if ((tmp = zend_hash_str_find_ptr(ht, param_name, strlen(param_name))) != NULL) {
return tmp;
} else {
ZEND_HASH_FOREACH_PTR(ht, tmp) {
if (tmp->paramName && strcmp(param_name, tmp->paramName) == 0) {
return tmp;
}
} ZEND_HASH_FOREACH_END();
}
} else {
if ((tmp = zend_hash_index_find_ptr(ht, index)) != NULL) {
return tmp;
}
}
return NULL;
}
/* }}} */
static sdlFunctionPtr get_function(sdlPtr sdl, const char *function_name) /* {{{ */
{
sdlFunctionPtr tmp;
int len = strlen(function_name);
char *str = estrndup(function_name,len);
php_strtolower(str,len);
if (sdl != NULL) {
if ((tmp = zend_hash_str_find_ptr(&sdl->functions, str, len)) != NULL) {
efree(str);
return tmp;
} else if (sdl->requests != NULL && (tmp = zend_hash_str_find_ptr(sdl->requests, str, len)) != NULL) {
efree(str);
return tmp;
}
}
efree(str);
return NULL;
}
/* }}} */
static sdlFunctionPtr get_doc_function(sdlPtr sdl, xmlNodePtr params) /* {{{ */
{
if (sdl) {
sdlFunctionPtr tmp;
sdlParamPtr param;
ZEND_HASH_FOREACH_PTR(&sdl->functions, tmp) {
if (tmp->binding && tmp->binding->bindingType == BINDING_SOAP) {
sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)tmp->bindingAttributes;
if (fnb->style == SOAP_DOCUMENT) {
if (params == NULL) {
if (tmp->requestParameters == NULL ||
zend_hash_num_elements(tmp->requestParameters) == 0) {
return tmp;
}
} else if (tmp->requestParameters != NULL &&
zend_hash_num_elements(tmp->requestParameters) > 0) {
int ok = 1;
xmlNodePtr node = params;
ZEND_HASH_FOREACH_PTR(tmp->requestParameters, param) {
if (param->element) {
if (strcmp(param->element->name, (char*)node->name) != 0) {
ok = 0;
break;
}
if (param->element->namens != NULL && node->ns != NULL) {
if (strcmp(param->element->namens, (char*)node->ns->href) != 0) {
ok = 0;
break;
}
} else if ((void*)param->element->namens != (void*)node->ns) {
ok = 0;
break;
}
} else if (strcmp(param->paramName, (char*)node->name) != 0) {
ok = 0;
break;
}
node = node->next;
} ZEND_HASH_FOREACH_END();
if (ok /*&& node == NULL*/) {
return tmp;
}
}
}
}
} ZEND_HASH_FOREACH_END();
}
return NULL;
}
/* }}} */
static void function_to_string(sdlFunctionPtr function, smart_str *buf) /* {{{ */
{
int i = 0;
sdlParamPtr param;
if (function->responseParameters &&
zend_hash_num_elements(function->responseParameters) > 0) {
if (zend_hash_num_elements(function->responseParameters) == 1) {
zend_hash_internal_pointer_reset(function->responseParameters);
param = zend_hash_get_current_data_ptr(function->responseParameters);
if (param->encode && param->encode->details.type_str) {
smart_str_appendl(buf, param->encode->details.type_str, strlen(param->encode->details.type_str));
smart_str_appendc(buf, ' ');
} else {
smart_str_appendl(buf, "UNKNOWN ", 8);
}
} else {
i = 0;
smart_str_appendl(buf, "list(", 5);
ZEND_HASH_FOREACH_PTR(function->responseParameters, param) {
if (i > 0) {
smart_str_appendl(buf, ", ", 2);
}
if (param->encode && param->encode->details.type_str) {
smart_str_appendl(buf, param->encode->details.type_str, strlen(param->encode->details.type_str));
} else {
smart_str_appendl(buf, "UNKNOWN", 7);
}
smart_str_appendl(buf, " $", 2);
smart_str_appendl(buf, param->paramName, strlen(param->paramName));
i++;
} ZEND_HASH_FOREACH_END();
smart_str_appendl(buf, ") ", 2);
}
} else {
smart_str_appendl(buf, "void ", 5);
}
smart_str_appendl(buf, function->functionName, strlen(function->functionName));
smart_str_appendc(buf, '(');
if (function->requestParameters) {
i = 0;
ZEND_HASH_FOREACH_PTR(function->requestParameters, param) {
if (i > 0) {
smart_str_appendl(buf, ", ", 2);
}
if (param->encode && param->encode->details.type_str) {
smart_str_appendl(buf, param->encode->details.type_str, strlen(param->encode->details.type_str));
} else {
smart_str_appendl(buf, "UNKNOWN", 7);
}
smart_str_appendl(buf, " $", 2);
smart_str_appendl(buf, param->paramName, strlen(param->paramName));
i++;
} ZEND_HASH_FOREACH_END();
}
smart_str_appendc(buf, ')');
smart_str_0(buf);
}
/* }}} */
static void model_to_string(sdlContentModelPtr model, smart_str *buf, int level) /* {{{ */
{
int i;
switch (model->kind) {
case XSD_CONTENT_ELEMENT:
type_to_string(model->u.element, buf, level);
smart_str_appendl(buf, ";\n", 2);
break;
case XSD_CONTENT_ANY:
for (i = 0;i < level;i++) {
smart_str_appendc(buf, ' ');
}
smart_str_appendl(buf, "<anyXML> any;\n", sizeof("<anyXML> any;\n")-1);
break;
case XSD_CONTENT_SEQUENCE:
case XSD_CONTENT_ALL:
case XSD_CONTENT_CHOICE: {
sdlContentModelPtr tmp;
ZEND_HASH_FOREACH_PTR(model->u.content, tmp) {
model_to_string(tmp, buf, level);
} ZEND_HASH_FOREACH_END();
break;
}
case XSD_CONTENT_GROUP:
model_to_string(model->u.group->model, buf, level);
default:
break;
}
}
/* }}} */
static void type_to_string(sdlTypePtr type, smart_str *buf, int level) /* {{{ */
{
int i;
smart_str spaces = {0};
for (i = 0;i < level;i++) {
smart_str_appendc(&spaces, ' ');
}
if (spaces.s) {
smart_str_appendl(buf, ZSTR_VAL(spaces.s), ZSTR_LEN(spaces.s));
}
switch (type->kind) {
case XSD_TYPEKIND_SIMPLE:
if (type->encode) {
smart_str_appendl(buf, type->encode->details.type_str, strlen(type->encode->details.type_str));
smart_str_appendc(buf, ' ');
} else {
smart_str_appendl(buf, "anyType ", sizeof("anyType ")-1);
}
smart_str_appendl(buf, type->name, strlen(type->name));
break;
case XSD_TYPEKIND_LIST:
smart_str_appendl(buf, "list ", 5);
smart_str_appendl(buf, type->name, strlen(type->name));
if (type->elements) {
sdlTypePtr item_type;
smart_str_appendl(buf, " {", 2);
ZEND_HASH_FOREACH_PTR(type->elements, item_type) {
smart_str_appendl(buf, item_type->name, strlen(item_type->name));
} ZEND_HASH_FOREACH_END();
smart_str_appendc(buf, '}');
}
break;
case XSD_TYPEKIND_UNION:
smart_str_appendl(buf, "union ", 6);
smart_str_appendl(buf, type->name, strlen(type->name));
if (type->elements) {
sdlTypePtr item_type;
int first = 0;
smart_str_appendl(buf, " {", 2);
ZEND_HASH_FOREACH_PTR(type->elements, item_type) {
if (!first) {
smart_str_appendc(buf, ',');
first = 0;
}
smart_str_appendl(buf, item_type->name, strlen(item_type->name));
} ZEND_HASH_FOREACH_END();
smart_str_appendc(buf, '}');
}
break;
case XSD_TYPEKIND_COMPLEX:
case XSD_TYPEKIND_RESTRICTION:
case XSD_TYPEKIND_EXTENSION:
if (type->encode &&
(type->encode->details.type == IS_ARRAY ||
type->encode->details.type == SOAP_ENC_ARRAY)) {
sdlAttributePtr attr;
sdlExtraAttributePtr ext;
if (type->attributes &&
(attr = zend_hash_str_find_ptr(type->attributes, SOAP_1_1_ENC_NAMESPACE":arrayType",
sizeof(SOAP_1_1_ENC_NAMESPACE":arrayType")-1)) != NULL &&
attr->extraAttributes &&
(ext = zend_hash_str_find_ptr(attr->extraAttributes, WSDL_NAMESPACE":arrayType", sizeof(WSDL_NAMESPACE":arrayType")-1)) != NULL) {
char *end = strchr(ext->val, '[');
int len;
if (end == NULL) {
len = strlen(ext->val);
} else {
len = end - ext->val;
}
if (len == 0) {
smart_str_appendl(buf, "anyType", sizeof("anyType")-1);
} else {
smart_str_appendl(buf, ext->val, len);
}
smart_str_appendc(buf, ' ');
smart_str_appendl(buf, type->name, strlen(type->name));
if (end != NULL) {
smart_str_appends(buf, end);
}
} else {
sdlTypePtr elementType;
if (type->attributes &&
(attr = zend_hash_str_find_ptr(type->attributes, SOAP_1_2_ENC_NAMESPACE":itemType",
sizeof(SOAP_1_2_ENC_NAMESPACE":itemType")-1)) != NULL &&
attr->extraAttributes &&
(ext = zend_hash_str_find_ptr(attr->extraAttributes, WSDL_NAMESPACE":itemType", sizeof(WSDL_NAMESPACE":arrayType")-1)) != NULL) {
smart_str_appends(buf, ext->val);
smart_str_appendc(buf, ' ');
} else if (type->elements &&
zend_hash_num_elements(type->elements) == 1 &&
(zend_hash_internal_pointer_reset(type->elements),
(elementType = zend_hash_get_current_data_ptr(type->elements)) != NULL) &&
elementType->encode && elementType->encode->details.type_str) {
smart_str_appends(buf, elementType->encode->details.type_str);
smart_str_appendc(buf, ' ');
} else {
smart_str_appendl(buf, "anyType ", 8);
}
smart_str_appendl(buf, type->name, strlen(type->name));
if (type->attributes &&
(attr = zend_hash_str_find_ptr(type->attributes, SOAP_1_2_ENC_NAMESPACE":arraySize",
sizeof(SOAP_1_2_ENC_NAMESPACE":arraySize")-1)) != NULL &&
attr->extraAttributes &&
(ext = zend_hash_str_find_ptr(attr->extraAttributes, WSDL_NAMESPACE":itemType", sizeof(WSDL_NAMESPACE":arraySize")-1)) != NULL) {
smart_str_appendc(buf, '[');
smart_str_appends(buf, ext->val);
smart_str_appendc(buf, ']');
} else {
smart_str_appendl(buf, "[]", 2);
}
}
} else {
smart_str_appendl(buf, "struct ", 7);
smart_str_appendl(buf, type->name, strlen(type->name));
smart_str_appendc(buf, ' ');
smart_str_appendl(buf, "{\n", 2);
if ((type->kind == XSD_TYPEKIND_RESTRICTION ||
type->kind == XSD_TYPEKIND_EXTENSION) && type->encode) {
encodePtr enc = type->encode;
while (enc && enc->details.sdl_type &&
enc != enc->details.sdl_type->encode &&
enc->details.sdl_type->kind != XSD_TYPEKIND_SIMPLE &&
enc->details.sdl_type->kind != XSD_TYPEKIND_LIST &&
enc->details.sdl_type->kind != XSD_TYPEKIND_UNION) {
enc = enc->details.sdl_type->encode;
}
if (enc) {
if (spaces.s) {
smart_str_appendl(buf, ZSTR_VAL(spaces.s), ZSTR_LEN(spaces.s));
}
smart_str_appendc(buf, ' ');
smart_str_appendl(buf, type->encode->details.type_str, strlen(type->encode->details.type_str));
smart_str_appendl(buf, " _;\n", 4);
}
}
if (type->model) {
model_to_string(type->model, buf, level+1);
}
if (type->attributes) {
sdlAttributePtr attr;
ZEND_HASH_FOREACH_PTR(type->attributes, attr) {
if (spaces.s) {
smart_str_appendl(buf, ZSTR_VAL(spaces.s), ZSTR_LEN(spaces.s));
}
smart_str_appendc(buf, ' ');
if (attr->encode && attr->encode->details.type_str) {
smart_str_appends(buf, attr->encode->details.type_str);
smart_str_appendc(buf, ' ');
} else {
smart_str_appendl(buf, "UNKNOWN ", 8);
}
smart_str_appends(buf, attr->name);
smart_str_appendl(buf, ";\n", 2);
} ZEND_HASH_FOREACH_END();
}
if (spaces.s) {
smart_str_appendl(buf, ZSTR_VAL(spaces.s), ZSTR_LEN(spaces.s));
}
smart_str_appendc(buf, '}');
}
break;
default:
break;
}
smart_str_free(&spaces);
smart_str_0(buf);
}
/* }}} */
static void delete_url(void *handle) /* {{{ */
{
php_url_free((php_url*)handle);
}
/* }}} */
static void delete_service(void *data) /* {{{ */
{
soapServicePtr service = (soapServicePtr)data;
if (service->soap_functions.ft) {
zend_hash_destroy(service->soap_functions.ft);
efree(service->soap_functions.ft);
}
if (service->typemap) {
zend_hash_destroy(service->typemap);
efree(service->typemap);
}
if (service->soap_class.argc) {
int i;
for (i = 0; i < service->soap_class.argc;i++) {
zval_ptr_dtor(&service->soap_class.argv[i]);
}
efree(service->soap_class.argv);
}
if (service->actor) {
efree(service->actor);
}
if (service->uri) {
efree(service->uri);
}
if (service->sdl) {
delete_sdl(service->sdl);
}
if (service->encoding) {
xmlCharEncCloseFunc(service->encoding);
}
if (service->class_map) {
zend_hash_destroy(service->class_map);
FREE_HASHTABLE(service->class_map);
}
zval_ptr_dtor(&service->soap_object);
efree(service);
}
/* }}} */
static void delete_hashtable(void *data) /* {{{ */
{
HashTable *ht = (HashTable*)data;
zend_hash_destroy(ht);
efree(ht);
}
/* }}} */