可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I need a replacement for PHP's rand()
function that uses a cryptographically strong random number generator.
The openssl_random_pseudo_bytes()
function gets you access to the strong random number generator, but it outputs its data as a byte string. Instead, I need an integer between 0 and X.
I imagine the key is to get the output of openssl_random_pseudo_bytes()
into an integer, then you can do any math on it that you need to. I can think of a few "brute force" ways of converting from a byte string to an integer, but I was hoping for something ... elegant.
回答1:
Using provided suggestions, I've created a drop-in replacement for rand() using OpenSSL. I'll include it here for posterity.
The $pedantic option gives bias-free results by starting over when results won't be evenly distributed across the possible range.
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;
// e.g. 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;
}
回答2:
The manual page for openssl_random_pseudo_bytes()
has an example I think you want. You can just call bin2hex()
on the output of openssl_random_pseudo_bytes()
to convert to a hexadecimal number, then hexdec()
on that value to convert to decimal.
$rand_num = hexdec(bin2hex(openssl_random_pseudo_bytes($length, $strong)));
At that point you can do whatever math you want to get a value in the range you need. The other (cheater) option you might have is to run a system command to generate a random number - there are a few good options for random number generators for various operating systems available online.
回答3:
Heres a version of the solutions above, which doesn't use recursive function calls:
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;
}
回答4:
Since PHP 7 is out now, the easiest way to solve this problem is to replace all instances of mt_rand
with random_int
.
(Assuming you've upgraded, that is.)
回答5:
well, just use hexdec on the result of openssl_random_pseudo_bytes and you will get your integer. It is as elegant as it gets :)
print hexdec('45261b8f');
> 1160125327
回答6:
The easiest way to do this (and the most secure out of all the options here) is to use CryptoLib which has a randomInt function that provides a drop-in replacement for rand.
First download CryptoLib from and stick it in your project: https://github.com/IcyApril/CryptoLib
Two, drop in this code. replace path/to/ with the directory of cryptolib.php and the min max with your minimum and maximum numbers:
<?php
require_once('path/to/cryptoLib.php');
$min = 1;
$max = 5;
$randomNum = CryptoLib::randomInt($min, $max);
?>
The CryptoLib full documentation is at: https://cryptolib.ju.je/
回答7:
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;
}