php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #46363 json_decode lacks a 'num_as_string' feature
Submitted: 2008-10-22 08:57 UTC Modified: 2010-09-16 16:09 UTC
Votes:3
Avg. Score:5.0 ± 0.0
Reproduced:3 of 3 (100.0%)
Same Version:2 (66.7%)
Same OS:3 (100.0%)
From: 191919 at gmail dot com Assigned: aharvey (profile)
Status: Closed Package: JSON related
PHP Version: 5.2.6 OS: *
Private report: No CVE-ID: None
 [2008-10-22 08:57 UTC] 191919 at gmail dot com
Description:
------------
json_decode lacks a 'num_as_string' feature. I made a patch which adds a third optional 'num_as_string' parameter to json_decode to force it to decode all numbers as strings.

diff -u json_orig/JSON_parser.c json/JSON_parser.c
--- json_orig/JSON_parser.c	2007-06-14 01:56:41.000000000 +0800
+++ json/JSON_parser.c	2008-10-22 16:33:32.000000000 +0800
@@ -278,10 +278,15 @@
 }
 
 
-static void json_create_zval(zval **z, smart_str *buf, int type)
+static void json_create_zval(zval **z, smart_str *buf, int type, int num_as_string)
 {
     ALLOC_INIT_ZVAL(*z);
 
+    if (num_as_string)
+    {
+        type = IS_STRING;
+    }
+
     if (type == IS_LONG)
     {
 	double d = zend_strtod(buf->c, NULL);
@@ -399,7 +404,7 @@
     machine with a stack.
 */
 int
-JSON_parser(zval *z, unsigned short p[], int length, int assoc TSRMLS_DC)
+JSON_parser(zval *z, unsigned short p[], int length, int assoc, int num_as_string TSRMLS_DC)
 {
     int b;  /* the next character */
     int c;  /* the next character class */
@@ -501,7 +506,7 @@
                     zval *mval;
                     smart_str_0(&buf);
 
-                    json_create_zval(&mval, &buf, type);
+                    json_create_zval(&mval, &buf, type, num_as_string);
 
                     if (!assoc)
                     {
@@ -573,7 +578,7 @@
                     zval *mval;
                     smart_str_0(&buf);
 
-                    json_create_zval(&mval, &buf, type);
+                    json_create_zval(&mval, &buf, type, num_as_string);
                     add_next_index_zval(JSON(the_zstack)[JSON(the_top)], mval);
                     buf.len = 0;
                     JSON_RESET_TYPE();
@@ -626,7 +631,7 @@
                      JSON(the_stack[JSON(the_top)]) == MODE_ARRAY))
                 {
                     smart_str_0(&buf);
-                    json_create_zval(&mval, &buf, type);
+                    json_create_zval(&mval, &buf, type, num_as_string);
                 }
 
                 switch (JSON(the_stack)[JSON(the_top)]) {
diff -u json/JSON_parser.h json/JSON_parser.h
--- json_orig/JSON_parser.h	2006-07-20 00:17:15.000000000 +0800
+++ json/JSON_parser.h	2008-10-22 16:32:56.000000000 +0800
@@ -3,4 +3,4 @@
 #include "php.h"
 #include "ext/standard/php_smart_str.h"
 
-extern int JSON_parser(zval *z, unsigned short p[], int length, int assoc TSRMLS_DC);
+extern int JSON_parser(zval *z, unsigned short p[], int length, int assoc, int num_as_string TSRMLS_DC);
diff -u json/json.c json/json.c
--- json_orig/json.c	2007-12-31 15:20:07.000000000 +0800
+++ json/json.c	2008-10-22 16:33:53.000000000 +0800
@@ -411,10 +411,11 @@
     char *parameter;
     int parameter_len, utf16_len;
     zend_bool assoc = 0; /* return JS objects as PHP objects by default */
+    zend_bool num_as_string = 0; /* don't decode integers and doubles as strings */
     zval *z;
     unsigned short *utf16;
 
-    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &parameter, &parameter_len, &assoc) == FAILURE) {
+    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bb", &parameter, &parameter_len, &assoc, &num_as_string) == FAILURE) {
         return;
     }
 
@@ -437,7 +438,7 @@
     }
 
     ALLOC_INIT_ZVAL(z);
-    if (JSON_parser(z, utf16, utf16_len, assoc TSRMLS_CC))
+    if (JSON_parser(z, utf16, utf16_len, assoc, num_as_string TSRMLS_CC))
     {
         *return_value = *z;






Reproduce code:
---------------
<?
$json = '{"a":1232487234.97323948}';
var_dump(json_decode($json, true));
?>


Expected result:
----------------
array(1) {
  ["a"]=>
  string(19) "1232487234.97323948"
}


Actual result:
--------------
array(1) {
  ["a"]=>
  float(1232487234.9732)
}


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2008-10-22 10:17 UTC] 191919 at gmail dot com
New patch

---

diff -u json_old/JSON_parser.c json/JSON_parser.c
--- json_old/JSON_parser.c	2007-06-14 01:56:41.000000000 +0800
+++ json/JSON_parser.c	2008-10-22 18:10:26.000000000 +0800
@@ -278,10 +278,15 @@
 }
 
 
-static void json_create_zval(zval **z, smart_str *buf, int type)
+static void json_create_zval(zval **z, smart_str *buf, int type, int num_as_string)
 {
     ALLOC_INIT_ZVAL(*z);
 
+    if (num_as_string && (type == IS_LONG || type == IS_DOUBLE))
+    {
+        type = IS_STRING;
+    }
+
     if (type == IS_LONG)
     {
 	double d = zend_strtod(buf->c, NULL);
@@ -399,7 +404,7 @@
     machine with a stack.
 */
 int
-JSON_parser(zval *z, unsigned short p[], int length, int assoc TSRMLS_DC)
+JSON_parser(zval *z, unsigned short p[], int length, int assoc, int num_as_string TSRMLS_DC)
 {
     int b;  /* the next character */
     int c;  /* the next character class */
@@ -501,7 +506,7 @@
                     zval *mval;
                     smart_str_0(&buf);
 
-                    json_create_zval(&mval, &buf, type);
+                    json_create_zval(&mval, &buf, type, num_as_string);
 
                     if (!assoc)
                     {
@@ -573,7 +578,7 @@
                     zval *mval;
                     smart_str_0(&buf);
 
-                    json_create_zval(&mval, &buf, type);
+                    json_create_zval(&mval, &buf, type, num_as_string);
                     add_next_index_zval(JSON(the_zstack)[JSON(the_top)], mval);
                     buf.len = 0;
                     JSON_RESET_TYPE();
@@ -626,7 +631,7 @@
                      JSON(the_stack[JSON(the_top)]) == MODE_ARRAY))
                 {
                     smart_str_0(&buf);
-                    json_create_zval(&mval, &buf, type);
+                    json_create_zval(&mval, &buf, type, num_as_string);
                 }
 
                 switch (JSON(the_stack)[JSON(the_top)]) {
diff -u json/JSON_parser.h json/JSON_parser.h
--- json_old/JSON_parser.h	2006-07-20 00:17:15.000000000 +0800
+++ json/JSON_parser.h	2008-10-22 16:32:56.000000000 +0800
@@ -3,4 +3,4 @@
 #include "php.h"
 #include "ext/standard/php_smart_str.h"
 
-extern int JSON_parser(zval *z, unsigned short p[], int length, int assoc TSRMLS_DC);
+extern int JSON_parser(zval *z, unsigned short p[], int length, int assoc, int num_as_string TSRMLS_DC);
diff -u json/json.c json/json.c
--- json_old/json.c	2007-12-31 15:20:07.000000000 +0800
+++ json/json.c	2008-10-22 16:33:53.000000000 +0800
@@ -411,10 +411,11 @@
     char *parameter;
     int parameter_len, utf16_len;
     zend_bool assoc = 0; /* return JS objects as PHP objects by default */
+    zend_bool num_as_string = 0; /* don't decode integers and doubles as strings */
     zval *z;
     unsigned short *utf16;
 
-    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &parameter, &parameter_len, &assoc) == FAILURE) {
+    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bb", &parameter, &parameter_len, &assoc, &num_as_string) == FAILURE) {
         return;
     }
 
@@ -437,7 +438,7 @@
     }
 
     ALLOC_INIT_ZVAL(z);
-    if (JSON_parser(z, utf16, utf16_len, assoc TSRMLS_CC))
+    if (JSON_parser(z, utf16, utf16_len, assoc, num_as_string TSRMLS_CC))
     {
         *return_value = *z;
 [2008-11-04 07:18 UTC] kalle@php.net
As a workaround you can always change the precision:

C:\php\src>php -r "var_dump(json_decode('{\"a\": 1232487234.97323948}'));"
object(stdClass)#1 (1) {
  ["a"]=>
  float(1232487234.9732)
}

C:\php\src>php -d precision=24 -r "var_dump(json_decode('{\"a\": 1232487234.9732
3948}'));"
object(stdClass)#1 (1) {
  ["a"]=>
  float(1232487234.97323942184448)
}

:), but I would still like a feature like this
 [2010-03-30 17:59 UTC] myfbcompany at gmail dot com
I have the same problem, but with integers.

I'm retrieving facebook information and some ids are 15 digits long, and the json_decode function round the number to 12 digits and add 3 zeros at the end.

It would be nice to have the numbers as string.

Thanks
 [2010-09-16 16:09 UTC] aharvey@php.net
-Status: Open +Status: Closed -Package: Feature/Change Request +Package: JSON related -Assigned To: +Assigned To: aharvey
 [2010-09-16 16:09 UTC] aharvey@php.net
Trunk now has the JSON_BIGINT_AS_STRING option for json_decode() which does just this.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed Dec 04 21:01:29 2024 UTC