Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP randomly decrements large integers by 1 [duplicate]

Tags:

json

php

mysql

I've stumbled across a weird bug/problem.

I have a MySQL table with a column filled with numbers (BIGINT). These numbers are too big for a regular 32 bit integer, so PHP will cast them to a string on 32-bit. This gives the correct result every time.

When run on 64 bit PHP and not forcibly cast to a string with $variable = (string)$variable, the result will sometimes be decremented by 1, such that a number like 1293203059233 becomes 1293203059232. This is no good obviously. The odd thing is that I cannot see any pattern.

It does not happen randomly such that one row from MySQL is decremented sometimes and sometimes not, but such that the same integers/rows are always decremented, and always by 1.

What could cause this? I use json_encode to convert stdClass-objects or arrays() to text, then send them by regular HTTP responses.

The rows are retrieved by mysqli using prepared statements such as :

$stmt = $sql->prepare->("SELECT BIGNUMBER FROM table WHERE SOMEID = ?");
$stmt->bind_result($bignumber);
$stmt->bind_param("i",$someid);
$stmt->execute();
$stmt->fetch();
$stmt->close();

$obj = new stdClass();
$obj->number = $bignumber;

echo json_encode($obj);

I have verified that all the integers are correct when browsing the database table.

Some examples (these are the actual values):

without cast to string:

10205160559939609 -> 10205160669939608 // bad

with:

10205160559939609 -> "10205160559939609" // good

without cast to string:

10154493437278508 -> 10154493437278508 // good (?)

with:

10154493437278508 -> "10154493437278508" // good

Edit: I did a error_log test pre-json_encode to test, yielding:

as Strng: (used error_log((string)$number);)
10205160559939609
as int: (used error_log($number);)
10205160559939609

Which would indicate that php does get the correct value, and that the error occurs in either php json_encode or in the browser's decode method.

like image 510
nickdnk Avatar asked Oct 06 '15 11:10

nickdnk


1 Answers

Simply typing in 10205150669939609 in the chrome console will give you the number 10205150669939608 printed out (rounding effect). I guess integers this big aren't valid in JS so neither should they be in JSON. I'd use strings if I had values that large.

like image 191
andrrs Avatar answered Oct 20 '22 22:10

andrrs