From bd96cca64f7208342e15799acb83a068ef8fea79 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 10 Aug 2004 16:30:31 +0000 Subject: [PATCH] Fixed bug #28969 (Wrong data encoding of special characters) --- NEWS | 1 + ext/soap/php_encoding.c | 95 +++++++++++++++++++++++++++++++++-- ext/soap/php_soap.h | 2 + ext/soap/soap.c | 46 +++++++++++++++++ ext/soap/tests/server021.phpt | 2 +- 5 files changed, 141 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index d19363a9a9..9336b11919 100644 --- a/NEWS +++ b/NEWS @@ -44,6 +44,7 @@ PHP NEWS - Fixed bug #29109 (SoapFault exception: [WSDL] Out of memory). (Dmitry) - Fixed bug #29061 (soap extension segfaults). (Dmitry) - Fixed bug #28985 (__getTypes() returning nothing on complex WSDL). (Dmitry) +- Fixed bug #28969 (Wrong data encoding of special characters). (Dmitry) - Fixed bug #28895 (ReflectionClass::isAbstract always returns false). (Marcus) - Fixed bug #28829 (Thread-unsafety in bcmath elementary values). (Sara) - Fixed bug #28464 (catch() does not catch exceptions by interfaces). (Marcus) diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index 7174eb9f16..08e80c223f 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -31,6 +31,7 @@ static zval *to_zval_bool(encodeTypePtr type, xmlNodePtr data); static zval *to_zval_string(encodeTypePtr type, xmlNodePtr data); static zval *to_zval_stringr(encodeTypePtr type, xmlNodePtr data); static zval *to_zval_stringc(encodeTypePtr type, xmlNodePtr data); +static zval *to_zval_stringb(encodeTypePtr type, xmlNodePtr data); static zval *to_zval_map(encodeTypePtr type, xmlNodePtr data); static zval *to_zval_null(encodeTypePtr type, xmlNodePtr data); @@ -145,8 +146,8 @@ encode defaultEncoding[] = { {{XSD_GMONTH, XSD_GMONTH_STRING, XSD_NAMESPACE, NULL}, to_zval_stringc, to_xml_gmonth}, {{XSD_DURATION, XSD_DURATION_STRING, XSD_NAMESPACE, NULL}, to_zval_stringc, to_xml_duration}, - {{XSD_HEXBINARY, XSD_HEXBINARY_STRING, XSD_NAMESPACE, NULL}, to_zval_stringc, to_xml_stringl}, - {{XSD_BASE64BINARY, XSD_BASE64BINARY_STRING, XSD_NAMESPACE, NULL}, to_zval_stringc, to_xml_stringl}, + {{XSD_HEXBINARY, XSD_HEXBINARY_STRING, XSD_NAMESPACE, NULL}, to_zval_stringb, to_xml_stringl}, + {{XSD_BASE64BINARY, XSD_BASE64BINARY_STRING, XSD_NAMESPACE, NULL}, to_zval_stringb, 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_long}, @@ -460,7 +461,23 @@ static zval *to_zval_string(encodeTypePtr type, xmlNodePtr data) FIND_XML_NULL(data, ret); if (data && data->children) { if (data->children->type == XML_TEXT_NODE && data->children->next == NULL) { - ZVAL_STRING(ret, data->children->content, 1); + TSRMLS_FETCH(); + + if (SOAP_GLOBAL(encoding) != NULL) { + xmlBufferPtr in = xmlBufferCreateStatic(data->children->content, strlen(data->children->content)); + xmlBufferPtr out = xmlBufferCreate(); + int n = xmlCharEncOutFunc(SOAP_GLOBAL(encoding), out, in); + + if (n >= 0) { + ZVAL_STRING(ret, (char*)xmlBufferContent(out), 1); + } else { + ZVAL_STRING(ret, data->children->content, 1); + } + xmlBufferFree(out); + xmlBufferFree(in); + } else { + ZVAL_STRING(ret, data->children->content, 1); + } } else if (data->children->type == XML_CDATA_SECTION_NODE && data->children->next == NULL) { ZVAL_STRING(ret, data->children->content, 1); } else { @@ -479,8 +496,24 @@ static zval *to_zval_stringr(encodeTypePtr type, xmlNodePtr data) FIND_XML_NULL(data, ret); if (data && data->children) { if (data->children->type == XML_TEXT_NODE && data->children->next == NULL) { + TSRMLS_FETCH(); + whiteSpace_replace(data->children->content); - ZVAL_STRING(ret, data->children->content, 1); + if (SOAP_GLOBAL(encoding) != NULL) { + xmlBufferPtr in = xmlBufferCreateStatic(data->children->content, strlen(data->children->content)); + xmlBufferPtr out = xmlBufferCreate(); + int n = xmlCharEncOutFunc(SOAP_GLOBAL(encoding), out, in); + + if (n >= 0) { + ZVAL_STRING(ret, (char*)xmlBufferContent(out), 1); + } else { + ZVAL_STRING(ret, data->children->content, 1); + } + xmlBufferFree(out); + xmlBufferFree(in); + } else { + ZVAL_STRING(ret, data->children->content, 1); + } } else if (data->children->type == XML_CDATA_SECTION_NODE && data->children->next == NULL) { ZVAL_STRING(ret, data->children->content, 1); } else { @@ -493,6 +526,42 @@ static zval *to_zval_stringr(encodeTypePtr type, xmlNodePtr data) } static zval *to_zval_stringc(encodeTypePtr type, xmlNodePtr data) +{ + zval *ret; + MAKE_STD_ZVAL(ret); + FIND_XML_NULL(data, ret); + if (data && data->children) { + if (data->children->type == XML_TEXT_NODE && data->children->next == NULL) { + TSRMLS_FETCH(); + + whiteSpace_collapse(data->children->content); + if (SOAP_GLOBAL(encoding) != NULL) { + xmlBufferPtr in = xmlBufferCreateStatic(data->children->content, strlen(data->children->content)); + xmlBufferPtr out = xmlBufferCreate(); + int n = xmlCharEncOutFunc(SOAP_GLOBAL(encoding), out, in); + + if (n >= 0) { + ZVAL_STRING(ret, (char*)xmlBufferContent(out), 1); + } else { + ZVAL_STRING(ret, data->children->content, 1); + } + xmlBufferFree(out); + xmlBufferFree(in); + } else { + ZVAL_STRING(ret, data->children->content, 1); + } + } else if (data->children->type == XML_CDATA_SECTION_NODE && data->children->next == NULL) { + ZVAL_STRING(ret, data->children->content, 1); + } else { + soap_error0(E_ERROR, "Encoding: Violation of encoding rules"); + } + } else { + ZVAL_EMPTY_STRING(ret); + } + return ret; +} + +static zval *to_zval_stringb(encodeTypePtr type, xmlNodePtr data) { zval *ret; MAKE_STD_ZVAL(ret); @@ -534,6 +603,24 @@ static xmlNodePtr to_xml_string(encodeTypePtr type, zval *data, int style, xmlNo zval_dtor(&tmp); } + if (SOAP_GLOBAL(encoding) != NULL) { + xmlBufferPtr in = xmlBufferCreateStatic(str, new_len); + xmlBufferPtr out = xmlBufferCreate(); + int n = xmlCharEncInFunc(SOAP_GLOBAL(encoding), out, in); + + if (n >= 0) { + efree(str); + str = estrdup(xmlBufferContent(out)); + new_len = n; + } else if (!xmlCheckUTF8(str)) { + soap_error1(E_ERROR, "Encoding: string '%s' is not a valid utf-8 string", str); + } + xmlBufferFree(out); + xmlBufferFree(in); + } else if (!xmlCheckUTF8(str)) { + soap_error1(E_ERROR, "Encoding: string '%s' is not a valid utf-8 string", str); + } + xmlNodeSetContentLen(ret, str, new_len); efree(str); diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h index dfe1af553e..7b631f9578 100644 --- a/ext/soap/php_soap.h +++ b/ext/soap/php_soap.h @@ -115,6 +115,7 @@ struct _soapService { int type; char *actor; char *uri; + xmlCharEncodingHandlerPtr encoding; }; #define SOAP_CLASS 1 @@ -158,6 +159,7 @@ ZEND_BEGIN_MODULE_GLOBALS(soap) zend_bool cache_enabled; char* cache_dir; long cache_ttl; + xmlCharEncodingHandlerPtr encoding; ZEND_END_MODULE_GLOBALS(soap) #ifdef PHP_WIN32 diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 604e1062a5..45947e1375 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -423,6 +423,7 @@ PHP_RINIT_FUNCTION(soap) SOAP_GLOBAL(error_object) = NULL; SOAP_GLOBAL(sdl) = NULL; SOAP_GLOBAL(soap_version) = SOAP_1_1; + SOAP_GLOBAL(encoding) = NULL; return SUCCESS; } @@ -835,6 +836,19 @@ PHP_METHOD(SoapServer, SoapServer) Z_TYPE_PP(tmp) == IS_STRING) { service->actor = estrndup(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); } + + if (zend_hash_find(ht, "encoding", sizeof("encoding"), (void**)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING) { + xmlCharEncodingHandlerPtr encoding; + + encoding = xmlFindCharEncodingHandler(Z_STRVAL_PP(tmp)); + if (encoding == NULL) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid arguments. Invalid 'encoding' option - '%s'.", Z_STRVAL_PP(tmp)); + } else { + service->encoding = encoding; + } + } + } else if (wsdl == NULL) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid arguments. 'uri' option is required in nonWSDL mode."); } @@ -1233,6 +1247,7 @@ PHP_METHOD(SoapServer, handle) sdlFunctionPtr function; char *arg = NULL; int arg_len; + xmlCharEncodingHandlerPtr old_encoding; SOAP_SERVER_BEGIN_CODE(); @@ -1374,6 +1389,8 @@ PHP_METHOD(SoapServer, handle) old_sdl = SOAP_GLOBAL(sdl); SOAP_GLOBAL(sdl) = service->sdl; + old_encoding = SOAP_GLOBAL(encoding); + SOAP_GLOBAL(encoding) = service->encoding; old_soap_version = SOAP_GLOBAL(soap_version); function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, ¶ms, &soap_version, &soap_headers TSRMLS_CC); xmlFreeDoc(doc_request); @@ -1636,6 +1653,7 @@ PHP_METHOD(SoapServer, handle) fail: SOAP_GLOBAL(soap_version) = old_soap_version; + SOAP_GLOBAL(encoding) = old_encoding; SOAP_GLOBAL(sdl) = old_sdl; /* Free soap headers */ @@ -1936,6 +1954,18 @@ PHP_METHOD(SoapClient, SoapClient) zend_hash_exists(EG(function_table), "gzencode", sizeof("gzencode"))) { add_property_long(this_ptr, "compression", Z_LVAL_PP(tmp)); } + if (zend_hash_find(ht, "encoding", sizeof("encoding"), (void**)&tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING) { + xmlCharEncodingHandlerPtr encoding; + + encoding = xmlFindCharEncodingHandler(Z_STRVAL_PP(tmp)); + if (encoding == NULL) { + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid 'encoding' option - '%s'.", Z_STRVAL_PP(tmp)); + } else { + xmlCharEncCloseFunc(encoding); + add_property_stringl(this_ptr, "_encoding", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1); + } + } } else if (wsdl == NULL) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "'location' and 'uri' options are requred in nonWSDL mode."); return; @@ -2046,6 +2076,7 @@ static void do_soap_call(zval* this_ptr, int ret = FALSE; int soap_version; zval response; + xmlCharEncodingHandlerPtr old_encoding; SOAP_CLIENT_BEGIN_CODE(); @@ -2070,6 +2101,14 @@ static void do_soap_call(zval* this_ptr, SOAP_GLOBAL(soap_version) = soap_version; old_sdl = SOAP_GLOBAL(sdl); SOAP_GLOBAL(sdl) = sdl; + old_encoding = SOAP_GLOBAL(encoding); + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_encoding", sizeof("_encoding"), (void **) &tmp) == SUCCESS && + Z_TYPE_PP(tmp) == IS_STRING) { + SOAP_GLOBAL(encoding) = xmlFindCharEncodingHandler(Z_STRVAL_PP(tmp)); + } else { + SOAP_GLOBAL(encoding) = NULL; + } + if (sdl != NULL) { fn = get_function(sdl, function); if (fn != NULL) { @@ -2166,6 +2205,10 @@ static void do_soap_call(zval* this_ptr, zend_throw_exception_object(exception TSRMLS_CC); } #endif + if (SOAP_GLOBAL(encoding) != NULL) { + xmlCharEncCloseFunc(SOAP_GLOBAL(encoding)); + } + SOAP_GLOBAL(encoding) = old_encoding; SOAP_GLOBAL(sdl) = old_sdl; SOAP_CLIENT_END_CODE(); } @@ -3910,5 +3953,8 @@ static void delete_service(void *data) if (service->sdl) { delete_sdl(service->sdl); } + if (service->encoding) { + xmlCharEncCloseFunc(service->encoding); + } efree(service); } diff --git a/ext/soap/tests/server021.phpt b/ext/soap/tests/server021.phpt index d557204b5f..787e959fb3 100644 --- a/ext/soap/tests/server021.phpt +++ b/ext/soap/tests/server021.phpt @@ -5,7 +5,7 @@ SOAP Server 21: SoapServer::setClass and __call() --FILE--