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
{
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);
--- /dev/null
+--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>
?>
--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
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));
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] = '-';
/*
* * 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;
}
s_len = strlen(s);
-
- if (fmt == 'G' && (q = strchr(s, 'e')) != NULL) {
- *q = 'E';
- }
break;
}
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) {
sign = 0;
src = digits;
*dst++ = *src++;
- *dst++ = *lconv->decimal_point;
+ *dst++ = dec_point;
if (*src == '\0') {
*dst++ = '0';
} else {
*dst++ = *src++;
} while (*src != '\0');
}
- *dst++ = 'e';
+ *dst++ = exponent;
if (sign)
*dst++ = '-';
else
} 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);
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];
}
* 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
char num_buf[NUM_BUF_SIZE];
char char_buf[2]; /* for printing %% and %<unknown> */
+ struct lconv *lconv = NULL;
+
/*
* Flag variables
*/
case 'f':
+ case 'F':
case 'e':
case 'E':
switch(modifier) {
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 = '-';
/*
* * 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)
if (alternate_form && (q = strchr(s, '.')) == NULL)
s[s_len++] = '.';
- if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
- *q = 'E';
break;
#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
#endif
#define sprintf php_sprintf
-typedef enum {
- NO = 0, YES = 1
-} boolean_e;
-
typedef enum {
LM_STD = 0,
#if SIZEOF_INTMAX_T
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 */
/*
#include <inttypes.h>
#endif
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
#include "snprintf.h"
#define FALSE 0
char num_buf[NUM_BUF_SIZE];
char char_buf[2]; /* for printing %% and %<unknown> */
+ struct lconv *lconv = NULL;
+
/*
* Flag variables
*/
case 'f':
+ case 'F':
case 'e':
case 'E':
switch(modifier) {
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 = '-';
/*
* * 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)
if (alternate_form && (q = strchr(s, '.')) == NULL)
s[s_len++] = '.';
- if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
- *q = 'E';
break;