Мне нужна замена для функции rand()
PHP, которая использует криптографически сильный генератор случайных чисел.
Функция openssl_random_pseudo_bytes()
дает вам доступ к генератору сильных случайных чисел, но выводит свои данные в виде байтовой строки. Вместо этого мне нужно целое число от 0 до X.
Я полагаю, что ключ состоит в том, чтобы получить вывод openssl_random_pseudo_bytes()
в целое число, тогда вы можете выполнить любую математику, на которой это необходимо. Я могу придумать несколько способов «перебора» для преобразования из байтовой строки в целое число, но я надеялся на что-то … элегантное.
Используя предоставленные предложения, я создал замену для rand () с помощью OpenSSL. Я включу его здесь для потомства.
Параметр $ pedantic дает результаты без смещения, начиная с того момента, когда результаты не будут равномерно распределены по всему диапазону.
function crypto_rand($min,$max,$pedantic=True) { $diff = $max - $min; if ($diff <= 0) return $min; // not so random... $range = $diff + 1; // because $max is inclusive $bits = ceil(log(($range),2)); $bytes = ceil($bits/8.0); $bits_max = 1 << $bits; // eg if $range = 3000 (bin: 101110111000) // +--------+--------+ // |....1011|10111000| // +--------+--------+ // bits=12, bytes=2, bits_max=2^12=4096 $num = 0; do { $num = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes))) % $bits_max; if ($num >= $range) { if ($pedantic) continue; // start over instead of accepting bias // else $num = $num % $range; // to hell with security } break; } while (True); // because goto attracts velociraptors return $num + $min; }
На странице руководства для openssl_random_pseudo_bytes()
есть пример, который, я думаю, вы хотите. Вы можете просто вызвать bin2hex()
на выходе openssl_random_pseudo_bytes()
для преобразования в шестнадцатеричное число, а затем hexdec()
для этого значения, чтобы преобразовать в десятичный.
$rand_num = hexdec(bin2hex(openssl_random_pseudo_bytes($length, $strong)));
В этот момент вы можете сделать любую математику, которую хотите получить, в нужном вам диапазоне. Другой вариант (cheater), который у вас есть, – запустить системную команду для генерации случайного числа – есть несколько хороших вариантов для генераторов случайных чисел для различных операционных систем, доступных в Интернете.
Heres версия решения выше, которая не использует рекурсивные вызовы функций:
function secure_rand($min,$max) { $range = $max - $min + 1; if ($range == 0) return $min; $length = (int) (log($range,2) / 8) + 1; $max = pow(2, 8 * $length); $num = $max + 1; // Hackish, I know.. while ($num > $max) { $num = hexdec(bin2hex(openssl_random_pseudo_bytes($length,$s))); } return ($num % $range) + $min; }
Поскольку PHP 7 сейчас отсутствует, самый простой способ решить эту проблему – заменить все экземпляры random_int
.
(Предполагая, что вы обновили, то есть.)
ну, просто используйте hexdec по результатам openssl_random_pseudo_bytes, и вы получите свое целое число. Это так же изящно, как и получается 🙂
print hexdec('45261b8f'); > 1160125327
Самый простой способ сделать это (и самый безопасный из всех вариантов здесь) – использовать CryptoLib, который имеет функцию randomInt, которая обеспечивает замену для rand.
Сначала загрузите CryptoLib и вставьте его в свой проект: https://github.com/IcyApril/CryptoLib
Два, запустите этот код. замените путь / на / с каталогом cryptolib.php и min max с минимальным и максимальным номерами:
<?php require_once('path/to/cryptoLib.php'); $min = 1; $max = 5; $randomNum = CryptoLib::randomInt($min, $max); ?>
Полная документация CryptoLib: https://cryptolib.ju.je/
function ($min,$max){ $range = $max-$min+1; do{ $result = floor($range*(hexdec(bin2hex(openssl_random_pseudo_bytes(4)))/0xffffffff)); } while($result == $range); return $result + $min; }