使用PHP5.6生成范围内的安全随机整数

使用PHP5.6生成范围内的安全随机整数,php,security,random,entropy,Php,Security,Random,Entropy,我想在PHP5.6中生成一个介于$min和$max之间的安全随机整数。PHP中的rand()和mt_rand()都被认为是不安全的 从: 小心 此函数不生成加密安全值,不应用于加密目的。如果需要加密的安全值,请考虑使用RealthyIn()、RealthyByTeSe()、或OpenSSLIVRAPIONPIDOOYBYTESE()来代替。 PHP7添加了random_int()(),非常适合我的用例: random_int-生成加密安全的伪随机整数 但是如何在PHP5.6中实现这一功能呢 我天

我想在PHP5.6中生成一个介于
$min
$max
之间的安全随机整数。PHP中的
rand()
mt_rand()
都被认为是不安全的

从:

小心

此函数不生成加密安全值,不应用于加密目的。如果需要加密的安全值,请考虑使用RealthyIn()、RealthyByTeSe()、或OpenSSLIVRAPIONPIDOOYBYTESE()来代替。 PHP7添加了
random_int()
(),非常适合我的用例:

random_int-生成加密安全的伪随机整数

但是如何在PHP5.6中实现这一功能呢

我天真的尝试是:

<?php
function secure_rand($min, $max)
{
    return (unpack("N", openssl_random_pseudo_bytes(4)) % ($max - $min)) + $min;
}

您可以使用openssl\u random\u pseudo\u bytes,因为它从PHP5.3开始就可用

生成伪随机字节字符串,字节数由长度参数确定

它还指示是否使用加密强算法生成伪随机字节,并通过可选的crypto_strong参数实现。这很少是错误的,但有些系统可能已经损坏或陈旧


上阅读更多内容,找到了一个非常有效的解决方案。在本例中,使用了mcrypt扩展,但如果需要更多信息,它也可以与
openssl\u random\u pseudo\u bytes()
一起使用

功能安全等级($min,$max){
$diff=$max-$min;
如果($diff<0 | |$diff>0x7fffff){
抛出新的RuntimeException(“坏范围”);
}
$bytes=mcrypt\u create\u iv(4,mcrypt\u DEV\u uradom);
//如果服务器上未启用mcrypt,则可以使用此选项
//$bytes=openssl_随机_伪_字节(4);
//如果未启用mbstring,也可以使用iconv\U strlen
如果($bytes==false | | mb|strlen($bytes,'8bit')!=4){
抛出新的RuntimeException(“无法获取4字节”);
}
$ary=解包(“Nint”,$bytes);
$val=$ary['int']&0x7FFFFFFF;//32位安全
$fp=$val/2147483647.0;//转换为[0,1]
//如果你真的需要一种int类型,就用这个
//返回(整数)轮($fp*$diff)+$min;
//否则,它将返回不带小数的浮点
返回轮($fp*$diff)+$min;
}
var_dump(安全等级(11000));
var_dump(secure_rand(1,20));
var_dump(安全等级(1,10));
var_dump(安全朗(15000));
var_dump(安全等级(1111111));
更新:源代码中的注释,删除了对float/int的强制转换,使用了
mb_strlen()
而不是
strlen()
我可以向您介绍PHP5项目中的哪个polyfills
random_bytes()
random_int()
?(旁注:在其他项目中,Wordpress在4.4中介绍了它。)


即使这是你想要它做的,这也是一个when
($max-$min)
不是2的偶数幂。

值得一看,但那是字节,我需要一个范围内的随机整数,同时保持一个完整的熵范围。好的,只要看第一个例子,使用bindec转换为dec,您就差不多完成了。转换为float可能会失去精度(导致偏差)或泄漏数据(intfloat转换不是常数时间IIRC),并且
strlen()
会受到
mbstring.func\u重载的影响,请随意编辑我的答案谢谢!我最终选择了,但这看起来也是个不错的选择。谢谢斯科特!我想这就是答案;我看过random_compat,这正是我想要的。PHP7的
random_int()
是我想要的,这似乎是下一个最好的东西。
function secure_rand( $min, $max ) {
    $diff = $max - $min;
    if ($diff < 0 || $diff > 0x7FFFFFFF) {
        throw new RuntimeException("Bad range");
    }
    $bytes = mcrypt_create_iv( 4, MCRYPT_DEV_URANDOM );

    // if mcrypt is not enabled on your server, you can use this
    //$bytes = openssl_random_pseudo_bytes( 4 );

    // if mbstring is not enabled, you can also use iconv_strlen
    if ($bytes === false || mb_strlen($bytes, '8bit') != 4) {
        throw new RuntimeException("Unable to get 4 bytes");
    }

    $ary = unpack("Nint", $bytes);
    $val = $ary['int'] & 0x7FFFFFFF;   // 32-bit safe
    $fp = $val / 2147483647.0; // convert to [0,1]
    // if you really need a type of int take this
    // return (int) round($fp * $diff) + $min;
    // otherwise it will return a float without decimal numbers
    return round($fp * $diff) + $min;
}

var_dump( secure_rand( 1, 1000 ) );
var_dump( secure_rand( 1, 20 ) );
var_dump( secure_rand( 1, 10 ) );
var_dump( secure_rand( 1, 5000 ) );
var_dump( secure_rand( 1, 1111111 ) );
function secure_rand($min, $max)
{
    return (unpack("N", openssl_random_pseudo_bytes(4)) % ($max - $min)) + $min;
}