【问题标题】:One-line PHP random string generator?单行 PHP 随机字符串生成器?
【发布时间】:2013-10-01 19:10:47
【问题描述】:

我正在寻找生成随机/唯一字符串的最短方法,为此我使用了以下两个:

$cClass = sha1(time());

$cClass = md5(time());

但是,我需要字符串以字母开头,我正在查看 base64 编码,但在末尾添加了 ==,然后我需要摆脱它。

用一行代码实现这一目标的最佳方法是什么?


更新:

PRNDL 提出了一个很好的建议,我最终使用了它,但做了一些修改

echo substr(str_shuffle(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ),0, 1) . substr(str_shuffle(aBcEeFgHiJkLmNoPqRstUvWxYz0123456789),0, 31)

会产生 32 个模仿 md5 哈希的字符,但它总是将第一个字符生成一个字母,就像这样;

然而,Uours 确实改进了他的回答;

substr(str_shuffle("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 1).substr(md5(time()),1);

更短更甜

Anonymous2011 的另一个建议非常棒,但出于某种原因,第一个字符总是 M、N、Y、Z,所以不符合我的目的,但会是选择的答案,顺便说一句,有人知道为什么它总是会产生那些特定的字母吗?

这是我修改后的预览版

echo  rtrim(base64_encode(md5(microtime())),"=");

【问题讨论】:

  • 为什么需要在一行代码中实现?
  • 与此相关的问题不输出字母表中的第一个字符...为什么要关闭我的?
  • 如果你们想知道为什么是第一个字母,那么我正在用 div 元素做一些测试......类或 ids 不接受第一个字符上的数字,它们不接受任何地方的特殊字符跨度>
  • 加下划线_0000的前缀有效。
  • 前缀什么?可以举个例子吗

标签: php random


【解决方案1】:

以下单行符符合您问题中的要求:值得注意的是,它以字母开头。

substr("abcdefghijklmnop",random_int(0, 16),1) . Bin2hex(random_bytes(15))

如果你不关心字符串是否以字母开头,你可以使用:

bin2hex(random_bytes(16))

请注意,这里我们使用random_bytesrandom_int,它们是在 PHP 7 中引入的并使用加密随机生成器,如果您希望唯一的字符串难以猜测,这一点很重要。许多其他解决方案,包括涉及time()microtime()uniqid()rand()mt_rand()str_shuffle()array_rand()shuffle() 的解决方案,更容易预测并且不适合随机字符串将用作密码、承载凭证、随机数、会话标识符、“验证码”或“确认码”或其他秘密值。

在生成唯一标识符时,我还会列出other things to keep in mind,尤其是随机标识符。

【讨论】:

    【解决方案2】:

    比起随机排列字母串,获得单个随机字符更快。

    从字符串中获取单个随机字符,然后将 md5( time( ) ) 附加到它。在添加 md5( time( ) ) 之前,从其中删除一个字符,以便将生成的字符串长度保持为 32 个字符:

    substr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", mt_rand(0, 51), 1).substr(md5(time()), 1);
    

    小写版本:

    substr("abcdefghijklmnopqrstuvwxyz", mt_rand(0, 25), 1).substr(md5(time()), 1);
    

    甚至更短、更快的小写版本:

    chr(mt_rand(97, 122)).substr(md5(time()), 1);
    
    /* or */
    
    chr(mt_rand(ord('a'), ord('z'))).substr(md5(time()), 1);
    


    给任何试图在一秒钟内生成许多随机字符串的人的说明:
    因为
    time( ) 以秒为单位返回时间, md5( time( ) ) 在给定的第二时间中将是相同的,因此如果在第二时间中生成了许多随机字符串,那么这些可能最终会产生一些重复。


    我已经使用下面的代码进行了测试。这测试小写版本:

        $num_of_tests = 100000;
    
        $correct = $incorrect = 0;
    
        for( $i = 0; $i < $num_of_tests; $i++ )
        {
            $rand_str = substr( "abcdefghijklmnopqrstuvwxyz" ,mt_rand( 0 ,25 ) ,1 ) .substr( md5( time( ) ) ,1 );
    
            $first_char_of_rand_str = substr( $rand_str ,0 ,1 );
    
            if( ord( $first_char_of_rand_str ) < ord( 'a' ) or ord( $first_char_of_rand_str ) > ord( 'z' ) )
            {
                $incorrect++;
                echo $rand_str ,'<br>';
            }
            else
            {
                $correct++;
            }
        }
    
        echo 'Correct: ' ,$correct ,' . Incorrect: ' ,$incorrect ,' . Total: ' ,( $correct + $incorrect );
    

    【讨论】:

    • 第一个是否有可能是一个数字?我执行了大约 50 次,并得到一个数字作为第一个字符,但发生了一次 30128fb9b80c5697a4a3954b96e1295
    • 我看不出任何原因,除非 mt_rand 中的值不正确。我认为应该是 mt_rand(0, 50) 。以前是mt_rand(0, 51)
    • 也许你是对的,第一个字符是 0,我现在只使用小写字符,因为字母表有 26 个字母,那么最大参数应该是 25
    • 通过我更正的解决方案,我生成了 100,000 个字符串,并且没有一个以数字字符开头。我已经测试了 100,000 个字符串的小写解决方案,并且解决方案看起来很完美。
    • 太棒了,你用什么来生成字符串,还有,只是想知道如何对这些代码的性能进行基准测试?任何建议都会很棒
    【解决方案3】:

    如何以糟糕的方式匹配 OP 的原始请求(为提高可读性而扩展):

    // [0-9] ASCII DEC 48-57
    // [A-Z] ASCII DEC 65-90
    // [a-z] ASCII DEC 97-122
    // Generate: [A-Za-z][0-9A-Za-z]
    $r = implode("", array_merge(array_map(function($a)
                                 {
                                     $a = [rand(65, 90), rand(97, 122)];
                                     return chr($a[array_rand($a)]);
                                 }, array_fill(0, 1, '.')),
                                 array_map(function($a)
                                 {
                                     $a = [rand(48, 57), rand(65, 90), rand(97, 122)];
                                     return chr($a[array_rand($a)]);
                                 }, array_fill(0, 7, '.'))));
    

    最后一个 array_fill() 会将“7”更改为您的长度 - 1。

    对于所有字母数字(而且仍然很慢)的人:

    // [0-9A-Za-z]
    $x = implode("", array_map(function($a)
                               {
                                   $a = [rand(48, 57), rand(65, 90), rand(97, 122)];
                                   return chr($a[array_rand($a)]);
                               }, array_fill(0, 8, '.')));
    

    【讨论】:

      【解决方案4】:

      这真的取决于你的要求。

      我需要字符串在测试运行之间是唯一的,但没有太多其他限制。

      我还需要我的字符串以一个字符开头,这对我的目的来说已经足够了。

      $mystring = "/a" . microtime(true);

      示例输出:

      a1511953584.0997

      【讨论】:

      • microtime 不使用任何随机部分,以固定字母开头不再提供任何随机性
      • @NicoHaase 我没有声称这两件事中的任何一个,所以不知道你为什么对此发表评论(并投反对票?)
      • 您所说的“我没有声称这两件事中的任何一个”是什么意思?这就是整个问题的意义所在:生成随机字符串
      • 问题以to generate random/unique strings 开头,就我而言,就像 OP(可能)一样,函数调用之间的唯一性就足够了,它不需要真正随机。他们还写了I need the string to begin with a letter,但没有指定字母本身的随机性要求。由于我自己有一个具有类似要求的用例,它有效,所以我发布了它。
      【解决方案5】:

      生成由随机字符组成的字符串,可以使用这个函数

      public function generate_random_name_for_file($length=50){
          $key = '';
          $keys = array_merge(range(0, 9), range('a', 'z'));
          for ($i = 0; $i < $length; $i++) {
              $key .= $keys[array_rand($keys)];
          }
          return $key;
      }
      

      【讨论】:

        【解决方案6】:

        我发现 base64 编码对于创建随机字符串很有用,并使用这一行:

        base64_encode(openssl_random_pseudo_bytes(9));
        

        它给了我一个包含 12 个位置的随机字符串,还有一个额外的好处是随机性是“加密性强”。

        【讨论】:

          【解决方案7】:

          你可以试试这个:

           function KeyGenerator($uid) {
              $tmp = '';
              for($z=0;$z<5;$z++) {
                $tmp .= chr(rand(97,122)) . rand(0,100);
              }
              $tmp .= $uid;
              return $tmp;
            }
          

          【讨论】:

            【解决方案8】:

            此函数返回随机小写字符串:

            function randomstring($len=10){
             $randstr='';
             for($iii=1; $iii<=$len; $iii++){$randstr.=chr(rand(97,122));};
             return($randstr);
            };
            

            【讨论】:

              【解决方案9】:

              JavaScript 解决方案:

              function randomString(pIntLenght) {  
                var strChars = “0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz”;
                var strRandomstring = ”;
              
                for (var intCounterForLoop=0; intCounterForLoop < pIntLenght; intCounterForLoop++) {
                    var rnum = Math.floor(Math.random() * strChars.length);
                    strRandomstring += strChars.substring(rnum,rnum+1);
                }
                 return strRandomstring;
              }
              
              alert(randomString(20));
              

              参考网址:Generate random string using JavaScript

              PHP 解决方案:

              function getRandomString($pIntLength = 30) {
                    $strAlphaNumericString     = ’0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ’;
              
                    $strReturnString         = ”;
              
                    for ($intCounter = 0; $intCounter < $pIntLength; $intCounter++) {
                         $strReturnString .= $strAlphaNumericString[rand(0, strlen($strAlphaNumericString) - 1)];
                    }
                    return $strReturnString;
              }
              
              echo getRandomString(20);
              

              参考网址:Generate random String using PHP

              【讨论】:

                【解决方案10】:

                根据上面的其他很好的例子,我正在使用这个一次性生成几十个独特的字符串,而不重复它们:

                $string = chr(mt_rand(97, 122))
                          . substr(md5(str_shuffle(time() . rand(0, 999999))), 1);
                

                这样,我能够在大约 5 秒内生成 1.000.000 个唯一字符串。这不是那么快,我知道,但因为我只需要少数几个,我可以接受。顺便说一句,生成 10 个字符串的时间不到 0.0001 毫秒。

                【讨论】:

                  【解决方案11】:

                  创建一个 200 字符长的十六进制字符串:

                  $string = bin2hex(openssl_random_pseudo_bytes(100));
                  

                  maaarghk's answer 不过更好。

                  【讨论】:

                    【解决方案12】:

                    我认为这个问题需要一个更好的答案。喜欢代码高尔夫!这也使用了更好的随机字节生成器。

                    preg_replace("/[\/=+]/", "", base64_encode(openssl_random_pseudo_bytes(8)));
                    

                    显然,为更长的密码增加字节数。

                    【讨论】:

                    • 你可以使用str_replace(array('/', '=', '+'), '', ...,这样可能会更快。
                    【解决方案13】:

                    base_convert(microtime(true), 10, 36);

                    【讨论】:

                    • 请分享更多细节。该 sn-p 的哪些部分提供随机性?
                    【解决方案14】:

                    我发现了这样的东西:

                    $length = 10;
                    $randomString = substr(str_shuffle(md5(time())),0,$length);
                    echo $randomString;
                    

                    【讨论】:

                    • 这是比上面那个更好的版本,因为它是独一无二的,并且有字符长度。
                    【解决方案15】:

                    我用这个功能

                    用法:

                     echo randomString(20, TRUE, TRUE, FALSE);
                    
                      /**
                       * Generate Random String
                       * @param Int Length of string(50)
                       * @param Bool Upper Case(True,False)
                       * @param Bool Numbers(True,False)
                       * @param Bool Special Chars(True,False)
                       * @return String  Random String
                       */
                      function randomString($length, $uc, $n, $sc) {
                          $rstr='';
                          $source = 'abcdefghijklmnopqrstuvwxyz';
                          if ($uc)
                              $source .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
                          if ($n)
                              $source .= '1234567890';
                          if ($sc)
                              $source .= '|@#~$%()=^*+[]{}-_';
                          if ($length > 0) {
                              $rstr = "";
                              $length1= $length-1;
                              $input=array('a','b','c','d','e','f','g','h','i','j,''k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z')  
                              $rand = array_rand($input, 1)
                              $source = str_split($source, 1);
                              for ($i = 1; $i <= $length1; $i++) {
                                  $num = mt_rand(1, count($source));
                                  $rstr1 .= $source[$num - 1];
                                  $rstr = "{$rand}{$rstr1}";
                              }
                          }
                          return $rstr;
                      }
                    

                    【讨论】:

                    • $uc == 1, $n == 1 :-S
                    • @zerkms 1 为真,0 为假
                    • echo improve(constant(Alix),True); --- 它抛出一个MayBeAnotherDay 异常:-(
                    • @JoseDavidGarciaLlanos:OP = 原始海报 = 你。 =)
                    • @EmilioGort:我从来没有说过它需要。你可以放下它。
                    【解决方案16】:

                    我已经为您生成了此代码。简单、简短且(相当)优雅。

                    这使用你提到的 base64,如果长度对你不重要 - 但是它使用 str_replace 删除“==”。

                    <?php
                            echo  str_ireplace("==", "", base64_encode(time()));
                    ?>
                    

                    【讨论】:

                    • 嗯,改用 rtrim() 吧!
                    • 我同意使用 rtrim(),最后我检查的 == 没有大写和小写版本。那么为什么要使用不区分大小写的替换呢?
                    • 我从不知道 rtrim() - 我会在未来考虑到这一点,谢谢!至于不区分大小写,这是习惯。
                    • 请分享更多细节。该 sn-p 的哪些部分提供随机性?
                    【解决方案17】:

                    如果您需要它以字母开头,您可以这样做。它很乱……但它是一条线。

                    $randomString = substr(str_shuffle("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 1) . substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 10);
                    
                    echo $randomString;
                    

                    【讨论】:

                    • 他从未说过它必须是 alfanumeric
                    • @Alix Axel:你到底是什么意思?
                    • 你不需要第二个 str_shuffle。
                    • 其实可以是字母数字,但是第一个字符需要是字母]
                    • @Alix Axel:字符串左侧不会有数字。 OP 期望它是字母数字,除了第一个字符。从问题的base64 部分可以看出这一点。
                    猜你喜欢
                    • 2011-05-20
                    • 1970-01-01
                    • 2015-08-16
                    • 2014-02-01
                    • 1970-01-01
                    • 2023-04-06
                    • 2012-05-22
                    • 1970-01-01
                    相关资源
                    最近更新 更多