【问题标题】:Converting byte-stream into numeric data-type将字节流转换为数字数据类型
【发布时间】:2010-10-18 02:04:37
【问题描述】:

假设我有一个字节流,其中我知道 64 位值(64 位随机数)的位置。字节顺序是 Little-Endian。由于 PHP 的整数数据类型仅限于 32 位(至少在 32 位操作系统上),我如何将字节序列转换为 PHP 数字表示(我认为浮点数就足够了)?

$serverChallenge = substr($bytes, 24, 8);
// $serverChallenge now contains the byte-sequence 
// of which I know that it's a 64-bit value

【问题讨论】:

  • Here是如何在PHP中将字节数组转换为浮点数。

标签: php floating-point 64-bit integer 32-bit


【解决方案1】:

刚刚查找了处理此问题的Zend_Crypt_Math_BigInteger_BcmathZend_Crypt_Math_BigInteger_Gmp 的代码:

使用 BCmath(大端)

这基本上是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;
}

使用 GMP(大端)

相同的算法 - 只是不同的函数名称。

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);
}

将算法更改为使用 Litte-Endian 字节顺序非常简单:只需从头到尾读取二进制数据即可:

使用 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;
}

使用 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);
}

【讨论】:

    【解决方案2】:

    这似乎完全是 hack,但它应该可以完成工作,假设您拥有 daemonmoi 推荐的 BC 数学函数:

    $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);
    }
    

    【讨论】:

    • 其实看起来确实有点难看,但似乎是一个可行的解决方案。
    • 删除了投票,因为代码使用的是 Big-Endian 字节顺序。仍然接受答案,因为它引导了我正确的方式。
    • 哎呀,我太傻了,我会换掉它。很高兴它有帮助。
    【解决方案3】:

    晚了两年,但如果有人还在乎: unpack 是这里的内置方式,您可以将其解压缩为几个 32 位整数或双精度整数。

    【讨论】:

      【解决方案4】:

      我知道这不是问题的全部答案,但请查看 the BC Math functions 以处理大数字。

      【讨论】:

      • 实际上我知道 BCMath 扩展,但这些函数不会有帮助,因为它们需要整数值作为字符串 - 但我只有一个字节流,它必须转换为 PHP (或 BCMath 或 GMP)可以用作数字...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-05
      • 2020-12-16
      相关资源
      最近更新 更多