Let's say I have a byte-stream in which I know the location of a 64-bit value (a 64-bit nonce). The byte-order is Little-Endian. As PHP's integer data-type is limited to 32-bit (at least on 32-bit operating systems) how would I convert the byte-sequence into a PHP numeric representation (float would be sufficient I think)?
$serverChallenge = substr($bytes, 24, 8);
// $serverChallenge now contains the byte-sequence
// of which I know that it's a 64-bit value
Just looked up the code for Zend_Crypt_Math_BigInteger_Bcmath
and Zend_Crypt_Math_BigInteger_Gmp
which deals with this problem:
Using BCmath (Big-Endian)
This is essentially the solution posted by Chad Birch.
public static function bc_binaryToInteger($operand)
{
$result = '0';
while (strlen($operand)) {
$ord = ord(substr($operand, 0, 1));
$result = bcadd(bcmul($result, 256), $ord);
$operand = substr($operand, 1);
}
return $result;
}
Using GMP (Big-Endian)
Same algorithem - just different function names.
public static function gmp_binaryToInteger($operand)
{
$result = '0';
while (strlen($operand)) {
$ord = ord(substr($operand, 0, 1));
$result = gmp_add(gmp_mul($result, 256), $ord);
$operand = substr($operand, 1);
}
return gmp_strval($result);
}
Changing the algorithem to use Litte-Endian byte-order is quite simple: just read the binary data from end to start:
Using BCmath (Litte-Endian)
public static function bc_binaryToInteger($operand)
{
// Just reverse the binray data
$operand = strrev($operand);
$result = '0';
while (strlen($operand)) {
$ord = ord(substr($operand, 0, 1));
$result = bcadd(bcmul($result, 256), $ord);
$operand = substr($operand, 1);
}
return $result;
}
Using GMP (Litte-Endian)
public static function gmp_binaryToInteger($operand)
{
// Just reverse the binray data
$operand = strrev($operand);
$result = '0';
while (strlen($operand)) {
$ord = ord(substr($operand, 0, 1));
$result = gmp_add(gmp_mul($result, 256), $ord);
$operand = substr($operand, 1);
}
return gmp_strval($result);
}
Two years late to the party, but if anyone still cares:
unpack is the built-in way to go here, you can unpack it as a couple of 32-bit ints, or as a double.
This seems like a total hack, but it should do the job, assuming you have the BC Math functions that daemonmoi recommended:
$result = "0";
for ($i = strlen($serverChallenge) - 1; $i >= 0; $i--)
{
$result = bcmul($result, 256); // shift result
$nextByte = (string)(ord($serverChallenge[$i]));
$result = bcadd($result, $nextByte);
}
I know this is not quite the answer to the question, but check out the BC Math functions to handle big numbers.