5

So I'm using php 5.2.6 in a WAMP environment.

I'm trying to use the json_decode function to make a json string into an array. The JSON is coming from a REST API elsewhere so I have no control over formatting of the JSON string. Here is an example of one of the json strings I'm trying to use:

[{
    "webinarKey":795855906,
    "sessionKey":100000000041808257,
    "startTime":"2011-12-16T13:56:15Z",
    "endTime":"2011-12-16T14:48:37Z",
    "registrantsAttended":2
}]

I'm specifically after the sessionKey value here. PHP is treating the value as a float and I can't seem to do anything to retrieve the original value.

I've tried the following:

json_decode($json, true, 512, JSON_BIGINT_AS_STRING);
# This produces the following error because my php version isn't up to snuff and I
# can't upgrade to the version required
# Warning: json_decode() expects at most 2 parameters, 4 given

I've also tried this:

$json_obj = json_decode($json, true);
number_format($json_obj[0]["sessionKey"], 0, '.', '');
# This results in precision issues where the value was 100000000041808257
# but is number_formated out as 100000000041808256

As I said, upgrading to php 5.4 (where the 4 parameter json_decode call is supported) isn't an option. Please help!

Thanks!

hakre
  • 193,403
  • 52
  • 435
  • 836
Ryan
  • 6,756
  • 13
  • 49
  • 68
  • I think there is a duplicate here on SO somewhere, it might be worth searching – Pekka Jan 06 '12 at 14:28
  • 1
    You might look at this question. A few people listed solutions after the JSON has been returned but before it is decoded. http://stackoverflow.com/q/2907806/2863 – Scott Gottreu Jan 06 '12 at 14:35

4 Answers4

7

To quality JSON spec use:

// wrap numbers
$json = preg_replace('/:\s*(\-?\d+(\.\d+)?([e|E][\-|\+]\d+)?)/', ': "$1"', $json);
// as object
$object = json_decode($json);
// as array
$array = json_decode($json, true);
Ryan Schumacher
  • 1,816
  • 2
  • 21
  • 33
  • 2
    Wont this corrupt json containing strings with colons and numbers? – Phil Jul 09 '15 at 18:42
  • Phil_1984_ yes I think you are right. Specifically it would for a string with a colon and a json integer. I'm guessing you'd need to check for a non escaped double quote prior to the colon to guarantee it not being a string but property. – Ryan Schumacher Jul 11 '15 at 00:15
3

Meanwhile, PHP has fixed this problem ... well, somehow. Starting sometime around PHP 5.4 they added an option which does the just what the Regex solutions posted above do:

json_decode($json, false, 512, JSON_BIGINT_AS_STRING);

The 512 refers to the default maximum nesting depth.

wortwart
  • 3,139
  • 27
  • 31
3

Thanks @Scott Gottreu and @pospi.

The answer was in the last comment for the accepted answer on this question.

Use the preg_replace() function to surround all integer values with quotes.

json_decode(preg_replace('/("\w+"):(\d+)/', '\\1:"\\2"', $jsonString), true);

Actually after testing the above line it screws up JSON with floating point numbers in as values so to fix that issue I used the following to just enclose all numbers (integer or floating point numbers) in quotes:

json_decode(preg_replace('/("\w+"):(\d+(\.\d+)?)/', '\\1:"\\2"', $jsonString), true);
Community
  • 1
  • 1
Ryan
  • 6,756
  • 13
  • 49
  • 68
  • 2
    In case you are dealing with negative numbers, just add the `-` symbol as optional in the regexp: `$json = preg_replace('/("\w+"):(-?\d+(\.\d+)?)/', '\\1:"\\2"', $json)` – joserobleda Feb 14 '15 at 11:39
0

(I'm re-posting my answer from another question (Handling big user IDs returned by FQL in PHP) here, because this is more generic; not related to Facebook / FQL.)

A major oversight on PHP's part is that browsers don't choke on integers starting with BigInt (64 bits), but before that (53 bits). The introduction of BigInt to modern browsers doesn't help much, when JSON does not support it. So I am trying to remedy that.

The often cited versions using preg_replace() do not account for large integers in indexed arrays. My approach is to handle the decoded array (before potentially re-encoding it to a string):

function fix_large_int(&$value)
 {
  if (is_int($value) && $value > 9007199254740991)
    $value = strval($value);
 }
$json_arr = json_decode($json_str, flags: JSON_BIGINT_AS_STRING | JSON_OBJECT_AS_ARRAY);
echo('before: ' . json_encode($json_arr) . '<br />' . PHP_EOL);
array_walk_recursive($json_arr, 'fix_large_int');
echo('after:  ' . json_encode($json_arr) . '<br />' . PHP_EOL);

The number 9007199254740991 is what JavaScript has as its Number.MAX_SAFE_INTEGER value. Read about that here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER

Alien426
  • 1,097
  • 10
  • 12