DEV Community

Segun Olaiya
Segun Olaiya

Posted on

I tried to json_decode a string in scientific notation

I spent 6 hours trying to work on a bug ticket assigned to me. It turns out the code has been trying to json_decode a floating-point number in scientific notation.

Okay, let me give some context, we have this method somewhere in a Utils.php file:

function is_value_empty($value): bool {
    $value = json_decode($value ?: '');
    if (!is_array($value)) {
        return empty($value);
    }

    $has_non_empty_value = false;
    foreach ($value as $row) {
        if ($has_non_empty_value) {
            break;
        }

        $has_non_empty_value = !empty($row);
    }

    return !$has_non_empty_value;
}
Enter fullscreen mode Exit fullscreen mode

The job of this method, in the context that it is been used, is to check if the $value passed is empty. But it also needs to check the following:

  • if [] is passed, it needs to return true
  • If ['', ''] is passed it still needs to return true.
  • If a JSON encoded array with falsy values is passed it still needs to return true

Now the issue we were facing was that a certain user was trying to validate if 0E86023 was empty or not.

As you can see, the first thing this method does is to attempt a json_decode( ). It then checks if it successfully decodes the value. If the decoded value is not an array, it simply use the php empty( ) method and that's it.

The issue with 0E86023 or any floating-point number is that, if this expresssion is executed:

json_decode('0E86023')
Enter fullscreen mode Exit fullscreen mode

We would get a floating point response from php as 0.0

Psy Shell v0.11.22 (PHP 7.4.33 — cli) by Justin Hileman
> json_decode('0E86023')
= 0.0

>
Enter fullscreen mode Exit fullscreen mode

But this number might look like its exactly 0.0. But its not, its a number very very close to zero but not exactly zero. Therefore checking empty(json_decode('0E86023')) would return false.

This is why this method has been failing for the user and they have not been able to update their information with a value like 0E86023.

For a quick fix, I added a simple if statement on top of the method like so:

function is_value_empty($value): bool {
    if (is_numeric($value)) {
        return false;
    }

    $value = json_decode($value ?: '');
    if (!is_array($value)) {
        return empty($value);
    }

    $has_non_empty_value = false;
    foreach ($value as $row) {
        if ($has_non_empty_value) {
            break;
        }

        $has_non_empty_value = !empty($row);
    }

    return !$has_non_empty_value;
}
Enter fullscreen mode Exit fullscreen mode

It's interesting that this happened in a case where thousands of other records are been successfully updated but this particular user kept complaining that they could not use the feature.

So yea, not sure which is weird, json_decode( ) or empty( )

Top comments (1)

Collapse
 
kwnaidoo profile image
Kevin Naidoo
is_numeric($num) && is_float((float) $num)
Enter fullscreen mode Exit fullscreen mode

You can do the same for ints and other types. There are various other ways you should optimize this function, here are a couple of suggestions:

  1. json_decode($value ?: '') ~ you can just pass a value, you don't need the "?:".
  2. is_array is not valid because json_decode by default returns an object.

For large JSON objects, use "json_validate" instead - it won't parse the whole JSON but just check that it is valid JSON.