ID:               39815
 Updated by:       [EMAIL PROTECTED]
 Reported By:      fredrik at wangel dot net
-Status:           Open
+Status:           Assigned
 Bug Type:         SOAP related
 Operating System: Irrelevant
 PHP Version:      6CVS-2006-12-13 (snap)
-Assigned To:      
+Assigned To:      dmitry


Previous Comments:
------------------------------------------------------------------------

[2006-12-13 13:15:06] fredrik at wangel dot net

Description:
------------
[Note: This is an inherent problem within a PHP extension's C code, not
with a PHP script]

Problem: The SOAPClient/SOAPServer converts xsd:float values in a
locale-dependent fashion, causing serious issues when the caller's
locale is not English.

According to "XML Schema Part 2: Datatypes", a decimal (either
xsd:float or xsd:double) is always written using a period (.) as a
decimal indicator [See http://www.w3.org/TR/xmlschema-2/#decimal]

However, SOAPServer writes decimals using the current locale's
(LC_NUMERIC) formatting rules, which is a violation of the standard.
Likewise, on the client side, the function to_zval_double() in
ext/soap/php_encoding.c uses atof() which parses a string according to
the current locale. Since the server and client can have totally
different settings for locale, the conversion fails.

Hence, if the SOAP server's locale is set to "sv_SE" (Swedish) or some
other language that does not use period as decimal indicator, and the
SOAP client is in English, the resulting float is truncated into an
integer value.

Suggested fix is to either either temporarily change LC_NUMERIC [via
setlocale()] into "POSIX" (or "C"), or use zend_strtod() for conversion
from XML. When converting to XML [using convert_to_string()] the
simplest solution should be to change LC_NUMERIC temporarily, since
zend_sprintf() also uses current locale settings.

PLEASE NOTE: If you do not have the locales from the example (sv_SE and
en_US) on your test server, this will likely fallback into C locale, and
thus the result always looks good. Verify that your test server formats
123.456 into "123,456". Try "se" or "Swedish" if "sv_SE" fails.

Reproduce code:
---------------
-- SERVER --
class Server {function getValue(){return (float)123.456;}}
setlocale(LC_ALL,"sv_SE");
$server = new SoapServer(null,array('uri'=>'http://localhost/',
'soap_version'=>SOAP_1_2, 'encoding'=>'ISO-8859-1'));
$server->setClass("Server");
$server->handle();

--- CLIENT --
$client = new
SoapClient(null,array('location'=>'http://localhost/soap/Server.php',
'uri'=>'http://localhost/', 'soap_version'=>SOAP_1_2,
'encoding'=>'ISO-8859-1'));
header("Content-Type: text/plain; charset=ISO-8859-1");
setlocale(LC_ALL,"sv_SE");
print((float)123.456 . "\n");
setlocale(LC_ALL,"en_US");
$value = $client->getValue();
var_dump($value);


Expected result:
----------------
123,456
float(123.456)

Actual result:
--------------
123,456
float(123)


------------------------------------------------------------------------


-- 
Edit this bug report at http://bugs.php.net/?id=39815&edit=1

Reply via email to