diff options
author | Stanislav Malyshev <stas@php.net> | 2015-01-19 10:05:57 -0800 |
---|---|---|
committer | Stanislav Malyshev <stas@php.net> | 2015-01-19 10:05:57 -0800 |
commit | 1fdd558e39beeeca9166eef4311b98f1926f642b (patch) | |
tree | 8e0ffff2fdfa5ff5debb65bed15e5fdee5ed6d9f | |
parent | 1b53a99fbf847ce346e24bb2f25a0ca2298b94a1 (diff) | |
parent | ac7cfad3b54b04b7ff2d0e4bfd26e8b61d233613 (diff) | |
download | php-git-1fdd558e39beeeca9166eef4311b98f1926f642b.tar.gz |
Merge branch 'PHP-5.6'
* PHP-5.6:
Fixed bug #50224 where float without decimals were converted to integer
Updated NEWS for #68371
-rw-r--r-- | ext/json/json.c | 37 | ||||
-rw-r--r-- | ext/json/php_json.h | 1 | ||||
-rw-r--r-- | ext/json/tests/bug50224.phpt | 60 |
3 files changed, 90 insertions, 8 deletions
diff --git a/ext/json/json.c b/ext/json/json.c index 22c6353803..baad4bc399 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -31,6 +31,14 @@ #include "php_json.h" #include <zend_exceptions.h> +#include <float.h> +#if defined(DBL_MANT_DIG) && defined(DBL_MIN_EXP) +#define NUM_BUF_SIZE (3 + DBL_MANT_DIG - DBL_MIN_EXP) +#else +#define NUM_BUF_SIZE 1080 +#endif + + static PHP_MINFO_FUNCTION(json); static PHP_FUNCTION(json_encode); static PHP_FUNCTION(json_decode); @@ -103,6 +111,7 @@ static PHP_MINIT_FUNCTION(json) REGISTER_LONG_CONSTANT("JSON_PRETTY_PRINT", PHP_JSON_PRETTY_PRINT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_UNESCAPED_UNICODE", PHP_JSON_UNESCAPED_UNICODE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_PARTIAL_OUTPUT_ON_ERROR", PHP_JSON_PARTIAL_OUTPUT_ON_ERROR, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("JSON_PRESERVE_ZERO_FRACTION", PHP_JSON_PRESERVE_ZERO_FRACTION, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT); @@ -407,10 +416,17 @@ static void json_escape_string(smart_str *buf, char *s, size_t len, int options) smart_str_append_long(buf, p); } else if (type == IS_DOUBLE) { if (!zend_isinf(d) && !zend_isnan(d)) { - char *tmp; - int l = spprintf(&tmp, 0, "%.*k", (int) EG(precision), d); - smart_str_appendl(buf, tmp, l); - efree(tmp); + char num[NUM_BUF_SIZE]; + int l; + + php_gcvt(d, EG(precision), '.', 'e', (char *)num); + l = strlen(num); + if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && l < NUM_BUF_SIZE - 2) { + num[l++] = '.'; + num[l++] = '0'; + num[l] = '\0'; + } + smart_str_appendl(buf, num, l); } else { JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN; smart_str_appendc(buf, '0'); @@ -627,14 +643,19 @@ again: case IS_DOUBLE: { - char *d = NULL; + char num[NUM_BUF_SIZE]; int len; double dbl = Z_DVAL_P(val); if (!zend_isinf(dbl) && !zend_isnan(dbl)) { - len = spprintf(&d, 0, "%.*k", (int) EG(precision), dbl); - smart_str_appendl(buf, d, len); - efree(d); + php_gcvt(dbl, EG(precision), '.', 'e', (char *)num); + len = strlen(num); + if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < NUM_BUF_SIZE - 2) { + num[len++] = '.'; + num[len++] = '0'; + num[len] = '\0'; + } + smart_str_appendl(buf, num, len); } else { JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN; smart_str_appendc(buf, '0'); diff --git a/ext/json/php_json.h b/ext/json/php_json.h index b175d9a157..0ba4154f2f 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -68,6 +68,7 @@ extern PHP_JSON_API zend_class_entry *php_json_serializable_ce; #define PHP_JSON_PRETTY_PRINT (1<<7) #define PHP_JSON_UNESCAPED_UNICODE (1<<8) #define PHP_JSON_PARTIAL_OUTPUT_ON_ERROR (1<<9) +#define PHP_JSON_PRESERVE_ZERO_FRACTION (1<<10) /* Internal flags */ #define PHP_JSON_OUTPUT_ARRAY 0 diff --git a/ext/json/tests/bug50224.phpt b/ext/json/tests/bug50224.phpt new file mode 100644 index 0000000000..3408ac906f --- /dev/null +++ b/ext/json/tests/bug50224.phpt @@ -0,0 +1,60 @@ +--TEST-- +bug #50224 (json_encode() does not always encode a float as a float) +--SKIPIF-- +<?php if (!extension_loaded("json")) print "skip"; ?> +--FILE-- +<?php +echo "* Testing JSON output\n\n"; +var_dump(json_encode(12.3, JSON_PRESERVE_ZERO_FRACTION)); +var_dump(json_encode(12, JSON_PRESERVE_ZERO_FRACTION)); +var_dump(json_encode(12.0, JSON_PRESERVE_ZERO_FRACTION)); +var_dump(json_encode(0.0, JSON_PRESERVE_ZERO_FRACTION)); +var_dump(json_encode(array(12, 12.0, 12.3), JSON_PRESERVE_ZERO_FRACTION)); +var_dump(json_encode((object)array('float' => 12.0, 'integer' => 12), JSON_PRESERVE_ZERO_FRACTION)); + +echo "\n* Testing encode/decode symmetry\n\n"; + +var_dump(json_decode(json_encode(12.3, JSON_PRESERVE_ZERO_FRACTION))); +var_dump(json_decode(json_encode(12, JSON_PRESERVE_ZERO_FRACTION))); +var_dump(json_decode(json_encode(12.0, JSON_PRESERVE_ZERO_FRACTION))); +var_dump(json_decode(json_encode(0.0, JSON_PRESERVE_ZERO_FRACTION))); +var_dump(json_decode(json_encode(array(12, 12.0, 12.3), JSON_PRESERVE_ZERO_FRACTION))); +var_dump(json_decode(json_encode((object)array('float' => 12.0, 'integer' => 12), JSON_PRESERVE_ZERO_FRACTION))); +var_dump(json_decode(json_encode((object)array('float' => 12.0, 'integer' => 12), JSON_PRESERVE_ZERO_FRACTION), true)); +?> +--EXPECTF-- +* Testing JSON output + +string(4) "12.3" +string(2) "12" +string(4) "12.0" +string(3) "0.0" +string(14) "[12,12.0,12.3]" +string(27) "{"float":12.0,"integer":12}" + +* Testing encode/decode symmetry + +float(12.3) +int(12) +float(12) +float(0) +array(3) { + [0]=> + int(12) + [1]=> + float(12) + [2]=> + float(12.3) +} +object(stdClass)#%d (2) { + ["float"]=> + float(12) + ["integer"]=> + int(12) +} +array(2) { + ["float"]=> + float(12) + ["integer"]=> + int(12) +}
\ No newline at end of file |