Как сгенерировать случайное 64-битное значение в виде десятичной строки в PHP - PullRequest
8 голосов
/ 14 марта 2011

Для Oauth требуется случайное 64-разрядное число без знака, закодированное в виде строки ASCII в десятичном формате.Ребята, можете ли вы помочь мне достичь этого с помощью php?Спасибо

Ответы [ 3 ]

27 голосов
/ 14 марта 2011

Это была действительно интересная проблема (как создать десятичное представление случайного числа произвольной длины в PHP без использования дополнительных расширений).Вот решение:

Шаг 1: случайное число произвольной длины

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

Эта функция будет работать так, как объявлено, например try base_convert_arbitrary('ffffffffffffffff', 16, 10) == '18446744073709551615' и base_convert_arbitrary('10000000000000000', 16, 10) == '18446744073709551616'.

Соединяем все вместе

echo base_convert_arbitrary(random_bits(64), 16, 10);
4 голосов
/ 14 марта 2011

Вы можете использовать два 32-разрядных числа, четыре 16-разрядных числа и т. Д.

PHP имеет rand () и и mt_rand () , но какмногие случайные биты, которые они предоставляют, не определены стандартом (хотя их можно запрашивать с помощью getrandmax () и mt_getrandmax () соответственно.)

Таким образом, ваша самая безопасная самая простая ставка будет генерировать 64 случайных бита и устанавливать их один за другим.

Что касается работы с 64-разрядными целыми числами, я бы рекомендовал использовать GMP библиотека, так как она имеет хороший набор функций, чтобы помочь вам.

Вы можете создать число, вызвать 64 gmp_setbit () s с последовательными позициями и затем преобразовать его встрока с использованием gmp_strval ().

2 голосов
/ 14 марта 2011

Собираете ли вы 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));
}

Они выглядят так, будто им сходит с рук это без проблем с совместимостью.

...