统计脑筋急转弯:如何创建随机唯一的6位PIN并进行分配,以最大限度地降低碰撞概率


Statistical brainteaser: How to create random unique 6 digit PINs and distribute to minimise the probability collision

我想创建一个脚本,用户可以在注册电子邮件后使用该脚本生成pin。引脚需要为6位数字长且唯一;没有两个用户可以拥有相同的pin。

我有下面的代码,但是除了被困在一个不确定的循环中之外,我还没能取得进展。随着引脚的使用,while()函数循环的概率也会增加。有没有人想到一个更优雅的解决方案?

用户使用他们的密码访问网站上的免费服务。如果用户猜到另一个密码,服务不会失败,但会扰乱用户体验。

如果可能的话,我想以这样一种方式来分配pin,即在统计上猜测pin的概率是可以忽略的。

<?php
if($_POST['srSubmit'] && $_POST['srEmail'] && $_POST['srPass']) {
    $conn = mysqli_connect('localhost','root','','db_test');
    while(1) {
        $pin = rand(111111,999999);
        $sel = mysqli_query($conn,"SELECT * FROM formusers WHERE pin = '$pin'");
        if(mysqli_num_rows($sel) != 0) {    continue; }
        mysqli_query($conn,"INSERT INTO formusers(email,password,pin) VALUES('".$_POST['srEmail']."','".$_POST['srPass']."','".$pin."')");
        if(mysqli_affected_rows($conn)!=-1)  {
            echo "Pin:" . $pin;
            exit;
        } else {
            echo "Existing email, try again<br />";
        }
        break;
    }
}
?>
<form method="POST" action="">
<input type="email" name="srEmail" value="" placeholder="Email" /><br />
<input type="password" name="srPass" value="" placeholder="Password" /><br />
<input type="submit" name="srSubmit" value="Register" />
</form>

我同意一些评论者的意见,即您可能需要重新思考您的方法。然而,如果你决定采用它,并且你用数字距离来解释接近度(例如,与Levenstein距离相反),那么你可以考虑使用Halton序列或其他准随机序列。来自维基百科:

Halton序列是根据确定性方法构造的以素数为基数的。举个简单的例子Halton序列的一个维度基于2,另一个基于3.为了生成2的序列,我们首先将区间(0,1)一分为二,然后再除以四分之一、八分之一等,从而生成

1/2、1/4、3/4、1/8、5/8、3/8、7/8、1/16、9/16,。。。

要将这个想法应用于您的情况,只需将序列乘以您的最大PIN即可发言。这种方法不会产生碰撞,直到你真正开始填满你的空间,并均匀地分散你的PIN。只要你的用户数量远少于你的PIN数量,用户就很难随机猜测其他用户的PIN,但如果有人发现了你使用的序列,他们当然可以复制完整的列表。