Skip to content

Commit

Permalink
Fixed bug #39815 (SOAP double encoding is not locale-independent)
Browse files Browse the repository at this point in the history
  • Loading branch information
dstogov committed Dec 19, 2006
1 parent 39a7719 commit c43fc2a
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 56 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ PHP NEWS
when trying to open "php://wrong"). (Tony)
- Fixed bug #39832 (SOAP Server: parameter not matching the WSDL specified type
are set to 0). (Dmitry)
- Fixed bug #39815 (SOAP double encoding is not locale-independent). (Dmitry)

14 Dec 2006, PHP 5.2.1RC1
- Added a meta tag to phpinfo() output to prevent search engines from indexing
Expand Down
12 changes: 8 additions & 4 deletions ext/soap/php_encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -961,19 +961,23 @@ static xmlNodePtr to_xml_double(encodeTypePtr type, zval *data, int style, xmlNo
{
xmlNodePtr ret;
zval tmp;
char *str;
TSRMLS_FETCH();

ret = xmlNewNode(NULL, BAD_CAST("BOGUS"));
xmlAddChild(parent, ret);
FIND_ZVAL_NULL(data, ret, style);

tmp = *data;
zval_copy_ctor(&tmp);
if (Z_TYPE(tmp) != IS_DOUBLE) {
zval_copy_ctor(&tmp);
convert_to_double(&tmp);
}
convert_to_string(&tmp);
xmlNodeSetContentLen(ret, BAD_CAST(Z_STRVAL(tmp)), Z_STRLEN(tmp));
zval_dtor(&tmp);

str = (char *) emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
php_gcvt(Z_DVAL(tmp), EG(precision), '.', 'E', str);
xmlNodeSetContentLen(ret, BAD_CAST(str), strlen(str));
efree(str);

if (style == SOAP_ENCODED) {
set_ns_and_type(ret, type);
Expand Down
42 changes: 42 additions & 0 deletions ext/soap/tests/bugs/bug39815.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
--TEST--
Bug #39815 (to_zval_double() in ext/soap/php_encoding.c is not locale-independent)
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
<?php
function test(){
return 123.456;
}
class LocalSoapClient extends SoapClient {

function __construct($wsdl, $options) {
parent::__construct($wsdl, $options);
$this->server = new SoapServer($wsdl, $options);
$this->server->addFunction('test');
}

function __doRequest($request, $location, $action, $version) {
ob_start();
$this->server->handle($request);
$response = ob_get_contents();
ob_end_clean();
return $response;
}

}
$x = new LocalSoapClient(NULL,array('location'=>'test://',
'uri'=>'http://testuri.org',
"trace"=>1));
setlocale(LC_ALL,"sv_SE");
var_dump($x->test());
echo $x->__getLastResponse();
setlocale(LC_ALL,"en_US");
var_dump($x->test());
echo $x->__getLastResponse();
--EXPECT--
float(123,456)
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://testuri.org" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:testResponse><return xsi:type="xsd:float">123.456</return></ns1:testResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
float(123.456)
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://testuri.org" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:testResponse><return xsi:type="xsd:float">123.456</return></ns1:testResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ echo "ok\n";
?>
--EXPECT--
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://soapinterop.org/person" xmlns:ns2="http://soapinterop.org/employee"><SOAP-ENV:Body><ns2:x_Employee><ns2:person><ns1:Name>Shane</ns1:Name><ns1:Male>true</ns1:Male></ns2:person><ns2:salary>1000000</ns2:salary><ns2:ID>12345</ns2:ID></ns2:x_Employee></SOAP-ENV:Body></SOAP-ENV:Envelope>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://soapinterop.org/person" xmlns:ns2="http://soapinterop.org/employee"><SOAP-ENV:Body><ns2:x_Employee><ns2:person><ns1:Name>Shane</ns1:Name><ns1:Male>true</ns1:Male></ns2:person><ns2:salary>1.0E+6</ns2:salary><ns2:ID>12345</ns2:ID></ns2:x_Employee></SOAP-ENV:Body></SOAP-ENV:Envelope>
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://soapinterop.org/person" xmlns:ns2="http://soapinterop.org/employee"><SOAP-ENV:Body><ns2:result_Employee><ns2:person><ns1:Name>Shane</ns1:Name><ns1:Male>true</ns1:Male></ns2:person><ns2:salary>1000000</ns2:salary><ns2:ID>12345</ns2:ID></ns2:result_Employee></SOAP-ENV:Body></SOAP-ENV:Envelope>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://soapinterop.org/person" xmlns:ns2="http://soapinterop.org/employee"><SOAP-ENV:Body><ns2:result_Employee><ns2:person><ns1:Name>Shane</ns1:Name><ns1:Male>true</ns1:Male></ns2:person><ns2:salary>1.0E+6</ns2:salary><ns2:ID>12345</ns2:ID></ns2:result_Employee></SOAP-ENV:Body></SOAP-ENV:Envelope>
ok
14 changes: 7 additions & 7 deletions ext/standard/formatted_print.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,9 @@ php_sprintf_appenddouble(char **buffer, int *pos,
TSRMLS_DC)
{
char num_buf[NUM_BUF_SIZE];
char *s = NULL, *q;
char *s = NULL;
int s_len = 0, is_negative = 0;
struct lconv *lconv;

PRINTF_DEBUG(("sprintf: appenddouble(%x, %x, %x, %f, %d, '%c', %d, %c)\n",
*buffer, pos, size, number, width, padding, alignment, fmt));
Expand Down Expand Up @@ -229,7 +230,9 @@ php_sprintf_appenddouble(char **buffer, int *pos,
case 'E':
case 'f':
case 'F':
s = ap_php_conv_fp(fmt, number, 0, precision,
lconv = localeconv();
s = php_conv_fp((fmt == 'f')?'F':fmt, number, 0, precision,
(fmt == 'f')?(*lconv->decimal_point):'.',
&is_negative, &num_buf[1], &s_len);
if (is_negative) {
num_buf[0] = '-';
Expand All @@ -249,7 +252,8 @@ php_sprintf_appenddouble(char **buffer, int *pos,
/*
* * We use &num_buf[ 1 ], so that we have room for the sign
*/
s = bsd_gcvt(number, precision, &num_buf[1]);
lconv = localeconv();
s = php_gcvt(number, precision, *lconv->decimal_point, (fmt == 'G')?'E':'e', &num_buf[1]);
is_negative = 0;
if (*s == '-') {
is_negative = 1;
Expand All @@ -260,10 +264,6 @@ php_sprintf_appenddouble(char **buffer, int *pos,
}

s_len = strlen(s);

if (fmt == 'G' && (q = strchr(s, 'e')) != NULL) {
*q = 'E';
}
break;
}

Expand Down
49 changes: 23 additions & 26 deletions main/snprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,23 +115,20 @@ static char * __cvt(double value, int ndigit, int *decpt, int *sign, int fmode,
return(s);
}

char *bsd_ecvt(double value, int ndigit, int *decpt, int *sign)
static inline char *php_ecvt(double value, int ndigit, int *decpt, int *sign)
{
return(__cvt(value, ndigit, decpt, sign, 0, 1));
}

char *bsd_fcvt(double value, int ndigit, int *decpt, int *sign)
static inline char *php_fcvt(double value, int ndigit, int *decpt, int *sign)
{
return(__cvt(value, ndigit, decpt, sign, 1, 1));
}

char *bsd_gcvt(double value, int ndigit, char *buf)
PHPAPI char *php_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf)
{
char *digits, *dst, *src;
int i, decpt, sign;
struct lconv *lconv;

lconv = localeconv();

digits = zend_dtoa(value, 2, ndigit, &decpt, &sign, NULL);
if (decpt == 9999) {
Expand Down Expand Up @@ -161,15 +158,15 @@ char *bsd_gcvt(double value, int ndigit, char *buf)
sign = 0;
src = digits;
*dst++ = *src++;
*dst++ = *lconv->decimal_point;
*dst++ = dec_point;
if (*src == '\0') {
*dst++ = '0';
} else {
do {
*dst++ = *src++;
} while (*src != '\0');
}
*dst++ = 'e';
*dst++ = exponent;
if (sign)
*dst++ = '-';
else
Expand All @@ -190,7 +187,7 @@ char *bsd_gcvt(double value, int ndigit, char *buf)
} else if (decpt < 0) {
/* standard format 0. */
*dst++ = '0'; /* zero before decimal point */
*dst++ = *lconv->decimal_point;
*dst++ = dec_point;
do {
*dst++ = '0';
} while (++decpt < 0);
Expand All @@ -210,7 +207,7 @@ char *bsd_gcvt(double value, int ndigit, char *buf)
if (*src != '\0') {
if (src == digits)
*dst++ = '0'; /* zero before decimal point */
*dst++ = *lconv->decimal_point;
*dst++ = dec_point;
for (i = decpt; digits[i] != '\0'; i++) {
*dst++ = digits[i];
}
Expand Down Expand Up @@ -357,29 +354,21 @@ char * ap_php_conv_10(register wide_int num, register bool_int is_unsigned,
* The sign is returned in the is_negative argument (and is not placed
* in buf).
*/
char * ap_php_conv_fp(register char format, register double num,
boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len)
PHPAPI char * php_conv_fp(register char format, register double num,
boolean_e add_dp, int precision, char dec_point, bool_int * is_negative, char *buf, int *len)
{
register char *s = buf;
register char *p, *p_orig;
int decimal_point;
char dec_point = '.';

if (format == 'f') {
struct lconv *lconv;
lconv = localeconv();
dec_point = *lconv->decimal_point;
format = 'F';
}

if (precision >= NDIG - 1) {
precision = NDIG - 2;
}

if (format == 'F')
p_orig = p = bsd_fcvt(num, precision, &decimal_point, is_negative);
p_orig = p = php_fcvt(num, precision, &decimal_point, is_negative);
else /* either e or E format */
p_orig = p = bsd_ecvt(num, precision + 1, &decimal_point, is_negative);
p_orig = p = php_ecvt(num, precision + 1, &decimal_point, is_negative);

/*
* Check for Infinity and NaN
Expand Down Expand Up @@ -595,6 +584,8 @@ static int format_converter(register buffy * odp, const char *fmt,
char num_buf[NUM_BUF_SIZE];
char char_buf[2]; /* for printing %% and %<unknown> */

struct lconv *lconv = NULL;

/*
* Flag variables
*/
Expand Down Expand Up @@ -930,6 +921,7 @@ static int format_converter(register buffy * odp, const char *fmt,


case 'f':
case 'F':
case 'e':
case 'E':
switch(modifier) {
Expand All @@ -950,8 +942,12 @@ static int format_converter(register buffy * odp, const char *fmt,
s = "inf";
s_len = 3;
} else {
s = ap_php_conv_fp(*fmt, fp_num, alternate_form,
if (!lconv) {
lconv = localeconv();
}
s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
(adjust_precision == NO) ? FLOAT_DIGITS : precision,
(*fmt == 'f')?(*lconv->decimal_point):'.',
&is_negative, &num_buf[1], &s_len);
if (is_negative)
prefix_char = '-';
Expand Down Expand Up @@ -998,7 +994,10 @@ static int format_converter(register buffy * odp, const char *fmt,
/*
* * We use &num_buf[ 1 ], so that we have room for the sign
*/
s = bsd_gcvt(fp_num, precision, &num_buf[1]);
if (!lconv) {
lconv = localeconv();
}
s = php_gcvt(fp_num, precision, *lconv->decimal_point, (*fmt == 'G')?'E':'e', &num_buf[1]);
if (*s == '-')
prefix_char = *s++;
else if (print_sign)
Expand All @@ -1010,8 +1009,6 @@ static int format_converter(register buffy * odp, const char *fmt,

if (alternate_form && (q = strchr(s, '.')) == NULL)
s[s_len++] = '.';
if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
*q = 'E';
break;


Expand Down
24 changes: 11 additions & 13 deletions main/snprintf.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,21 @@ spprintf is the dynamical version of snprintf. It allocates the buffer in size
#ifndef SNPRINTF_H
#define SNPRINTF_H

typedef int bool_int;

typedef enum {
NO = 0, YES = 1
} boolean_e;


BEGIN_EXTERN_C()
PHPAPI int ap_php_snprintf(char *, size_t, const char *, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4);
PHPAPI int ap_php_vsnprintf(char *, size_t, const char *, va_list ap) PHP_ATTRIBUTE_FORMAT(printf, 3, 0);
PHPAPI int php_sprintf (char* s, const char* format, ...) PHP_ATTRIBUTE_FORMAT(printf, 2, 3);
PHPAPI char * php_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf);
PHPAPI char * php_conv_fp(register char format, register double num,
boolean_e add_dp, int precision, char dec_point, bool_int * is_negative, char *buf, int *len);

END_EXTERN_C()

#ifdef snprintf
Expand All @@ -86,10 +97,6 @@ END_EXTERN_C()
#endif
#define sprintf php_sprintf

typedef enum {
NO = 0, YES = 1
} boolean_e;

typedef enum {
LM_STD = 0,
#if SIZEOF_INTMAX_T
Expand Down Expand Up @@ -118,21 +125,12 @@ typedef enum {
typedef WIDE_INT wide_int;
typedef unsigned WIDE_INT u_wide_int;

typedef int bool_int;

extern char * ap_php_conv_10(register wide_int num, register bool_int is_unsigned,
register bool_int * is_negative, char *buf_end, register int *len);

extern char * ap_php_conv_fp(register char format, register double num,
boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len);

extern char * ap_php_conv_p2(register u_wide_int num, register int nbits,
char format, char *buf_end, register int *len);

extern char * bsd_ecvt(double value, int ndigit, int *decpt, int *sign);
extern char * bsd_fcvt(double value, int ndigit, int *decpt, int *sign);
extern char * bsd_gcvt(double value, int ndigit, char *buf);

#endif /* SNPRINTF_H */

/*
Expand Down
20 changes: 16 additions & 4 deletions main/spprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@
#include <inttypes.h>
#endif

#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif

#include "snprintf.h"

#define FALSE 0
Expand Down Expand Up @@ -195,6 +199,8 @@ static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap)
char num_buf[NUM_BUF_SIZE];
char char_buf[2]; /* for printing %% and %<unknown> */

struct lconv *lconv = NULL;

/*
* Flag variables
*/
Expand Down Expand Up @@ -527,6 +533,7 @@ static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap)


case 'f':
case 'F':
case 'e':
case 'E':
switch(modifier) {
Expand All @@ -547,8 +554,12 @@ static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap)
s = "inf";
s_len = 3;
} else {
s = ap_php_conv_fp(*fmt, fp_num, alternate_form,
if (!lconv) {
lconv = localeconv();
}
s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
(adjust_precision == NO) ? FLOAT_DIGITS : precision,
(*fmt == 'f')?(*lconv->decimal_point):'.',
&is_negative, &num_buf[1], &s_len);
if (is_negative)
prefix_char = '-';
Expand Down Expand Up @@ -595,7 +606,10 @@ static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap)
/*
* * We use &num_buf[ 1 ], so that we have room for the sign
*/
s = bsd_gcvt(fp_num, precision, &num_buf[1]);
if (!lconv) {
lconv = localeconv();
}
s = php_gcvt(fp_num, precision, *lconv->decimal_point, (*fmt == 'G')?'E':'e', &num_buf[1]);
if (*s == '-')
prefix_char = *s++;
else if (print_sign)
Expand All @@ -607,8 +621,6 @@ static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap)

if (alternate_form && (q = strchr(s, '.')) == NULL)
s[s_len++] = '.';
if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
*q = 'E';
break;


Expand Down

0 comments on commit c43fc2a

Please sign in to comment.