8

Oauth 需要一个随机的 64 位无符号数字,以十进制格式编码为 ASCII 字符串。你们能帮我用php实现这个吗?谢谢

4

3 回答 3

28

这是一个非常有趣的问题(如何在 PHP 中创建任意长度随机数的十进制表示,不使用可选扩展)。这是解决方案:

第一步:任意长度的随机数

// Counts how many bits are needed to represent $value
function count_bits($value) {
    for($count = 0; $value != 0; $value >>= 1) {
        ++$count;
    }
    return $count;
}

// Returns a base16 random string of at least $bits bits
// Actual bits returned will be a multiple of 4 (1 hex digit)
function random_bits($bits) {
    $result = '';
    $accumulated_bits = 0;
    $total_bits = count_bits(mt_getrandmax());
    $usable_bits = intval($total_bits / 8) * 8;

    while ($accumulated_bits < $bits) {
        $bits_to_add = min($total_bits - $usable_bits, $bits - $accumulated_bits);
        if ($bits_to_add % 4 != 0) {
            // add bits in whole increments of 4
            $bits_to_add += 4 - $bits_to_add % 4;
        }

        // isolate leftmost $bits_to_add from mt_rand() result
        $more_bits = mt_rand() & ((1 << $bits_to_add) - 1);

        // format as hex (this will be safe)
        $format_string = '%0'.($bits_to_add / 4).'x';
        $result .= sprintf($format_string, $more_bits);
        $accumulated_bits += $bits_to_add;
    }

    return $result;
}

此时,调用random_bits(2048)会给你 2048 个随机位作为十六进制编码的字符串,没问题。

第 2 步:任意精度基数转换

数学很难,所以这里是代码:

function base_convert_arbitrary($number, $fromBase, $toBase) {
    $digits = '0123456789abcdefghijklmnopqrstuvwxyz';
    $length = strlen($number);
    $result = '';

    $nibbles = array();
    for ($i = 0; $i < $length; ++$i) {
        $nibbles[$i] = strpos($digits, $number[$i]);
    }

    do {
        $value = 0;
        $newlen = 0;
        for ($i = 0; $i < $length; ++$i) {
            $value = $value * $fromBase + $nibbles[$i];
            if ($value >= $toBase) {
                $nibbles[$newlen++] = (int)($value / $toBase);
                $value %= $toBase;
            }
            else if ($newlen > 0) {
                $nibbles[$newlen++] = 0;
            }
        }
        $length = $newlen;
        $result = $digits[$value].$result;
    }
    while ($newlen != 0);
    return $result;
}

此功能将按照宣传的方式工作,例如 trybase_convert_arbitrary('ffffffffffffffff', 16, 10) == '18446744073709551615'base_convert_arbitrary('10000000000000000', 16, 10) == '18446744073709551616'.

把它放在一起

echo base_convert_arbitrary(random_bits(64), 16, 10);
于 2011-03-14T18:07:03.683 回答
4

您可以使用两个 32 位数字、四个 16 位数字等。

PHP 有rand()mt_rand()但标准没有指定它们提供多少随机位(尽管可以分别在getrandmax()mt_getrandmax()的帮助下查询它们。)

所以你最安全最简单的赌注是生成 64 个随机位并一一设置。

至于使用 64 位整数,我建议使用GMP库,因为它有很多功能可以帮助您。

您可以创建一个数字,在其上调用 64 个gmp_setbit()并使用连续位置,然后使用 gmp_strval() 将其转换为字符串。

于 2011-03-14T16:12:57.217 回答
2

您是否正在自己构建 OAuth 适配器?如果是这样,您可能需要重新考虑。那里有很多好的 OAuth 库,其中一个来自 PECL一个来自 PEAR另一个来自 Zend Framework另一个托管在 Google Code 上。我和前三个一起工作过,他们都很不错。

如果你真的想自己做,你可能会遇到一个问题。PHP 无法思考 64 位数字,除非它是在 64 位平台上编译的,或者您安装了高级数学扩展。这将使将 64 位数字表示为十进制非常困难。看起来我上面链接的许多库完全忽略了格式要求,只使用原始 MD5 哈希。这是 ZF 适配器的代码:

/**
 * Generate nonce
 * 
 * @return string
 */
public function generateNonce()
{
    return md5(uniqid(rand(), true));
}

他们看起来好像在没有互操作性问题的情况下侥幸逃脱。

于 2011-03-14T16:23:09.503 回答