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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: 191919 at gmail dot com
New email:
PHP Version: OS:

 

 [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: Sun Oct 27 16:01:27 2024 UTC