diff options
author | Shane Caraveo <shane@php.net> | 2002-07-07 23:03:43 +0000 |
---|---|---|
committer | Shane Caraveo <shane@php.net> | 2002-07-07 23:03:43 +0000 |
commit | f8875adaab9fe973ab798ead093e21972ed43a13 (patch) | |
tree | d5495bb982d966a5bb42afb20fb80338cccce1f4 | |
parent | a6d815fb7c98c32a4180e30dfaca316cbeae8912 (diff) | |
download | php-git-f8875adaab9fe973ab798ead093e21972ed43a13.tar.gz |
import php-soap library from sourceforge
-rw-r--r-- | ext/soap/EXPERIMENTAL | 0 | ||||
-rw-r--r-- | ext/soap/Makefile | 13 | ||||
-rw-r--r-- | ext/soap/Makefile.in | 8 | ||||
-rw-r--r-- | ext/soap/TODO | 36 | ||||
-rw-r--r-- | ext/soap/config.m4 | 16 | ||||
-rw-r--r-- | ext/soap/libs.mk | 7 | ||||
-rw-r--r-- | ext/soap/package.xml | 54 | ||||
-rw-r--r-- | ext/soap/php_encoding.c | 1085 | ||||
-rw-r--r-- | ext/soap/php_encoding.h | 248 | ||||
-rw-r--r-- | ext/soap/php_http.c | 495 | ||||
-rw-r--r-- | ext/soap/php_http.h | 25 | ||||
-rw-r--r-- | ext/soap/php_packet_soap.c | 124 | ||||
-rw-r--r-- | ext/soap/php_packet_soap.h | 6 | ||||
-rw-r--r-- | ext/soap/php_schema.c | 1047 | ||||
-rw-r--r-- | ext/soap/php_schema.h | 28 | ||||
-rw-r--r-- | ext/soap/php_sdl.c | 915 | ||||
-rw-r--r-- | ext/soap/php_sdl.h | 112 | ||||
-rw-r--r-- | ext/soap/php_soap.dsp | 156 | ||||
-rw-r--r-- | ext/soap/php_soap.h | 375 | ||||
-rw-r--r-- | ext/soap/php_xml.c | 214 | ||||
-rw-r--r-- | ext/soap/php_xml.h | 23 | ||||
-rw-r--r-- | ext/soap/soap.c | 2037 |
22 files changed, 7024 insertions, 0 deletions
diff --git a/ext/soap/EXPERIMENTAL b/ext/soap/EXPERIMENTAL new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/ext/soap/EXPERIMENTAL diff --git a/ext/soap/Makefile b/ext/soap/Makefile new file mode 100644 index 0000000000..1107a700bd --- /dev/null +++ b/ext/soap/Makefile @@ -0,0 +1,13 @@ +top_srcdir = /usr/local/src/php-4.2.0 +top_builddir = /usr/local/src/php-4.2.0 +srcdir = /usr/local/src/php-4.2.0/ext/soap +builddir = /usr/local/src/php-4.2.0/ext/soap +VPATH = /usr/local/src/php-4.2.0/ext/soap +# $Id$ + +LTLIBRARY_NAME = libsoap.la +LTLIBRARY_SOURCES = soap.c php_sdl.c php_schema.c php_xml.c php_encoding.c php_http.c php_packet_soap.c +LTLIBRARY_SHARED_NAME = soap.la +LTLIBRARY_SHARED_LIBADD = $(SOAP_SHARED_LIBADD) + +include $(top_srcdir)/build/dynlib.mk diff --git a/ext/soap/Makefile.in b/ext/soap/Makefile.in new file mode 100644 index 0000000000..eb52167d2d --- /dev/null +++ b/ext/soap/Makefile.in @@ -0,0 +1,8 @@ +# $Id$ + +LTLIBRARY_NAME = libsoap.la +LTLIBRARY_SOURCES = soap.c php_sdl.c php_schema.c php_xml.c php_encoding.c php_http.c php_packet_soap.c +LTLIBRARY_SHARED_NAME = soap.la +LTLIBRARY_SHARED_LIBADD = $(SOAP_SHARED_LIBADD) + +include $(top_srcdir)/build/dynlib.mk diff --git a/ext/soap/TODO b/ext/soap/TODO new file mode 100644 index 0000000000..b70760add7 --- /dev/null +++ b/ext/soap/TODO @@ -0,0 +1,36 @@ +TODO: +make sure soap 1.1 and 1.2 is supported fully +Better WSDL support Client and server (how much validation is needed here?) +UDDI?? +make internal refrences for soap encoding (use seralization logic) +add ini option for always soap_error_handler +provide user space overriding of serialization certin objects and types +serialization in general needs to be polished/finished... all xsd types +make perstistant objects and work with or without register_globals on +look to see if php-soap will work with out always_populate_raw_post_data on +see if client will work with ssl.. should be eaiser with php_streams +work on soap seralizer (php serialization) +work on a soap-service 'regiestry' and 'proxy' (apache soap style) +convert all string mainpulation to use smart_str +make the 'soap' packet abstract.. maybe incorperate xml-rpc +make the transport layer abstract.. what other transport layers are needed?... who uses smtp? what about jabber? +make $soap_object->data = 'text'; maybe invoke a set_*() and/or get_*() method +when using wsdls and function names are similar find the best match + void test(int); + void test(string); + maybe use the same alogrithim as ext/java. +investigate further http keep_alive... inital testing proved slower.. maybe php_streams will speed things up.. +provide schema 1999/2001 support.... +through memory leak testing +possible using shared memory for sdl caching... +api for clearing/checking sdl caching... +make php-soap work as a standalone server using php_streams and the new socket extension +http authication +proxy support +wsdl generation static and auto (.net style (http://server.com/soapserver.php?WSDL)) using phpdoc parsing engine +interpo testing... +BENCHMARKING...... lets prove how fast it is. +do some more work on website + +does this list stop... what exactly have i done? +im sure im forgetting 20 thousand more things.... diff --git a/ext/soap/config.m4 b/ext/soap/config.m4 new file mode 100644 index 0000000000..44c12cb037 --- /dev/null +++ b/ext/soap/config.m4 @@ -0,0 +1,16 @@ +dnl $Id$ +dnl config.m4 for extension soap + +dnl Comments in this file start with the string 'dnl'. +dnl Remove where necessary. This file will not work +dnl without editing. + +PHP_ARG_ENABLE(soap, whether to enable soap support, +Make sure that the comment is aligned: +[ --enable-soap Enable soap support]) + +if test "$PHP_SOAP" != "no"; then + PHP_ADD_INCLUDE(/usr/local/include/libxml2) + PHP_ADD_LIBRARY_WITH_PATH(xml2,/usr/local/lib,SOAP_SHARED_LIBADD) + PHP_EXTENSION(soap, $ext_shared) +fi diff --git a/ext/soap/libs.mk b/ext/soap/libs.mk new file mode 100644 index 0000000000..7c6e176717 --- /dev/null +++ b/ext/soap/libs.mk @@ -0,0 +1,7 @@ +include $(top_builddir)/config_vars.mk +LTLIBRARY_OBJECTS = $(LTLIBRARY_SOURCES:.c=.lo) $(LTLIBRARY_OBJECTS_X) +LTLIBRARY_SHARED_OBJECTS = $(LTLIBRARY_OBJECTS:.lo=.slo) +$(LTLIBRARY_NAME): $(LTLIBRARY_OBJECTS) $(LTLIBRARY_DEPENDENCIES) + $(LINK) $(LTLIBRARY_LDFLAGS) $(LTLIBRARY_OBJECTS) $(LTLIBRARY_LIBADD) + +targets = $(LTLIBRARY_NAME) diff --git a/ext/soap/package.xml b/ext/soap/package.xml new file mode 100644 index 0000000000..2299be5468 --- /dev/null +++ b/ext/soap/package.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<!-- do not use the "Type" attribute here, that one is only for + generated package.xml files --> +<package> + <name>php_soap</name> + <summary>Provides SOAP Services</summary> + <status>beta</status> + <maintainer> + <user>rodif_bl</user> + <name>Brad Lafountain</name> + <email>rodif_bl@yahoo.com</email> + <role>lead</role> + </maintainer> + <maintainer> + <user>shane</user> + <name>Shane Caraveo</name> + <email>shane@caraveo.com</email> + <role>lead</role> + </maintainer> + <release> + <version>0.1</version> + <date>2002-07-07</date> + <notes> + - First offical PEAR/PECL release + </notes> + </release> + <filelist> + <dir role="source" name="/" baseinstalldir="iisfunc"> + <file>EXPERIMENTAL</file> + <file>TODO</file> + <file>config.m4</file> + <file>Makefile</file> + <file>Makefile.in</file> + <file>libs.mk</file> + <file>php_encoding.c</file> + <file>php_encoding.h</file> + <file>php_http.c</file> + <file>php_http.h</file> + <file>php_packet_soap.c</file> + <file>php_packet_soap.h</file> + <file>php_schema.c</file> + <file>php_schema.h</file> + <file>php_sdl.c</file> + <file>php_sdl.h</file> + <file>php_soap.h</file> + <file>php_soap.h</file> + <file>php_xml.c</file> + <file>php_xml.h</file> + <file>soap.c</file> + <file>soap.dsp</file> + </dir> + </filelist> +</package> + diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c new file mode 100644 index 0000000000..55e4e4f4f4 --- /dev/null +++ b/ext/soap/php_encoding.c @@ -0,0 +1,1085 @@ +#include <time.h> + +#include "php_soap.h" + +encode defaultEncoding[] = { + {{UNKNOWN_TYPE, NULL, NULL, NULL}, guess_zval_convert, guess_xml_convert}, + + {{IS_NULL, "null", "null", NULL}, to_zval_null, to_xml_null}, + {{IS_STRING, XSD_STRING_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_string}, + {{IS_LONG, XSD_INT_STRING, XSD_NAMESPACE, NULL}, to_zval_long, to_xml_long}, + {{IS_DOUBLE, XSD_FLOAT_STRING, XSD_NAMESPACE, NULL}, to_zval_double, to_xml_string}, + {{IS_BOOL, XSD_BOOLEAN_STRING, XSD_NAMESPACE, NULL}, to_zval_bool, to_xml_bool}, + {{IS_CONSTANT, XSD_STRING_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_string}, + {{IS_ARRAY, SOAP_ENC_ARRAY_STRING, SOAP_ENC_NAMESPACE, NULL}, to_zval_array, guess_array_map}, + {{IS_CONSTANT_ARRAY, SOAP_ENC_ARRAY_STRING, SOAP_ENC_NAMESPACE, NULL}, to_zval_array, to_xml_array}, + {{IS_OBJECT, SOAP_ENC_OBJECT_STRING, SOAP_ENC_NAMESPACE, NULL}, to_zval_object, to_xml_object}, + + {{XSD_STRING, XSD_STRING_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_string}, + {{XSD_BOOLEAN, XSD_BOOLEAN_STRING, XSD_NAMESPACE, NULL}, to_zval_bool, to_xml_bool}, + {{XSD_DECIMAL, XSD_DECIMAL_STRING, XSD_NAMESPACE, NULL}, to_zval_long, to_xml_string}, + {{XSD_FLOAT, XSD_FLOAT_STRING, XSD_NAMESPACE, NULL}, to_zval_double, to_xml_string}, + {{XSD_DOUBLE, XSD_DOUBLE_STRING, XSD_NAMESPACE, NULL}, to_zval_double, to_xml_string}, + {{XSD_DATETIME, XSD_DATETIME_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_datetime}, + {{XSD_TIME, XSD_TIME_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_time}, + {{XSD_DATE, XSD_DATE_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_date}, + {{XSD_GYEARMONTH, XSD_GYEARMONTH_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_gyearmonth}, + {{XSD_GYEAR, XSD_GYEAR_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_gyear}, + {{XSD_GMONTHDAY, XSD_GMONTHDAY_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_gmonthday}, + {{XSD_GDAY, XSD_GDAY_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_gday}, + {{XSD_GMONTH, XSD_GMONTH_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_gmonth}, + {{XSD_HEXBINARY, XSD_HEXBINARY_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_stringl}, + {{XSD_BASE64BINARY, XSD_BASE64BINARY_STRING, XSD_NAMESPACE, NULL}, to_zval_string, to_xml_stringl}, + + {{XSD_LONG, XSD_LONG_STRING, XSD_NAMESPACE, NULL}, to_zval_long, to_xml_long}, + {{XSD_INT, XSD_INT_STRING, XSD_NAMESPACE, NULL}, to_zval_long, to_xml_string}, + {{XSD_SHORT, XSD_SHORT_STRING, XSD_NAMESPACE, NULL}, to_zval_long, to_xml_string}, + + {{APACHE_MAP, APACHE_MAP_STRING, APACHE_NAMESPACE, NULL}, to_zval_map, to_xml_map}, + + {{SOAP_ENC_OBJECT, SOAP_ENC_OBJECT_STRING, SOAP_ENC_NAMESPACE, NULL}, to_zval_object, to_xml_object}, + {{SOAP_ENC_ARRAY, SOAP_ENC_ARRAY_STRING, SOAP_ENC_NAMESPACE, NULL}, to_zval_array, to_xml_array}, + + //support some of the 1999 data types + {{XSD_STRING, XSD_STRING_STRING, XSD_1999_NAMESPACE, NULL}, to_zval_string, to_xml_string}, + {{XSD_BOOLEAN, XSD_BOOLEAN_STRING, XSD_1999_NAMESPACE, NULL}, to_zval_bool, to_xml_bool}, + {{XSD_DECIMAL, XSD_DECIMAL_STRING, XSD_1999_NAMESPACE, NULL}, to_zval_long, to_xml_string}, + {{XSD_FLOAT, XSD_FLOAT_STRING, XSD_1999_NAMESPACE, NULL}, to_zval_double, to_xml_string}, + {{XSD_DOUBLE, XSD_DOUBLE_STRING, XSD_1999_NAMESPACE, NULL}, to_zval_double, to_xml_string}, + {{XSD_LONG, XSD_LONG_STRING, XSD_1999_NAMESPACE, NULL}, to_zval_long, to_xml_long}, + {{XSD_INT, XSD_INT_STRING, XSD_1999_NAMESPACE, NULL}, to_zval_long, to_xml_string}, + {{XSD_SHORT, XSD_SHORT_STRING, XSD_1999_NAMESPACE, NULL}, to_zval_long, to_xml_string}, + {{XSD_1999_TIMEINSTANT, XSD_1999_TIMEINSTANT_STRING, XSD_1999_NAMESPACE, NULL}, to_zval_string, to_xml_string}, + + {{END_KNOWN_TYPES, NULL, NULL, NULL}, guess_zval_convert, guess_xml_convert} + +//TODO: finish off encoding +/* +#define XSD_DURATION 107 +#define XSD_DURATION_STRING "duration" +#define XSD_ANYURI 118 +#define XSD_ANYURI_STRING "anyURI" +#define XSD_QNAME 119 +#define XSD_QNAME_STRING "QName" +#define XSD_NOTATION 120 +#define XSD_NOTATION_STRING "NOTATION" +*/ + +/* +#define XSD_NORMALIZEDSTRING 121 +#define XSD_NORMALIZEDSTRING_STRING "normalizedString" +#define XSD_TOKEN 122 +#define XSD_TOKEN_STRING "token" +#define XSD_LANGUAGE 123 +#define XSD_LANGUAGE_STRING "language" +#define XSD_NMTOKEN 124 +#define XSD_NMTOKEN_STRING "NMTOKEN" +#define XSD_NAME 124 +#define XSD_NAME_STRING "Name" +#define XSD_NCNAME 125 +#define XSD_NCNAME_STRING "NCName" +#define XSD_ID 126 +#define XSD_ID_STRING "ID" +#define XSD_IDREF 127 +#define XSD_IDREF_STRING "IDREF" +#define XSD_IDREFS 127 +#define XSD_IDREFS_STRING "IDREFS" +#define XSD_ENTITY 128 +#define XSD_ENTITY_STRING "ENTITY" +#define XSD_ENTITYS 129 +#define XSD_ENTITYS_STRING "ENTITYS" +#define XSD_INTEGER 130 +#define XSD_INTEGER_STRING "integer" +#define XSD_NONPOSITIVEINTEGER 131 +#define XSD_NONPOSITIVEINTEGER_STRING "nonPositiveInteger" +#define XSD_NEGATIVEINTEGER 132 +#define XSD_NEGATIVEINTEGER_STRING "negativeInteger" +#define XSD_NONNEGATIVEINTEGER 137 +#define XSD_NONNEGATIVEINTEGER_STRING "nonNegativeInteger" +#define XSD_UNSIGNEDLONG 138 +#define XSD_UNSIGNEDLONG_STRING "unsignedLong" +#define XSD_UNSIGNEDINT 139 +#define XSD_UNSIGNEDINT_STRING "unsignedInt" +#define XSD_UNSIGNEDSHORT 140 +#define XSD_UNSIGNEDSHORT_STRING "unsignedShort" +#define XSD_UNSIGNEDBYTE 141 +#define XSD_UNSIGNEDBYTE_STRING "unsignedByte" +#define XSD_POSITIVEINTEGER 142 +#define XSD_POSITIVEINTEGER_STRING "positiveInteger" +*/ +}; + +xmlNodePtr master_to_xml(encodePtr encode, zval *data) +{ + xmlNodePtr node; + + if(encode->to_xml_before) + data = encode->to_xml_before(encode->details, data); + if(encode->to_xml) + node = encode->to_xml(encode->details, data); + if(encode->to_xml_after) + node = encode->to_xml_after(encode->details, node); + + return node; +} + +zval *master_to_zval(encodePtr encode, xmlNodePtr data) +{ + zval *ret; + + data = check_and_resolve_href(data); + if(encode->to_zval_before) + data = encode->to_zval_before(encode->details, data); + if(encode->to_zval) + ret = encode->to_zval(encode->details, data); + if(encode->to_zval_after) + ret = encode->to_zval_after(encode->details, ret); + + return ret; +} + +#ifdef HAVE_PHP_DOMXML +zval *to_xml_before_user(encodeType type, zval *data) +{ + TSRMLS_FETCH(); + + if(type.map->map_functions.to_xml_before) + { + if(call_user_function(EG(function_table), NULL, type.map->map_functions.to_xml_before, data, 1, &data TSRMLS_CC) == FAILURE) + php_error(E_ERROR, "Error calling to_xml_before"); + } + return data; +} + +xmlNodePtr to_xml_user(encodeType type, zval *data) +{ + zval *ret, **addr; + xmlNodePtr node; + TSRMLS_FETCH(); + + if(type.map->map_functions.to_xml) + { + MAKE_STD_ZVAL(ret); + if(call_user_function(EG(function_table), NULL, type.map->map_functions.to_xml, ret, 1, &data TSRMLS_CC) == FAILURE) + php_error(E_ERROR, "Error calling to_xml"); + + if(Z_TYPE_P(ret) != IS_OBJECT) + php_error(E_ERROR, "Error serializing object from to_xml_user"); + + if(zend_hash_index_find(Z_OBJPROP_P(ret), 1, (void **)&addr) == SUCCESS) + { + node = (xmlNodePtr)Z_LVAL_PP(addr); + node = xmlCopyNode(node, 1); + set_ns_and_type(node, type); + } + zval_ptr_dtor(&ret); + } + return node; +} + +xmlNodePtr to_xml_after_user(encodeType type, xmlNodePtr node) +{ + zval *ret, *param, **addr; + int found; + TSRMLS_FETCH(); + + if(type.map->map_functions.to_xml_after) + { + MAKE_STD_ZVAL(ret); + MAKE_STD_ZVAL(param); + param = php_domobject_new(node, &found, NULL TSRMLS_CC); + + if(call_user_function(EG(function_table), NULL, type.map->map_functions.to_xml_after, ret, 1, ¶m TSRMLS_CC) == FAILURE) + php_error(E_ERROR, "Error calling to_xml_after"); + if(zend_hash_index_find(Z_OBJPROP_P(ret), 1, (void **)&addr) == SUCCESS) + { + node = (xmlNodePtr)Z_LVAL_PP(addr); + set_ns_and_type(node, type); + } + zval_ptr_dtor(&ret); + zval_ptr_dtor(¶m); + } + return node; +} + +xmlNodePtr to_zval_before_user(encodeType type, xmlNodePtr node) +{ + zval *ret, *param, **addr; + int found; + TSRMLS_FETCH(); + + if(type.map->map_functions.to_zval_before) + { + MAKE_STD_ZVAL(ret); + MAKE_STD_ZVAL(param); + param = php_domobject_new(node, &found, NULL TSRMLS_CC); + + if(call_user_function(EG(function_table), NULL, type.map->map_functions.to_zval_before, ret, 1, ¶m TSRMLS_CC) == FAILURE) + php_error(E_ERROR, "Error calling to_zval_before"); + if(zend_hash_index_find(Z_OBJPROP_P(ret), 1, (void **)&addr) == SUCCESS) + { + node = (xmlNodePtr)Z_LVAL_PP(addr); + set_ns_and_type(node, type); + } + zval_ptr_dtor(&ret); + zval_ptr_dtor(¶m); + } + return node; +} + +zval *to_zval_user(encodeType type, xmlNodePtr node) +{ + zval *ret, *param; + int found; + TSRMLS_FETCH(); + + if(type.map->map_functions.to_zval) + { + MAKE_STD_ZVAL(ret); + MAKE_STD_ZVAL(param); + param = php_domobject_new(node, &found, NULL TSRMLS_CC); + + if(call_user_function(EG(function_table), NULL, type.map->map_functions.to_zval, ret, 1, ¶m TSRMLS_CC) == FAILURE) + php_error(E_ERROR, "Error calling to_zval"); + zval_ptr_dtor(¶m); + } + return ret; +} + +zval *to_zval_after_user(encodeType type, zval *data) +{ + TSRMLS_FETCH(); + + if(type.map->map_functions.to_zval_after) + { + if(call_user_function(EG(function_table), NULL, type.map->map_functions.to_zval_after, data, 1, &data TSRMLS_CC) == FAILURE) + php_error(E_ERROR, "Error calling to_xml_before"); + } + return data; +} +#endif + +//TODO: get rid of "bogus".. ither by passing in the already created xmlnode or passing in the node name +//String encode/decode +zval *to_zval_string(encodeType type, xmlNodePtr data) +{ + zval *ret; + MAKE_STD_ZVAL(ret); + FIND_XML_NULL(data, ret); + + if(data && data->children) + ZVAL_STRING(ret, data->children->content, 1); + return ret; +} + +zval *to_zval_stringl(encodeType type, xmlNodePtr data) +{ + zval *ret; + MAKE_STD_ZVAL(ret); + FIND_XML_NULL(data, ret); + + if(data && data->children) + ZVAL_STRINGL(ret, data->children->content, xmlStrlen(data->children->content), 1); + return ret; +} + +xmlNodePtr to_xml_string(encodeType type, zval *data) +{ + xmlNodePtr ret; + char *str; + int new_len; + + ret = xmlNewNode(NULL, "BOGUS"); + FIND_ZVAL_NULL(data, ret); + + convert_to_string(data); + str = php_escape_html_entities(Z_STRVAL_P(data), Z_STRLEN_P(data), &new_len, 0, 0, NULL); + xmlNodeSetContentLen(ret, str, new_len); + set_ns_and_type(ret, type); + return ret; +} + +xmlNodePtr to_xml_stringl(encodeType type, zval *data) +{ + xmlNodePtr ret; + + ret = xmlNewNode(NULL, "BOGUS"); + FIND_ZVAL_NULL(data, ret); + + convert_to_string(data); + xmlNodeSetContentLen(ret, estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data)), Z_STRLEN_P(data)); + set_ns_and_type(ret, type); + return ret; +} + +zval *to_zval_double(encodeType type, xmlNodePtr data) +{ + zval *ret; + MAKE_STD_ZVAL(ret); + FIND_XML_NULL(data, ret); + + ZVAL_DOUBLE(ret, atof(data->children->content)); + return ret; +} + +zval *to_zval_long(encodeType type, xmlNodePtr data) +{ + zval *ret; + MAKE_STD_ZVAL(ret); + FIND_XML_NULL(data, ret); + + ZVAL_LONG(ret, atol(data->children->content)); + return ret; +} + +xmlNodePtr to_xml_long(encodeType type, zval *data) +{ + xmlNodePtr ret; + + ret = xmlNewNode(NULL, "BOGUS"); + FIND_ZVAL_NULL(data, ret); + + convert_to_long(data); + convert_to_string(data); + xmlNodeSetContentLen(ret, Z_STRVAL_P(data), Z_STRLEN_P(data)); + set_ns_and_type(ret, type); + return ret; +} + +zval *to_zval_bool(encodeType type, xmlNodePtr data) +{ + zval *ret; + MAKE_STD_ZVAL(ret); + FIND_XML_NULL(data, ret); + + if(stricmp(data->children->content,"true") == 0 || + stricmp(data->children->content,"t") == 0 || + strcmp(data->children->content,"1") == 0) + { + ZVAL_BOOL(ret, 1); + } + else + { + ZVAL_BOOL(ret, 0); + } + return ret; +} + +xmlNodePtr to_xml_bool(encodeType type, zval *data) +{ + xmlNodePtr ret; + + ret = xmlNewNode(NULL, "BOGUS"); + FIND_ZVAL_NULL(data, ret); + + convert_to_boolean(data); + if(data->value.lval == 1) + xmlNodeSetContent(ret, "1"); + else + xmlNodeSetContent(ret, "0"); + + set_ns_and_type(ret, type); + return ret; +} + +//Null encode/decode +zval *to_zval_null(encodeType type, xmlNodePtr data) +{ + zval *ret; + MAKE_STD_ZVAL(ret); + ZVAL_NULL(ret); + return ret; +} + +xmlNodePtr to_xml_null(encodeType type, zval *data) +{ + xmlNodePtr ret; + + ret = xmlNewNode(NULL, "BOGUS"); + FIND_ZVAL_NULL(data, ret); + xmlSetProp(ret, "xsi:null", "1"); + + return ret; +} + +//Struct encode/decode +zval *to_zval_object(encodeType type, xmlNodePtr data) +{ + zval *ret; + xmlNodePtr trav; + encodePtr enc; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(ret); + FIND_XML_NULL(data, ret); + + object_init(ret); + trav = data->children; + + enc = get_conversion(UNKNOWN_TYPE); + do + { + if(trav->type == XML_ELEMENT_NODE) + { + zval *tmpVal; + + tmpVal = master_to_zval(enc, trav); + add_property_zval(ret, (char *)trav->name, tmpVal); + } + } + while(trav = trav->next); + + return ret; +} + +xmlNodePtr to_xml_object(encodeType type, zval *data) +{ + xmlNodePtr xmlParam; + HashTable *prop; + int i; + TSRMLS_FETCH(); + + //Special handling of class SoapVar + if(data && Z_TYPE_P(data) == IS_OBJECT && !strcmp(Z_OBJCE_P(data)->name, soap_var_class_entry.name)) + { + zval **ztype, **zdata, **zns, **zstype; + encodePtr enc; + + if(zend_hash_find(Z_OBJPROP_P(data), "enc_type", sizeof("enc_type"), (void **)&ztype) == FAILURE) + php_error(E_ERROR, "error encoding SoapVar"); + if(zend_hash_find(Z_OBJPROP_P(data), "enc_value", sizeof("enc_value"), (void **)&zdata) == FAILURE) + php_error(E_ERROR, "error encoding SoapVar"); + + enc = get_conversion(Z_LVAL_P(*ztype)); + xmlParam = master_to_xml(enc, *zdata); + + if(zend_hash_find(Z_OBJPROP_P(data), "enc_stype", sizeof("enc_stype"), (void **)&zstype) == SUCCESS) + { + if(zend_hash_find(Z_OBJPROP_P(data), "enc_ns", sizeof("enc_ns"), (void **)&zns) == SUCCESS) + set_ns_and_type_ex(xmlParam, Z_STRVAL_PP(zns), Z_STRVAL_PP(zstype)); + else + set_ns_and_type_ex(xmlParam, NULL, Z_STRVAL_PP(zstype)); + } + } + else + { + xmlParam = xmlNewNode(NULL, "BOGUS"); + FIND_ZVAL_NULL(data, xmlParam); + + if(Z_TYPE_P(data) == IS_OBJECT) + { + prop = Z_OBJPROP_P(data); + i = zend_hash_num_elements(prop); + zend_hash_internal_pointer_reset(prop); + + for(;i > 0;i--) + { + xmlNodePtr property; + encodePtr enc; + zval **zprop; + char *str_key; + + zend_hash_get_current_key(prop, &str_key, NULL, FALSE); + zend_hash_get_current_data(prop, (void **)&zprop); + + enc = get_conversion((*zprop)->type); + property = master_to_xml(enc, (*zprop)); + + xmlNodeSetName(property, str_key); + xmlAddChild(xmlParam, property); + zend_hash_move_forward(prop); + } + } + set_ns_and_type(xmlParam, type); + } + return xmlParam; +} + +//Array encode/decode +xmlNodePtr guess_array_map(encodeType type, zval *data) +{ + encodePtr enc = NULL; + TSRMLS_FETCH(); + + if(data && Z_TYPE_P(data) == IS_ARRAY) + { + if(zend_hash_num_elements(Z_ARRVAL_P(data)) > 0) + { + if(is_map(data)) + enc = get_conversion(APACHE_MAP); + else + enc = get_conversion(SOAP_ENC_ARRAY); + } + } + if(!enc) + enc = get_conversion(IS_NULL); + + return master_to_xml(enc, data); +} + +xmlNodePtr to_xml_array(encodeType type, zval *data) +{ + smart_str array_type_and_size = {0}, array_type = {0}; + int i; + xmlNodePtr xmlParam; + TSRMLS_FETCH(); + + xmlParam = xmlNewNode(NULL,"BOGUS"); + + FIND_ZVAL_NULL(data, xmlParam); + + if(Z_TYPE_P(data) == IS_ARRAY) + { + i = zend_hash_num_elements(Z_ARRVAL_P(data)); + get_array_type(data, &array_type); + smart_str_append(&array_type_and_size, &array_type); + smart_str_appendc(&array_type_and_size, '['); + smart_str_append_long(&array_type_and_size, i); + smart_str_appendc(&array_type_and_size, ']'); + smart_str_0(&array_type_and_size); + + xmlSetProp(xmlParam, "SOAP-ENC:arrayType", array_type_and_size.c); + + smart_str_free(&array_type_and_size); + smart_str_free(&array_type); + + zend_hash_internal_pointer_reset(data->value.ht); + for(;i > 0;i--) + { + xmlNodePtr xparam; + zval **zdata; + encodePtr enc; + zend_hash_get_current_data(data->value.ht, (void **)&zdata); + + enc = get_conversion((*zdata)->type); + xparam = master_to_xml(enc, (*zdata)); + + xmlNodeSetName(xparam, "val"); + xmlAddChild(xmlParam, xparam); + zend_hash_move_forward(data->value.ht); + } + } + set_ns_and_type(xmlParam, type); + return xmlParam; +} + +zval *to_zval_array(encodeType type, xmlNodePtr data) +{ + zval *ret; + xmlNodePtr trav; + encodePtr enc; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(ret); + FIND_XML_NULL(data, ret); + + array_init(ret); + trav = data->children; + + enc = get_conversion(UNKNOWN_TYPE); + while(trav) + { + if(trav->type == XML_ELEMENT_NODE) + { + zval *tmpVal; + tmpVal = master_to_zval(enc, trav); + zend_hash_next_index_insert(Z_ARRVAL_P(ret), &tmpVal, sizeof(zval *), NULL); + } + trav = trav->next; + } + + return ret; +} + +//Map encode/decode +xmlNodePtr to_xml_map(encodeType type, zval *data) +{ + xmlNodePtr xmlParam; + int i; + TSRMLS_FETCH(); + + xmlParam = xmlNewNode(NULL, "BOGUS"); + FIND_ZVAL_NULL(data, xmlParam); + + if(Z_TYPE_P(data) == IS_ARRAY) + { + i = zend_hash_num_elements(Z_ARRVAL_P(data)); + //TODO: Register namespace...??? + xmlSetProp(xmlParam, "xmlns:apache", "http://xml.apache.org/xml-soap"); + zend_hash_internal_pointer_reset(data->value.ht); + for(;i > 0;i--) + { + xmlNodePtr xparam, item; + xmlNodePtr key; + zval **temp_data; + char *key_val; + int int_val; + encodePtr enc; + + zend_hash_get_current_data(data->value.ht, (void **)&temp_data); + if(Z_TYPE_PP(temp_data) != IS_NULL) + { + item = xmlNewNode(NULL, "item"); + key = xmlNewNode(NULL, "key"); + if(zend_hash_get_current_key(data->value.ht, &key_val, (long *)&int_val, FALSE) == HASH_KEY_IS_STRING) + { + xmlSetProp(key, "xsi:type", "xsd:string"); + xmlNodeSetContent(key, key_val); + } + else + { + smart_str tmp = {0}; + smart_str_append_long(&tmp, int_val); + smart_str_0(&tmp); + + xmlSetProp(key, "xsi:type", "xsd:int"); + xmlNodeSetContentLen(key, tmp.c, tmp.len); + + smart_str_free(&tmp); + } + + + enc = get_conversion((*temp_data)->type); + xparam = master_to_xml(enc, (*temp_data)); + + xmlNodeSetName(xparam, "value"); + xmlAddChild(item, key); + xmlAddChild(item, xparam); + xmlAddChild(xmlParam, item); + } + zend_hash_move_forward(data->value.ht); + } + } + set_ns_and_type(xmlParam, type); + + return xmlParam; +} + +zval *to_zval_map(encodeType type, xmlNodePtr data) +{ + zval *ret, *key, *value; + xmlNodePtr trav, item, xmlKey, xmlValue; + encodePtr enc; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(ret); + FIND_XML_NULL(data, ret); + + array_init(ret); + trav = data->children; + + enc = get_conversion(UNKNOWN_TYPE); + trav = data->children; + FOREACHNODE(trav, "item", item) + { + xmlKey = get_node(item->children, "key"); + if(!xmlKey) + php_error(E_ERROR, "Error encoding apache map, missing key"); + + xmlValue = get_node(item->children, "value"); + if(!xmlKey) + php_error(E_ERROR, "Error encoding apache map, missing value"); + + key = master_to_zval(enc, xmlKey); + value = master_to_zval(enc, xmlValue); + + if(Z_TYPE_P(key) == IS_STRING) + zend_hash_update(Z_ARRVAL_P(ret), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof(zval *), NULL); + else if(Z_TYPE_P(key) == IS_LONG) + zend_hash_index_update(Z_ARRVAL_P(ret), Z_LVAL_P(key), &value, sizeof(zval *), NULL); + else + php_error(E_ERROR, "Error encoding apache map, only Strings or Longs are allowd as keys"); + } + ENDFOREACH(trav); + + return ret; +} + +//Unknown encode/decode +xmlNodePtr guess_xml_convert(encodeType type, zval *data) +{ + encodePtr enc; + TSRMLS_FETCH(); + + if(data) + enc = get_conversion(data->type); + else + enc = get_conversion(IS_NULL); + return master_to_xml(enc, data); +} + +zval *guess_zval_convert(encodeType type, xmlNodePtr data) +{ + encodePtr enc = NULL; + xmlAttrPtr tmpattr; + TSRMLS_FETCH(); + + data = check_and_resolve_href(data); + + if(data == NULL || data->children == NULL) + enc = get_conversion(IS_NULL); + else + { + tmpattr = get_attribute(data->properties,"type"); + if(tmpattr != NULL) + { + enc = get_conversion_from_type(data, tmpattr->children->content); + // if(enc == NULL) + // php_error(E_ERROR, "Error (Don't know how to encode/decode \"%s\")", tmpattr->children->content); + } + + if(enc == NULL) + { + //Didn't have a type, totally guess here + //Logic: has children = IS_OBJECT else IS_STRING + xmlNodePtr trav; + + if(get_attribute(data->properties, "arrayType")) + enc = get_conversion(SOAP_ENC_ARRAY); + else + { + enc = get_conversion(XSD_STRING); + trav = data->children; + do + { + if(trav->type == XML_ELEMENT_NODE) + { + enc = get_conversion(SOAP_ENC_OBJECT); + break; + } + } + while(trav = trav->next); + } + } + } + return master_to_zval(enc, data); +} + +//Time encode/decode +xmlNodePtr to_xml_datetime_ex(encodeType type, zval *data, char *format) +{ + //logic hacked from ext/standard/datetime.c + struct tm *ta, tmbuf; + time_t timestamp; + int max_reallocs = 5; + size_t buf_len=64, real_len; + char *buf; + xmlNodePtr xmlParam; + + xmlParam = xmlNewNode(NULL, "BOGUS"); + FIND_ZVAL_NULL(data, xmlParam); + + timestamp = Z_LVAL_P(data); + + time(×tamp); + ta = php_localtime_r(×tamp, &tmbuf); + + buf = (char *) emalloc(buf_len); + while ((real_len = strftime(buf, buf_len, format, ta)) == buf_len || real_len == 0) + { + buf_len *= 2; + buf = (char *) erealloc(buf, buf_len); + if(!--max_reallocs) break; + } + + xmlNodeSetContent(xmlParam, buf); + efree(buf); + set_ns_and_type(xmlParam, type); + return xmlParam; +} + +xmlNodePtr to_xml_datetime(encodeType type, zval *data) +{ + return to_xml_datetime_ex(type, data, "%Y-%m-%dT%H:%M:%S"); +} + +xmlNodePtr to_xml_time(encodeType type, zval *data) +{ + return to_xml_datetime_ex(type, data, "%H:%M:%S"); +} + +xmlNodePtr to_xml_date(encodeType type, zval *data) +{ + return to_xml_datetime_ex(type, data, "%Y-%m-%d"); +} + +xmlNodePtr to_xml_gyearmonth(encodeType type, zval *data) +{ + return to_xml_datetime_ex(type, data, "%Y-%m"); +} + +xmlNodePtr to_xml_gyear(encodeType type, zval *data) +{ + return to_xml_datetime_ex(type, data, "%Y"); +} + +xmlNodePtr to_xml_gmonthday(encodeType type, zval *data) +{ + return to_xml_datetime_ex(type, data, "--%m-%d"); +} + +xmlNodePtr to_xml_gday(encodeType type, zval *data) +{ + return to_xml_datetime_ex(type, data, "%d"); +} + +xmlNodePtr to_xml_gmonth(encodeType type, zval *data) +{ + return to_xml_datetime_ex(type, data, "%m"); +} + +void set_ns_and_type(xmlNodePtr node, encodeType type) +{ + set_ns_and_type_ex(node, type.ns, type.type_str); +} + +void set_ns_and_type_ex(xmlNodePtr node, char *ns, char *type) +{ + if(ns != NULL) + { + char *sprefix; + smart_str *prefix; + smart_str xmlns = {0}, nstype = {0}; + + TSRMLS_FETCH(); + + if(zend_hash_find(SOAP_GLOBAL(defEncNs), ns, strlen(ns) + 1, (void **)&sprefix) == FAILURE) + { + prefix = encode_new_ns(); + smart_str_appendl(&xmlns, "xmlns:", 6); + smart_str_append(&xmlns, prefix); + smart_str_0(&xmlns); + + xmlSetProp(node, xmlns.c, ns); + } + else + { + prefix = emalloc(sizeof(smart_str)); + memset(prefix, 0, sizeof(smart_str)); + smart_str_appends(prefix, sprefix); + } + + smart_str_append(&nstype, prefix); + smart_str_appendc(&nstype, ':'); + smart_str_appends(&nstype, type); + smart_str_0(&nstype); + xmlSetProp(node, "xsi:type", nstype.c); + smart_str_free(&nstype); + smart_str_free(&xmlns); + smart_str_free(prefix); + efree(prefix); + } + else + xmlSetProp(node, "xsi:type", type); +} + +smart_str *encode_new_ns() +{ + int num; + smart_str *ns = emalloc(sizeof(smart_str)); + + TSRMLS_FETCH(); + + memset(ns, 0, sizeof(smart_str)); + num = ++SOAP_GLOBAL(cur_uniq_ns); + smart_str_appendl(ns, "ns", 2); + smart_str_append_long(ns, num); + smart_str_0(ns); + return ns; +} + +void encode_reset_ns() +{ + TSRMLS_FETCH(); + SOAP_GLOBAL(cur_uniq_ns) = 0; +} + +encodePtr get_conversion_ex(HashTable *encoding, int encode) +{ + encodePtr *enc; + TSRMLS_FETCH(); + + if(zend_hash_index_find(encoding, encode, (void **)&enc) == FAILURE) + php_error(E_ERROR, "Cannot find encoding"); + + if(SOAP_GLOBAL(overrides)) + { + smart_str nscat = {0}; + + smart_str_appendl(&nscat, (*enc)->details.ns, strlen((*enc)->details.ns)); + smart_str_appendc(&nscat, ':'); + smart_str_appendl(&nscat, (*enc)->details.type_str, strlen((*enc)->details.type_str)); + smart_str_0(&nscat); + + zend_hash_find(SOAP_GLOBAL(overrides), nscat.c, nscat.len + 1, (void **)&enc); + smart_str_free(&nscat); + } + + return *enc; +} + +encodePtr get_conversion_from_href_type_ex(HashTable *encoding, char *type) +{ + encodePtr *enc = NULL; + + if(encoding == NULL) + return NULL; + + if(zend_hash_find(encoding, type, strlen(type), (void **)&enc) == FAILURE) + return NULL; + + return (*enc); +} + +encodePtr get_conversion_from_type_ex(HashTable *encoding, xmlNodePtr node, char *type) +{ + encodePtr *enc = NULL; + xmlNsPtr nsptr; + char *ns, *cptype; + char *nscat; + + if(encoding == NULL) + return NULL; + + parse_namespace(type, &cptype, &ns); + nsptr = xmlSearchNs(node->doc, node, ns); + if(nsptr != NULL) + { + nscat = emalloc(strlen(nsptr->href) + strlen(cptype) + 2); + sprintf(nscat, "%s:%s", nsptr->href, cptype); + + if(zend_hash_find(encoding, nscat, strlen(nscat), (void **)&enc) == FAILURE) + { + if(zend_hash_find(encoding, type, strlen(type) + 1, (void **)&enc) == FAILURE) + enc = NULL; + } + efree(nscat); + } + else + { + if(zend_hash_find(encoding, type, strlen(type) + 1, (void **)&enc) == FAILURE) + enc = NULL; + } + + if(cptype) efree(cptype); + if(ns) efree(ns); + if(enc == NULL) + return NULL; + else + return (*enc); +} + +int is_map(zval *array) +{ + int i, count = zend_hash_num_elements(Z_ARRVAL_P(array)); + for(i = 0;i < count;i++) + { + if(zend_hash_get_current_key_type(Z_ARRVAL_P(array)) == HASH_KEY_IS_STRING) + return TRUE; + zend_hash_move_forward(Z_ARRVAL_P(array)); + } + return FALSE; +} + +void get_array_type(zval *array, smart_str *type) +{ + HashTable *ht = array->value.ht; + int i, count, cur_type, prev_type, different; + char *name = NULL; + zval **tmp; + TSRMLS_FETCH(); + + if(!array || Z_TYPE_P(array) != IS_ARRAY) + smart_str_appendl(type, "xsd:ur-type", 11); + + different = FALSE; + cur_type = prev_type = 0; + count = zend_hash_num_elements(ht); + + zend_hash_internal_pointer_reset(ht); + for(i = 0;i < count;i++) + { + zend_hash_get_current_data(ht, (void **)&tmp); + + if(Z_TYPE_PP(tmp) == IS_OBJECT && !strcmp(Z_OBJCE_PP(tmp)->name, soap_var_class_entry.name)) + { + zval **ztype; + + if(zend_hash_find(Z_OBJPROP_PP(tmp), "enc_type", sizeof("enc_type"), (void **)&ztype) == FAILURE) + php_error(E_ERROR, "error encoding SoapVar"); + cur_type = Z_LVAL_P(*ztype); + } + else if(Z_TYPE_PP(tmp) == IS_ARRAY && is_map(*tmp)) + cur_type = APACHE_MAP; + else + cur_type = Z_TYPE_PP(tmp); + + if(i > 0) + { + if(cur_type != prev_type) + { + different = TRUE; + break; + } + } + + prev_type = cur_type; + zend_hash_move_forward(ht); + } + + if(different) + smart_str_appendl(type, "xsd:ur-type", 11); + else + { + encodePtr enc; + char *prefix; + + enc = get_conversion(cur_type); + + if(enc->details.ns != NULL) + { + if(zend_hash_find(SOAP_GLOBAL(defEncNs), enc->details.ns, strlen(enc->details.ns) + 1, (void **)&prefix) == FAILURE) + php_error(E_ERROR, "fix me"); + + smart_str_appendl(type, prefix, strlen(prefix)); + smart_str_appendc(type, ':'); + smart_str_appendl(type, enc->details.type_str, strlen(enc->details.type_str)); + smart_str_0(type); + } + else + smart_str_appendl(type, enc->details.type_str, strlen(enc->details.type_str)); + } +} + + +smart_str *build_soap_action(zval *this_ptr, char *soapaction) +{ + zval **uri; + smart_str *tmp; + + tmp = emalloc(sizeof(smart_str)); + memset(tmp, 0, sizeof(smart_str)); + + if(zend_hash_find(Z_OBJPROP_P(this_ptr), "uri", sizeof("uri"), (void *)&uri) == FAILURE) + php_error(E_ERROR, "Error finding uri"); + + smart_str_appendl(tmp, Z_STRVAL_PP(uri), Z_STRLEN_PP(uri)); + smart_str_appends(tmp, "/#"); + smart_str_appendl(tmp, soapaction, strlen(soapaction)); + smart_str_0(tmp); + + return tmp; +} + +void delete_encoder(void *encode) +{ + encodePtr t = *((encodePtr*)encode); + if(t->details.ns) + free(t->details.ns); + if(t->details.type_str) + free(t->details.type_str); + if(t->details.map) + delete_mapping(t->details.map); + free(t); +} + diff --git a/ext/soap/php_encoding.h b/ext/soap/php_encoding.h new file mode 100644 index 0000000000..7e422dcf9e --- /dev/null +++ b/ext/soap/php_encoding.h @@ -0,0 +1,248 @@ +#ifndef PHP_ENCODING_H +#define PHP_ENCODING_H + +#define XSD_1999_NAMESPACE "http://www.w3.org/1999/XMLSchema" +#define XSD_1999_TIMEINSTANT 401 +#define XSD_1999_TIMEINSTANT_STRING "timeInstant" + +#define XSD_NAMESPACE "http://www.w3.org/2001/XMLSchema" +#define XSD_NS_PREFIX "xsd" +#define XSD_STRING 101 +#define XSD_STRING_STRING "string" +#define XSD_BOOLEAN 103 +#define XSD_BOOLEAN_STRING "boolean" +#define XSD_DECIMAL 104 +#define XSD_DECIMAL_STRING "decimal" +#define XSD_FLOAT 105 +#define XSD_FLOAT_STRING "float" +#define XSD_DOUBLE 106 +#define XSD_DOUBLE_STRING "double" +#define XSD_DURATION 107 +#define XSD_DURATION_STRING "duration" +#define XSD_DATETIME 108 +#define XSD_DATETIME_STRING "dateTime" +#define XSD_TIME 109 +#define XSD_TIME_STRING "time" +#define XSD_DATE 110 +#define XSD_DATE_STRING "date" +#define XSD_GYEARMONTH 111 +#define XSD_GYEARMONTH_STRING "gYearMonth" +#define XSD_GYEAR 112 +#define XSD_GYEAR_STRING "gYear" +#define XSD_GMONTHDAY 113 +#define XSD_GMONTHDAY_STRING "gMonthDay" +#define XSD_GDAY 114 +#define XSD_GDAY_STRING "gDay" +#define XSD_GMONTH 115 +#define XSD_GMONTH_STRING "gMonth" +#define XSD_HEXBINARY 116 +#define XSD_HEXBINARY_STRING "hexBinary" +#define XSD_BASE64BINARY 117 +#define XSD_BASE64BINARY_STRING "base64Binary" +#define XSD_ANYURI 118 +#define XSD_ANYURI_STRING "anyURI" +#define XSD_QNAME 119 +#define XSD_QNAME_STRING "QName" +#define XSD_NOTATION 120 +#define XSD_NOTATION_STRING "NOTATION" +#define XSD_NORMALIZEDSTRING 121 +#define XSD_NORMALIZEDSTRING_STRING "normalizedString" +#define XSD_TOKEN 122 +#define XSD_TOKEN_STRING "token" +#define XSD_LANGUAGE 123 +#define XSD_LANGUAGE_STRING "language" +#define XSD_NMTOKEN 124 +#define XSD_NMTOKEN_STRING "NMTOKEN" +#define XSD_NAME 124 +#define XSD_NAME_STRING "Name" +#define XSD_NCNAME 125 +#define XSD_NCNAME_STRING "NCName" +#define XSD_ID 126 +#define XSD_ID_STRING "ID" +#define XSD_IDREF 127 +#define XSD_IDREF_STRING "IDREF" +#define XSD_IDREFS 127 +#define XSD_IDREFS_STRING "IDREFS" +#define XSD_ENTITY 128 +#define XSD_ENTITY_STRING "ENTITY" +#define XSD_ENTITYS 129 +#define XSD_ENTITYS_STRING "ENTITYS" +#define XSD_INTEGER 130 +#define XSD_INTEGER_STRING "integer" +#define XSD_NONPOSITIVEINTEGER 131 +#define XSD_NONPOSITIVEINTEGER_STRING "nonPositiveInteger" +#define XSD_NEGATIVEINTEGER 132 +#define XSD_NEGATIVEINTEGER_STRING "negativeInteger" +#define XSD_LONG 133 +#define XSD_LONG_STRING "long" +#define XSD_INT 134 +#define XSD_INT_STRING "int" +#define XSD_SHORT 135 +#define XSD_SHORT_STRING "short" +#define XSD_BYTE 136 +#define XSD_BYTE_STRING "byte" +#define XSD_NONNEGATIVEINTEGER 137 +#define XSD_NONNEGATIVEINTEGER_STRING "nonNegativeInteger" +#define XSD_UNSIGNEDLONG 138 +#define XSD_UNSIGNEDLONG_STRING "unsignedLong" +#define XSD_UNSIGNEDINT 139 +#define XSD_UNSIGNEDINT_STRING "unsignedInt" +#define XSD_UNSIGNEDSHORT 140 +#define XSD_UNSIGNEDSHORT_STRING "unsignedShort" +#define XSD_UNSIGNEDBYTE 141 +#define XSD_UNSIGNEDBYTE_STRING "unsignedByte" +#define XSD_POSITIVEINTEGER 142 +#define XSD_POSITIVEINTEGER_STRING "positiveInteger" + +#define APACHE_NAMESPACE "http://xml.apache.org/xml-soap" +#define APACHE_NS_PREFIX "apache" +#define APACHE_MAP 200 +#define APACHE_MAP_STRING "Map" + +#define SOAP_ENC_NAMESPACE "http://schemas.xmlsoap.org/soap/encoding/" +#define SOAP_ENC_NS_PREFIX "SOAP-ENC" +#define SOAP_ENC_ARRAY 300 +#define SOAP_ENC_ARRAY_STRING "Array" +#define SOAP_ENC_OBJECT 301 +#define SOAP_ENC_OBJECT_STRING "Struct" + +#define SCHEMA_NAMESPACE "http://www.w3.org/2001/XMLSchema" +#define SCHEMA_NS_PREFIX "s" + +#define WSDL_NAMESPACE "http://schemas.xmlsoap.org/wsdl/" +#define WSDL_NS_PREFIX "wsdl" + +#define UNKNOWN_TYPE 999998 +#define END_KNOWN_TYPES 999999 + +struct _encodeType +{ + int type; + char *type_str; + char *ns; + sdlTypePtr sdl_type; + soapMappingPtr map; +}; + +struct _encode +{ + encodeType details; + zval *(*to_zval)(encodeType type, xmlNodePtr data); + xmlNodePtr (*to_xml)(encodeType type, zval *data); + + xmlNodePtr (*to_zval_before)(encodeType type, xmlNodePtr data); + zval *(*to_zval_after)(encodeType type, zval *data); + + zval *(*to_xml_before)(encodeType type, zval *data); + xmlNodePtr (*to_xml_after)(encodeType type, xmlNodePtr data); +}; + +smart_str *build_soap_action(zval *this_ptr, char *soapaction); + +// Master functions all encode/decode should be called thur these functions +xmlNodePtr master_to_xml(encodePtr encode, zval *data); +zval *master_to_zval(encodePtr encode, xmlNodePtr data); + +#ifdef HAVE_PHP_DOMXML +//user defined mapping +zval *to_xml_before_user(encodeType type, zval *data); +xmlNodePtr to_xml_user(encodeType type, zval *data); +xmlNodePtr to_xml_after_user(encodeType type, xmlNodePtr node); +xmlNodePtr to_zval_before_user(encodeType type, xmlNodePtr node); +zval *to_zval_user(encodeType type, xmlNodePtr node); +zval *to_zval_after_user(encodeType type, zval *data); +#endif + +//zval type decode +zval *to_zval_double(encodeType type, xmlNodePtr data); +zval *to_zval_long(encodeType type, xmlNodePtr data); +zval *to_zval_bool(encodeType type, xmlNodePtr data); +zval *to_zval_object(encodeType type, xmlNodePtr data); +zval *to_zval_string(encodeType type, xmlNodePtr data); +zval *to_zval_array(encodeType type, xmlNodePtr data); +zval *to_zval_map(encodeType type, xmlNodePtr data); +zval *to_zval_null(encodeType type, xmlNodePtr data); +zval *guess_zval_convert(encodeType type, xmlNodePtr data); + +xmlNodePtr to_xml_long(encodeType type, zval *data); +xmlNodePtr to_xml_bool(encodeType type, zval *data); + +//String encode +xmlNodePtr to_xml_string(encodeType type, zval *data); +xmlNodePtr to_xml_stringl(encodeType type, zval *data); + +//Null encode +xmlNodePtr to_xml_null(encodeType type, zval *data); + +//Struct encode +xmlNodePtr to_xml_object(encodeType type, zval *data); + +//Array encode +xmlNodePtr guess_array_map(encodeType type, zval *data); +xmlNodePtr to_xml_array(encodeType type, zval *data); +xmlNodePtr to_xml_map(encodeType type, zval *data); + +//Try and guess for non-wsdl clients and servers +xmlNodePtr guess_xml_convert(encodeType type, zval *data); + +//Datetime encode/decode +xmlNodePtr to_xml_datetime_ex(encodeType type, zval *data, char *format); +xmlNodePtr to_xml_datetime(encodeType type, zval *data); +xmlNodePtr to_xml_time(encodeType type, zval *data); +xmlNodePtr to_xml_date(encodeType type, zval *data); +xmlNodePtr to_xml_gyearmonth(encodeType type, zval *data); +xmlNodePtr to_xml_gyear(encodeType type, zval *data); +xmlNodePtr to_xml_gmonthday(encodeType type, zval *data); +xmlNodePtr to_xml_gday(encodeType type, zval *data); +xmlNodePtr to_xml_gmonth(encodeType type, zval *data); + +#define get_conversion(e) get_conversion_ex(SOAP_GLOBAL(defEncIndex), e) +#define get_conversion_from_type(n, t) get_conversion_from_type_ex(SOAP_GLOBAL(defEnc), n, t) +#define get_conversion_from_href_type(t) get_conversion_from_href_type_ex(SOAP_GLOBAL(defEnc), t) + +void encode_reset_ns(); +smart_str *encode_new_ns(); + +void set_ns_and_type(xmlNodePtr node, encodeType type); +void set_ns_and_type_ex(xmlNodePtr node, char *ns, char *type); +encodePtr get_conversion_ex(HashTable *encoding, int encode); +encodePtr get_conversion_from_type_ex(HashTable *encoding, xmlNodePtr node, char *type); +encodePtr get_conversion_from_href_type_ex(HashTable *encoding, char *type); + +int is_map(zval *array); +void get_array_type(zval *array, smart_str *out_type); + +void delete_encoder(void *handle); + +extern encode defaultEncoding[]; + +#define FIND_XML_NULL(xml,zval) \ + { \ + xmlAttrPtr null; \ + if(!xml || !xml->children) \ + { \ + ZVAL_NULL(zval); \ + return zval; \ + } \ + if(xml->properties) \ + { \ + null = get_attribute(xml->properties, "null"); \ + if(null) \ + { \ + ZVAL_NULL(zval); \ + return zval; \ + } \ + } \ + } + +#define FIND_ZVAL_NULL(zval, xml) \ +{ \ + if(!zval) \ + { \ + xmlSetProp(xml, "xsi:null", "1"); \ + return xml; \ + } \ +} + + +#endif diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c new file mode 100644 index 0000000000..73c60a3e05 --- /dev/null +++ b/ext/soap/php_http.c @@ -0,0 +1,495 @@ +#include "php_soap.h" + +void send_http_soap_request(zval *this_ptr, xmlDoc *doc, char *function_name, char *soapaction) +{ + xmlChar *buf; + char *soap_headers; + int buf_size,err,ret; + sdlPtr sdl; + php_url *phpurl = NULL; + SOAP_STREAM stream; + +#ifdef PHP_DEBUG + zval *raw_request; +#endif + + TSRMLS_FETCH(); + + FETCH_THIS_SOCKET(stream); + FETCH_THIS_URL(phpurl); + FETCH_THIS_SDL(sdl); + + xmlDocDumpMemory(doc, &buf, &buf_size); + +#ifdef PHP_DEBUG + MAKE_STD_ZVAL(raw_request); + ZVAL_STRINGL(raw_request, buf, buf_size, 1); + add_property_zval(this_ptr, "__last_request", raw_request); +#endif + + if(!stream) + { + char *url; + + if(sdl == NULL) + { + zval **location; + if(zend_hash_find(Z_OBJPROP_P(this_ptr), "location", sizeof("location"),(void **) &location) == FAILURE) + php_error(E_ERROR, "Error could not find location"); + url = Z_STRVAL_PP(location); + } + else + url = sdl->location; + + phpurl = php_url_parse(url); + +#ifdef PHP_STREAMS + stream = php_stream_sock_open_host(phpurl->host, (unsigned short)(phpurl->port == 0 ? 80 : phpurl->port), SOCK_STREAM, 0, 0); +#else + stream = get_socket(phpurl->host, (phpurl->port == 0 ? 80 : phpurl->port), 10); +#endif + if(stream) + { + ret = zend_list_insert((void *)stream, le_http_socket); + add_property_resource(this_ptr, "httpsocket", ret); + zend_list_addref(ret); + + ret = zend_list_insert(phpurl, le_url); + add_property_resource(this_ptr, "httpurl", ret); + zend_list_addref(ret); + } + else + php_error(E_ERROR,"Could not connect to host"); + //php_url_free(phpurl); + } + + if(stream) + { + zval **cookies; + char *header = "POST %s HTTP/1.1\r\nConnection: close\r\nAccept: text/html; text/xml; text/plain\r\nUser-Agent: PHP SOAP 0.1\r\nHost: %s\r\nContent-Type: text/xml\r\nContent-Length: %d\r\nSOAPAction: \"%s\"\r\n"; + int size = strlen(header) + strlen(phpurl->host) + strlen(phpurl->path) + 10; + + // TODO: Add authication + if(sdl != NULL) + { + // TODO: need to grab soap action from wsdl.... + soap_headers = emalloc(size + strlen(soapaction)); + sprintf(soap_headers, header, phpurl->path, phpurl->host, buf_size, soapaction); + } + else + { + soap_headers = emalloc(size + strlen(soapaction)); + sprintf(soap_headers, header, phpurl->path, phpurl->host, buf_size, soapaction); + } + +#ifdef PHP_STREAMS + err = php_stream_write(stream, soap_headers, strlen(soap_headers)); +#else + err = send(stream, soap_headers, strlen(soap_headers), 0); +#endif + if(err != (int)strlen(soap_headers)) + php_error(E_ERROR,"Failed Sending HTTP Headers"); + + // Send cookies along with request + if(zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) == SUCCESS) + { + smart_str cookie_str = {0}; + zval **data; + char *key; + int index, i; + + zend_hash_internal_pointer_reset(Z_ARRVAL_PP(cookies)); + for(i = 0;i < (int)Z_ARRVAL_PP(cookies)->nNumOfElements;i++) + { + zend_hash_get_current_data(Z_ARRVAL_PP(cookies), (void **)&data); + zend_hash_get_current_key(Z_ARRVAL_PP(cookies), &key, (long *)&index, FALSE); + + smart_str_appendl(&cookie_str, "Cookie: ", 8); + smart_str_appendl(&cookie_str, key, strlen(key)); + smart_str_appendc(&cookie_str, '='); + smart_str_appendl(&cookie_str, Z_STRVAL_PP(data), Z_STRLEN_PP(data)); + smart_str_appendc(&cookie_str, ';'); + zend_hash_move_forward(Z_ARRVAL_PP(cookies)); + } + smart_str_appendl(&cookie_str, "\r\n", 2); + smart_str_0(&cookie_str); + +#ifdef PHP_STREAMS + err = php_stream_write(stream, cookie_str.c, cookie_str.len); +#else + err = send(stream, cookie_str.c, cookie_str.len,0); +#endif + if(err != (int)cookie_str.len) + php_error(E_ERROR,"Failed Sending HTTP Headers"); + + smart_str_free(&cookie_str); + } + +#ifdef PHP_STREAMS + err = php_stream_write(stream, "\r\n", 2); +#else + err = send(stream, "\r\n", 2, 0); +#endif + if(err != 2) + php_error(E_ERROR,"Failed Sending HTTP Headers"); + + +#ifdef PHP_STREAMS + err = php_stream_write(stream, buf, buf_size); +#else + err = send(stream, buf, buf_size, 0); +#endif + if(err != (int)strlen(buf)) + php_error(E_ERROR,"Failed Sending HTTP Content"); + + efree(soap_headers); + } + xmlFree(buf); +} + +void get_http_soap_response(zval *this_ptr, char **buffer, int *buffer_len) +{ + char *http_headers, *http_body, *content_type, *http_version, http_status[4], *cookie_itt, *connection; + int http_header_size, http_body_size, http_close; + sdlPtr sdl; + zval **socket_ref; + SOAP_STREAM stream; + +#ifdef PHP_DEBUG + zval *raw_response; +#endif + + TSRMLS_FETCH(); + + FETCH_THIS_SDL(sdl); + + if(FIND_SOCKET_PROPERTY(this_ptr, socket_ref) != FAILURE) + { + FETCH_SOCKET_RES(stream, socket_ref); + } + + if(!get_http_headers(stream, &http_headers, &http_header_size)) + php_error(E_ERROR, "Error Fetching http headers"); + + //Check to see what HTTP status was sent + http_version = get_http_header_value(http_headers,"HTTP/"); + if(http_version) + { + char *tmp; + + tmp = strstr(http_version," "); + + if(tmp != NULL) + { + tmp++; + strncpy(http_status,tmp,4); + http_status[3] = '\0'; + } + + /* + Try and process any respsone that is xml might contain fault code + + Maybe try and test for some of the 300's 400's specfics but not + right now. + + if(strcmp(http_status,"200")) + { + zval *err; + char *http_err; + + MAKE_STD_ZVAL(err); + ZVAL_STRING(err, http_body, 1); + http_err = emalloc(strlen("HTTP request failed ()") + 4); + sprintf(http_err, "HTTP request failed (%s)", http_status); + add_soap_fault(thisObj, "SOAP-ENV:Client", http_err, NULL, err); + efree(http_err); + return; + }*/ + + //Try and get headers again + if(!strcmp(http_status, "100")) + { + if(!get_http_headers(stream, &http_headers, &http_header_size)) + php_error(E_ERROR, "Error Fetching http headers"); + } + + efree(http_version); + } + + + if(!get_http_body(stream, http_headers, &http_body, &http_body_size)) + php_error(E_ERROR, "Error Fetching http body"); + +#ifdef PHP_DEBUG + MAKE_STD_ZVAL(raw_response); + ZVAL_STRINGL(raw_response, http_body, http_body_size, 1); + add_property_zval(this_ptr, "__last_response", raw_response); +#endif + + // Close every time right now till i can spend more time on it + // it works.. it's just slower?? + //See if the server requested a close + http_close = TRUE; + connection = get_http_header_value(http_headers,"Connection: "); + if(connection) + { + if(!strcmp(connection, "Keep-Alive")) + http_close = FALSE; + efree(connection); + } + else + { + if(!strncmp(http_version,"1.1", 3)) + http_close = FALSE; + } + + if(http_close) + { +#ifdef PHP_STREAMS + php_stream_close(stream); +#else + SOCK_CLOSE(stream); +#endif + zend_list_delete(Z_RESVAL_PP(socket_ref)); + zend_hash_del(Z_OBJPROP_P(this_ptr), "httpsocket", strlen("httpsocket") + 1); + } + + //Check and see if the server even sent a xml document + content_type = get_http_header_value(http_headers,"Content-Type: "); + if(content_type) + { + char *pos = NULL; + int cmplen; + pos = strstr(content_type,";"); + if(pos != NULL) + cmplen = pos - content_type; + else + cmplen = strlen(content_type); + + if(strncmp(content_type, "text/xml", cmplen)) + { + if(strncmp(http_body, "<?xml", 5)) + { + zval *err; + MAKE_STD_ZVAL(err); + ZVAL_STRINGL(err, http_body, http_body_size, 1); + add_soap_fault(this_ptr, "SOAP-ENV:Client", "Didn't recieve an xml document", NULL, err); + efree(content_type); + return; + } + } + efree(content_type); + } + + //Grab and send back every cookie + //Not going to worry about Path: because + //we shouldn't be changing urls so path dont + //matter too much + cookie_itt = strstr(http_headers,"Set-Cookie: "); + while(cookie_itt) + { + char *end_pos, *cookie; + char *eqpos, *sempos; + smart_str name = {0}, value = {0}; + zval **cookies, *z_cookie; + + if(zend_hash_find(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), (void **)&cookies) == FAILURE) + { + zval *tmp_cookies; + MAKE_STD_ZVAL(tmp_cookies); + array_init(tmp_cookies); + zend_hash_update(Z_OBJPROP_P(this_ptr), "_cookies", sizeof("_cookies"), &tmp_cookies, sizeof(zval *), (void **)&cookies); + } + + end_pos = strstr(cookie_itt,"\r\n"); + cookie = get_http_header_value(cookie_itt,"Set-Cookie: "); + + eqpos = strstr(cookie, "="); + sempos = strstr(cookie, ";"); + + smart_str_appendl(&name, cookie, eqpos - cookie); + smart_str_0(&name); + + smart_str_appendl(&value, eqpos + 1, sempos - (eqpos + 1)); + smart_str_0(&value); + + MAKE_STD_ZVAL(z_cookie); + ZVAL_STRINGL(z_cookie, value.c, value.len, 1); + + zend_hash_update(Z_ARRVAL_PP(cookies), name.c, name.len + 1, &z_cookie, sizeof(zval *), NULL); + + cookie_itt = strstr(cookie_itt + sizeof("Set-Cookie: "), "Set-Cookie: "); + + smart_str_free(&value); + smart_str_free(&name); + efree(cookie); + cookie_itt = FALSE; + } + + *buffer = http_body; + *buffer_len = http_body_size; + efree(http_headers); +} + +char *get_http_header_value(char *headers, char *type) +{ + char *tmp = NULL,*var = NULL; + int size; + + tmp = strstr(headers, type); + if(tmp != NULL) + { + tmp += strlen(type); + size = strstr(tmp, "\r\n") - tmp; + var = emalloc(size + 1); + strncpy(var, tmp, size); + var[size] = '\0'; + } + return var; +} + +int get_http_body(SOAP_STREAM stream, char *headers, char **response, int *out_size) +{ + char *trans_enc, *content_length, *http_buf; + int http_buf_size = 0; + TSRMLS_FETCH(); + + trans_enc = get_http_header_value(headers, "Transfer-Encoding: "); + content_length = get_http_header_value(headers, "Content-Length: "); + + //this is temp... + // netscape enterprise server sends in lowercase??? + if(content_length == NULL) + content_length = get_http_header_value(headers, "Content-length: "); + + if(trans_enc && !strcmp(trans_enc, "chunked")) + { + int cur = 0, size = 0, buf_size = 0, len_size; + char done, chunk_size[10]; + + done = FALSE; + http_buf = emalloc(1); + while(!done) + { + cur = 0; + while(!(chunk_size[cur - 2] == '\r' && chunk_size[cur - 1] == '\n')) +#ifdef PHP_STREAMS + chunk_size[cur++] = php_stream_getc(stream); +#else + chunk_size[cur++] = php_sock_fgetc(stream); +#endif + if(sscanf(chunk_size,"%x",&buf_size) != -1) + { + http_buf = erealloc(http_buf,http_buf_size + buf_size); + len_size = 0; + while(http_buf_size < buf_size) + { +#ifdef PHP_STREAMS + len_size += php_stream_read(stream, &http_buf[http_buf_size], buf_size - len_size); +#else + len_size += php_sock_fread(&http_buf[http_buf_size], buf_size - len_size, stream); +#endif + http_buf_size += len_size; + } +#ifdef PHP_STREAMS + php_stream_getc(stream);php_stream_getc(stream); +#else + //Eat up '\r' '\n' + php_sock_fgetc(stream);php_sock_fgetc(stream); +#endif + } + if(buf_size == 0) + done = TRUE; + } + efree(trans_enc); + } + else if(content_length) + { + int size; + size = atoi(content_length); + http_buf = emalloc(size + 1); + + while(http_buf_size < size) +#ifdef PHP_STREAMS + http_buf_size += php_stream_read(stream, &http_buf[http_buf_size], size - http_buf_size); +#else + http_buf_size += php_sock_fread(&http_buf[http_buf_size], size - http_buf_size, stream); +#endif + http_buf[size] = '\0'; + efree(content_length); + } + else + php_error(E_ERROR,"Don't know how to read http body, No Content-Length or chunked data"); + + (*response) = http_buf; + (*out_size) = http_buf_size; + return TRUE; +} + +int get_http_headers(SOAP_STREAM stream, char **response, int *out_size) +{ + int done; + char chr; + smart_str tmp_response = {0}; + TSRMLS_FETCH(); + + done = FALSE; + + while(!done) + { +#ifdef PHP_STREAMS + chr = php_stream_getc(stream); +#else + chr = php_sock_fgetc(stream); +#endif + if(chr != EOF) + { + smart_str_appendc(&tmp_response, chr); + if(tmp_response.c[tmp_response.len - 2] == '\r' && tmp_response.c[tmp_response.len - 1] == '\n' && + tmp_response.c[tmp_response.len - 4] == '\r' && tmp_response.c[tmp_response.len - 3] == '\n') + { + smart_str_0(&tmp_response); + done = TRUE; + } + } + else + return FALSE; + } + (*response) = tmp_response.c; + (*out_size) = tmp_response.len; + return TRUE; +} + +#ifndef PHP_STREAMS +SOCKET get_socket(char* host,int portno,int time) +{ + SOCKET socketd = -1; + struct sockaddr_in server; + struct timeval timeout; + + memset(&server, 0, sizeof(server)); + socketd = socket(AF_INET,SOCK_STREAM,0); + if (socketd == SOCK_ERR) { + if(socketd > 0) + SOCK_CLOSE(socketd); + return FALSE; + } + server.sin_family = AF_INET; + + if(php_lookup_hostname(host,&server.sin_addr)) { + if(socketd > 0) + SOCK_CLOSE(socketd); + return FALSE; + } + server.sin_port = htons((unsigned short)portno); + timeout.tv_sec = time; + timeout.tv_usec = 0; + if (php_connect_nonb(socketd, (struct sockaddr *)&server, sizeof(struct sockaddr_in), &timeout) == SOCK_CONN_ERR) { + if(socketd > 0) + SOCK_CLOSE(socketd); + return FALSE; + } + + return socketd; +} +#endif diff --git a/ext/soap/php_http.h b/ext/soap/php_http.h new file mode 100644 index 0000000000..4e4fff7f4d --- /dev/null +++ b/ext/soap/php_http.h @@ -0,0 +1,25 @@ +#ifndef PHP_HTTP_H +#define PHP_HTTP_H + +void send_http_soap_request(zval *this_ptr, xmlDoc *doc, char *function_name, char *soapaction); +void get_http_soap_response(zval *this_ptr, char **buffer, int *buffer_len); + +char *get_http_header_value(char *headers, char *type); +int get_http_body(SOAP_STREAM socketd, char *headers, char **response, int *out_size); +int get_http_headers(SOAP_STREAM socketd,char **response, int *out_size); + +#ifndef PHP_STREAMS +#ifndef ZEND_WIN32 +# ifndef closesocket +# define closesocket close +# endif +#endif + +#ifndef SOCK_CLOSE +# define SOCK_CLOSE(s) shutdown(s, 0); closesocket(s) +#endif + +SOCKET get_socket(char* host,int portno,int timeout); +#endif + +#endif diff --git a/ext/soap/php_packet_soap.c b/ext/soap/php_packet_soap.c new file mode 100644 index 0000000000..3414f970eb --- /dev/null +++ b/ext/soap/php_packet_soap.c @@ -0,0 +1,124 @@ +#include "php_soap.h" + +int parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctionPtr fn, char *fn_name, zval ***ret, int *num_params) +{ + xmlDocPtr response; + xmlNodePtr trav, trav2, env, body, resp, cur, fault; + zval **tmp_ret; + TSRMLS_FETCH(); + + response = xmlParseMemory(buffer, buffer_size); + xmlCleanupParser(); + + trav = response->children; + FOREACHNODE(trav,"Envelope",env) + { + trav2 = env->children; + FOREACHNODE(trav2,"Body",body) + { + fault = get_node(body->children,"Fault"); + if(fault != NULL) + { + char *faultcode = NULL, *faultstring = NULL, *faultactor = NULL; + zval *details = NULL; + xmlNodePtr tmp; + + tmp = get_node(fault->children,"faultcode"); + if(tmp != NULL && tmp->children != NULL) + faultcode = tmp->children->content; + + tmp = get_node(fault->children,"faultstring"); + if(tmp != NULL && tmp->children != NULL) + faultstring = tmp->children->content; + + tmp = get_node(fault->children,"faultactor"); + if(tmp != NULL && tmp->children != NULL) + faultactor = tmp->children->content; + + tmp = get_node(fault->children,"detail"); + if(tmp != NULL) + { + encodePtr enc; + enc = get_conversion(UNKNOWN_TYPE); + details = enc->to_zval(enc->details, tmp); + } + + add_soap_fault(this_ptr, faultcode, faultstring, faultactor, details); + } + else + { + resp = body->children; + if(fn != NULL) + { + cur = get_node(resp, fn->responseName); + if(cur != NULL) + { + int num_resp = zend_hash_num_elements(fn->responseParameters); + if(num_resp <= 1) + { + sdlParamPtr *h_param, param; + xmlNodePtr val; + + zend_hash_internal_pointer_reset(fn->responseParameters); + if(zend_hash_get_current_data(fn->responseParameters, (void **)&h_param) != SUCCESS) + { + (*num_params) = 0; + } + else + { + param = (*h_param); + val = get_node(cur->children, param->paramName); + if(val != NULL) + { + encodePtr enc; + tmp_ret = emalloc(sizeof(zval **)); + if(param != NULL) + enc = param->encode; + else + enc = get_conversion(UNKNOWN_TYPE); + + tmp_ret[0] = master_to_zval(enc, val); + (*ret) = tmp_ret; + (*num_params) = 1; + } + else + php_error(E_ERROR, "Can't find response parameter \"%s\"", param->paramName); + } + } + else + { + php_error(E_ERROR,"Doesn't handle multiple return values"); + } + } + } + else + { + cur = resp; + while(cur && cur->type != XML_ELEMENT_NODE) + cur = cur->next; + if(cur != NULL) + { + xmlNodePtr val; + val = cur->children; + while(val && val->type != XML_ELEMENT_NODE) + val = val->next; + + if(val != NULL) + { + encodePtr enc; + enc = get_conversion(UNKNOWN_TYPE); + tmp_ret = emalloc(sizeof(zval **)); + tmp_ret[0] = master_to_zval(enc, val); + (*ret) = tmp_ret; + (*num_params) = 1; + } + } + } + } + } + ENDFOREACH(trav2); + } + ENDFOREACH(trav); + xmlFreeDoc(response); + return TRUE; +} diff --git a/ext/soap/php_packet_soap.h b/ext/soap/php_packet_soap.h new file mode 100644 index 0000000000..0d094269da --- /dev/null +++ b/ext/soap/php_packet_soap.h @@ -0,0 +1,6 @@ +#ifndef PHP_PACKET_SOAP_H +#define PHP_PACKET_SOAP_H + +int parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctionPtr fn, char *fn_name, zval ***ret, int *num_params); + +#endif
\ No newline at end of file diff --git a/ext/soap/php_schema.c b/ext/soap/php_schema.c new file mode 100644 index 0000000000..020b299d47 --- /dev/null +++ b/ext/soap/php_schema.c @@ -0,0 +1,1047 @@ +#include "php_soap.h" +/* +2.6.1 xsi:type +2.6.2 xsi:nil +2.6.3 xsi:schemaLocation, xsi:noNamespaceSchemaLocation +*/ + +/* +<schema + attributeFormDefault = (qualified | unqualified) : unqualified + blockDefault = (#all | List of (extension | restriction | substitution)) : '' + elementFormDefault = (qualified | unqualified) : unqualified + finalDefault = (#all | List of (extension | restriction)) : '' + id = ID + targetNamespace = anyURI + version = token + xml:lang = language + {any attributes with non-schema namespace . . .}> + Content: ((include | import | redefine | annotation)*, (((simpleType | complexType | group | attributeGroup) | element | attribute | notation), annotation*)*) +</schema> +*/ +int load_schema(sdlPtr *sdl,xmlNodePtr schema) +{ + xmlNodePtr trav, element, compType, simpleType, attribute; + xmlAttrPtr tns; + + if(!(*sdl)->types) + { + (*sdl)->types = malloc(sizeof(HashTable)); + zend_hash_init((*sdl)->types, 0, NULL, delete_type, 1); + } + + tns = get_attribute(schema->properties, "targetNamespace"); + + trav = schema->children; + FOREACHNODE(trav,"complexType",compType) + { + schema_complexType(sdl, tns, compType, NULL); + } + ENDFOREACH(trav); + + trav = schema->children; + FOREACHNODE(trav,"simpleType",simpleType) + { + schema_simpleType(sdl, tns, simpleType, NULL); + } + ENDFOREACH(trav); + + trav = schema->children; + FOREACHNODE(trav,"element",element) + { + schema_element(sdl, tns, element, NULL); + } + ENDFOREACH(trav); + + trav = schema->children; + FOREACHNODE(trav, "attribute", attribute) + { + schema_attribute(sdl, tns, attribute, NULL); + } + ENDFOREACH(trav); + return FALSE; +} +/* +<simpleType + final = (#all | (list | union | restriction)) + id = ID + name = NCName + {any attributes with non-schema namespace . . .}> + Content: (annotation?, (restriction | list | union)) +</simpleType> +*/ +int schema_simpleType(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr simpleType, sdlTypePtr cur_type) +{ + xmlNodePtr content; + xmlAttrPtr name, ns; + + ns = get_attribute(simpleType->properties, "targetNamespace"); + if(ns == NULL) + ns = tsn; + + name = get_attribute(simpleType->properties, "name"); + if(name != NULL) + { + HashTable *ht; + char *key; + sdlTypePtr newType, *ptr; + + newType = malloc(sizeof(sdlType)); + memset(newType, 0, sizeof(sdlType)); + newType->name = strdup(name->children->content); + newType->namens = strdup(ns->children->content); + + if(cur_type == NULL) + { + ht = (*sdl)->types; + key = emalloc(strlen(newType->namens) + strlen(newType->name) + 2); + sprintf(key, "%s:%s", newType->namens, newType->name); + } + else + { + if(cur_type->elements == NULL) + { + cur_type->elements = malloc(sizeof(HashTable)); + zend_hash_init(cur_type->elements, 0, NULL, delete_type, 1); + } + key = strdup(newType->name); + ht = cur_type->elements; + } + + zend_hash_add(ht, key, strlen(key), &newType, sizeof(sdlTypePtr), (void **)&ptr); + cur_type = (*ptr); + efree(key); + } + + content = get_node(simpleType->children, "restriction"); + if(content != NULL) + { + schema_restriction_simpleType(sdl, tsn, content, cur_type); + return TRUE; + } + + content = get_node(simpleType->children, "list"); + if(content != NULL) + { + schema_list(sdl, tsn, content, cur_type); + return TRUE; + } + + content = get_node(simpleType->children, "union"); + if(content != NULL) + { + schema_union(sdl, tsn, content, cur_type); + return TRUE; + } + + return FALSE; +} + +/* +<list + id = ID + itemType = QName + {any attributes with non-schema namespace . . .}> + Content: (annotation?, (simpleType?)) +</list> +*/ +int schema_list(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr listType, sdlTypePtr cur_type) +{ + return TRUE; +} + +/* +<union + id = ID + memberTypes = List of QName + {any attributes with non-schema namespace . . .}> + Content: (annotation?, (simpleType*)) +</union> +*/ +int schema_union(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr unionType, sdlTypePtr cur_type) +{ + return TRUE; +} + +/* +<simpleContent + id = ID + {any attributes with non-schema namespace . . .}> + Content: (annotation?, (restriction | extension)) +</simpleContent> +*/ +int schema_simpleContent(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr simpCompType, sdlTypePtr cur_type) +{ + xmlNodePtr content; + + content = get_node(simpCompType->children, "restriction"); + if(content == NULL) + { + schema_restriction_simpleContent(sdl, tsn, content, cur_type); + return TRUE; + } + + content = get_node(simpCompType->children, "extension"); + if(content == NULL) + { + //schema_extension(sdl, tsn, content, cur_type); + php_error(E_ERROR, "Error parsing schema (doesn't support extensions on simpleContent)"); + return TRUE; + } + + php_error(E_ERROR, "Error parsing schema (simpleContent)"); + return FALSE; +} + +/* +<restriction + base = QName + id = ID + {any attributes with non-schema namespace . . .}> + Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*)?, ((attribute | attributeGroup)*, anyAttribute?)) +</restriction> +*/ +int schema_restriction_simpleType(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr restType, sdlTypePtr cur_type) +{ + xmlNodePtr content, trav; + xmlAttrPtr base; + + content = get_node(restType->children, "simpleType"); + if(content != NULL) + { + schema_simpleType(sdl, tsn, content, cur_type); + return TRUE; + } + + base = get_attribute(restType->properties, "base"); + if(base != NULL) + { + //cur_type->base = estrdup(base->children->content); + } + + if(cur_type->restrictions == NULL) + { + cur_type->restrictions = malloc(sizeof(sdlRestrictions)); + memset(cur_type->restrictions, 0, sizeof(sdlRestrictions)); + } + + trav = restType->children; + do + { + if(trav->type == XML_ELEMENT_NODE) + { + if(!strcmp(trav->name, "minExclusive")) + schema_restriction_var_int(trav, &cur_type->restrictions->minExclusive); + else if(!strcmp(trav->name, "minInclusive")) + schema_restriction_var_int(trav, &cur_type->restrictions->minInclusive); + else if(!strcmp(trav->name, "maxExclusive")) + schema_restriction_var_int(trav, &cur_type->restrictions->maxExclusive); + else if(!strcmp(trav->name, "maxInclusive")) + schema_restriction_var_int(trav, &cur_type->restrictions->maxInclusive); + else if(!strcmp(trav->name, "totalDigits")) + schema_restriction_var_int(trav, &cur_type->restrictions->totalDigits); + else if(!strcmp(trav->name, "fractionDigits")) + schema_restriction_var_int(trav, &cur_type->restrictions->fractionDigits); + else if(!strcmp(trav->name, "length")) + schema_restriction_var_int(trav, &cur_type->restrictions->length); + else if(!strcmp(trav->name, "minLength")) + schema_restriction_var_int(trav, &cur_type->restrictions->minLength); + else if(!strcmp(trav->name, "maxLength")) + schema_restriction_var_int(trav, &cur_type->restrictions->maxLength); + else if(!strcmp(trav->name, "whiteSpace")) + schema_restriction_var_char(trav, &cur_type->restrictions->whiteSpace); + else if(!strcmp(trav->name, "pattern")) + schema_restriction_var_char(trav, &cur_type->restrictions->pattern); + else if(!strcmp(trav->name, "enumeration")) + { + sdlRestrictionCharPtr enumval = NULL; + + schema_restriction_var_char(trav, &enumval); + if(cur_type->restrictions->enumeration == NULL) + { + cur_type->restrictions->enumeration = malloc(sizeof(HashTable)); + zend_hash_init(cur_type->restrictions->enumeration, 0, NULL, delete_schema_restriction_var_char, 1); + } + zend_hash_next_index_insert(cur_type->restrictions->enumeration, &enumval, sizeof(sdlRestrictionCharPtr), NULL); + } + } + }while(trav = trav->next); + + return TRUE; +} + +/* +<restriction + base = QName + id = ID + {any attributes with non-schema namespace . . .}> + Content: (annotation?, (group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?)) +</restriction> +*/ +int schema_restriction_complexContent(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr restType, sdlTypePtr cur_type) +{ + xmlAttrPtr base; + xmlNodePtr trav; + + base = get_attribute(restType->properties, "base"); + if(base != NULL) + { + char *type, *ns; + xmlNsPtr nsptr; + + parse_namespace(base->children->content, &type, &ns); + nsptr = xmlSearchNs(restType->doc, restType, ns); + if(nsptr != NULL) + { + cur_type->encode = get_encoder((*sdl), (char *)nsptr->href, type); + } + if(type) efree(type); + if(ns) efree(ns); + } + + trav = restType->children; + do + { + if(trav->type == XML_ELEMENT_NODE) + { + if(!strcmp(trav->name, "group")) + { + schema_group(sdl, tsn, trav, cur_type); + return TRUE; + } + else if(!strcmp(trav->name, "all")) + { + schema_all(sdl, tsn, trav, cur_type); + return TRUE; + } + else if(!strcmp(trav->name, "choice")) + { + schema_choice(sdl, tsn, trav, cur_type); + return TRUE; + } + else if(!strcmp(trav->name, "sequence")) + { + schema_sequence(sdl, tsn, trav, cur_type); + return TRUE; + } + else if(!strcmp(trav->name, "attribute")) + { + schema_attribute(sdl, tsn, trav, cur_type); + } + } + }while(trav = trav->next); + + return TRUE; +} + +/* +<restriction + base = QName + id = ID + {any attributes with non-schema Namespace . . .}> + Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*)) +</restriction> +*/ +int schema_restriction_simpleContent(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr restType, sdlTypePtr cur_type) +{ + xmlNodePtr content, trav; + xmlAttrPtr base; + + base = get_attribute(restType->properties, "base"); + if(base != NULL) + cur_type->encode = get_encoder_from_prefix((*sdl), restType, base->children->content); + + content = get_node(restType->children, "simpleType"); + if(content != NULL) + { + schema_simpleType(sdl, tsn, content, cur_type); + return TRUE; + } + + if(cur_type->restrictions == NULL) + cur_type->restrictions = malloc(sizeof(sdlRestrictions)); + + trav = restType->children; + do + { + if(trav->type == XML_ELEMENT_NODE) + { + if(!strcmp(trav->name, "minExclusive")) + schema_restriction_var_int(trav, &cur_type->restrictions->minExclusive); + else if(!strcmp(trav->name, "minInclusive")) + schema_restriction_var_int(trav, &cur_type->restrictions->minInclusive); + else if(!strcmp(trav->name, "maxExclusive")) + schema_restriction_var_int(trav, &cur_type->restrictions->maxExclusive); + else if(!strcmp(trav->name, "maxInclusive")) + schema_restriction_var_int(trav, &cur_type->restrictions->maxInclusive); + else if(!strcmp(trav->name, "totalDigits")) + schema_restriction_var_int(trav, &cur_type->restrictions->totalDigits); + else if(!strcmp(trav->name, "fractionDigits")) + schema_restriction_var_int(trav, &cur_type->restrictions->fractionDigits); + else if(!strcmp(trav->name, "length")) + schema_restriction_var_int(trav, &cur_type->restrictions->length); + else if(!strcmp(trav->name, "minLength")) + schema_restriction_var_int(trav, &cur_type->restrictions->minLength); + else if(!strcmp(trav->name, "maxLength")) + schema_restriction_var_int(trav, &cur_type->restrictions->maxLength); + else if(!strcmp(trav->name, "whiteSpace")) + schema_restriction_var_char(trav, &cur_type->restrictions->whiteSpace); + else if(!strcmp(trav->name, "pattern")) + schema_restriction_var_char(trav, &cur_type->restrictions->pattern); + else if(!strcmp(trav->name, "enumeration")) + { + sdlRestrictionCharPtr enumval = NULL; + + schema_restriction_var_char(trav, &enumval); + if(cur_type->restrictions->enumeration == NULL) + { + cur_type->restrictions->enumeration = malloc(sizeof(HashTable)); + zend_hash_init(cur_type->restrictions->enumeration, 0, NULL, delete_schema_restriction_var_char, 1); + } + zend_hash_next_index_insert(cur_type->restrictions->enumeration, &enumval, sizeof(sdlRestrictionCharPtr), NULL); + } + } + }while(trav = trav->next); + + return TRUE; +} + +int schema_restriction_var_int(xmlNodePtr val, sdlRestrictionIntPtr *valptr) +{ + xmlAttrPtr fixed, value, id; + + if((*valptr) == NULL) + (*valptr) = malloc(sizeof(sdlRestrictionInt)); + + fixed = get_attribute(val->properties, "fixed"); + (*valptr)->fixed = FALSE; + if(fixed != NULL) + { + if(!strcmp(fixed->children->content, "true") || + !strcmp(fixed->children->content, "1")) + (*valptr)->fixed = TRUE; + } + + id = get_attribute(val->properties, "id"); + if(id != NULL) + (*valptr)->id = strdup(id->children->content); + + value = get_attribute(val->properties, "value"); + if(value == NULL) + php_error(E_ERROR, "Error parsing wsdl schema \"missing value for minExclusive\""); + + (*valptr)->value = atoi(value->children->content); + + return TRUE; +} + +void delete_restriction_var_int(void *rvi) +{ + sdlRestrictionIntPtr ptr = *((sdlRestrictionIntPtr*)rvi); + if(ptr->id); + free(ptr->id); + + free(ptr); +} + +int schema_restriction_var_char(xmlNodePtr val, sdlRestrictionCharPtr *valptr) +{ + xmlAttrPtr fixed, value, id; + + if((*valptr) == NULL) + (*valptr) = malloc(sizeof(sdlRestrictionChar)); + + fixed = get_attribute(val->properties, "fixed"); + (*valptr)->fixed = FALSE; + if(fixed != NULL) + { + if(!strcmp(fixed->children->content, "true") || + !strcmp(fixed->children->content, "1")) + (*valptr)->fixed = TRUE; + } + + id = get_attribute(val->properties, "id"); + if(id != NULL) + (*valptr)->id = strdup(id->children->content); + + value = get_attribute(val->properties, "value"); + if(value == NULL) + php_error(E_ERROR, "Error parsing wsdl schema \"missing value restriction\""); + + (*valptr)->value = strdup(value->children->content); + return TRUE; +} + +void delete_schema_restriction_var_char(void *srvc) +{ + sdlRestrictionCharPtr ptr = *((sdlRestrictionCharPtr*)srvc); + if(ptr->id) + free(ptr->id); + if(ptr->value) + free(ptr->value); + free(ptr); +} + +/* +From simpleContent (not supported): +<extension + base = QName + id = ID + {any attributes with non-schema namespace . . .}> + Content: (annotation?, ((attribute | attributeGroup)*, anyAttribute?)) +</extension> + +From complexContent: +<extension + base = QName + id = ID + {any attributes with non-schema namespace . . .}> + Content: (annotation?, ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?))) +</extension> +*/ +int schema_extension(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type) +{ + xmlNodePtr content; + xmlAttrPtr base; + + base = get_attribute(extType->properties, "base"); + + content = get_node(extType->children, "group"); + if(content != NULL) + { + schema_group(sdl, tsn, content, cur_type); + return TRUE; + } + + content = get_node(extType->children, "all"); + if(content != NULL) + { + schema_all(sdl, tsn, content, cur_type); + return TRUE; + } + + content = get_node(extType->children, "choice"); + if(content != NULL) + { + schema_choice(sdl, tsn, content, cur_type); + return TRUE; + } + + content = get_node(extType->children, "sequence"); + if(content != NULL) + { + schema_sequence(sdl, tsn, content, cur_type); + return TRUE; + } + return FALSE; +} + +/* +<all + id = ID + maxOccurs = 1 : 1 + minOccurs = (0 | 1) : 1 + {any attributes with non-schema namespace . . .}> + Content: (annotation?, element*) +</all> +*/ +int schema_all(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr all, sdlTypePtr cur_type) +{ + xmlNodePtr element, trav; + + trav = all->children; + FOREACHNODE(trav, "element", element) + { + schema_element(sdl, tsn, element, cur_type); + } + ENDFOREACH(trav); + return TRUE; +} + +/* +<group + name = NCName> + Content: (annotation?, (all | choice | sequence)) +</group> +*/ +int schema_group(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr groupType, sdlTypePtr cur_type) +{ + xmlNodePtr content; + xmlAttrPtr name; + + name = get_attribute(groupType->properties, "name"); + if(name != NULL) + { + + } + + content = get_node(groupType->children, "all"); + if(content != NULL) + { + schema_all(sdl, tsn, content, cur_type); + return TRUE; + } + + content = get_node(groupType->children, "choice"); + if(content != NULL) + { + schema_choice(sdl, tsn, content, cur_type); + return TRUE; + } + + content = get_node(groupType->children, "sequence"); + if(content != NULL) + { + schema_sequence(sdl, tsn, content, cur_type); + return TRUE; + } + return FALSE; +} +/* +<choice + id = ID + maxOccurs = (nonNegativeInteger | unbounded) : 1 + minOccurs = nonNegativeInteger : 1 + {any attributes with non-schema namespace . . .}> + Content: (annotation?, (element | group | choice | sequence | any)*) +</choice> +*/ +int schema_choice(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr choiceType, sdlTypePtr cur_type) +{ + xmlNodePtr trav, data; + + //cur_type->property_type = CHOICE; + + trav = choiceType->children; + FOREACHNODE(trav, "element", data) + { + schema_element(sdl, tsn, data, cur_type); + } + ENDFOREACH(trav); + + trav = choiceType->children; + FOREACHNODE(trav, "group", data) + { + schema_group(sdl, tsn, data, cur_type); + } + ENDFOREACH(trav); + + trav = choiceType->children; + FOREACHNODE(trav, "choice", data) + { + schema_choice(sdl, tsn, data, cur_type); + } + ENDFOREACH(trav); + + trav = choiceType->children; + FOREACHNODE(trav, "sequence", data) + { + schema_sequence(sdl, tsn, data, cur_type); + } + ENDFOREACH(trav); + + trav = choiceType->children; + FOREACHNODE(trav, "any", data) + { + schema_any(sdl, tsn, data, cur_type); + } + ENDFOREACH(trav); + + return TRUE; +} + +/* +<sequence + id = ID + maxOccurs = (nonNegativeInteger | unbounded) : 1 + minOccurs = nonNegativeInteger : 1 + {any attributes with non-schema namespace . . .}> + Content: (annotation?, (element | group | choice | sequence | any)*) +</sequence> +*/ +int schema_sequence(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr seqType, sdlTypePtr cur_type) +{ + xmlNodePtr trav; + + trav = seqType->children; + do + { + if(trav->type == XML_ELEMENT_NODE) + { + if(!strcmp(trav->name, "element")) + { + schema_element(sdl, tsn, trav, cur_type); + } + else if(!strcmp(trav->name, "group")) + { + schema_group(sdl, tsn, trav, cur_type); + } + else if(!strcmp(trav->name, "choice")) + { + schema_choice(sdl, tsn, trav, cur_type); + } + else if(!strcmp(trav->name, "sequence")) + { + schema_sequence(sdl, tsn, trav, cur_type); + } + else if(!strcmp(trav->name, "any")) + { + schema_any(sdl, tsn, trav, cur_type); + } + } + } + while(trav = trav->next); + + return TRUE; +} + +int schema_any(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type) +{ + return TRUE; +} + +/* +<complexContent + id = ID + mixed = boolean + {any attributes with non-schema namespace . . .}> + Content: (annotation?, (restriction | extension)) +</complexContent> +*/ +int schema_complexContent(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr compCont, sdlTypePtr cur_type) +{ + xmlNodePtr content; + + content = get_node(compCont->children, "restriction"); + if(content != NULL) + { + schema_restriction_complexContent(sdl, tsn, content, cur_type); + return TRUE; + } + + return TRUE; +} + +/* +<complexType + abstract = boolean : false + block = (#all | List of (extension | restriction)) + final = (#all | List of (extension | restriction)) + id = ID + mixed = boolean : false + name = NCName + {any attributes with non-schema namespace . . .}> + Content: (annotation?, (simpleContent | complexContent | ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?)))) +</complexType> +*/ +int schema_complexType(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr compType, sdlTypePtr cur_type) +{ + xmlNodePtr content; + xmlAttrPtr attrs, name, ns; + + attrs = compType->properties; + ns = get_attribute(attrs, "targetNamespace"); + if(ns == NULL) + ns = tsn; + + name = get_attribute(attrs, "name"); + if(name) + { + HashTable *ht; + sdlTypePtr newType, *ptr; + char *key; + + newType = malloc(sizeof(sdlType)); + memset(newType, 0, sizeof(sdlType)); + newType->name = strdup(name->children->content); + newType->namens = strdup(ns->children->content); + + if(cur_type == NULL) + { + ht = (*sdl)->types; + key = emalloc(strlen(newType->namens) + strlen(newType->name) + 2); + sprintf(key, "%s:%s", newType->namens, newType->name); + } + else + { + if(cur_type->elements == NULL) + { + cur_type->elements = malloc(sizeof(HashTable)); + zend_hash_init(cur_type->elements, 0, NULL, delete_type, 1); + } + ht = cur_type->elements; + key = estrdup(cur_type->name); + } + + zend_hash_add(ht, key, strlen(key), &newType, sizeof(sdlTypePtr), (void **)&ptr); + cur_type = (*ptr); + create_encoder((*sdl), cur_type, ns->children->content, name->children->content); + efree(key); + } + + content = get_node(compType->children, "simpleContent"); + if(content != NULL) + { + schema_simpleContent(sdl, tsn, content, cur_type); + return TRUE; + } + + content = get_node(compType->children, "complexContent"); + if(content != NULL) + { + schema_complexContent(sdl, tsn, content, cur_type); + return TRUE; + } + + //(group | all | choice | sequence) + content = get_node(compType->children, "group"); + if(content != NULL) + { + schema_group(sdl, tsn, content, cur_type); + return TRUE; + } + + content = get_node(compType->children, "all"); + if(content != NULL) + { + schema_all(sdl, tsn, content, cur_type); + return TRUE; + } + + content = get_node(compType->children, "choice"); + if(content != NULL) + { + schema_choice(sdl, tsn, content, cur_type); + return TRUE; + } + + content = get_node(compType->children, "sequence"); + if(content != NULL) + schema_sequence(sdl, tsn, content, cur_type); + + return TRUE; +} +/* +<element + abstract = boolean : false + block = (#all | List of (extension | restriction | substitution)) + default = string + final = (#all | List of (extension | restriction)) + fixed = string + form = (qualified | unqualified) + id = ID + maxOccurs = (nonNegativeInteger | unbounded) : 1 + minOccurs = nonNegativeInteger : 1 + name = NCName + nillable = boolean : false + ref = QName + substitutionGroup = QName + type = QName + {any attributes with non-schema namespace . . .}> + Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*)) +</element> +*/ +int schema_element(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTypePtr cur_type) +{ + xmlNodePtr content; + xmlAttrPtr attrs, curattr, name, ns; + TSRMLS_FETCH(); + + attrs = element->properties; + ns = get_attribute(attrs, "targetNamespace"); + if(ns == NULL) + ns = tsn; + + name = get_attribute(attrs, "name"); + if(!name) + name = get_attribute(attrs, "ref"); + if(name) + { + HashTable *addHash; + sdlTypePtr newType, *tmp; + + newType = malloc(sizeof(sdlType)); + + memset(newType, 0, sizeof(sdlType)); + newType->name = strdup(name->children->content); + newType->namens = strdup(tsn->children->content); + newType->nullable = FALSE; + newType->min_occurs = 1; + newType->max_occurs = 1; + + if(cur_type == NULL) + addHash = (*sdl)->types; + else + { + if(cur_type->elements == NULL) + { + cur_type->elements = malloc(sizeof(HashTable)); + zend_hash_init(cur_type->elements, 0, NULL, delete_type, 1); + } + addHash = cur_type->elements; + } + + zend_hash_add(addHash, newType->name, strlen(newType->name), &newType, sizeof(sdlTypePtr), (void **)&tmp); + cur_type = (*tmp); + } + + //nillable = boolean : false + attrs = element->properties; + curattr = get_attribute(attrs, "nillable"); + if(curattr != NULL) + { + if(!stricmp(curattr->children->content, "true") || + !stricmp(curattr->children->content, "1")) + cur_type->nullable = TRUE; + else + cur_type->nullable = FALSE; + } + else + cur_type->nullable = FALSE; + + //type = QName + curattr = get_attribute(attrs, "type"); + if(!curattr) + curattr = name; + if(curattr) + { + char *cptype, *str_ns; + xmlNsPtr nsptr; + + parse_namespace(curattr->children->content, &cptype, &str_ns); + if(str_ns) + nsptr = xmlSearchNs(element->doc, element, str_ns); + else + nsptr = xmlSearchNsByHref(element->doc, element, ns->children->content); + + cur_type->encode = get_create_encoder((*sdl), cur_type, (char *)nsptr->href, (char *)cptype); + if(str_ns) efree(str_ns); + if(cptype) efree(cptype); + } + + content = get_node(element->children, "simpleType"); + if(content) + schema_simpleType(sdl, tsn, content, cur_type); + + content = get_node(element->children, "complexType"); + if(content) + schema_complexType(sdl, tsn, content, cur_type); + + return FALSE; +} + +/* +<attribute + default = string + fixed = string + form = (qualified | unqualified) + id = ID + name = NCName + ref = QName + type = QName + use = (optional | prohibited | required) : optional + {any attributes with non-schema namespace . . .}> + Content: (annotation?, (simpleType?)) +</attribute> +*/ +int schema_attribute(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr attrType, sdlTypePtr cur_type) +{ + xmlAttrPtr attr; + sdlAttributePtr newAttr; + xmlAttrPtr trav; + smart_str key = {0}; + + newAttr = malloc(sizeof(sdlAttribute)); + memset(newAttr, 0, sizeof(sdlAttribute)); + + if(cur_type->attributes == NULL) + { + cur_type->attributes = malloc(sizeof(HashTable)); + zend_hash_init(cur_type->attributes, 0, NULL, delete_attribute, 1); + } + + trav = attrType->properties; + FOREACHATTRNODE(trav, NULL, attr) + { + if(attr_is_equal_ex(trav, "default", SCHEMA_NAMESPACE)) + newAttr->def = strdup(attr->children->content); + else if(attr_is_equal_ex(trav, "fixed", SCHEMA_NAMESPACE)) + newAttr->fixed = strdup(attr->children->content); + else if(attr_is_equal_ex(trav, "form", SCHEMA_NAMESPACE)) + newAttr->form = strdup(attr->children->content); + else if(attr_is_equal_ex(trav, "id", SCHEMA_NAMESPACE)) + newAttr->id = strdup(attr->children->content); + else if(attr_is_equal_ex(trav, "name", SCHEMA_NAMESPACE)) + newAttr->name = strdup(attr->children->content); + else if(attr_is_equal_ex(trav, "ref", SCHEMA_NAMESPACE)) + newAttr->ref= strdup(attr->children->content); + else if(attr_is_equal_ex(trav, "type", SCHEMA_NAMESPACE)) + newAttr->type = strdup(attr->children->content); + else if(attr_is_equal_ex(trav, "use", SCHEMA_NAMESPACE)) + newAttr->use = strdup(attr->children->content); + else + { + xmlNsPtr nsPtr = attr_find_ns(trav); + + if(strcmp(nsPtr->href, SCHEMA_NAMESPACE)) + { + smart_str key2 = {0}; + + if(!newAttr->extraAttributes) + { + newAttr->extraAttributes = malloc(sizeof(HashTable)); + zend_hash_init(newAttr->extraAttributes, 0, NULL, NULL, 1); + } + + smart_str_appends(&key2, nsPtr->href); + smart_str_appendc(&key2, ':'); + smart_str_appends(&key2, trav->name); + smart_str_0(&key2); + zend_hash_add(newAttr->extraAttributes, key2.c, key2.len + 1, &trav, sizeof(xmlAttrPtr), NULL); + smart_str_free(&key2); + } + } + } + ENDFOREACH(trav); + + + if(newAttr->ref || newAttr->name) + { + xmlNsPtr ns; + + if(newAttr->ref) + { + char *value, *prefix = NULL; + + parse_namespace(newAttr->ref, &value, &prefix); + ns = xmlSearchNs(attrType->doc, attrType, prefix); + smart_str_appends(&key, ns->href); + smart_str_appendc(&key, ':'); + smart_str_appends(&key, value); + + if(value) + efree(value); + if(prefix) + efree(prefix); + } + else + { + ns = node_find_ns(attrType); + smart_str_appends(&key, ns->href); + smart_str_appendc(&key, ':'); + smart_str_appends(&key, newAttr->name); + } + + + if(ns) + { + smart_str_0(&key); + zend_hash_add(cur_type->attributes, key.c, key.len + 1, &newAttr, sizeof(sdlAttributePtr), NULL); + smart_str_free(&key); + return TRUE; + } + } + + zend_hash_next_index_insert(cur_type->attributes, &newAttr, sizeof(sdlAttributePtr), NULL); + return TRUE; +}
\ No newline at end of file diff --git a/ext/soap/php_schema.h b/ext/soap/php_schema.h new file mode 100644 index 0000000000..c43a221608 --- /dev/null +++ b/ext/soap/php_schema.h @@ -0,0 +1,28 @@ +#ifndef PHP_SCHEMA_H +#define PHP_SCHEMA_H + +int load_schema(sdlPtr *sdl,xmlNodePtr schema); +int schema_simpleType(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr simpleType, sdlTypePtr cur_type); +int schema_complexType(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr compType, sdlTypePtr cur_type); +int schema_sequence(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr seqType, sdlTypePtr cur_type); +int schema_list(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr listType, sdlTypePtr cur_type); +int schema_union(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr unionType, sdlTypePtr cur_type); +int schema_simpleContent(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr simpCompType, sdlTypePtr cur_type); +int schema_restriction_simpleType(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr restType, sdlTypePtr cur_type); +int schema_restriction_simpleContent(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr restType, sdlTypePtr cur_type); +int schema_restriction_complexContent(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr restType, sdlTypePtr cur_type); +int schema_extension(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type); +int schema_all(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type); +int schema_group(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr groupType, sdlTypePtr cur_type); +int schema_choice(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr choiceType, sdlTypePtr cur_type); +int schema_element(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTypePtr cur_type); +int schema_attribute(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr attrType, sdlTypePtr cur_type); +int schema_any(sdlPtr *sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type); + +int schema_restriction_var_int(xmlNodePtr val, sdlRestrictionIntPtr *valptr); +void delete_restriction_var_int(void *rvi); + +int schema_restriction_var_char(xmlNodePtr val, sdlRestrictionCharPtr *valptr); +void delete_schema_restriction_var_char(void *srvc); + +#endif diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c new file mode 100644 index 0000000000..9d73d2fbe8 --- /dev/null +++ b/ext/soap/php_sdl.c @@ -0,0 +1,915 @@ +#include "php_soap.h" + +encodePtr get_encoder_from_prefix(sdlPtr sdl, xmlNodePtr data, char *type) +{ + encodePtr enc = NULL; + TSRMLS_FETCH(); + + enc = get_conversion_from_type(data, type); + if(enc == NULL && sdl) + enc = get_conversion_from_type_ex(sdl->encoders, data, type); + if(enc == NULL) + enc = get_conversion(UNKNOWN_TYPE); + + return enc; +} + +encodePtr get_encoder(sdlPtr sdl, char *ns, char *type) +{ + encodePtr enc = NULL; + char *nscat; + TSRMLS_FETCH(); + + nscat = emalloc(strlen(ns) + strlen(type) + 2); + sprintf(nscat, "%s:%s", ns, type); + + enc = get_encoder_ex(sdl, nscat); + + efree(nscat); + return enc; +} + +encodePtr get_encoder_ex(sdlPtr sdl, char *nscat) +{ + encodePtr enc = NULL; + TSRMLS_FETCH(); + + enc = get_conversion_from_href_type(nscat); + if(enc == NULL && sdl) + enc = get_conversion_from_href_type_ex(sdl->encoders, nscat); + if(enc == NULL) + enc = get_conversion(UNKNOWN_TYPE); + return enc; +} + +encodePtr get_create_encoder(sdlPtr sdl, sdlTypePtr cur_type, char *ns, char *type) +{ + encodePtr enc = NULL; + char *nscat; + TSRMLS_FETCH(); + + nscat = emalloc(strlen(ns) + strlen(type) + 2); + sprintf(nscat, "%s:%s", ns, type); + + enc = get_conversion_from_href_type(nscat); + if(enc == NULL) + enc = get_conversion_from_href_type_ex(sdl->encoders, nscat); + if(enc == NULL) + enc = create_encoder(sdl, cur_type, ns, type); + + efree(nscat); + return enc; +} + +encodePtr create_encoder(sdlPtr sdl, sdlTypePtr cur_type, char *ns, char *type) +{ + char *nscat; + encodePtr enc; + + enc = malloc(sizeof(encode)); + memset(enc, 0, sizeof(encode)); + + nscat = emalloc(strlen(ns) + strlen(type) + 2); + sprintf(nscat, "%s:%s", ns, type); + + enc->details.ns = strdup(ns); + enc->details.type_str = strdup(type); + enc->details.sdl_type = cur_type; + enc->to_xml = sdl_guess_convert_xml; + enc->to_zval = guess_zval_convert; + + if(sdl->encoders == NULL) + { + sdl->encoders = malloc(sizeof(HashTable)); + zend_hash_init(sdl->encoders, 0, NULL, delete_encoder, 1); + } + zend_hash_add(sdl->encoders, nscat, strlen(nscat), &enc, sizeof(encodePtr), NULL); + efree(nscat); + return enc; +} + +xmlNodePtr sdl_guess_convert_xml(encodeType enc, zval *data) +{ + sdlTypePtr type; + xmlNodePtr ret; + + ret = xmlNewNode(NULL, "BOGUS"); + type = enc.sdl_type; + + if(type->encode->details.type == IS_ARRAY || + type->encode->details.type == SOAP_ENC_ARRAY) + { + ret = sdl_to_xml_array(type, data); + } + else if(type->encode != NULL) + { + ret = master_to_xml(type->encode, data); + } + else if(type->elements != NULL) + { + ret = sdl_to_xml_object(type, data); + } + else + { + ret = guess_xml_convert(enc, data); + } + + //set_ns_and_type(ret, enc); + return ret; +} + +xmlNodePtr sdl_to_xml_object(sdlTypePtr type, zval *data) +{ + xmlNodePtr ret; + sdlTypePtr *t, tmp; + + ret = xmlNewNode(NULL, "BOGUS"); + + zend_hash_internal_pointer_reset(type->elements); + while(zend_hash_get_current_data(type->elements, (void **)&t) != FAILURE) + { + zval **prop; + tmp = *t; + if(zend_hash_find(Z_OBJPROP_P(data), tmp->name, strlen(tmp->name) + 1, (void **)&prop) == FAILURE) + { + if(tmp->nullable == FALSE) + php_error(E_ERROR, "Error encoding object to xml missing property \"%s\"", tmp->name); + } + else + { + xmlNodePtr newNode; + + newNode = master_to_xml(tmp->encode, (*prop)); + xmlNodeSetName(newNode, tmp->name); + xmlAddChild(ret, newNode); + } + zend_hash_move_forward(type->elements); + } + + return ret; +} + +xmlNodePtr sdl_to_xml_array(sdlTypePtr type, zval *data) +{ + smart_str array_type_and_size = {0}, array_type = {0}; + int i; + xmlNodePtr xmlParam; + TSRMLS_FETCH(); + + xmlParam = xmlNewNode(NULL,"BOGUS"); + + FIND_ZVAL_NULL(data, xmlParam); + + if(Z_TYPE_P(data) == IS_ARRAY) + { + sdlAttributePtr *arrayType; + i = zend_hash_num_elements(Z_ARRVAL_P(data)); + + if(zend_hash_find(type->attributes, SOAP_ENC_NAMESPACE":arrayType", sizeof(SOAP_ENC_NAMESPACE":arrayType"), (void **)&arrayType) == SUCCESS) + { + xmlAttrPtr *wsdl; + if(zend_hash_find((*arrayType)->extraAttributes, WSDL_NAMESPACE":arrayType", sizeof(WSDL_NAMESPACE":arrayType"), (void **)&wsdl) == SUCCESS) + { + char *ns = NULL, *value; + smart_str *prefix = encode_new_ns(); + smart_str smart_ns = {0}; + xmlNsPtr myNs; + + parse_namespace((*wsdl)->children->content, &value, &ns); + myNs = xmlSearchNs((*wsdl)->doc, (*wsdl)->parent, ns); + + smart_str_appendl(&smart_ns, "xmlns:", sizeof("xmlns:") - 1); + smart_str_appendl(&smart_ns, prefix->c, prefix->len); + smart_str_0(&smart_ns); + + xmlSetProp(xmlParam, smart_ns.c, myNs->href); + smart_str_appends(&array_type_and_size, prefix->c); + smart_str_appendc(&array_type_and_size, ':'); + smart_str_appends(&array_type_and_size, value); + smart_str_0(&array_type_and_size); + } + } + else + { + smart_str_appends(&array_type_and_size, type->name); + smart_str_appendc(&array_type_and_size, '['); + smart_str_append_long(&array_type_and_size, i); + smart_str_appendc(&array_type_and_size, ']'); + smart_str_0(&array_type_and_size); + } + + xmlSetProp(xmlParam, SOAP_ENC_NS_PREFIX":arrayType", array_type_and_size.c); + + smart_str_free(&array_type_and_size); + smart_str_free(&array_type); + + zend_hash_internal_pointer_reset(data->value.ht); + for(;i > 0;i--) + { + xmlNodePtr xparam; + zval **zdata; + encodePtr enc; + zend_hash_get_current_data(data->value.ht, (void **)&zdata); + + enc = get_conversion((*zdata)->type); + xparam = master_to_xml(enc, (*zdata)); + + xmlNodeSetName(xparam, "val"); + xmlAddChild(xmlParam, xparam); + zend_hash_move_forward(data->value.ht); + } + } + set_ns_and_type_ex(xmlParam, type->namens, type->name); + return xmlParam; +} + +zval *sdl_convert_zval(encodeType enc, xmlNodePtr data) +{ + zval *ret; + MAKE_STD_ZVAL(ret); + ZVAL_STRING(ret, "blah", 1); + + return ret; +} + +/* +zval *sdl_convert_zval(xmlNodePtr data, sdlTypePtr type) +{ + found = zend_hash_find(EG(class_table), class_name, class_name_len + 1, (void **)&ce); + if(found != FAILURE) + { + service->type = SOAP_CLASS; + service->soap_class.ce = ce; + } +} +//this function will take a zval and apply all attributes of sldTypePtr +zval *sdl_convert_zval_to_zval(zval *data, sdlTypePtr type) +{ +} +*/ + + +sdlPtr get_sdl(char *uri) +{ + sdlPtr tmp, *hndl; + TSRMLS_FETCH(); + + tmp = NULL; + hndl = NULL; + if(zend_hash_find(SOAP_GLOBAL(sdls), uri, strlen(uri), (void **)&hndl) == FAILURE) + { + tmp = load_wsdl(uri); + zend_hash_add(SOAP_GLOBAL(sdls), uri, strlen(uri), &tmp, sizeof(sdlPtr), NULL); + } + else + tmp = *hndl; + + return tmp; +} + +int load_php_sdl() +{ +/* xmlNodePtr rootElement; + xmlNodePtr services; + + SOAP_SERVER_GLOBAL_VARS(); + SOAP_SERVER_GLOBAL(availableServices) = xmlParseFile(servicesFile); + rootElement = SOAP_SERVER_GLOBAL(availableServices)->children; + services = rootElement->children; + + do + { + if(IS_ELEMENT_TYPE(services,PHP_SOAPSERVER_SERVICE)) + { + phpSoapServicePtr newService; + xmlNodePtr attrib, trav; + HashTable *fn = NULL; + HashTable *include = NULL; + HashTable *cl = NULL; + + //Init New Service + newService = emalloc(sizeof(phpSoapService)); + newService->serviceNode = services; + newService->started = FALSE; + + fn = newService->functions = emalloc(sizeof(HashTable)); + include = newService->include_files = emalloc(sizeof(HashTable)); + zend_hash_init(fn, 0, NULL, free_function, 0); + zend_hash_init(include, 0, NULL, ZVAL_PTR_DTOR, 0); + + attrib = services->properties; + trav = attrib; + //Get Attributes of Service + do + { + if(IS_ATTRIBUTE_TYPE(trav,PHP_SOAPSERVER_SERVICE_NAME)) + { + char* name = ATTRIBUTE_VALUE(trav); + + //Assign Service Vals + ALLOC_INIT_ZVAL(newService->serviceName); + ZVAL_STRING(newService->serviceName,name,1); + } + + if(IS_ATTRIBUTE_TYPE(trav,PHP_SOAPSERVER_SERVICE_STARTED)) + { + char* started = ATTRIBUTE_VALUE(trav); + + //Assign Service Vals + if(!stricmp(started,"true")) + newService->started = TRUE; + } + } + while(trav = trav->next); + + //Get ChildNodes of Service + trav = services->children; + do + { + //Include Files + if(IS_ELEMENT_TYPE(trav,PHP_SOAPSERVER_SERVICE_INCLUDE_FILE)) + { + xmlNodePtr trav1 = trav->properties; + do + { + if(IS_ATTRIBUTE_TYPE(trav1,PHP_SOAPSERVER_SERVICE_INCLUDE_FILE_NAME)) + { + char* name = ATTRIBUTE_VALUE(trav1); + zval* z_name; + ALLOC_INIT_ZVAL(z_name); + ZVAL_STRING(z_name,name,1); + zend_hash_next_index_insert(include,&z_name,sizeof(zval),NULL); + } + } + while(trav1 = trav1->next); + } + + //Functions + if(IS_ELEMENT_TYPE(trav,PHP_SOAPSERVER_SERVICE_FUNCTION)) + { + phpSoapServiceFunctionPtr function; + xmlNodePtr trav1; + HashTable *par = NULL; + + function = emalloc(sizeof(phpSoapServiceFunction)); + function->functionNode = trav; + + par = function->functionParams = emalloc(sizeof(HashTable)); + zend_hash_init(par, 0, NULL, free_param, 0); + + trav1 = trav->properties; + + do + { + if(IS_ATTRIBUTE_TYPE(trav1,PHP_SOAPSERVER_SERVICE_FUNCTION_NAME)) + { + char* name = ATTRIBUTE_VALUE(trav1); + ALLOC_INIT_ZVAL(function->functionName); + ZVAL_STRING(function->functionName,name,1); + } + } + while(trav1 = trav1->next); + + trav1 = trav->children; + do + { + if(IS_ELEMENT_TYPE(trav1,PHP_SOAPSERVER_SERVICE_FUNCTION_PARAM)) + { + phpSoapServiceParamPtr param; + xmlNodePtr trav2; + + param = emalloc(sizeof(phpSoapServiceParam)); + param->paramNode = trav1; + + trav2 = trav1->properties; + + do + { + if(IS_ATTRIBUTE_TYPE(trav2,PHP_SOAPSERVER_SERVICE_FUNCTION_PARAM_NAME)) + { + char* name = ATTRIBUTE_VALUE(trav2); + ALLOC_INIT_ZVAL(param->paramName); + ZVAL_STRING(param->paramName,name,1); + } + else if(IS_ATTRIBUTE_TYPE(trav2,PHP_SOAPSERVER_SERVICE_FUNCTION_PARAM_TYPE)) + { + char* type = ATTRIBUTE_VALUE(trav2); + ALLOC_INIT_ZVAL(param->paramType); + ZVAL_STRING(param->paramType,type,1); + } + else if(IS_ATTRIBUTE_TYPE(trav2,PHP_SOAPSERVER_SERVICE_FUNCTION_PARAM_POSITION)) + { + char* val = ATTRIBUTE_VALUE(trav2); + ALLOC_INIT_ZVAL(param->paramName); + ZVAL_LONG(param->paramName,atoi(val)); + } + } + while(trav2 = trav2->next); + zend_hash_add(par,Z_STRVAL_P(param->paramName),Z_STRLEN_P(param->paramName),param,sizeof(phpSoapServiceParam),NULL); + } + } + while(trav1 = trav1->next); + zend_hash_add(fn,Z_STRVAL_P(function->functionName),Z_STRLEN_P(function->functionName),function,sizeof(phpSoapServiceFunction),NULL); + } + + //Classes + if(IS_ELEMENT_TYPE(trav,PHP_SOAPSERVER_SERVICE_CLASS)) + { + xmlNodePtr att, func; + att = trav->properties; + + if(fn == NULL) + { + fn = newService->functions = emalloc(sizeof(HashTable)); + zend_hash_init(fn, 0, NULL, ZVAL_PTR_DTOR, 0); + } + + } + + }while(trav = trav->next); + + zend_hash_add(SOAP_SERVER_GLOBAL(services),Z_STRVAL_P(newService->serviceName),Z_STRLEN_P(newService->serviceName),newService,sizeof(phpSoapService),NULL); + } + } + while(services = services->next); +*/ + return TRUE; +} + +int write_php_sdl() +{ + return TRUE; +} + +sdlPtr load_wsdl(char *struri) +{ + xmlDocPtr wsdl; + xmlNodePtr root, definitions, types, binding, schema, service; + xmlNodePtr trav, trav2, trav3; + xmlAttrPtr targetNamespace; + sdlPtr tmpsdl; + TSRMLS_FETCH(); + + tmpsdl = malloc(sizeof(sdl)); + memset(tmpsdl, 0, sizeof(sdl)); + + tmpsdl->source = strdup(struri); + + wsdl = xmlParseFile(struri); + xmlCleanupParser(); + + if(!wsdl) + php_error(E_ERROR, "Error parsing wsdl file"); + + tmpsdl->doc = wsdl; + root = wsdl->children; + definitions = get_node(root, "definitions"); + if(!definitions) + php_error(E_ERROR, "Error parsing wsdl file"); + + targetNamespace = get_attribute(definitions->properties, "targetNamespace"); + if(targetNamespace) + { + tmpsdl->target_ns = strdup(targetNamespace->children->content); + } + + types = get_node(definitions->children, "types"); + if(types) + { + trav = types->children; + FOREACHNODE(trav, "schema", schema) + { + load_schema(&tmpsdl, schema); + } + ENDFOREACH(trav); + } + + service = get_node(definitions->children, "service"); + if(service != NULL) + { + xmlAttrPtr name; + xmlNodePtr trav, port; + + name = get_attribute(service->properties, "name"); + if(name == NULL) + php_error(E_ERROR, "Error parsing wsdl (\"No name associated with service\")"); + + trav = service->children; + FOREACHNODE(trav, "port", port) + { + xmlAttrPtr name, binding, location; + xmlNodePtr address; + + name = get_attribute(port->properties, "name"); + if(name == NULL) + php_error(E_ERROR, "Error parsing wsdl (\"No name associated with port\")"); + + binding = get_attribute(port->properties, "binding"); + if(binding == NULL) + php_error(E_ERROR, "Error parsing wsdl (\"No binding associated with port\")"); + + //TODO: validate this is "soap" namespace + address = get_node(port->children, "address"); + if(address == NULL) + php_error(E_ERROR, "Error parsing wsdl (\"No soap:address associated with port\")"); + + location = get_attribute(address->properties, "location"); + if(location == NULL) + php_error(E_ERROR, "Error parsing wsdl (\"No location associated with soap:address\")"); + + tmpsdl->location = strdup(location->children->content); + } + ENDFOREACH(trav); + + } + else + php_error(E_ERROR, "Error parsing wsdl (\"Couldn't bind to service\")"); + + trav = definitions->children; + FOREACHNODE(trav, "binding", binding) + { + xmlAttrPtr name, type; + xmlNodePtr portType, operation; + char *ns, *ctype; + + name = get_attribute(binding->properties, "name"); + if(name == NULL) + php_error(E_ERROR, "Error parsing wsdl (Missing \"name\" attribute for \"binding\")"); + + type = get_attribute(binding->properties, "type"); + if(type == NULL) + php_error(E_ERROR, "Error parsing wsdl (Missing \"type\" attribute for \"binding\")"); + + parse_namespace(type->children->content, &ctype, &ns); + portType = get_node_with_attribute(definitions->children, "portType", "name", ctype); + if(portType == NULL) + php_error(E_ERROR, "Error parsing wsdl (Missing \"portType\" with name \"%s\")", name->children->content); + if(ctype) efree(ctype); + if(ns) efree(ns); + + trav2 = binding->children; + FOREACHNODE(trav2, "operation", operation) + { + sdlFunctionPtr function; + xmlNodePtr input, output, fault, portTypeOperation, msgInput, msgOutput, soapOperation; + xmlAttrPtr op_name, paramOrder; + + op_name = get_attribute(operation->properties, "name"); + if(op_name == NULL) + php_error(E_ERROR, "Error parsing wsdl (Missing \"name\" attribute for \"operation\")"); + + portTypeOperation = get_node_with_attribute(portType->children, "operation", "name", op_name->children->content); + if(portTypeOperation == NULL) + php_error(E_ERROR, "Error parsing wsdl (Missing \"portType/operation\" with name \"%s\")", op_name->children->content); + + if(tmpsdl->functions == NULL) + { + tmpsdl->functions = malloc(sizeof(HashTable)); + zend_hash_init(tmpsdl->functions, 0, NULL, delete_function, 1); + } + + function = malloc(sizeof(sdlFunction)); + function->functionName = strdup(op_name->children->content); + function->requestParameters = NULL; + function->responseParameters = NULL; + function->responseName = NULL; + function->soapAction = NULL; + + soapOperation = get_node(operation->children, "operation"); + if(soapOperation) + { + xmlAttrPtr action = get_attribute(soapOperation->properties, "soapAction"); + if(action) + function->soapAction = strdup(action->children->content); + } + + input = get_node(portTypeOperation->children, "input"); + if(input != NULL) + { + xmlAttrPtr message; + xmlNodePtr part; + char *ns, *ctype; + + message = get_attribute(input->properties, "message"); + if(message == NULL) + php_error(E_ERROR, "Error parsing wsdl (Missing name for \"input\" of \"%s\")", op_name->children->content); + + function->requestName = strdup(function->functionName); + function->requestParameters = malloc(sizeof(HashTable)); + zend_hash_init(function->requestParameters, 0, NULL, delete_paramater, 1); + + parse_namespace(message->children->content, &ctype, &ns); + msgInput = get_node_with_attribute(definitions->children, "message", "name", ctype); + if(msgInput == NULL) + php_error(E_ERROR, "Error parsing wsdl (Missing \"message\" with name \"%s\")", message->children->content); + if(ctype) efree(ctype); + if(ns) efree(ns); + + trav3 = msgInput->children; + FOREACHNODE(trav3, "part", part) + { + xmlAttrPtr element, type, name; + sdlParamPtr param; + + param = malloc(sizeof(sdlParam)); + param->order = 0; + + name = get_attribute(part->properties, "name"); + if(name == NULL) + php_error(E_ERROR, "Error parsing wsdl (No name associated with part \"%s\")", msgInput->name); + + param->paramName = strdup(name->children->content); + + element = get_attribute(part->properties, "element"); + if(element != NULL) + param->encode = get_encoder_from_prefix(tmpsdl, part, element->children->content); + + type = get_attribute(part->properties, "type"); + if(type != NULL) + param->encode = get_encoder_from_prefix(tmpsdl, part, type->children->content); + + zend_hash_next_index_insert(function->requestParameters, ¶m, sizeof(sdlParamPtr), NULL); + } + ENDFOREACH(trav3); + } + + paramOrder = get_attribute(portTypeOperation->properties, "parameterOrder"); + if(paramOrder) + { + + } + + output = get_node(portTypeOperation->children, "output"); + if(output != NULL) + { + xmlAttrPtr message; + xmlNodePtr part; + char *ns, *ctype; + + + function->responseName = malloc(strlen(function->functionName) + strlen("Response") + 1); + sprintf(function->responseName, "%sResponse\0", function->functionName); + function->responseParameters = malloc(sizeof(HashTable)); + zend_hash_init(function->responseParameters, 0, NULL, delete_paramater, 1); + + message = get_attribute(output->properties, "message"); + if(message == NULL) + php_error(E_ERROR, "Error parsing wsdl (Missing name for \"output\" of \"%s\")", op_name->children->content); + + parse_namespace(message->children->content, &ctype, &ns); + msgOutput = get_node_with_attribute(definitions->children, "message", "name", ctype); + if(msgOutput == NULL) + php_error(E_ERROR, "Error parsing wsdl (Missing \"message\" with name \"%s\")", message->children->content); + if(ctype) efree(ctype); + if(ns) efree(ns); + + trav3 = msgOutput->children; + FOREACHNODE(trav3, "part", part) + { + sdlParamPtr param; + xmlAttrPtr element, type, name; + + param = malloc(sizeof(sdlParam)); + param->order = 0; + + name = get_attribute(part->properties, "name"); + if(name == NULL) + php_error(E_ERROR, "Error parsing wsdl (No name associated with part \"%s\")", msgOutput->name); + + param->paramName = strdup(name->children->content); + + element = get_attribute(part->properties, "element"); + if(element) + param->encode = get_encoder_from_prefix(tmpsdl, part, element->children->content); + + type = get_attribute(part->properties, "type"); + if(type) + param->encode = get_encoder_from_prefix(tmpsdl, part, type->children->content); + + zend_hash_next_index_insert(function->responseParameters, ¶m, sizeof(sdlParamPtr), NULL); + } + ENDFOREACH(trav3); + } + + fault = get_node(operation->children, "fault"); + if(fault != NULL) + { + } + + zend_hash_add(tmpsdl->functions, php_strtolower(function->functionName, strlen(function->functionName)), strlen(function->functionName), &function, sizeof(sdlFunctionPtr), NULL); + } + ENDFOREACH(trav2); + } + ENDFOREACH(trav); + + return tmpsdl; +} + +int write_wsdl() +{ + return TRUE; +} + +int write_ms_sdl() +{ + return TRUE; +} + +int load_ms_sdl(char *struri,int force_load) +{ +/* Commenting this out. Does anyone need it? + + if(get_sdl(struri) == NULL || force_load) + { + SOAP_TLS_VARS(); + xmlDocPtr sdl = xmlParseFile(struri); + xmlNodePtr schema,trav,trav2,req,res,paramOrd,reqRes,address,serviceAdd,service,soap,serviceDesc,root = sdl->children; + xmlAttrPtr tmpattr,uri; + char *add,*functionName,*soapAction,*request,*response,*parameterOrder,*value,*namespace; + SDLPtr sdlPtr; + SoapFunctionPtr tmpFunction; + zval *tempZval; + serviceDesc = get_node(root,"serviceDescription"); + soap = get_node(serviceDesc->children,"soap"); + trav = soap->children; + sdlPtr = emalloc(sizeof(SDL)); + + ALLOC_INIT_ZVAL(sdlPtr->sdlUri); + ZVAL_STRING(sdlPtr->sdlUri,struri,1); + + FOREACHNODE(trav,"service",service) + { + sdlPtr->soapFunctions = emalloc(sizeof(HashTable)); + sdlPtr->addresses = emalloc(sizeof(HashTable)); + zend_hash_init(sdlPtr->soapFunctions, 0, NULL, delete_function, 0); + zend_hash_init(sdlPtr->addresses, 0, NULL, ZVAL_PTR_DTOR, 0); + + serviceAdd = get_node(service->children,"addresses"); + trav2 = serviceAdd->children; + ALLOC_INIT_ZVAL(tempZval); + FOREACHNODE(trav2,"address",address) + { + uri = get_attribute(address->properties,"uri"); + add = uri->children->content; + ZVAL_STRING(tempZval,add,1); + zend_hash_next_index_insert(sdlPtr->addresses,tempZval,sizeof(zval),NULL); + } + ENDFOREACH(trav2); + trav2 = service->children; + FOREACHNODE(trav2,"requestResponse",reqRes) + { + tmpFunction = emalloc(sizeof(SoapFunction)); + + tmpattr = get_attribute(reqRes->properties,"name"); + functionName = tmpattr->children->content; + ALLOC_INIT_ZVAL(tmpFunction->functionName); + ZVAL_STRING(tmpFunction->functionName,functionName,1); + + tmpattr = get_attribute(reqRes->properties,"soapAction"); + soapAction = tmpattr->children->content; + ALLOC_INIT_ZVAL(tmpFunction->soapAction); + ZVAL_STRING(tmpFunction->soapAction,soapAction,1); + + //Request + req = get_node(reqRes->children,"request"); + tmpattr = get_attribute(req->properties,"ref"); + if(tmpattr != NULL) + { + request = tmpattr->children->content; + parse_namespace(request,&value,&namespace); + ALLOC_INIT_ZVAL(tmpFunction->requestName); + ZVAL_STRING(tmpFunction->requestName,value,1); + tmpFunction->requestParameters = emalloc(sizeof(HashTable)); + zend_hash_init(tmpFunction->requestParameters, 0, NULL, delete_paramater, 0); + efree(value); + efree(namespace); + } + + //Response + res = get_node(reqRes->children,"response"); + tmpattr = get_attribute(res->properties,"ref"); + if(tmpattr != NULL) + { + response = tmpattr->children->content; + parse_namespace(response,&value,&namespace); + ALLOC_INIT_ZVAL(tmpFunction->responseName); + ZVAL_STRING(tmpFunction->responseName,value,1); + tmpFunction->responseParameters = emalloc(sizeof(HashTable)); + zend_hash_init(tmpFunction->responseParameters, 0, NULL, delete_paramater, 0); + efree(value); + efree(namespace); + } + + //Parameters + paramOrd = get_node(reqRes->children,"parameterorder"); + if(paramOrd != NULL) + { + zval *space,*array,**strval; + int count,i; + ALLOC_INIT_ZVAL(space); + ZVAL_STRING(space," ",0); + parameterOrder = paramOrd->children->content; + ZVAL_STRING(tempZval,parameterOrder,1); + ALLOC_INIT_ZVAL(array); + array_init(array); + + //Split on space + php_explode(space, tempZval, array, -1); + zend_hash_internal_pointer_reset(array->value.ht); + count = zend_hash_num_elements(array->value.ht); + + for(i = 0;i < count;i++) + { + SoapParamPtr param; + param = emalloc(sizeof(SoapParam)); + param->order = i+1; + param->type = NULL; + zend_hash_get_current_data(array->value.ht,(void **)&strval); + ALLOC_INIT_ZVAL(param->paramName); + ZVAL_STRING(param->paramName,Z_STRVAL_PP(strval),1); + zend_hash_next_index_insert(tmpFunction->requestParameters,param,sizeof(SoapParam),NULL); + zend_hash_move_forward(array->value.ht); + } + } + zend_hash_add(sdlPtr->soapFunctions,(char *)php_strtolower(functionName,strlen(functionName)),strlen(functionName),tmpFunction,sizeof(SoapFunction),NULL); + } + ENDFOREACH(trav2); + } + ENDFOREACH(trav); + + trav = serviceDesc->children; + FOREACHNODE(trav,"schema",schema) + { + load_schema(&sdlPtr, schema); + } + ENDFOREACH(trav); + sdlPtr->have_sdl = 1; + map_types_to_functions(sdlPtr); + zend_hash_add(SOAP_GLOBAL(SDLs),struri,strlen(struri),sdlPtr,sizeof(SDL),NULL); + }*/ + return FALSE; +} + +void delete_type(void *data) +{ + sdlTypePtr type = *((sdlTypePtr*)data); + if(type->name) + free(type->name); + if(type->namens) + free(type->namens); + if(type->elements) + { + zend_hash_destroy(type->elements); + free(type->elements); + } + if(type->attributes) + { + zend_hash_destroy(type->attributes); + free(type->attributes); + } + if(type->restrictions) + { + delete_restriction_var_int(&type->restrictions->minExclusive); + delete_restriction_var_int(&type->restrictions->minInclusive); + delete_restriction_var_int(&type->restrictions->maxExclusive); + delete_restriction_var_int(&type->restrictions->maxInclusive); + delete_restriction_var_int(&type->restrictions->totalDigits); + delete_restriction_var_int(&type->restrictions->fractionDigits); + delete_restriction_var_int(&type->restrictions->length); + delete_restriction_var_int(&type->restrictions->minLength); + delete_restriction_var_int(&type->restrictions->maxLength); + delete_schema_restriction_var_char(&type->restrictions->whiteSpace); + delete_schema_restriction_var_char(&type->restrictions->pattern); + zend_hash_destroy(type->restrictions->enumeration); + free(type->restrictions->enumeration); + free(type->restrictions); + } + free(type); +} + +void delete_attribute(void *attribute) +{ + sdlAttributePtr attr = *((sdlAttributePtr*)attribute); + + if(attr->def) + free(attr->def); + if(attr->fixed) + free(attr->fixed); + if(attr->form) + free(attr->form); + if(attr->id) + free(attr->id); + if(attr->name) + free(attr->name); + if(attr->ref) + free(attr->ref); + if(attr->type) + free(attr->type); + if(attr->use) + free(attr->use); + if(attr->extraAttributes) + { + zend_hash_destroy(attr->extraAttributes); + free(attr->extraAttributes); + } +} diff --git a/ext/soap/php_sdl.h b/ext/soap/php_sdl.h new file mode 100644 index 0000000000..66a2520bfb --- /dev/null +++ b/ext/soap/php_sdl.h @@ -0,0 +1,112 @@ +#ifndef PHP_SDL_H +#define PHP_SDL_H + +#define XSD_WHITESPACE_COLLAPSE 1 +#define XSD_WHITESPACE_PRESERVE 1 +#define XSD_WHITESPACE_REPLACE 1 + +struct _sdl +{ + xmlDocPtr doc; + HashTable *functions; //array of SoapFunctionsPtr + HashTable *types; //array of sdlTypesPtr + HashTable *encoders; //array of encodePtr + char *location; + char *target_ns; + char *source; +}; + +struct _sdlRestrictionInt +{ + int value; + char fixed; + char *id; +}; + +struct _sdlRestrictionChar +{ + char *value; + char fixed; + char *id; +}; + +struct _sdlRestrictions +{ + HashTable *enumeration; //array of sdlRestrictionCharPtr + sdlRestrictionIntPtr minExclusive; + sdlRestrictionIntPtr minInclusive; + sdlRestrictionIntPtr maxExclusive; + sdlRestrictionIntPtr maxInclusive; + sdlRestrictionIntPtr totalDigits; + sdlRestrictionIntPtr fractionDigits; + sdlRestrictionIntPtr length; + sdlRestrictionIntPtr minLength; + sdlRestrictionIntPtr maxLength; + sdlRestrictionCharPtr whiteSpace; + sdlRestrictionCharPtr pattern; +}; + +struct _sdlType +{ + char *name; + char *namens; + int nullable; + int min_occurs; + int max_occurs; + HashTable *elements; //array of sdlTypePtr + HashTable *attributes; //array of sdlAttributePtr + sdlRestrictionsPtr restrictions; + encodePtr encode; +}; + +struct _sdlParam +{ + int order; + encodePtr encode; + char *paramName; +}; + +struct _sdlFunction +{ + int enabled; + char *functionName; + char *requestName; + char *responseName; + HashTable *requestParameters; //array of sdlParamPtr + HashTable *responseParameters; //array of sdlParamPtr (this should only be one) + char *soapAction; +}; + +struct _sdlAttribute +{ + char *def; + char *fixed; + char *form; + char *id; + char *name; + char *ref; + char *type; + char *use; + HashTable *extraAttributes; +}; + +sdlPtr get_sdl(char *uri); +sdlPtr load_wsdl(char *struri); +int load_sdl(char *struri, int force_load); +int load_ms_sdl(char *struri, int force_load); + +encodePtr get_encoder_from_prefix(sdlPtr sdl, xmlNodePtr data, char *type); +encodePtr get_encoder(sdlPtr sdl, char *ns, char *type); +encodePtr get_encoder_ex(sdlPtr sdl, char *nscat); +encodePtr get_create_encoder(sdlPtr sdl, sdlTypePtr cur_type, char *ns, char *type); +encodePtr create_encoder(sdlPtr sdl, sdlTypePtr cur_type, char *ns, char *type); + +xmlNodePtr sdl_guess_convert_xml(encodeType enc, zval* data); + +xmlNodePtr sdl_to_xml_array(sdlTypePtr type, zval *data); +xmlNodePtr sdl_to_xml_object(sdlTypePtr type, zval *data); + +void delete_type(void *type); +void delete_attribute(void *attribute); +#endif + diff --git a/ext/soap/php_soap.dsp b/ext/soap/php_soap.dsp new file mode 100644 index 0000000000..7ee12777e1 --- /dev/null +++ b/ext/soap/php_soap.dsp @@ -0,0 +1,156 @@ +# Microsoft Developer Studio Project File - Name="php_soap" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=php_soap - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "php_soap.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "php_soap.mak" CFG="php_soap - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "php_soap - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "php_soap - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "php_soap - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PHP_SOAP_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\php4" /I "..\..\..\php4\Zend" /I "..\..\..\php4\TSRM" /I "..\..\..\php4\main" /I "..\..\..\libxml2-2.4.12\include" /I "..\..\bind" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PHP_SOAP_EXPORTSWS" /D "PHP_SOAP_EXPORTS" /D "ZEND_WIN32" /D "PHP_WIN32" /D "ZTS" /D ZEND_DEBUG=0 /D "COMPILE_DL_SOAP" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts.lib libxml2.lib wsock32.lib resolv.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS\php_soap.dll" /libpath:"..\..\..\php4\Release_TS" /libpath:"..\..\..\libxml2-2.4.12\lib"
+
+!ELSEIF "$(CFG)" == "php_soap - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PHP_SOAP_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\php4" /I "..\..\..\php4\Zend" /I "..\..\..\php4\TSRM" /I "..\..\..\php4\main" /I "..\..\..\libxml2-2.4.12\include" /I "..\..\..\bind" /D "WS" /D "_MBCS" /D "_USRDLL" /D "PHP_SOAP_EXPORTS" /D "ZEND_WIN32" /D "PHP_WIN32" /D "ZTS" /D ZEND_DEBUG=1 /D "COMPILE_DL_SOAP" /FR"Release_TS/" /Fp"Release_TS/gd.pch" /YX /Fo"Release_TS/" /Fd"Release_TS/" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib php4ts_debug.lib libxml2.lib wsock32.lib resolv.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS\php_soap.dll" /implib:"Release_TS/php_gd.lib" /pdbtype:sept /libpath:"..\..\..\php4\Debug_TS" /libpath:"..\..\..\libxml2-2.4.12\lib"
+# SUBTRACT LINK32 /pdb:none /incremental:no
+
+!ENDIF
+
+# Begin Target
+
+# Name "php_soap - Win32 Release"
+# Name "php_soap - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\php_encoding.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\php_http.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\php_packet_soap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\php_schema.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\php_sdl.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\php_xml.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\soap.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\php_encoding.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\php_http.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\php_packet_soap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\php_schema.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\php_sdl.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\php_soap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\php_xml.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h new file mode 100644 index 0000000000..98c9e57f35 --- /dev/null +++ b/ext/soap/php_soap.h @@ -0,0 +1,375 @@ +#ifndef PHP_SOAP_H +#define PHP_SOAP_H + +#include "php.h" +#include "php_globals.h" +#include "ext/standard/info.h" +#include "ext/standard/php_standard.h" +#include "ext/session/php_session.h" +#include "ext/standard/php_smart_str.h" +#include "php_ini.h" +#include "SAPI.h" +#include <libxml/parser.h> +#include <libxml/xpath.h> + +#ifdef HAVE_PHP_DOMXML +# include "ext/domxml/php_domxml.h" +#endif + +// PHP_STREAMS were introduced php-4.2.0.. i think +// Make this part of configure +#ifdef STREAMS_DC +# define PHP_STREAMS +#endif + +#ifdef PHP_WIN32 +# ifdef PHP_STREAMS +# define SOAP_STREAM php_stream * +# else +# define SOAP_STREAM SOCKET +# endif +#else +# ifdef PHP_STREAMS +# define SOAP_STREAM php_stream * +# else +# define SOCKET unsigned int +# define SOAP_STREAM SOCKET +# endif +# define TRUE 1 +# define FALSE 0 +# define stricmp strcasecmp +#endif + +typedef struct _encodeType encodeType, *encodeTypePtr; +typedef struct _encode encode, *encodePtr; + +typedef struct _sdl sdl, *sdlPtr; +typedef struct _sdlRestrictionInt sdlRestrictionInt, *sdlRestrictionIntPtr; +typedef struct _sdlRestrictionChar sdlRestrictionChar, *sdlRestrictionCharPtr; +typedef struct _sdlRestrictions sdlRestrictions, *sdlRestrictionsPtr; +typedef struct _sdlType sdlType, *sdlTypePtr; +typedef struct _sdlParam sdlParam, *sdlParamPtr; +typedef struct _sdlFunction sdlFunction, *sdlFunctionPtr; +typedef struct _sdlAttribute sdlAttribute, *sdlAttributePtr; + +typedef struct _soapMapping soapMapping, *soapMappingPtr; +typedef struct _soapService soapService, *soapServicePtr; + +#include "php_xml.h" +#include "php_encoding.h" +#include "php_sdl.h" +#include "php_schema.h" +#include "php_http.h" +#include "php_packet_soap.h" + +extern int le_sdl; +extern int le_http_socket; +extern int le_url; +extern int le_service; + +struct _soapMapping +{ + char *ns; + char *ctype; + int type; + + struct _map_functions + { + zval *to_xml_before; + zval *to_xml; + zval *to_xml_after; + zval *to_zval_before; + zval *to_zval; + zval *to_zval_after; + } map_functions; + + struct _map_class + { + int type; + zend_class_entry *ce; + } map_class; +}; + +struct _soapService +{ + sdlPtr sdl; + + struct _soap_functions + { + HashTable *ft; + int functions_all; + } soap_functions; + + struct _soap_class + { + zend_class_entry *ce; + zval **argv; + int argc; + int persistance; + } soap_class; + + HashTable *mapping; + int type; + int enabled; + char *uri; +}; + +#define SOAP_CLASS 1 +#define SOAP_FUNCTIONS 2 +#define SOAP_FUNCTIONS_ALL 999 + +#define SOAP_MAP_FUNCTION 1 +#define SOAP_MAP_CLASS 2 + +#define SOAP_PERSISTENCE_SESSION 1 +#define SOAP_PERSISTENCE_REQUEST 2 + +ZEND_BEGIN_MODULE_GLOBALS(soap) + HashTable *defEncNs; + HashTable *defEncPrefix; + HashTable *defEnc; + HashTable *defEncIndex; + HashTable *sdls; + HashTable *services; + HashTable *overrides; + int cur_uniq_ns; +ZEND_END_MODULE_GLOBALS(soap) + +ZEND_EXTERN_MODULE_GLOBALS(soap); + +#ifdef ZTS +# define SOAP_GLOBAL(v) TSRMG(soap_globals_id, zend_soap_globals *, v) +#else +# define SOAP_GLOBAL(v) (soap_globals.v) +#endif + +#define PHP_SOAP_SERVER_CLASSNAME "soapserver" +#define PHP_SOAP_CLASSNAME "soapobject" +#define PHP_SOAP_VAR_CLASSNAME "soapvar" +#define PHP_SOAP_FAULT_CLASSNAME "soapfault" +#define PHP_SOAP_PARAM_CLASSNAME "soapparam" + + +extern zend_module_entry soap_module_entry; +#define soap_module_ptr & soap_module_entry + +PHP_MINIT_FUNCTION(soap); +PHP_MSHUTDOWN_FUNCTION(soap); +PHP_MINFO_FUNCTION(soap); + +//Registry Functions +//TODO: this! +PHP_FUNCTION(load_sdl); +PHP_FUNCTION(unload_sdl); +PHP_FUNCTION(unload_all_sdls); +PHP_FUNCTION(get_available_sdls); +PHP_FUNCTION(get_available_functions); +PHP_FUNCTION(get_function_parameters); +PHP_FUNCTION(soap_encode_to_xml); +PHP_FUNCTION(soap_encode_to_zval); + + +//Server Functions +PHP_FUNCTION(soapserver); +PHP_FUNCTION(setclass); +PHP_FUNCTION(addfunction); +PHP_FUNCTION(getfunctions); +PHP_FUNCTION(handle); +PHP_FUNCTION(setpersistence); +PHP_FUNCTION(bind); +#ifdef HAVE_PHP_DOMXML +PHP_FUNCTION(map); +#endif + +//Client Functions +PHP_FUNCTION(soapobject); +PHP_FUNCTION(__isfault); +PHP_FUNCTION(__getfault); +PHP_FUNCTION(__call); +PHP_FUNCTION(__parse); +#ifdef PHP_DEBUG +PHP_FUNCTION(__getfunctions); +PHP_FUNCTION(__gettypes); +PHP_FUNCTION(__getlastresponse); +PHP_FUNCTION(__getlastrequest); +#endif + +//SoapVar Functions +PHP_FUNCTION(soapvar); + +//SoapFault Functions +PHP_FUNCTION(soapfault); + +//SoapParam Functions +PHP_FUNCTION(soapparam); + + +#define DECLARE_TRACE(file) \ + FILE *trace_fp; \ + char *trace_file = file; + +#define TRACE(place) \ + trace_fp = fopen(trace_file, "a+"); \ + fwrite(place, strlen(place), 1, trace_fp); \ + fclose(trace_fp); + +extern zend_class_entry soap_var_class_entry; + +PS_SERIALIZER_FUNCS(soap); + +void clear_soap_fault(zval *obj); +void set_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail); +void add_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail); + +sdlParamPtr get_param(sdlFunctionPtr function, char *param_name, int index, int); +sdlFunctionPtr get_function(sdlPtr sdl, char *function_name); +void delete_sdl(void *handle); +void delete_function(void *function); +void delete_paramater(void *paramater); +void delete_service(void *service); +void delete_http_socket(void *handle); +void delete_url(void *handle); +void delete_mapping(void *data); + +void soap_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference); +zval soap_get_property_handler(zend_property_reference *property_reference); +int soap_set_property_handler(zend_property_reference *property_reference, zval *value); +void soap_destructor(void *jobject); + +void deseralize_function_call(sdlPtr sdl, xmlDocPtr request, zval *function_name, int *num_params, zval **parameters[]); +xmlDocPtr seralize_response_call(sdlFunctionPtr function, char *function_name,char *uri,zval *ret); +xmlDocPtr seralize_function_call(sdlFunctionPtr function, char *urn, char *function_name, zval **arguments, int arg_count); +xmlNodePtr seralize_parameter(sdlParamPtr param,zval *param_val,int index,char *name); +xmlNodePtr seralize_zval(zval *val, sdlParamPtr param, char *paramName); +zval *desearlize_zval(sdlPtr sdl, xmlNodePtr data, sdlParamPtr param); + +void soap_error_handler(int error_num, const char *error_filename, const uint error_lineno, const char *format, va_list args); +int my_call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, int param_count, zval *params[] TSRMLS_DC); + +#define phpext_soap_ptr soap_module_ptr + +#define HTTP_RAW_POST_DATA "HTTP_RAW_POST_DATA" + +#define SOAP_SERVER_BEGIN_CODE() \ + zend_error_cb = soap_error_handler + +#define SOAP_SERVER_END_CODE() \ + zend_error_cb = old_handler + + +#define FOREACHATTRNODE(n,c,i) \ + do \ + { \ + if(n == NULL) \ + break; \ + if(c) \ + i = get_attribute(n,c); \ + else \ + i = n; \ + if(i != NULL) \ + { \ + n = i; + +#define FOREACHNODE(n,c,i) \ + do \ + { \ + if(n == NULL) \ + break; \ + if(c) \ + i = get_node(n,c); \ + else \ + i = n; \ + if(i != NULL) \ + { \ + n = i; + +#define ENDFOREACH(n) \ + } \ + } while(n = n->next); + +#define ZERO_PARAM() \ + if(ZEND_NUM_ARGS() != 0) \ + WRONG_PARAM_COUNT; + +#define ONE_PARAM(p) \ + if(ZEND_NUM_ARGS() != 1 || getParameters(ht, 1, &p) == FAILURE) \ + WRONG_PARAM_COUNT; + +#define TWO_PARAM(p,p1) \ + if(ZEND_NUM_ARGS() != 1 || getParameters(ht, 2, &p, &p1) == FAILURE) \ + WRONG_PARAM_COUNT; + +#define THREE_PARAM(p,p1,p2) \ + if(ZEND_NUM_ARGS() != 1 || getParameters(ht, 3, &p, &p1, &p2) == FAILURE) \ + WRONG_PARAM_COUNT; + +#define FETCH_THIS_SDL(ss) \ + { \ + zval *__thisObj,**__tmp; \ + GET_THIS_OBJECT(__thisObj) \ + if(FIND_SDL_PROPERTY(__thisObj,__tmp) != FAILURE) \ + { \ + FETCH_SDL_RES(ss,__tmp); \ + } \ + else \ + ss = NULL; \ + } + +#define FIND_SDL_PROPERTY(ss,tmp) zend_hash_find(ss->value.obj.properties, "sdl", sizeof("sdl"), (void **)&tmp) +#define FETCH_SDL_RES(ss,tmp) ss = (sdlPtr) zend_fetch_resource(tmp TSRMLS_CC, -1, "sdl", NULL, 1, le_sdl) + +#define FETCH_THIS_SERVICE(ss) \ + { \ + zval *__thisObj,**__tmp; \ + GET_THIS_OBJECT(__thisObj) \ + if(FIND_SERVICE_PROPERTY(__thisObj,__tmp) != FAILURE) \ + { \ + FETCH_SERVICE_RES(ss,__tmp); \ + } \ + else \ + ss = NULL; \ + } + +#define FIND_SERVICE_PROPERTY(ss,tmp) zend_hash_find(ss->value.obj.properties, "service", sizeof("service"), (void **)&tmp) +#define FETCH_SERVICE_RES(ss,tmp) ss = (soapServicePtr) zend_fetch_resource(tmp TSRMLS_CC, -1, "service", NULL, 1, le_service) + +#define FETCH_THIS_URL(ss) \ + { \ + zval *__thisObj,**__tmp; \ + GET_THIS_OBJECT(__thisObj) \ + if(FIND_URL_PROPERTY(__thisObj,__tmp) != FAILURE) \ + { \ + FETCH_URL_RES(ss,__tmp); \ + } \ + else \ + ss = NULL; \ + } + +#define FIND_URL_PROPERTY(ss,tmp) zend_hash_find(ss->value.obj.properties, "httpurl", sizeof("httpurl"), (void **)&tmp) +#define FETCH_URL_RES(ss,tmp) ss = (php_url *) zend_fetch_resource(tmp TSRMLS_CC, -1, "httpurl", NULL, 1, le_url) + +#define FETCH_THIS_SOCKET(ss) \ + { \ + zval *__thisObj,**__tmp; \ + GET_THIS_OBJECT(__thisObj) \ + if(FIND_SOCKET_PROPERTY(__thisObj,__tmp) != FAILURE) \ + { \ + FETCH_SOCKET_RES(ss,__tmp); \ + } \ + else \ + ss = NULL; \ + } + +#define FIND_SOCKET_PROPERTY(ss,tmp) zend_hash_find(ss->value.obj.properties, "httpsocket", sizeof("httpsocket"), (void **)&tmp) +#define FETCH_SOCKET_RES(ss,tmp) ss = (SOAP_STREAM)zend_fetch_resource(tmp TSRMLS_CC, -1, "httpsocket", NULL, 1, le_http_socket) + +#define GET_THIS_OBJECT(o) \ + o = getThis(); \ + if (!o) \ + { \ + php_error(E_WARNING, "Cannot Get Class Info"); \ + return; \ + } + + +#endif diff --git a/ext/soap/php_xml.c b/ext/soap/php_xml.c new file mode 100644 index 0000000000..707d073984 --- /dev/null +++ b/ext/soap/php_xml.c @@ -0,0 +1,214 @@ +#include "php_soap.h" + +xmlNsPtr attr_find_ns(xmlAttrPtr node) +{ + if(node->ns) + return node->ns; + else if(node->parent->ns) + return node->parent->ns; + else + return xmlSearchNs(node->doc, node->parent, NULL); +} + +xmlNsPtr node_find_ns(xmlNodePtr node) +{ + if(node->ns) + return node->ns; + else + return xmlSearchNs(node->doc, node, NULL); +} + +int attr_is_equal_ex(xmlAttrPtr node, char *name, char *ns) +{ + if(!strcmp(node->name, name)) + { + if(ns) + { + xmlNsPtr nsPtr; + if(node->ns) + nsPtr = node->ns; + else if(node->parent->ns) + nsPtr = node->parent->ns; + else + nsPtr = xmlSearchNs(node->doc, node->parent, NULL); + if(!strcmp(nsPtr->href, ns)) + return TRUE; + return FALSE; + } + return TRUE; + } + return FALSE; +} + +int node_is_equal_ex(xmlNodePtr node, char *name, char *ns) +{ + if(!strcmp(node->name, name)) + { + if(ns) + { + xmlNsPtr nsPtr; + if(node->ns) + nsPtr = node->ns; + else + nsPtr = xmlSearchNs(node->doc, node, NULL); + if(!strcmp(nsPtr->href, ns)) + return TRUE; + return FALSE; + } + return TRUE; + } + return FALSE; +} + +xmlAttrPtr get_attribute_ex(xmlAttrPtr node, char *name, char *ns) +{ + xmlAttrPtr trav = node; + if(node == NULL) return NULL; + do { + if(attr_is_equal_ex(trav, name, ns)) + return trav; + } while(trav = trav->next); + return NULL; +} + +xmlNodePtr get_node_ex(xmlNodePtr node, char *name, char *ns) +{ + xmlNodePtr trav = node; + if(node == NULL) return NULL; + do { + if(node_is_equal_ex(trav, name, ns)) + return trav; + } while(trav = trav->next); + return NULL; +} + +xmlNodePtr get_node_recurisve_ex(xmlNodePtr node, char *name, char *ns) +{ + xmlNodePtr trav = node; + if(node == NULL) return NULL; + do + { + if(node_is_equal_ex(trav, name, ns)) + return trav; + else + { + if(node->children != NULL) + { + xmlNodePtr tmp; + tmp = get_node_recurisve_ex(node->children, name, ns); + if(tmp) + return tmp; + } + } + } while(trav = trav->next); + return NULL; +} + +xmlNodePtr get_node_with_attribute_ex(xmlNodePtr node, char *name, char *name_ns, char *attribute, char *value, char *attr_ns) +{ + xmlNodePtr trav = node, cur; + xmlAttrPtr attr; + + if(node == NULL) return NULL; + do + { + if(name != NULL) + { + cur = get_node_ex(trav, name, name_ns); + if(!cur) + return cur; + } + else + cur = trav; + + attr = get_attribute_ex(cur->properties, attribute, attr_ns); + if(attr != NULL && strcmp(attr->children->content, value) == 0) + return cur; + else + { + if(cur->children != NULL) + { + xmlNodePtr tmp; + tmp = get_node_with_attribute_ex(cur->children, name, name_ns, attribute, value, attr_ns); + if(tmp) + return tmp; + } + } + }while(trav = trav->next); + return NULL; +} + +xmlNodePtr get_node_with_attribute_recursive_ex(xmlNodePtr node, char *name, char *name_ns, char *attribute, char *value, char *attr_ns) +{ + xmlNodePtr trav = node, cur; + xmlAttrPtr attr; + + if(node == NULL) return NULL; + do + { + if(name != NULL) + { + cur = get_node_recurisve_ex(trav, name, name_ns); + if(!cur) + return cur; + } + else + cur = trav; + + attr = get_attribute_ex(cur->properties, attribute, attr_ns); + if(attr != NULL && strcmp(attr->children->content, value) == 0) + return cur; + else + { + if(cur->children != NULL) + { + xmlNodePtr tmp; + tmp = get_node_with_attribute_recursive_ex(cur->children, name, name_ns, attribute, value, attr_ns); + if(tmp) + return tmp; + } + } + }while(trav = trav->next); + return NULL; +} + +xmlNodePtr check_and_resolve_href(xmlNodePtr data) +{ + xmlAttrPtr href; + xmlNodePtr ret = data; + + if(!data || !data->properties) + return ret; + + href = get_attribute(data->properties, "href"); + if(href) + { + // Internal href try and find node + if(href->children->content[0] == '#') + { + ret = get_node_with_attribute_recursive(data->doc->children, NULL, "id", &href->children->content[1]); + } + // External href....? + } + + return ret; +} + +int parse_namespace(char *inval, char **value, char **namespace) +{ + char *found = strchr(inval, ':'); + + if(found != NULL) + { + (*namespace) = estrndup(inval, found - inval); + (*value) = estrdup(++found); + } + else + { + (*value) = estrdup(inval); + (*namespace) = NULL; + } + + return FALSE; +} + diff --git a/ext/soap/php_xml.h b/ext/soap/php_xml.h new file mode 100644 index 0000000000..d17caba007 --- /dev/null +++ b/ext/soap/php_xml.h @@ -0,0 +1,23 @@ +#ifndef PHP_SOAP_XML_H +#define PHP_SOAP_XML_H + +#define get_attribute(node, name) get_attribute_ex(node, name, NULL) +#define get_node(node, name) get_node_ex(node, name, NULL) +#define get_node_recursive(node, name) get_node_recursive_ex(node, name, NULL) +#define get_node_with_attribute(node, name, attr, val) get_node_with_attribute_ex(node, name, NULL, attr, val, NULL) +#define get_node_with_attribute_recursive(node, name, attr, val) get_node_with_attribute_recursive_ex(node, name, NULL, attr, val, NULL) +#define attr_is_equal(node, name) attr_is_equal_ex(node, name, NULL) + +xmlNsPtr attr_find_ns(xmlAttrPtr node); +xmlNsPtr node_find_ns(xmlNodePtr node); +int attr_is_equal_ex(xmlAttrPtr node, char *name, char *ns); +int node_is_equal_ex(xmlNodePtr node, char *name, char *ns); +xmlAttrPtr get_attribute_ex(xmlAttrPtr node,char *name, char *ns); +xmlNodePtr get_node_ex(xmlNodePtr node,char *name, char *ns); +xmlNodePtr get_node_recurisve_ex(xmlNodePtr node,char *name, char *ns); +xmlNodePtr get_node_with_attribute_ex(xmlNodePtr node, char *name, char *name_ns, char *attribute, char *value, char *attr_ns); +xmlNodePtr get_node_with_attribute_recursive_ex(xmlNodePtr node, char *name, char *name_ns, char *attribute, char *value, char *attr_ns); +int parse_namespace(char *inval,char **value,char **namespace); +xmlNodePtr check_and_resolve_href(xmlNodePtr data); + +#endif diff --git a/ext/soap/soap.c b/ext/soap/soap.c new file mode 100644 index 0000000000..fbc889a81b --- /dev/null +++ b/ext/soap/soap.c @@ -0,0 +1,2037 @@ +#include "php_soap.h" + +int le_sdl = 0; +int le_http_socket = 0; +int le_url = 0; +int le_service = 0; + +// 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 zend_class_entry soap_class_entry; +static zend_class_entry soap_server_class_entry; +static zend_class_entry soap_fault_class_entry; +zend_class_entry soap_var_class_entry; +zend_class_entry soap_param_class_entry; + +ZEND_DECLARE_MODULE_GLOBALS(soap); + +static void (*old_handler)(int, const char *, const uint, const char*, va_list); + +static zend_function_entry soap_functions[] = { +#ifdef HAVE_PHP_DOMXML + PHP_FE(soap_encode_to_xml, NULL) + PHP_FE(soap_encode_to_zval, NULL) +#endif + {NULL, NULL, NULL} +}; + +static zend_function_entry soap_fault_functions[] = { + PHP_FE(soapfault, NULL) + {NULL, NULL, NULL} +}; + +static zend_function_entry soap_server_functions[] = { + PHP_FE(soapserver,NULL) + PHP_FE(setpersistence,NULL) + PHP_FE(setclass,NULL) + PHP_FE(addfunction,NULL) + PHP_FE(getfunctions,NULL) + PHP_FE(handle,NULL) + PHP_FE(bind,NULL) +#ifdef HAVE_PHP_DOMXML + PHP_FE(map, NULL) +#endif + {NULL, NULL, NULL} +}; + +static zend_function_entry soap_client_functions[] = { + PHP_FE(soapobject, NULL) + PHP_FE(__isfault, NULL) + PHP_FE(__getfault, NULL) + PHP_FE(__call, NULL) + PHP_FE(__parse, NULL) +#ifdef PHP_DEBUG + PHP_FE(__getlastrequest, NULL) + PHP_FE(__getlastresponse, NULL) + PHP_FE(__getfunctions, NULL) + PHP_FE(__gettypes, NULL) +#endif + {NULL, NULL, NULL} +}; + +static zend_function_entry soap_var_functions[] = { + PHP_FE(soapvar, NULL) + {NULL, NULL, NULL} +}; + +static zend_function_entry soap_param_functions[] = { + PHP_FE(soapparam, NULL) + {NULL, NULL, NULL} +}; + +zend_module_entry soap_module_entry = { +#ifdef STANDARD_MODULE_HEADER + STANDARD_MODULE_HEADER, +#endif + "soap", + soap_functions, + PHP_MINIT(soap), + PHP_MSHUTDOWN(soap), + NULL, + NULL, + PHP_MINFO(soap), +#ifdef STANDARD_MODULE_HEADER + NO_VERSION_YET, +#endif + STANDARD_MODULE_PROPERTIES, +}; + +#ifdef COMPILE_DL_SOAP +ZEND_GET_MODULE(soap) +#endif + +static void php_soap_init_globals(zend_soap_globals *soap_globals) +{ + int i; + long enc; + + soap_globals->sdls = malloc(sizeof(HashTable)); + zend_hash_init(soap_globals->sdls, 0, NULL, delete_sdl, 1); + + soap_globals->services = malloc(sizeof(HashTable)); + zend_hash_init(soap_globals->services, 0, NULL, delete_service, 1); + + soap_globals->defEnc = malloc(sizeof(HashTable)); + zend_hash_init(soap_globals->defEnc, 0, NULL, NULL, 1); + + soap_globals->defEncIndex = malloc(sizeof(HashTable)); + zend_hash_init(soap_globals->defEncIndex, 0, NULL, NULL, 1); + + soap_globals->defEncNs = malloc(sizeof(HashTable)); + zend_hash_init(soap_globals->defEncNs, 0, NULL, NULL, 1); + + soap_globals->defEncPrefix = malloc(sizeof(HashTable)); + zend_hash_init(soap_globals->defEncPrefix, 0, NULL, NULL, 1); + + soap_globals->overrides = NULL; + + i = 0; + do + { + enc = (long)&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; + ns_type = emalloc(strlen(defaultEncoding[i].details.ns) + strlen(defaultEncoding[i].details.type_str) + 2); + sprintf(ns_type, "%s:%s", defaultEncoding[i].details.ns, defaultEncoding[i].details.type_str); + zend_hash_add(soap_globals->defEnc, ns_type, strlen(ns_type), &enc, sizeof(encodePtr), NULL); + efree(ns_type); + } + else + { + zend_hash_add(soap_globals->defEnc, defaultEncoding[i].details.type_str, strlen(defaultEncoding[i].details.type_str), &enc, sizeof(encodePtr), NULL); + } + } + //Index everything by number + zend_hash_index_update(soap_globals->defEncIndex, defaultEncoding[i].details.type, &enc, sizeof(encodePtr), NULL); + i++; + } + while(defaultEncoding[i].details.type != END_KNOWN_TYPES); + + //hash by namespace + zend_hash_add(soap_globals->defEncNs, XSD_1999_NAMESPACE, sizeof(XSD_1999_NAMESPACE), XSD_NS_PREFIX, sizeof(XSD_NS_PREFIX), NULL); + zend_hash_add(soap_globals->defEncNs, XSD_NAMESPACE, sizeof(XSD_NAMESPACE), XSD_NS_PREFIX, sizeof(XSD_NS_PREFIX), NULL); + zend_hash_add(soap_globals->defEncNs, APACHE_NAMESPACE, sizeof(APACHE_NAMESPACE), APACHE_NS_PREFIX, sizeof(APACHE_NS_PREFIX), NULL); + zend_hash_add(soap_globals->defEncNs, SOAP_ENC_NAMESPACE, sizeof(SOAP_ENC_NAMESPACE), SOAP_ENC_NS_PREFIX, sizeof(SOAP_ENC_NS_PREFIX), NULL); + //and by prefix + zend_hash_add(soap_globals->defEncPrefix, XSD_NS_PREFIX, sizeof(XSD_NS_PREFIX), XSD_NAMESPACE, sizeof(XSD_NAMESPACE), NULL); + zend_hash_add(soap_globals->defEncPrefix, APACHE_NS_PREFIX, sizeof(APACHE_NS_PREFIX), APACHE_NAMESPACE, sizeof(APACHE_NAMESPACE), NULL); + zend_hash_add(soap_globals->defEncPrefix, SOAP_ENC_NS_PREFIX, sizeof(SOAP_ENC_NS_PREFIX), SOAP_ENC_NAMESPACE, sizeof(SOAP_ENC_NAMESPACE), NULL); + +} + +static void php_soap_del_globals(zend_soap_globals *soap_globals) +{ +/* zend_hash_destroy(soap_globals->sdls); + zend_hash_destroy(soap_globals->services); + zend_hash_destroy(soap_globals->defEnc); + zend_hash_destroy(soap_globals->defEncIndex); + zend_hash_destroy(soap_globals->defEncNs);*/ +} + +PHP_MSHUTDOWN_FUNCTION(soap) +{ + zend_hash_destroy(SOAP_GLOBAL(sdls)); + zend_hash_destroy(SOAP_GLOBAL(services)); + zend_hash_destroy(SOAP_GLOBAL(defEnc)); + zend_hash_destroy(SOAP_GLOBAL(defEncIndex)); + zend_hash_destroy(SOAP_GLOBAL(defEncNs)); + zend_hash_destroy(SOAP_GLOBAL(defEncPrefix)); + return SUCCESS; +} + +PHP_MINIT_FUNCTION(soap) +{ + //TODO: add ini entry for always use soap errors + ZEND_INIT_MODULE_GLOBALS(soap, php_soap_init_globals, php_soap_del_globals); + + //Register SoapObject class + INIT_OVERLOADED_CLASS_ENTRY(soap_class_entry, PHP_SOAP_CLASSNAME, soap_client_functions, soap_call_function_handler, NULL, NULL); + zend_register_internal_class(&soap_class_entry TSRMLS_CC); + + //Register SoapVar class + INIT_CLASS_ENTRY(soap_var_class_entry, PHP_SOAP_VAR_CLASSNAME, soap_var_functions); + zend_register_internal_class(&soap_var_class_entry TSRMLS_CC); + + //Register SoapServer class + INIT_CLASS_ENTRY(soap_server_class_entry, PHP_SOAP_SERVER_CLASSNAME, soap_server_functions); + zend_register_internal_class(&soap_server_class_entry TSRMLS_CC); + + //Register SoapFault class + INIT_CLASS_ENTRY(soap_fault_class_entry, PHP_SOAP_FAULT_CLASSNAME, soap_fault_functions); + zend_register_internal_class(&soap_fault_class_entry TSRMLS_CC); + + //Register SoapParam class + INIT_CLASS_ENTRY(soap_param_class_entry, PHP_SOAP_PARAM_CLASSNAME, soap_param_functions); + zend_register_internal_class(&soap_param_class_entry TSRMLS_CC); + + le_sdl = register_list_destructors(NULL, NULL); + le_http_socket = register_list_destructors(delete_http_socket, NULL); + le_url = register_list_destructors(delete_url, NULL); + le_service = register_list_destructors(delete_service, NULL); + + 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("XSD_1999_TIMEINSTANT", XSD_1999_TIMEINSTANT, CONST_CS | CONST_PERSISTENT); + + REGISTER_LONG_CONSTANT("UNKNOWN_TYPE", UNKNOWN_TYPE, 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_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_ENTITYS", XSD_ENTITYS, 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); + + old_handler = zend_error_cb; + +#if HAVE_PHP_SESSION + php_session_register_serializer("soap", PS_SERIALIZER_ENCODE_NAME(soap), PS_SERIALIZER_DECODE_NAME(soap)); +#endif + + return SUCCESS; +} + +#if HAVE_PHP_SESSION +PS_SERIALIZER_ENCODE_FUNC(soap) +{ +/* + char *key; \ + uint key_length; \ + ulong num_key; \ + zval **struc; + + wddx_packet *packet; + PS_ENCODE_VARS; + + packet = php_wddx_constructor(); + if (!packet) + return FAILURE; + + php_wddx_packet_start(packet, NULL, 0); + php_wddx_add_chunk_static(packet, WDDX_STRUCT_S); + + PS_ENCODE_LOOP( + + php_wddx_serialize_var(packet, *struc, key, key_length); + ); + + php_wddx_add_chunk_static(packet, WDDX_STRUCT_E); + php_wddx_packet_end(packet); + *newstr = php_wddx_gather(packet); + php_wddx_destructor(packet); + + if (newlen) + *newlen = strlen(*newstr); +*/ + return SUCCESS; +} + +PS_SERIALIZER_DECODE_FUNC(soap) +{ +/* zval *retval; + zval **ent; + char *key; + uint key_length; + char tmp[128]; + ulong idx; + int hash_type; + int ret; + + if (vallen == 0) + return SUCCESS; + + MAKE_STD_ZVAL(retval); + + if ((ret = php_wddx_deserialize_ex((char *)val, vallen, retval)) == SUCCESS) { + + for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(retval)); + zend_hash_get_current_data(Z_ARRVAL_P(retval), (void **) &ent) == SUCCESS; + zend_hash_move_forward(Z_ARRVAL_P(retval))) { + hash_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(retval), &key, &key_length, &idx, 0, NULL); + + switch (hash_type) { + case HASH_KEY_IS_LONG: + sprintf(tmp, "%ld", idx); + key = tmp; + case HASH_KEY_IS_STRING: + php_set_session_var(key, key_length-1, *ent, NULL TSRMLS_CC); + PS_ADD_VAR(key); + } + } + } + + zval_ptr_dtor(&retval); +*/ + return TRUE; +} +#endif + + +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"); +#if HAVE_PHP_SESSION + php_info_print_table_row(2, "Soap Serializer", "enabled"); +#endif + php_info_print_table_end(); +} + +#ifdef HAVE_PHP_DOMXML +PHP_FUNCTION(soap_encode_to_xml) +{ + zval *pzval, *ret; + encodePtr enc; + char *name; + int found, name_len; + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name, &name_len, &pzval) == FAILURE) + php_error(E_ERROR, "wrong number of parameters to soap_encode_to_xml"); + + enc = get_conversion(Z_TYPE_P(pzval)); + ret = php_domobject_new(seralize_zval(pzval, NULL, name), &found, NULL TSRMLS_CC); + *return_value = *ret; + zval_copy_ctor(return_value); + zval_ptr_dtor(&ret); +} + +PHP_FUNCTION(soap_encode_to_zval) +{ + zval *dom, **addr, *ret; + xmlNodePtr node; + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &dom) == FAILURE) + php_error(E_ERROR, "wrong number of parameters to soap_encode_to_zval"); + + if(zend_hash_index_find(Z_OBJPROP_P(dom), 1, (void **)&addr) == FAILURE) + php_error(E_ERROR, "Cannot find domaddress to parameter passed to soap_encode_to_zval"); + + node = (xmlNodePtr)Z_LVAL_PP(addr); + ret = master_to_zval(get_conversion(UNKNOWN_TYPE), node); + *return_value = *ret; +} +#endif + +//SoapParam functions +PHP_FUNCTION(soapparam) +{ + zval *thisObj, *data; + char *name; + int name_length; + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs", &data, &name, &name_length) == FAILURE) + php_error(E_ERROR, "Invalid arguments to SoapParam constructor"); + + GET_THIS_OBJECT(thisObj); + + zval_add_ref(&data); + add_property_stringl(thisObj, "param_name", name, name_length, 1); + add_property_zval(thisObj, "param_data", data); +} + +//SoapFault functions +PHP_FUNCTION(soapfault) +{ + char *fault_string = NULL, *fault_code = NULL, *fault_actor = NULL; + int fault_string_len, fault_code_len, fault_actor_len; + zval *thisObj, *details = NULL; + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|zs", &fault_string, &fault_string_len, + &fault_code, &fault_code_len, &details, &fault_actor, &fault_actor_len) == FAILURE) + php_error(E_ERROR, "Invalid arguments to SoapFault constructor"); + + GET_THIS_OBJECT(thisObj); + + if(details) + zval_add_ref(&details); + set_soap_fault(thisObj, fault_code, fault_string, fault_actor, details); +} + +//SoapVar functions +PHP_FUNCTION(soapvar) +{ + zval *data, *thisObj, *type; + char *stype = NULL, *ns = NULL; + int stype_len, ns_len; + + GET_THIS_OBJECT(thisObj); + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!z|ss", &data, &type, &stype, &stype_len, &ns, &ns_len) == FAILURE) + php_error(E_ERROR, "Invalid arguments to SoapVal constructor"); + + zval_add_ref(&data); + if(Z_TYPE_P(type) == IS_NULL) + add_property_long(thisObj, "enc_type", UNKNOWN_TYPE); + else + { + if(zend_hash_index_exists(SOAP_GLOBAL(defEncIndex), Z_LVAL_P(type))) + add_property_long(thisObj, "enc_type", Z_LVAL_P(type)); + else + php_error(E_ERROR, "Cannot find encoding for SoapVar"); + } + + add_property_zval(thisObj, "enc_value", data); + + if(stype) + add_property_stringl(thisObj, "enc_stype", stype, stype_len, 1); + if(ns) + add_property_stringl(thisObj, "enc_ns", ns, ns_len, 1); +} + +//SoapServer functions +PHP_FUNCTION(soapserver) +{ + zval *thisObj; + soapServicePtr service; + char *uri; + int ret, uri_len; + + SOAP_SERVER_BEGIN_CODE(); + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &uri, &uri_len) == FAILURE) + php_error(E_ERROR, "Wrong number of parameters to SoapServer constructor"); + + GET_THIS_OBJECT(thisObj); + + service = emalloc(sizeof(soapService)); + memset(service, 0, sizeof(soapService)); + + service->uri = estrndup(uri, uri_len); + service->type = SOAP_FUNCTIONS; + service->soap_functions.functions_all = FALSE; + service->soap_functions.ft = emalloc(sizeof(HashTable)); + zend_hash_init(service->soap_functions.ft, 0, NULL, ZVAL_PTR_DTOR, 0); + + ret = zend_list_insert(service, le_service); + add_property_resource(thisObj, "service", ret); + zend_list_addref(ret); + + SOAP_SERVER_END_CODE(); +} + +#define NULL_OR_STRING(zval) \ + (!zval || Z_TYPE_P(zval) == IS_NULL || Z_TYPE_P(zval) == IS_STRING) + +#define IS_VALID_FUNCTION(zval) \ + (zval && Z_TYPE_P(zval) != IS_NULL) + +#ifdef HAVE_PHP_DOMXML +PHP_FUNCTION(map) +{ + char *type, *class_name; + zval *to_xml_before = NULL, *to_xml = NULL, *to_xml_after = NULL, + *to_zval_before = NULL, *to_zval = NULL, *to_zval_after = NULL; + int type_len, class_name_len; + char *ns, *ctype; + soapServicePtr service; + + SOAP_SERVER_BEGIN_CODE(); + + if(zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "sz|zzzzz", + &type, &type_len, &to_xml_before, &to_xml, &to_xml_after, &to_zval_before, &to_zval, + &to_zval_after) == SUCCESS && NULL_OR_STRING(to_xml_before) && NULL_OR_STRING(to_xml) && + NULL_OR_STRING(to_xml_after) && NULL_OR_STRING(to_zval_before) && NULL_OR_STRING(to_zval) && + NULL_OR_STRING(to_zval_after)) + { + soapMappingPtr map; + encodePtr enc, new_enc; + smart_str resloved_ns = {0}; + + FETCH_THIS_SERVICE(service); + + new_enc = malloc(sizeof(encode)); + memset(new_enc, 0, sizeof(encode)); + + ctype = strrchr(type, ':'); + if(ctype) { + smart_str_appendl(&resloved_ns, type, ctype - type); + smart_str_0(&resloved_ns); + ctype++; + } else { + ns = NULL; + } + + if(ns) + { + if(zend_hash_find(SOAP_GLOBAL(defEncPrefix), resloved_ns.c, resloved_ns.len + 1, &ns) == SUCCESS) + { + enc = get_encoder(service->sdl, ns, ctype); + smart_str_free(&resloved_ns); + smart_str_appendl(&resloved_ns, ns, strlen(ns)); + smart_str_appendc(&resloved_ns, ':'); + smart_str_appendl(&resloved_ns, ctype, strlen(ctype)); + smart_str_0(&resloved_ns); + type = resloved_ns.c; + type_len = resloved_ns.len; + } + else + enc = get_encoder_ex(service->sdl, type); + } + else + enc = get_encoder_ex(service->sdl, type); + + new_enc->details.type = enc->details.type; + new_enc->details.ns = strdup(enc->details.ns); + new_enc->details.type_str = strdup(enc->details.type_str); + new_enc->details.sdl_type = enc->details.sdl_type; + new_enc->to_xml = enc->to_xml; + new_enc->to_zval = enc->to_zval; + new_enc->to_xml_before = enc->to_xml_before; + new_enc->to_zval_before = enc->to_zval_before; + new_enc->to_xml_after = enc->to_xml_after; + new_enc->to_zval_after = enc->to_zval_after; + + map = emalloc(sizeof(soapMapping)); + memset(map, 0, sizeof(soapMapping)); + + map->type = SOAP_MAP_FUNCTION; + if(IS_VALID_FUNCTION(to_xml_before)) + { + zval_add_ref(&to_xml_before); + map->map_functions.to_xml_before = to_xml_before; + new_enc->to_xml_before = to_xml_before_user; + } + if(IS_VALID_FUNCTION(to_xml)) + { + zval_add_ref(&to_xml); + map->map_functions.to_xml = to_xml; + new_enc->to_xml = to_xml_user; + } + if(IS_VALID_FUNCTION(to_xml_after)) + { + zval_add_ref(&to_xml_after); + map->map_functions.to_xml_after = to_xml_after; + new_enc->to_xml_after = to_xml_after_user; + } + if(IS_VALID_FUNCTION(to_zval_before)) + { + zval_add_ref(&to_zval_before); + map->map_functions.to_zval_before = to_zval_before; + new_enc->to_zval_before = to_zval_before_user; + } + if(IS_VALID_FUNCTION(to_zval)) + { + zval_add_ref(&to_zval); + map->map_functions.to_zval = to_zval; + new_enc->to_zval = to_zval_user; + } + if(IS_VALID_FUNCTION(to_zval_after)) + { + zval_add_ref(&to_zval_after); + map->map_functions.to_zval_after = to_zval_after; + new_enc->to_zval_after = to_zval_after_user; + } + + new_enc->details.map = map; + + if(!service->mapping) + { + service->mapping = emalloc(sizeof(HashTable)); + zend_hash_init(service->mapping, 0, NULL, delete_encoder, 0); + } + zend_hash_update(service->mapping, type, type_len + 1, &new_enc, sizeof(encodePtr), NULL); + smart_str_free(&resloved_ns); + } + else if(zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &type, &type_len, &class_name, &class_name_len, &type) == SUCCESS) + { + } + else + php_error(E_ERROR, "Wrong number of parameters to SoapServer->map"); +} +#endif + +PHP_FUNCTION(bind) +{ + char *wsdl; + int wsdl_len; + soapServicePtr service; + + SOAP_SERVER_BEGIN_CODE(); + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &wsdl, &wsdl_len) == FAILURE) + php_error(E_ERROR, "Wrong number of parameters to SoapServer->bind"); + + FETCH_THIS_SERVICE(service); + service->sdl = get_sdl(wsdl); + + SOAP_SERVER_END_CODE(); +} + +PHP_FUNCTION(setpersistence) +{ + soapServicePtr service; + int value; + + SOAP_SERVER_BEGIN_CODE(); + FETCH_THIS_SERVICE(service); + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) != FAILURE) + { + if(service->type == SOAP_CLASS) + { + if(value == SOAP_PERSISTENCE_SESSION || + value == SOAP_PERSISTENCE_REQUEST) + service->soap_class.persistance = value; + else + php_error(E_ERROR, "Tried to set persistence with bogus value (%ld)", value); + } + else + php_error(E_ERROR, "Tried to set persistence when you are using you SOAP SERVER in function mode, no persistence needed"); + } + + SOAP_SERVER_END_CODE(); +} + +PHP_FUNCTION(setclass) +{ + soapServicePtr service; + zend_class_entry *ce; + char *class_name = NULL; + int found, argc; + zval ***argv; + + SOAP_SERVER_BEGIN_CODE(); + + FETCH_THIS_SERVICE(service); + + argc = ZEND_NUM_ARGS(); + argv = emalloc(argc * sizeof(zval **)); + + if (argc < 1 || zend_get_parameters_array_ex(argc, argv) == FAILURE) + { + efree(argv); + WRONG_PARAM_COUNT; + } + + if(Z_TYPE_PP(argv[0]) == IS_STRING) + { + class_name = estrdup(Z_STRVAL_PP(argv[0])); + + found = zend_hash_find(EG(class_table), php_strtolower(class_name, Z_STRLEN_PP(argv[0])), Z_STRLEN_PP(argv[0]) + 1, (void **)&ce); + efree(class_name); + if(found != FAILURE) + { + service->type = SOAP_CLASS; + service->soap_class.ce = ce; + service->soap_class.persistance = SOAP_PERSISTENCE_REQUEST; + service->soap_class.argc = argc - 1; + if(service->soap_class.argc > 0) + { + int i; + service->soap_class.argv = emalloc(sizeof(zval) * service->soap_class.argc); + for(i = 0;i < service->soap_class.argc;i++) + { + service->soap_class.argv[i] = *(argv[i + 1]); + zval_add_ref(&service->soap_class.argv[i]); + } + } + } + else + php_error(E_ERROR, "Tried to set a non existant class (%s)", Z_STRVAL_PP(argv[0])); + } + else + php_error(E_ERROR, "You must pass in a string to setclass"); + + efree(argv); + SOAP_SERVER_END_CODE(); +} + +PHP_FUNCTION(getfunctions) +{ + soapServicePtr service; + + SOAP_SERVER_BEGIN_CODE(); + + FETCH_THIS_SERVICE(service); + + array_init(return_value); + if(service->type == SOAP_CLASS) + { + zend_function *f; + zend_hash_internal_pointer_reset(&service->soap_class.ce->function_table); + while(zend_hash_get_current_data(&service->soap_class.ce->function_table, (void **)&f) != FAILURE) + { + add_next_index_string(return_value, f->common.function_name, 1); + zend_hash_move_forward(&service->soap_class.ce->function_table); + } + } + else if(service->soap_functions.functions_all == TRUE) + { + zend_function *f; + zend_hash_internal_pointer_reset(EG(function_table)); + while(zend_hash_get_current_data(EG(function_table), (void **)&f) != FAILURE) + { + add_next_index_string(return_value, f->common.function_name, 1); + zend_hash_move_forward(EG(function_table)); + } + } + else if(service->soap_functions.ft != NULL) + zend_hash_copy(Z_ARRVAL_P(return_value), service->soap_functions.ft, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + + SOAP_SERVER_END_CODE(); +} + +PHP_FUNCTION(addfunction) +{ + soapServicePtr service; + zval *function_name, *function_copy; + + SOAP_SERVER_BEGIN_CODE(); + + FETCH_THIS_SERVICE(service); + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &function_name) == FAILURE) + php_error(E_ERROR, "Invalid parameters passed to addfunction"); + + if(function_name->type == IS_ARRAY) + { + if(service->type == SOAP_FUNCTIONS) + { + zval **tmp_function, *function_copy; + + if(service->soap_functions.ft == NULL) + { + service->soap_functions.ft = emalloc(sizeof(HashTable)); + zend_hash_init(service->soap_functions.ft, 0, NULL, ZVAL_PTR_DTOR, 0); + } + + zend_hash_internal_pointer_reset(Z_ARRVAL_P(function_name)); + while(zend_hash_get_current_data(Z_ARRVAL_P(function_name), (void **)&tmp_function) != FAILURE) + { + if(Z_TYPE_PP(tmp_function) != IS_STRING) + php_error(E_ERROR, "Tried to add a function that isn't a string"); + + MAKE_STD_ZVAL(function_copy); + *function_copy = *(*tmp_function); + zval_copy_ctor(function_copy); + + php_strtolower(Z_STRVAL_P(function_copy), Z_STRLEN_P(function_copy)); + + if(zend_hash_exists(EG(function_table), Z_STRVAL_P(function_copy), Z_STRLEN_P(function_copy) + 1) == FALSE) + php_error(E_ERROR, "Tried to add a non existant function (\"%s\")", Z_STRVAL_PP(tmp_function)); + + zend_hash_update(service->soap_functions.ft, Z_STRVAL_P(function_copy), Z_STRLEN_P(function_copy) + 1, &function_copy, sizeof(zval *), NULL); + zend_hash_move_forward(Z_ARRVAL_P(function_name)); + } + } + } + else if(function_name->type == IS_STRING) + { + MAKE_STD_ZVAL(function_copy); + *function_copy = *function_name; + zval_copy_ctor(function_copy); + + php_strtolower(Z_STRVAL_P(function_copy), Z_STRLEN_P(function_copy)); + + if(zend_hash_exists(EG(function_table), Z_STRVAL_P(function_copy), Z_STRLEN_P(function_copy) + 1) == FALSE) + php_error(E_ERROR, "Tried to add a non existant function (\"%s\")", Z_STRVAL_P(function_name)); + if(service->soap_functions.ft == NULL) + { + service->soap_functions.functions_all = FALSE; + service->soap_functions.ft = emalloc(sizeof(HashTable)); + zend_hash_init(service->soap_functions.ft, 0, NULL, ZVAL_PTR_DTOR, 0); + } + + zend_hash_update(service->soap_functions.ft, Z_STRVAL_P(function_copy), Z_STRLEN_P(function_copy) + 1, &function_copy, sizeof(zval *), NULL); + } + else if(function_name->type == 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(E_ERROR, "Invalid value passed to addfunction (%ld)", Z_LVAL_P(function_name)); + } + + SOAP_SERVER_END_CODE(); +} + +PHP_FUNCTION(handle) +{ + soapServicePtr service; + xmlDocPtr doc_request, doc_return; + zval function_name, **params, **raw_post, *soap_obj, retval, **server_vars; + char *fn_name, cont_len[30], *response_name; + int num_params = 0, size, i, call_status; + xmlChar *buf; + HashTable *function_table; + + FETCH_THIS_SERVICE(service); + + SOAP_SERVER_BEGIN_CODE(); + ZERO_PARAM(); + + INIT_ZVAL(retval); + + if(zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **)&server_vars) == SUCCESS) + { + zval **req_method, **query_string; + if(zend_hash_find(Z_ARRVAL_PP(server_vars), "REQUEST_METHOD", sizeof("REQUEST_METHOD"), (void **)&req_method) == SUCCESS) + { + if(!strcmp(Z_STRVAL_PP(req_method), "GET") && zend_hash_find(Z_ARRVAL_PP(server_vars), "QUERY_STRING", sizeof("QUERY_STRING"), (void **)&query_string) == SUCCESS) + { + if(!strcmp(Z_STRVAL_PP(query_string), "WSDL")) + { + if(service->sdl) + { + zval readfile, readfile_ret, *param; + + INIT_ZVAL(readfile); + INIT_ZVAL(readfile_ret); + MAKE_STD_ZVAL(param); + + sapi_add_header("Content-Type: text/xml", sizeof("Content-Type: text/xml"), 1); + ZVAL_STRING(param, service->sdl->source, 1); + ZVAL_STRING(&readfile, "readfile", 1); + if(call_user_function(EG(function_table), NULL, &readfile, &readfile_ret, 1, ¶m TSRMLS_CC) == FAILURE) + php_error(E_ERROR, "Couldn't find WSDL"); + + zval_ptr_dtor(¶m); + zval_dtor(&readfile); + zval_dtor(&readfile_ret); + SOAP_SERVER_END_CODE(); + return; + } + } + } + } + } + +//Turn on output buffering... we don't want people print in their methods +//#if PHP_API_VERSION <= 20010901 +// if(php_start_ob_buffer(NULL, 0 TSRMLS_CC) != SUCCESS) +//#else + if(php_start_ob_buffer(NULL, 0, 0 TSRMLS_CC) != SUCCESS) +//#endif + php_error(E_ERROR,"ob_start failed"); + + if (zend_hash_find(&EG(symbol_table), HTTP_RAW_POST_DATA, sizeof(HTTP_RAW_POST_DATA), (void **) &raw_post)!=FAILURE + && ((*raw_post)->type==IS_STRING)) + { + doc_request = xmlParseMemory(Z_STRVAL_PP(raw_post),Z_STRLEN_PP(raw_post)); + xmlCleanupParser(); + + deseralize_function_call(service->sdl, doc_request, &function_name, &num_params, ¶ms); + xmlFreeDoc(doc_request); + + fn_name = estrndup(Z_STRVAL(function_name),Z_STRLEN(function_name)); + response_name = emalloc(Z_STRLEN(function_name) + strlen("Response") + 1); + sprintf(response_name,"%sResponse\0",fn_name); + + if(service->type == SOAP_CLASS) + { + soap_obj = NULL; + //If persistent then set soap_obj from from the previous created session (if available) + if(service->soap_class.persistance == SOAP_PERSISTENCE_SESSION) + { + zval **tmp_soap; + + //Try and call session regiser for our dummy session object + //The only reason that i use call_user_function is that + //their isn't a way to start the session from an extension + //so calling session_register will both register the var + //and start the session + { + zval *bogus_session_name, session_register, sess_retval; + + INIT_ZVAL(session_register); + INIT_ZVAL(sess_retval); + + if(!zend_ini_long("register_globals", sizeof("register_globals"), 0)) + php_error(E_ERROR, "PHP-SOAP requires 'register_globals' to be on when using persistent objects please check your php.ini file"); + + MAKE_STD_ZVAL(bogus_session_name); + + ZVAL_STRING(bogus_session_name, "_bogus_session_name", 1); + ZVAL_STRING(&session_register, "session_register", 1); + + if(call_user_function(EG(function_table), NULL, &session_register, &sess_retval, 1, &bogus_session_name TSRMLS_CC) == FAILURE) + php_error(E_ERROR,"session_register failed"); + + zval_ptr_dtor(&bogus_session_name); + zval_dtor(&session_register); + zval_dtor(&sess_retval); + } + + //Find the soap object and assign + if(zend_hash_find(&EG(symbol_table), "_bogus_session_name", sizeof("_bogus_session_name"), (void **) &tmp_soap) == SUCCESS) + soap_obj = *tmp_soap; + } + + //If new session or something wierd happned + if(soap_obj == NULL) + { + zval *tmp_soap; + MAKE_STD_ZVAL(tmp_soap); + object_init_ex(tmp_soap, service->soap_class.ce); + + //Call constructor + if(zend_hash_exists(&Z_OBJCE_P(tmp_soap)->function_table, service->soap_class.ce->name, strlen(service->soap_class.ce->name) + 1)) + { + zval c_ret, constructor; + + INIT_ZVAL(c_ret); + INIT_ZVAL(constructor); + + ZVAL_STRING(&constructor, service->soap_class.ce->name, 1); + if(call_user_function(NULL, &tmp_soap, &constructor, &c_ret, service->soap_class.argc, service->soap_class.argv TSRMLS_CC) == FAILURE) + php_error(E_ERROR, "Error calling constructor"); + zval_dtor(&constructor); + zval_dtor(&c_ret); + } + + //If session then update session hash with new object + if(service->soap_class.persistance == SOAP_PERSISTENCE_SESSION) + { + zval **tmp_soap_pp; + if(zend_hash_update(&EG(symbol_table), "_bogus_session_name", sizeof("_bogus_session_name"), &tmp_soap, sizeof(zval *), (void **)&tmp_soap_pp) == SUCCESS) + soap_obj = *tmp_soap_pp; + } + else + soap_obj = tmp_soap; + } + function_table = &(soap_obj->value.obj.ce->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; + if(zend_hash_exists(function_table, php_strtolower(Z_STRVAL(function_name), Z_STRLEN(function_name)), Z_STRLEN(function_name) + 1)) + { + if(service->type == SOAP_CLASS) + { + call_status = call_user_function(NULL, &soap_obj, &function_name, &retval, num_params, params TSRMLS_CC); + if(service->soap_class.persistance != SOAP_PERSISTENCE_SESSION) + zval_ptr_dtor(&soap_obj); + } + else + call_status = call_user_function(EG(function_table), NULL, &function_name, &retval, num_params, params TSRMLS_CC); + } + else + php_error(E_ERROR, "Function (%s) doesn't exist", Z_STRVAL(function_name)); + + if(call_status == SUCCESS) + { + sdlFunctionPtr function; + function = get_function(service->sdl, Z_STRVAL(function_name)); + SOAP_GLOBAL(overrides) = service->mapping; + doc_return = seralize_response_call(function, response_name, service->uri, &retval); + SOAP_GLOBAL(overrides) = NULL; + } + else + php_error(E_ERROR, "Function (%s) call failed", Z_STRVAL(function_name)); + + //Flush buffer + php_end_ob_buffer(0, 0 TSRMLS_CC); + + //xmlDocDumpMemoryEnc(doc_return, &buf, &size, XML_CHAR_ENCODING_UTF8); + xmlDocDumpMemory(doc_return, &buf, &size); + + if(size == 0) + php_error(E_ERROR, "Dump memory failed"); + + sprintf(cont_len, "Content-Length: %d\0", size); + sapi_add_header("Content-Type: text/xml", sizeof("Content-Type: text/xml"), 1); + sapi_add_header(cont_len, strlen(cont_len) + 1, 1); + + //Free Memory + if(num_params > 0) + { + for(i = 0; i < num_params;i++) + zval_ptr_dtor(¶ms[i]); + efree(params); + } + + zval_dtor(&function_name); + xmlFreeDoc(doc_return); + efree(response_name); + efree(fn_name); + + php_write(buf, size TSRMLS_CC); + xmlFree(buf); + } + else + { + if(!zend_ini_long("always_populate_raw_post_data", sizeof("always_populate_raw_post_data"), 0)) + php_error(E_ERROR, "PHP-SOAP requires 'always_populate_raw_post_data' to be on please check your php.ini file"); + + php_error(E_ERROR, "Couln't find HTTP_RAW_POST_DATA"); + } + + zval_dtor(&retval); + SOAP_SERVER_END_CODE(); +} + +void soap_error_handler(int error_num, const char *error_filename, const uint error_lineno, const char *format, va_list args) +{ + char buffer[1024]; + int buffer_len; + TSRMLS_FETCH(); + + buffer_len = vsnprintf(buffer, sizeof(buffer)-1, format, args); + buffer[sizeof(buffer)-1]=0; + if(buffer_len > sizeof(buffer) - 1 || buffer_len < 0) { + buffer_len = sizeof(buffer) - 1; + } + + //Trap all errors + //What do do with these warnings + // E_WARNING, E_NOTICE, E_CORE_WARNING, E_COMPILE_WARNING, E_USER_WARNING, E_USER_NOTICE + if(error_num == E_USER_ERROR || error_num == E_COMPILE_ERROR || error_num == E_CORE_ERROR || + error_num == E_ERROR || error_num == E_PARSE) + { + zval outbuf, outbuflen, ret; + xmlChar *buf, cont_len[30]; + int size; + xmlDocPtr doc_return; + + INIT_ZVAL(outbuf); + INIT_ZVAL(outbuflen); + INIT_ZVAL(ret); + + //Get output buffer and send as fault detials + if(php_ob_get_length(&outbuflen TSRMLS_CC) != FAILURE && Z_LVAL(outbuflen) != 0) + php_ob_get_buffer(&outbuf TSRMLS_CC); + php_end_ob_buffer(0, 0 TSRMLS_CC); + + set_soap_fault(&ret, "SOAP-ENV:Server", buffer, NULL, &outbuf); + doc_return = seralize_response_call(NULL, NULL, NULL, &ret); + + //Build and send our headers + http 500 status + //xmlDocDumpMemoryEnc(doc_return, &buf, &size, XML_CHAR_ENCODING_UTF8); + xmlDocDumpMemory(doc_return, &buf, &size); + sprintf(cont_len,"Content-Length: %d\0", size); + sapi_add_header(cont_len, strlen(cont_len) + 1, 1); + sapi_add_header("Content-Type: text/xml", sizeof("Content-Type: text/xml"), 1); + + // Want to return HTTP 500 but apache wants to over write + // our fault code with their own handling... Figure this out later + // sapi_add_header("HTTP/1.1 500 Internal Service Error", sizeof("HTTP/1.1 500 Internal Service Error"), 1); + php_write(buf, size TSRMLS_CC); + + xmlFreeDoc(doc_return); + xmlFree(buf); + + zval_dtor(&outbuf); + zval_dtor(&outbuflen); + zval_dtor(&ret); + + zend_bailout(); + } +} + +// SoapObject functions +PHP_FUNCTION(soapobject) +{ + char *location, *uri = NULL; + int location_len, uri_len = 0; + zval *thisObj; + + GET_THIS_OBJECT(thisObj); + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &location, &location_len, &uri, &uri_len) == SUCCESS) + { + if(uri) + { + // if two parameters assume 'proxy' and 'uri' + add_property_stringl(thisObj, "location", location, location_len, 1); + add_property_stringl(thisObj, "uri", uri, uri_len, 1); + } + else + { + // if one parameter assume 'wsdl' + sdlPtr sdl; + int ret; + + sdl = get_sdl(location); + ret = zend_list_insert(sdl, le_sdl); + add_property_resource(thisObj, "sdl", ret); + zend_list_addref(ret); + } + } +} + +PHP_FUNCTION(__parse) +{ + char *message, *function; + int message_len, function_len; + int num_params; + zval **ret_params; + sdlPtr sdl; + sdlFunctionPtr fn; + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &message, &message_len, &function, &function_len) == FAILURE) + php_error(E_ERROR, "Invalid arguments to SoapObject->__parse"); + + FETCH_THIS_SDL(sdl); + + if(sdl != NULL) + { + fn = get_function(sdl, function); + if(fn != NULL) + parse_packet_soap(getThis(), message, message_len, fn, NULL, &ret_params, &num_params); + } + else + parse_packet_soap(getThis(), message, message_len, NULL, function, &ret_params, &num_params); + + if(num_params > 0) + { + *return_value = *ret_params[0]; + zval_add_ref(&return_value); + efree(ret_params); + } + else + ZVAL_NULL(return_value) +} + +PHP_FUNCTION(__call) +{ + char *function, *soap_action, *uri; + int function_len, soap_action_len, uri_len, i = 0; + zval *args; + zval **real_args; + zval **param; + xmlDocPtr request = NULL; + int num_params, arg_count; + zval **ret_params; + char *buffer; + int len; + + if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|ss", + &function, &function_len, &args, &soap_action, &soap_action_len, &uri, &uri_len) == FAILURE) + php_error(E_ERROR, "Invalid arguments to SoapObject->__call"); + + arg_count = zend_hash_num_elements(Z_ARRVAL_P(args)); + + real_args = emalloc(sizeof(zval *) * arg_count); + for(zend_hash_internal_pointer_reset(Z_ARRVAL_P(args)); + zend_hash_get_current_data(Z_ARRVAL_P(args), (void **) ¶m) == SUCCESS; + zend_hash_move_forward(Z_ARRVAL_P(args))) + { + zval_add_ref(param); + real_args[i++] = *param; + } + + request = seralize_function_call(NULL, uri, function, real_args, arg_count); + send_http_soap_request(getThis(), request, function, soap_action); + xmlFreeDoc(request); + + get_http_soap_response(getThis(), &buffer, &len); + parse_packet_soap(getThis(), buffer, len, NULL, function, &ret_params, &num_params); + efree(buffer); + + if(num_params > 0) + { + *return_value = *ret_params[0]; + zval_add_ref(&return_value); + efree(ret_params); + } + else + ZVAL_NULL(return_value) +} + +PHP_FUNCTION(__isfault) +{ + zval *thisObj; + + GET_THIS_OBJECT(thisObj); + + if(zend_hash_exists(Z_OBJPROP_P(thisObj), "__soap_fault", sizeof("__soap_fault")) == SUCCESS) + RETURN_TRUE + else + RETURN_FALSE +} + +PHP_FUNCTION(__getfault) +{ + zval *thisObj; + zval **tmp; + + GET_THIS_OBJECT(thisObj); + + if(zend_hash_find(Z_OBJPROP_P(thisObj), "__soap_fault", sizeof("__soap_fault"), (void **)&tmp) == SUCCESS) + { + *return_value = *(*tmp); + zval_copy_ctor(return_value); + return; + } + RETURN_NULL(); +} + +#ifdef PHP_DEBUG +PHP_FUNCTION(__getfunctions) +{ + sdlPtr sdl; + zval *thisObj; + + GET_THIS_OBJECT(thisObj); + + FETCH_THIS_SDL(sdl); + + if(sdl) + { + smart_str buf = {0}; + sdlFunctionPtr *function; + + array_init(return_value); + zend_hash_internal_pointer_reset(sdl->functions); + while(zend_hash_get_current_data(sdl->functions, (void **)&function) != FAILURE) + { + function_to_string((*function), &buf); + add_next_index_stringl(return_value, buf.c, buf.len, 1); + zend_hash_move_forward(sdl->functions); + smart_str_free(&buf); + } + } +} + +PHP_FUNCTION(__gettypes) +{ + sdlPtr sdl; + zval *thisObj; + + GET_THIS_OBJECT(thisObj); + + FETCH_THIS_SDL(sdl); + + if(sdl) + { + sdlTypePtr *type; + smart_str buf = {0}; + + array_init(return_value); + if(sdl->types) + { + zend_hash_internal_pointer_reset(sdl->types); + while(zend_hash_get_current_data(sdl->types, (void **)&type) != FAILURE) + { + type_to_string((*type), &buf, 0); + add_next_index_stringl(return_value, buf.c, buf.len, 1); + zend_hash_move_forward(sdl->types); + smart_str_free(&buf); + } + } + } +} + +PHP_FUNCTION(__getlastrequest) +{ + zval *thisObj; + zval **tmp; + + GET_THIS_OBJECT(thisObj); + + if(zend_hash_find(Z_OBJPROP_P(thisObj), "__last_request", sizeof("__last_request"), (void **)&tmp) == SUCCESS) + { + *return_value = *(*tmp); + zval_copy_ctor(return_value); + return; + } + RETURN_NULL(); +} + +PHP_FUNCTION(__getlastresponse) +{ + zval *thisObj; + zval **tmp; + + GET_THIS_OBJECT(thisObj); + + if(zend_hash_find(Z_OBJPROP_P(thisObj), "__last_response", sizeof("__last_response"), (void **)&tmp) == SUCCESS) + { + *return_value = *(*tmp); + zval_copy_ctor(return_value); + return; + } + RETURN_NULL(); +} +#endif + + +void soap_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference) +{ + pval *object = property_reference->object; + zend_overloaded_element *function_name = (zend_overloaded_element *)property_reference->elements_list->tail->data; + zval *thisObj; + char *function = Z_STRVAL(function_name->element); + zend_function *builtin_function; + + GET_THIS_OBJECT(thisObj); + + //Find if the function being called is already defined... + // ( IMHO: zend should handle this functionality ) + if(zend_hash_find(&Z_OBJCE_P(thisObj)->function_table, function, Z_STRLEN(function_name->element) + 1, (void **) &builtin_function) == SUCCESS) + { + builtin_function->internal_function.handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); + } + else + { + zval **arguments = (zval **) emalloc(sizeof(zval *) * ZEND_NUM_ARGS()); + int arg_count = ZEND_NUM_ARGS(); + xmlDocPtr request = NULL; + sdlPtr sdl; + sdlFunctionPtr fn; + + zend_get_parameters_array(ht, arg_count, arguments); + + FETCH_THIS_SDL(sdl); + + clear_soap_fault(thisObj); + + if(sdl != NULL) + { + fn = get_function(sdl, function); + if(fn != NULL) + { + int num_params; + zval **ret_params; + char *buffer; + int len; + + request = seralize_function_call(fn, sdl->target_ns, NULL, arguments, arg_count); + + send_http_soap_request(getThis(), request, fn->soapAction, fn->soapAction); + + xmlFreeDoc(request); + + get_http_soap_response(getThis(), &buffer, &len); + parse_packet_soap(getThis(), buffer, len, fn, NULL, &ret_params, &num_params); + efree(buffer); + + if(num_params > 0) + { + *return_value = *ret_params[0]; + zval_add_ref(&return_value); + efree(ret_params); + } + else + ZVAL_NULL(return_value); + } + else + { + php_error(E_WARNING,"Function (\"%s\") not is not a valid method for this service", function); + } + } + else + { + int num_params; + zval **ret_params; + zval **uri; + smart_str *action; + char *buffer; + int len; + + if(zend_hash_find(Z_OBJPROP_P(thisObj), "uri", sizeof("uri"), (void *)&uri) == FAILURE) + php_error(E_ERROR, "Error finding uri in soap_call_function_handler"); + + request = seralize_function_call(NULL, Z_STRVAL_PP(uri), function, arguments, arg_count); + action = build_soap_action(thisObj, function); + send_http_soap_request(getThis(), request, function, action->c); + + smart_str_free(action); + xmlFreeDoc(request); + + get_http_soap_response(getThis(), &buffer, &len); + parse_packet_soap(getThis(), buffer, len, NULL, function, &ret_params, &num_params); + efree(buffer); + + if(num_params > 0) + { + *return_value = *ret_params[0]; + zval_add_ref(&return_value); + efree(ret_params); + } + else + ZVAL_NULL(return_value); + } + efree(arguments); + } + + zval_dtor(&function_name->element); +} + +void clear_soap_fault(zval *obj) +{ + if(obj != NULL && obj->type == IS_OBJECT) + zend_hash_del(obj->value.obj.properties, "__soap_fault", sizeof("__soap_fault")); +} + +void add_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail) +{ + zval *fault; + MAKE_STD_ZVAL(fault); + set_soap_fault(fault, fault_string, fault_code, fault_actor, fault_detail); + add_property_zval(obj, "__soap_fault", fault); +} + +void set_soap_fault(zval *obj, char *fault_code, char *fault_string, char *fault_actor, zval *fault_detail) +{ + TSRMLS_FETCH(); + + if(Z_TYPE_P(obj) != IS_OBJECT) + object_init_ex(obj, &soap_fault_class_entry); + + if(fault_string != NULL) + add_property_string(obj, "faultstring", fault_string, 1); + + if(fault_code != NULL) + add_property_string(obj, "faultcode", fault_code, 1); + + if(fault_actor != NULL) + add_property_string(obj, "faultactor", fault_actor, 1); + + if(fault_detail != NULL) + { + zval_add_ref(&fault_detail); + add_property_zval(obj, "detail", fault_detail); + } +} + +void deseralize_function_call(sdlPtr sdl, xmlDocPtr request, zval *function_name, int *num_params, zval ***parameters) +{ + xmlNodePtr trav,trav2,trav3,trav4,env,body; + int cur_param = 0,num_of_params = 0; + TSRMLS_FETCH(); + + trav = request->children; + FOREACHNODE(trav,"Envelope",env) + { + trav2 = env->children; + FOREACHNODE(trav2,"Body",body) + { + trav3 = body->children; + do + { + // TODO: make 'strict' (use th sdl defnintions) + if(trav3->type == XML_ELEMENT_NODE) + { + zval tmp_function_name, **tmp_parameters; + sdlFunctionPtr function; + + INIT_ZVAL(tmp_function_name); + ZVAL_STRING(&tmp_function_name, (char *)trav3->name, 1); + + (*function_name) = tmp_function_name; + + function = get_function(sdl, php_strtolower((char *)trav3->name, strlen(trav3->name))); + if(sdl != NULL && function == NULL) + php_error(E_ERROR, "Error function \"%s\" doesn't exists for this service \"%s\"", trav3->name, sdl->location); + + if(trav3->children) + { + trav4 = trav3->children; + if(function == NULL) + { + do + { + if(trav4->type == XML_ELEMENT_NODE) + num_of_params++; + + }while(trav4 = trav4->next); + } + else + num_of_params = zend_hash_num_elements(function->requestParameters); + + tmp_parameters = emalloc(num_of_params * sizeof(zval *)); + trav4 = trav3->children; + do + { + if(trav4->type == XML_ELEMENT_NODE) + { + encodePtr enc; + sdlParamPtr *param = NULL; + + if(function != NULL && zend_hash_index_find(function->requestParameters, cur_param, (void **)¶m) == FAILURE) + php_error(E_ERROR, "Error cannot find parameter"); + if(param == NULL) + enc = get_conversion(UNKNOWN_TYPE); + else + enc = (*param)->encode; + + tmp_parameters[cur_param] = master_to_zval(enc, trav4); + cur_param++; + } + + }while(trav4 = trav4->next); + } + (*parameters) = tmp_parameters; + (*num_params) = num_of_params; + break; + } + }while(trav3 = trav3->next); + + } + ENDFOREACH(trav2); + } + ENDFOREACH(trav); +} + + + +xmlDocPtr seralize_response_call(sdlFunctionPtr function, char *function_name, char *uri, zval *ret) +{ + xmlDoc *doc; + xmlNode *envelope,*body,*method, *param; + xmlNs *ns; + sdlParamPtr parameter = NULL; + smart_str *gen_ns; + + encode_reset_ns(); + + doc = xmlNewDoc("1.0"); + doc->charset = XML_CHAR_ENCODING_UTF8; + doc->encoding = xmlStrdup((xmlChar*)"UTF-8"); + doc->children = xmlNewDocNode(doc, NULL, "SOAP-ENV:Envelope", NULL); + envelope = doc->children; + + xmlSetProp(envelope, "SOAP-ENV:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"); + xmlSetProp(envelope, "xmlns:SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"); + xmlSetProp(envelope, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); + xmlSetProp(envelope, "xmlns:xsd", "http://www.w3.org/2001/XMLSchema"); + xmlSetProp(envelope, "xmlns:" APACHE_NS_PREFIX , APACHE_NAMESPACE); + + ns = xmlNewNs(envelope,"http://schemas.xmlsoap.org/soap/envelope/","SOAP-ENV"); + body = xmlNewChild(envelope, ns, "Body", NULL); + + if(Z_TYPE_P(ret) == IS_OBJECT && + Z_OBJCE_P(ret)->refcount == soap_var_class_entry.refcount) + { + param = seralize_zval(ret, NULL, "SOAP-ENV:Fault"); + xmlAddChild(body, param); + } + else + { + gen_ns = encode_new_ns(); + ns = xmlNewNs(envelope, uri, gen_ns->c); + + if(function != NULL) + method = xmlNewChild(body, ns, function->responseName , NULL); + else + method = xmlNewChild(body, ns, function_name, NULL); + + if(uri) + ns = xmlNewNs(method, uri, NULL); + + parameter = get_param(function, NULL, 0, TRUE); + + if(Z_TYPE_P(ret) == IS_OBJECT && + Z_OBJCE_P(ret)->refcount == soap_param_class_entry.refcount) + { + zval **ret_name; + zval **ret_data; + + if(zend_hash_find(Z_OBJPROP_P(ret), "param_name", sizeof("param_name"), (void **)&ret_name) == SUCCESS && + zend_hash_find(Z_OBJPROP_P(ret), "param_data", sizeof("param_data"), (void **)&ret_data) == SUCCESS) + param = seralize_parameter(parameter, *ret_data, 0, Z_STRVAL_PP(ret_name)); + else + param = seralize_parameter(parameter, ret, 0, "return"); + } + else + param = seralize_parameter(parameter, ret, 0, "return"); + + xmlAddChild(method,param); + } + + return doc; +} + +xmlDocPtr seralize_function_call(sdlFunctionPtr function, char *uri, char *function_name, zval **arguments, int arg_count) +{ + xmlDoc *doc; + xmlNode *envelope,*body,*method; + xmlNs *ns; + int i; + smart_str *gen_ns; + + encode_reset_ns(); + + doc = xmlNewDoc("1.0"); + doc->encoding = xmlStrdup((xmlChar*)"UTF-8"); + doc->charset = XML_CHAR_ENCODING_UTF8; + envelope = xmlNewDocNode(doc, NULL, "SOAP-ENV:Envelope", NULL); + xmlDocSetRootElement(doc, envelope); + xmlSetProp(envelope, "SOAP-ENV:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"); + xmlSetProp(envelope, "xmlns:SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"); + xmlSetProp(envelope, "xmlns:xsd", "http://www.w3.org/2001/XMLSchema"); + xmlSetProp(envelope, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); + ns = xmlNewNs(envelope,"http://schemas.xmlsoap.org/soap/envelope/","SOAP-ENV"); + body = xmlNewChild(envelope, ns, "Body", NULL); + + gen_ns = encode_new_ns(); + ns = xmlNewNs(envelope, uri, gen_ns->c); + + if(function != NULL) + method = xmlNewChild(body, ns, function->requestName , NULL); + else + method = xmlNewChild(body, ns, function_name , NULL); + + ns = xmlNewNs(method, uri, NULL); + + for(i = 0;i < arg_count;i++) + { + xmlNodePtr param; + sdlParamPtr parameter = get_param(function, NULL, i, FALSE); + + if(Z_TYPE_P(arguments[i]) == IS_OBJECT && + Z_OBJCE_P(arguments[i])->refcount == soap_param_class_entry.refcount) + { + zval **ret_name; + zval **ret_data; + + if(zend_hash_find(Z_OBJPROP_P(arguments[i]), "param_name", sizeof("param_name"), (void **)&ret_name) == SUCCESS && + zend_hash_find(Z_OBJPROP_P(arguments[i]), "param_data", sizeof("param_data"), (void **)&ret_data) == SUCCESS) + param = seralize_parameter(parameter, *ret_data, i, Z_STRVAL_PP(ret_name)); + else + param = seralize_parameter(parameter, arguments[i], i, NULL); + } + else + param = seralize_parameter(parameter, arguments[i], i, NULL); + xmlAddChild(method,param); + } + + return doc; +} + +xmlNodePtr seralize_parameter(sdlParamPtr param, zval *param_val, int index, char *name) +{ + int type = 0; + char *paramName; + xmlNodePtr xmlParam; + + if(param != NULL && param->paramName != NULL) + { + paramName = estrdup(param->paramName); + } + else + { + if(name == NULL) + { + paramName = emalloc(10); + sprintf(paramName,"param%d",index); + } + else + paramName = estrdup(name); + } + + xmlParam = seralize_zval(param_val, param, paramName); + + efree(paramName); + + return xmlParam; +} + +zval *desearlize_zval(sdlPtr sdl, xmlNodePtr data, sdlParamPtr param) +{ + encodePtr enc; + TSRMLS_FETCH(); + + if(param != NULL) + enc = param->encode; + else + enc = get_conversion(UNKNOWN_TYPE); + + return enc->to_zval(enc->details, data); +} + +xmlNodePtr seralize_zval(zval *val, sdlParamPtr param, char *paramName) +{ + xmlNodePtr xmlParam; + encodePtr enc; + TSRMLS_FETCH(); + + if(param != NULL) + enc = param->encode; + else + enc = get_conversion(val->type); + + xmlParam = master_to_xml(enc, val); + xmlNodeSetName(xmlParam, paramName); + + return xmlParam; +} + +sdlParamPtr get_param(sdlFunctionPtr function, char *param_name, int index, int response) +{ + sdlParamPtr *tmp = NULL; + HashTable *h; + + if(function == NULL) + return NULL; + + if(response == FALSE) + h = function->requestParameters; + else + h = function->responseParameters; + + if (function != NULL && (param_name == NULL || zend_hash_find(h, param_name, strlen(param_name), (void **)&tmp) == FAILURE)) + { + if(index != -1) + if(zend_hash_index_find(h, index, (void **)&tmp) != FAILURE) + return (*tmp); + } + else + return (*tmp); + + return NULL; +} + +sdlFunctionPtr get_function(sdlPtr sdl, char *function_name) +{ + sdlFunctionPtr *tmp; + if(sdl != NULL) + if(zend_hash_find(sdl->functions, function_name, strlen(function_name), (void **)&tmp) != FAILURE) + return (*tmp); + return NULL; +} + +static void function_to_string(sdlFunctionPtr function, smart_str *buf) +{ + int i = 0; + + if(function->responseParameters) + { + sdlParamPtr *param; + param = function->responseParameters->pListHead->pData; + smart_str_appendl(buf, (*param)->encode->details.type_str, strlen((*param)->encode->details.type_str)); + smart_str_appendc(buf, ' '); + } + else + smart_str_appendl(buf, "void ", 5); + + smart_str_appendl(buf, function->functionName, strlen(function->functionName)); + + smart_str_appendc(buf, '('); + if(function->requestParameters) + { + sdlParamPtr *param; + + i = 0; + zend_hash_internal_pointer_reset(function->requestParameters); + while(zend_hash_get_current_data(function->requestParameters, (void **)¶m) != FAILURE) + { + smart_str_appendl(buf, (*param)->encode->details.type_str, strlen((*param)->encode->details.type_str)); + smart_str_appendc(buf, ' '); + smart_str_appendc(buf, '$'); + smart_str_appendl(buf, (*param)->paramName, strlen((*param)->paramName)); + if(zend_hash_num_elements(function->requestParameters) > i + 1) + smart_str_appendl(buf, ", ", 2); + zend_hash_move_forward(function->requestParameters); + i++; + } + } + smart_str_appendc(buf, ')'); +} + +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, ' '); + + smart_str_appendl(buf, spaces.c, spaces.len); + if(type->elements) + { + sdlTypePtr *t_type; + + smart_str_appendl(buf, "struct ", 7); + smart_str_appendl(buf, type->name, strlen(type->name)); + smart_str_appendc(buf, '\n'); + smart_str_appendl(buf, spaces.c, spaces.len); + smart_str_appendl(buf, "{\n", 2); + + zend_hash_internal_pointer_reset(type->elements); + level++; + while(zend_hash_get_current_data(type->elements, (void **)&t_type) != FAILURE) + { + type_to_string((*t_type), buf, level); + zend_hash_move_forward(type->elements); + } + + smart_str_appendl(buf, spaces.c, spaces.len); + smart_str_appendl(buf, "}\n", 2); + } + else + { + smart_str_appendl(buf, type->encode->details.type_str, strlen(type->encode->details.type_str)); + smart_str_appendc(buf, ' '); + smart_str_appendl(buf, type->name, strlen(type->name)); + smart_str_appendl(buf, ";\n", 2); + } +} + +//Deletes +void delete_sdl(void *handle) +{ + sdlPtr tmp = *((sdlPtr*)handle); + + xmlFreeDoc(tmp->doc); + if(tmp->source) + free(tmp->source); + if(tmp->target_ns) + free(tmp->target_ns); + if(tmp->location) + free(tmp->location); + if(tmp->encoders) + { + zend_hash_destroy(tmp->encoders); + free(tmp->encoders); + } + if(tmp->types) + { + zend_hash_destroy(tmp->types); + free(tmp->types); + } + if(tmp->functions) + { + zend_hash_destroy(tmp->functions); + free(tmp->functions); + } + free(tmp); +} + +void delete_http_socket(void *handle) +{ + SOAP_STREAM stream = (SOAP_STREAM)handle; +#ifdef PHP_STREAMS + TSRMLS_FETCH(); + php_stream_close(stream); +#else + close(stream); +#endif +} + +void delete_url(void *handle) +{ + php_url_free((php_url*)handle); +} + +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->mapping) + { + zend_hash_destroy(service->mapping); + efree(service->mapping); + } + + 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); + } + + efree(service->uri); + efree(service); +} + +void delete_function(void *data) +{ + sdlFunctionPtr function = *((sdlFunctionPtr*)data); + + if(function->functionName) + free(function->functionName); + if(function->requestName) + free(function->requestName); + if(function->responseName) + free(function->responseName); + if(function->soapAction) + free(function->soapAction); + + if(function->requestParameters) + { + zend_hash_destroy(function->requestParameters); + free(function->requestParameters); + } + if(function->responseParameters) + { + zend_hash_destroy(function->responseParameters); + free(function->responseParameters); + } +} + +void delete_paramater(void *data) +{ + sdlParamPtr param = *((sdlParamPtr*)data); + if(param->paramName) + free(param->paramName); + free(param); +} + +void delete_mapping(void *data) +{ + soapMappingPtr map = (soapMappingPtr)data; + + if(map->ns) + efree(map->ns); + if(map->ctype) + efree(map->ctype); + + if(map->type == SOAP_MAP_FUNCTION) + { + if(map->map_functions.to_xml_before) + zval_ptr_dtor(&map->map_functions.to_xml_before); + if(map->map_functions.to_xml) + zval_ptr_dtor(&map->map_functions.to_xml); + if(map->map_functions.to_xml_after) + zval_ptr_dtor(&map->map_functions.to_xml_after); + + if(map->map_functions.to_zval_before) + zval_ptr_dtor(&map->map_functions.to_zval_before); + if(map->map_functions.to_zval) + zval_ptr_dtor(&map->map_functions.to_zval); + if(map->map_functions.to_zval_after) + zval_ptr_dtor(&map->map_functions.to_zval_after); + } + efree(map); +} + +// Should not need +int my_call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, int param_count, zval *params[] TSRMLS_DC) +{ + if(call_user_function(function_table, object_pp, function_name, retval_ptr, param_count, params TSRMLS_CC) == FAILURE) + { + if(Z_OBJCE_PP(object_pp)->handle_function_call != NULL) + { + zend_overloaded_element overloaded_element; + zend_property_reference property_reference; + zend_function_state function_state; + zend_function_state *original_function_state_ptr; + int i; + + overloaded_element.element = *function_name; + overloaded_element.type = OE_IS_METHOD; + + function_state.function = (zend_function *) emalloc(sizeof(zend_function)); + function_state.function->type = ZEND_OVERLOADED_FUNCTION; + function_state.function->common.arg_types = NULL; + function_state.function->overloaded_function.function_name = Z_STRVAL_P(function_name); + + property_reference.object = *object_pp; + property_reference.type = BP_VAR_NA; + property_reference.elements_list = (zend_llist *)emalloc(sizeof(zend_llist)); + zend_llist_init(property_reference.elements_list, sizeof(zend_overloaded_element), NULL, 0); + zend_llist_add_element(property_reference.elements_list, &overloaded_element); + + //Build argument stack + for(i = 0;i < param_count;i++) + zend_ptr_stack_push(&EG(argument_stack), params[i]); + zend_ptr_stack_n_push(&EG(argument_stack), 2, (void *)param_count, NULL); + + original_function_state_ptr = EG(function_state_ptr); + EG(function_state_ptr) = &function_state; + Z_OBJCE_PP(object_pp)->handle_function_call(param_count, retval_ptr, *object_pp, 1 TSRMLS_CC, &property_reference); + EG(function_state_ptr) = original_function_state_ptr; + + zend_llist_destroy(property_reference.elements_list); + efree(property_reference.elements_list); + efree(function_state.function); + + zend_ptr_stack_clear_multiple(TSRMLS_C); + return SUCCESS; + } + } + return FAILURE; +} + + |