Why do I get the following output on an x64 architecture?
$ php -r 'echo pow(2, 33) . "\n";print_r(unpack("Ivalue", pack("I", pow(2, 33))));'
8589934592
Array
(
[value] => 0
)
It seems as though it can handle signed 64-bit ints, but it can't pack / unpack them. According to the documentation, http://us3.php.net/pack, the size of I should be machine-dependent, which in this case is 64 bit.
$ php -r 'echo PHP_INT_MAX;'
9223372036854775807
$ php -v
PHP 5.2.9 (cli) (built: Apr 17 2009 03:29:14)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies
Here is a function to pack an integer value of any size into N bits:
function encode_int($in, $pad_to_bits=64, $little_endian=true) {
$in = decbin($in);
$in = str_pad($in, $pad_to_bits, '0', STR_PAD_LEFT);
$out = '';
for ($i = 0, $len = strlen($in); $i < $len; $i += 8) {
$out .= chr(bindec(substr($in,$i,8)));
}
if($little_endian) $out = strrev($out);
return $out;
}
Here is a function to decode the packed integers:
function decode_int(&$data, $bits=false) {
if ($bits === false) $bits = strlen($data) * 8;
if($bits <= 0 ) return false;
switch($bits) {
case 8:
$return = unpack('C',$data);
$return = $return[1];
break;
case 16:
$return = unpack('v',$data);
$return = $return[1];
break;
case 24:
$return = unpack('ca/ab/cc', $data);
$return = $return['a'] + ($return['b'] << 8) + ($return['c'] << 16);
break;
case 32:
$return = unpack('V', $data);
$return = $return[1];
break;
case 48:
$return = unpack('va/vb/vc', $data);
$return = $return['a'] + ($return['b'] << 16) + ($return['c'] << 32);
break;
case 64:
$return = unpack('Va/Vb', $data);
$return = $return['a'] + ($return['b'] << 32);
break;
}
return $return;
}
pack("I")
requests an integer, which, for the I32LP64 model on x86_64 still is usually 32 bits wide - at least in C. Interpreters often add their own definition on top.
There is no 64-bit version of PHP 5.2. The first 64-bit version was an experimental version of 5.3.0 on the Windows side. So if you're using 5.2.9 on Windows, you'll have to move up to 5.3.0 at least to be able to get a 64-bit build.
If my premise is correct, and you are using PHP on Windows, then this is way it's not working...
For you to have access to the 64-bit component of your CPU, your whole stack has to be 64 bits. That means that the CPU has to support 64 bit, the OS has to support 64 bit, and the application has to support 64 bit. If any of these use 32 bits, the the whole stack will be 32 bit from that point. It goes by the lowest common denominator.
Because pack takes the second parameter as a string and converts it to a 32-bit int. The only relief is unsigned as far as bit-size limitations. Looking at the source code I see a 64-bit version coming soon from Perl that uses 'Q' to force 64-bit machine endian.