[php]unpack “N” bug on 64 bit system

这个问题只有在64系统下有问题. 当一个数值为负数时候, unpack后会变成一个超大整数.这是由于PHP_INT_MAX导致的.
32为下的PHP_INT_MAX为 2147483647; 而64位下为9223372036854775807;
如何判断php是运行在64位下?

php -r "echo PHP_INT_SIZE;"

如何返回4为32bit, 8为64bit.

我们看下例子

<?php
$s = -379;
$a = pack("N", $s);//转化后还是正常的.得到 ff ff fe 85

print_r(unpack("N", $a));//在32为解出来的结果正常为-379. 而64bit下则为4294966917
?>

如何解决?
网上找到了这么一个处理办法

/// portably build 64bit id from 32bit hi and lo parts
function _Make64 ( $hi, $lo )
{
// on x64, we can just use int
if ( ((int)4294967296)!=0 )
return (((int)$hi)<<32) + ((int)$lo);// workaround signed/unsigned braindamage on x32 $hi = sprintf ( "%u", $hi ); $lo = sprintf ( "%u", $lo );// use GMP or bcmath if possible if ( function_exists("gmp_mul") ) return gmp_strval ( gmp_add ( gmp_mul ( $hi, "4294967296" ), $lo ) );if ( function_exists("bcmul") ) return bcadd ( bcmul ( $hi, "4294967296" ), $lo );// compute everything manually $a = substr ( $hi, 0, -5 ); $b = substr ( $hi, -5 ); $ac = $a*42949; // hope that float precision is enough $bd = $b*67296; $adbc = $a*67296+$b*42949; $r4 = substr ( $bd, -5 ) + + substr ( $lo, -5 ); $r3 = substr ( $bd, 0, -5 ) + substr ( $adbc, -5 ) + substr ( $lo, 0, -5 ); $r2 = substr ( $adbc, 0, -5 ) + substr ( $ac, -5 ); $r1 = substr ( $ac, 0, -5 ); while ( $r4>100000 ) { $r4-=100000; $r3++; }
while ( $r3>100000 ) { $r3-=100000; $r2++; }
while ( $r2>100000 ) { $r2-=100000; $r1++; }

$r = sprintf ( “%d%05d%05d%05d”, $r1, $r2, $r3, $r4 );
$l = strlen($r);
$i = 0;
while ( $r[$i]==”0″ && $i<$l-1 ) $i++; return substr ( $r, $i ); }list(,$a) = unpack ( "N", "\xff\xff\xff\xff" ); list(,$b) = unpack ( "N", "\xff\xff\xff\xff" ); $q = _Make64($a,$b); var_dump($q); [/php]

  1. 这里需要进行一些修正了,当时写这文章时候,已经有新的解决办法,使用 l 这个参数,就可以正确接触来。pack时候一般下是不会出问题的,只有在unpack解未知来源的数据时候,会出现此类问题。

    首先-379 在N下是 ff ff fe 85
    而在L下是 85 fe ff ff
    你可以尝试数据反过来在进行解密。
    这时候你unpack(“L”, bin2hex(“85feffff”)) 得出来的值就是-379

Leave a Comment

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: