From 95cef47afb0b5329915a178d34cf27efcb54607b Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Mon, 12 Jan 2015 21:29:52 -0500 Subject: [PATCH] Porting implementation of RFC json_preserve_fractional_part --- ext/json/json.c | 1 + ext/json/json_encoder.c | 11 +++++-- ext/json/php_json.h | 1 + ext/json/tests/bug50224.phpt | 60 ++++++++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 ext/json/tests/bug50224.phpt diff --git a/ext/json/json.c b/ext/json/json.c index 819a6dfe8ee2d..7db6136e87f2a 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -102,6 +102,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); diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index 8657fd2cdb710..510163d8238dd 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -95,13 +95,18 @@ static inline void php_json_pretty_print_indent(smart_str *buf, int options) /* /* }}} */ -static inline void php_json_encode_double(smart_str *buf, double d) /* {{{ */ +static inline void php_json_encode_double(smart_str *buf, double d, int options) /* {{{ */ { if (!zend_isinf(d) && !zend_isnan(d)) { size_t len; char num[PHP_JSON_DOUBLE_MAX_LENGTH]; php_gcvt(d, EG(precision), '.', 'e', &num[0]); len = strlen(num); + if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < PHP_JSON_DOUBLE_MAX_LENGTH - 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; @@ -290,7 +295,7 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti if (type == IS_LONG) { smart_str_append_long(buf, p); } else if (type == IS_DOUBLE) { - php_json_encode_double(buf, d); + php_json_encode_double(buf, d, options); } return; } @@ -502,7 +507,7 @@ void php_json_encode_zval(smart_str *buf, zval *val, int options) /* {{{ */ break; case IS_DOUBLE: - php_json_encode_double(buf, Z_DVAL_P(val)); + php_json_encode_double(buf, Z_DVAL_P(val), options); break; case IS_STRING: diff --git a/ext/json/php_json.h b/ext/json/php_json.h index 25c799b3832dd..2a26b971810a5 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -64,6 +64,7 @@ typedef enum { #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 0000000000000..3408ac906f9d6 --- /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-- + +--FILE-- + 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