go to bug id or search bugs for
We have a hex string like this: "eb3dd796efda2409" received from an upstream system. This is a big-nibble hex string containing this integer value: -1495802457948019703
This is a 64-bit signed integer.
When converting this using hexdec this is converted to a float and returns the wrong value, when assigned to a variable as a hex string and converted using intval() it loses precision.
When looking at the documentation: http://php.net/manual/en/function.hexdec.php it mentions this:
> The function can convert numbers that are too large to fit into the platforms integer type, larger values are returned as float in that case.
However, this happens on a 64-bit compiled PHP where this integer should fit into the platform's integer size.
PHP 7.2.3-1 (cli) (built: Mar 6 2018 11:15:04) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.3-1, Copyright (c) 1999-2018, by Zend Technologies
Interactive mode enabled
php > echo PHP_INT_MAX;
php > echo PHP_INT_SIZE;
As a side note:
We ended up using pack/unpack to avoid the interim float conversion, and we also had to use "J" as the unpack conversion type to get the right value which implies big-endianness in the packed value. I am not sure this is correct either as doing this conversion in other languages works just fine without specifying endianness. (tried in Python and Go)
(I can file a separate bug if this is also not intended)
$strhex = "eb3dd796efda2409";
$hex = 0xeb3dd796efda2409;
var_dump(unpack('J', pack("H*", $strhex)));
Add a Patch
Add a Pull Request
> […] which implies big-endianness in the packed value.
That is to be expected. `pack("H*", $strhex)` returns
"\xeb\x3d\xd7\x96\xef\xda\x24\x09", which is big-endian
(the highest byte is to the left).
> However, this happens on a 64-bit compiled PHP where this
> integer should fit into the platform's integer size.
No, it does not, since "PHP does not support unsigned
> when assigned to a variable as a hex string and converted using
> intval() it loses precision.
Hexadecimal number literals are regarded as non-negative numbers,
but this number exceeds PHP_INT_MAX, so it is stored as float.
Since the float value exceeds PHP_INT_MAX the result of the
conversion to integer is actually undefined.
So yes, if you want to convert unsigned 64bit values represented
as hexadecimal strings, you have to work-around the signed integer
limitations. Your (un)pack() solution appears to be appropriate.
Changing to doc-bug, since this info could be added to the
hexdec() man page.
Thank you for clarifying!
This should be documented though. I also ran into that problem.