【问题标题】:How to generate unique (forever) alphanumeric tokens (4 to 8 digits only)如何生成唯一(永久)字母数字标记(仅限 4 到 8 位)
【发布时间】:2017-05-05 12:23:51
【问题描述】:

我想知道 PHP 中是否有一种方法可以生成唯一的字母数字(区分大小写)标记,该标记可以永远唯一而不会发生任何冲突。如果我们从 time stamp 字符串派生它们,该字符串是 10 个字符,例如:1394452319,这可能是可能的,但我不确定我们是否可以将令牌缩短到 4人物?如果不可能,则 5、6、7 和最大为 8 个字符。因为我想生成简短的令牌以供用户阅读。

代币应如下所示:1aYc、ZoXq、3iU9 等。

我不想向用户展示任何序列。

还有一件事,我的应用程序将被多个用户使用,所以如果两个用户同时点击生成令牌,PHP 应用程序是否会生成相同的令牌(我假设我们使用时间戳来生成令牌)?我们怎样才能避免这个问题?

感谢您的帮助!

【问题讨论】:

  • 好吧,Random::alphanumericString($length) 与 4(含)和 8(含)之间的 $length 正是您想要的。如果你愿意,你甚至可以随机化长度,例如通过传递Random::intBetween(4, 8)。但是这个(以及任何其他解决方案)有理论上的限制:4 个字符只能有 14,776,336 个不同的值,8 个字符只能有 218,340,105,600,000 个值(虽然很多)。

标签: php


【解决方案1】:

这是另一个你也可以使用的功能

<?php 
    function generateRandomString($length = 8) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
       $randomString .= $characters[rand(0, strlen($characters) - 1)];
    }
    return $randomString;
}

echo generateRandomString();

?>

【讨论】:

    【解决方案2】:

    一种方法是拥有一个增量(即 auto_update)id,您可以在内部保持隐藏。由此,您生成一个散列,表示隐藏序列的 id。递增的 id 消除了冲突问题(即 MySQL 对此有一个集成的解决方案)。

    您现在需要使用的技巧是包含两列的随机哈希表,两列的值都为 n 到 m,但第二列是随机的。即

    col1 | col2
       1 | 2
       2 | 4
       3 | 5
       4 | 1
       5 | 3
    

    如果您的递增数字具有随机排序的数字,则很容易从中创建散列。只需将您可能的字符视为数字即可。你没看错吧?

    假设你有一个很好的随机数算法,你可以制作一个很好的哈希表。但是,还有一种方法可以找到一种算法,随着数字的增加为您提供数字。所以在这个例子中,它会给你col2 = fn(col1),即4 = fn(2)。 您所要做的就是获取结果并将其重新设计为公式:D 否则,您必须先填写表格。

    为了让您了解它的数学原理,请考虑一个使用数字的奇数/偶数特征并将其与加法相结合的函数。

    使用 n 位数字,每个字符使用 62 种可能性(区分大小写的字母和数字),您就有 62^n 种可能性。 对于 4 位数字,有 14776336 种可能性 (62^4)。

    这听起来可能很美妙,你可以想象有一张桌子,预先填满 14776336 id's 不是最干净的解决方案。

    不过,我希望这至少会导致正确的方向。

    编辑: 我们开始讨论math.stackexchange.com。 IT 有一些关于如何创建满足我们需求的函数的附加信息。

    【讨论】:

    • 非常感谢您的详细解决方案,听起来不错,但是如果我清除ID表并再次运行系统,新ID将与以前的ID相同:(并且会发生冲突!这就是为什么我会使用与时间戳相关的令牌,因为时间不会一直相同。还有一件事,你能提供一个示例代码来解释你的解释吗?再次感谢你!非常有用
    • @moderns 如果您找到适合您需求的方法,您不必保留/填充表格并且不会发生冲突,因为您可以使用条目数作为新起点为您的 auto_increase id,或将 auto_incremented id 存储在与公共 id 相同的表中。一个例子实际上会做很多工作,因为我上次写这样的代码是 10 年前,我找不到副本:D 正如所说,考虑在堆栈交换的数学部分询问这样的函数: math.stackexchange.com
    • 谢谢Andresch,我会尝试自己制作代码:)
    • @moderns 请考虑询问数学大师。他们可能看起来很奇怪,但这就是他们对我们的看法,对吧? ;-)
    • 感谢您一直以来的回答。如果我为生成的每个 ID 添加一个序列号,我的最后一个解决方案可能会起作用,而且字符数将为 11 个字符 :( 我的目标是获得 4 到 8 个字符的字符串长度 :( 我将尝试开发一个算法这给了我 4 个字符的字符串长度,看起来没有序列!
    【解决方案3】:

    你可以使用类似下面的东西

    <?php
          // chars
         $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-+';
    
         // convert to array
        $arr = str_split($chars, 1);
    
        // shuffle the array
        shuffle($arr);
    
       // array to chars with 8 chars
      echo substr(implode('', $arr), 0, 8);
    ?>
    

    【讨论】:

    • @moderns 然后尝试下面的代码..检查它是否给你合适的结果..
    【解决方案4】:

    你可以使用这个功能:

        // RETRUN 24 digit of UNIX ID :
        public function getComplexIDTicket(){  // duplicate method on Rest.php
            $arrAZ1 = range('A','Z');
            $arrAZ2 = range('A','Z');
            $arrAZ3 = range('A','Z');
    
            $arrs1 = range('A','Z');
            $arrs2 = range('A','Z');
            $arrs3 = range('A','Z');
    
            $a1 = $arrAZ1[rand(0,25)];
            $a2 = $arrAZ2[rand(0,25)];
            $a3 = $arrAZ3[rand(0,25)];
    
            $s1 = $arrs1[rand(0,25)];
            $s2 = $arrs2[rand(0,25)];
            $s3 = $arrs3[rand(0,25)];
    
            $s = $s1.$s2.$s3;
    
            $t = microtime(true);
            $micro = sprintf("%07d",($t - floor($t)) * 10000000);
            $id = date('ymdHis').strtoupper(dechex(substr($micro,0,7)));
            $id = str_pad($id, 24, $a3.$a2.$a1.$s, STR_PAD_RIGHT);
            // 151106214010 3DDBF0 L D C SM4
            return $id;
        }
    

    【讨论】:

      猜你喜欢
      • 2015-07-29
      • 1970-01-01
      • 2017-12-29
      • 1970-01-01
      • 1970-01-01
      • 2011-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多