|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #39815 to_zval_double() in ext/soap/php_encoding.c is not locale-independent
Submitted: 2006-12-13 13:15 UTC Modified: 2006-12-19 12:01 UTC
Avg. Score:4.0 ± 0.0
Reproduced:2 of 2 (100.0%)
Same Version:1 (50.0%)
Same OS:1 (50.0%)
From: fredrik at wangel dot net Assigned: dmitry
Status: Closed Package: SOAP related
PHP Version: 6CVS-2006-12-13 (snap) OS: Irrelevant
Private report: No CVE-ID:
 [2006-12-13 13:15 UTC] fredrik at wangel dot net
[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]

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;}}
$server = new SoapServer(null,array('uri'=>'http://localhost/', 'soap_version'=>SOAP_1_2, 'encoding'=>'ISO-8859-1'));

--- 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");
print((float)123.456 . "\n");
$value = $client->getValue();

Expected result:

Actual result:


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2006-12-19 12:01 UTC]
Fixed in CVS HEAD and PHP_5_2.
PHP Copyright © 2001-2015 The PHP Group
All rights reserved.
Last updated: Fri Nov 27 20:01:35 2015 UTC