一行PHP随机字符串生成器?

40

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

$cClass = sha1(time());
或者
$cClass = md5(time());

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

有什么一行代码的最佳方法来实现这一点?


更新:

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

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

会生成32个字符,模拟 MD5 哈希值,但它总是会让第一个字符成为英文字母,如下所示:

solution 1

然而,Uours 进一步改进了他的答案;

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

更简短更甜美

另一个由Anonymous2011提出的建议非常棒,但是由于某些原因,第一个字符总是 M、N、Y、Z,所以不符合我的要求,否则这会是最佳答案。顺便问一下,有人知道为什么它总是产生这些特定的字母吗?

以下是我修改后的预览

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

亚军


17
为什么需要在一行代码内完成? - SamT
如果你们想知道为什么第一个字母是这样的,那么我正在测试 div 元素...类或 ID 不接受以数字开头的字符,也不接受任何特殊字符。 - David Garcia
前缀为下划线 _0000 是有效的。 - Alix Axel
return "_0000" . sha1(time()); - 通过简单的字符串连接前缀 - Kai Qing
18个回答

30

与其打乱字母字符串,获取单个随机字符更快。

从字符串中获取单个随机字符,然后将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 );

1
第一个字符有可能是数字吗?我已经执行了大约50次,第一个字符都是数字,但其中一次出现了“30128fb9b80c5697a4a3954b96e1295”。 - David Garcia
1
除非 mt_rand 中的值不正确,否则我看不出任何原因。我认为应该是 mt_rand(0, 50)。之前是 mt_rand(0, 51) - Uours
1
也许你是对的,第一个字符是0,我现在只会使用小写字母,因为字母表有26个字母,所以最大参数应该是25。 - David Garcia
1
通过我的修正方案,我已经生成了 100,000 个字符串,其中没有一个以数字字符开头。我已经对 100,000 个字符串进行了小写解决方案的测试,该解决方案似乎完美无缺。 - Uours
太棒了,你用什么生成字符串的工具?另外,我想知道如何对这些代码进行性能基准测试?有什么建议吗?谢谢。 - David Garcia
显示剩余2条评论

29

我找到了类似这样的东西:

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

这个版本比上面的好,因为它总是独一无二的,并且包含字符长度。 - mrmut

6
我决定这个问题需要一个更好的答案。就像代码高尔夫一样!这也使用了一个更好的随机字节生成器。
preg_replace("/[\/=+]/", "", base64_encode(openssl_random_pseudo_bytes(8)));

显然,增加密码的字节数可以使密码更长。


1
你可以使用 str_replace(array('/', '=', '+'), '', ...,这可能会更快。 - Rudie

6
如果您需要以字母开头,您可以这样做。虽然有点混乱,但只需一行即可。
$randomString = substr(str_shuffle("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 1) . substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 10);

echo $randomString;

他从未说过它需要是字母数字组合。 - Alix Axel
@Alix Axel:你实际上是什么意思? - zerkms
实际上它可以是字母数字,但第一个字符必须是字母。 - David Garcia
@JoseDavidGarciaLlanos:可以不等于必须不等于。 - Alix Axel
1
@Alix Axel:那么左侧字符串中就不会有数字。 OP 期望它除了第一个字符之外都是字母数字的。这从问题中的“base64”部分是显而易见的。 - zerkms
显示剩余6条评论

4
创建一个200个字符长的十六进制字符串:
$string = bin2hex(openssl_random_pseudo_bytes(100));

maaarghk's answer is better though.


3
你可以尝试这样做:
 function KeyGenerator($uid) {
    $tmp = '';
    for($z=0;$z<5;$z++) {
      $tmp .= chr(rand(97,122)) . rand(0,100);
    }
    $tmp .= $uid;
    return $tmp;
  }

3

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


请分享更多细节。那段代码片段的哪些部分提供了随机性? - Nico Haase

2
我已经为您生成了这段代码。它简单、短小并且(相对)优雅。
如您所提到的,此代码使用了base64。但是,如果长度不重要,它会使用str_replace来去除“==”。
<?php
        echo  str_ireplace("==", "", base64_encode(time()));
?>

1
用 rtrim() 代替吧! - Alix Axel
2
我同意使用rtrim(),而且据我最后一次检查,==没有大小写版本。那么为什么要使用不区分大小写的替换呢? - cryptic ツ
我以前不知道 rtrim() 函数 - 我会在将来考虑使用,谢谢!至于大小写不敏感,那是我的习惯。 - RobAtStackOverflow
请分享更多细节。那个片段的哪些部分提供了随机性? - Nico Haase

2

I use this function

usage:

 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;
  }

2
回显改进(常量(阿里克斯),真); --- 它抛出了 MayBeAnotherDay 异常 :-( - zerkms
@EmilioGort:我想撤回我的踩票,但是你真的读了问题和/或运行了你的代码吗? - Alix Axel
@EmilioGort:你有没有在变量前加上 $,字符串没有用双引号或单引号括起来,而且 OP 要求的解决方案不能以数字开头。 - Alix Axel
1
@JoseDavidGarciaLlanos:OP = 原帖发布者 = 你。=) - Alix Axel
1
@EmilioGort:我从未说过它需要。你可以直接放弃它。 - Alix Axel
显示剩余18条评论

1
要生成由随机字符组成的字符串,您可以使用此函数。
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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接