Reputation: 6866
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!
Upvotes: 5
Views: 5188
Reputation: 1267
(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
Upvotes: 0
Reputation: 3360
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.
Upvotes: 3
Reputation: 1886
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);
Upvotes: 7
Reputation: 6866
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);
Upvotes: 3