生成随机的5个字符的字符串


102

我想创建精确的5个随机字符串,并尽可能减少重复。最好的方法是什么?谢谢。


2
您有设置特定字符还是仅0-9a-zA-Z
Yanick Rochon

可能会发现此代码高尔夫球挑战:codegolf.stackexchange.com/questions/119226/…–
Titus,

使用,Random::alphanumericString($length)您可以从加密安全的随机数据中获取带有0-9a-zA-Z的字符串。
Caw

Answers:


162
$rand = substr(md5(microtime()),rand(0,26),5);

这将是我最好的猜测-除非您也要寻找特殊字符:

$seed = str_split('abcdefghijklmnopqrstuvwxyz'
                 .'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                 .'0123456789!@#$%^&*()'); // and any other characters
shuffle($seed); // probably optional since array_is randomized; this may be redundant
$rand = '';
foreach (array_rand($seed, 5) as $k) $rand .= $seed[$k];

而且,对于基于时钟的时钟(由于它是递增的,因此冲突较少):

function incrementalHash($len = 5){
  $charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  $base = strlen($charset);
  $result = '';

  $now = explode(' ', microtime())[1];
  while ($now >= $base){
    $i = $now % $base;
    $result = $charset[$i] . $result;
    $now /= $base;
  }
  return substr($result, -5);
}

注意:增量意味着更容易猜测;如果您将其用作盐或验证令牌,请不要使用。盐(现在)为“ WCWyb”表示从现在起5秒钟为“ WCWyg”)


6
使用的问题md5()不过是,你得到了一个16字符集的字符串(10位和af,每串字符即4位)。对于某些目的,这可能就足够了,但对于密码目的而言可能太少了(16个符号中的五个字符= 16 ^ 5 = 20位= 1048576个可能性)。

3
array_rand($seed, 5)将返回数组键,而不是值,因此您的代码将不起作用
alumi

1
我认为使用密码哈希函数生成随机字符至少是不合适的。
gronostaj

是否有可能还包括"'和反斜线$charset?我是否需要使用转义序列来包含那些字符?

1
第二个片段甚至不使用$len输入参数...您忘了吗?
TechNyquist

76

如果for回路供不应求,这是我喜欢使用的方式:

$s = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", 5)), 0, 5);

有趣的解决方案...非常简洁,尽管我想知道这是比使用它快还是慢。虽然不能打扰基准测试:-)
电弧

@matthew str_shuffle将连续产生重复
SCC

@ user2826057:str_shuffle('ab')愿意付出abba但永远不会aa。添加str_repeat允许。但这就是说,我提供的解决方案虽然确实有效,但并不是真正的解决方案。
马修

2
假设RNG均匀分布,则发生这种情况的可能性为1/60466176。
马修

1
这对于我们生成凭单代码的用例来说是完美的。我们删除字符混乱,比如li10O,等,并拿出500个券有没有重复。
路加·考辛斯

25

一种快速的方法是使用uniqid函数的最易变的字符。

例如:

$rand = substr(uniqid('', true), -5);


15

以下内容应提供最小的重复机会(您可能希望mt_rand()用更好的随机数源代替,例如,来自/dev/*random或来自GUID):

<?php
    $characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    $result = '';
    for ($i = 0; $i < 5; $i++)
        $result .= $characters[mt_rand(0, 61)];
?>

编辑:
如果您担心安全性,请不要使用rand()mt_rand(),并确认您的随机数据设备实际上是生成随机数据的设备,而不是常规文件或可预测的东西/dev/zeromt_rand()被认为是有害的:https :
//spideroak.com/blog/20121205114003-exploit-information-leaks-in-random-numbers-from-python-ruby-and-php

编辑: 如果您在PHP中具有OpenSSL支持,则可以使用openssl_random_pseudo_bytes()

<?php
    $length = 5;
    $randomBytes = openssl_random_pseudo_bytes($length);
    $characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    $charactersLength = strlen($characters);
    $result = '';
    for ($i = 0; $i < $length; $i++)
        $result .= $characters[ord($randomBytes[$i]) % $charactersLength];
?>

$ result。= $ characters [mt_rand(0,strlen($ characters)-1)]更聪明的第一个例子
hamboy75'7

在这种情况下,您应该事先确定长度并将其至少存储在变量中。strlen()循环使用是不必要的开销,尤其是如果您已经知道字符集在此期间不会更改的话。

我对此表示怀疑,php已进行了优化,无论如何它都是一种选择:)
hamboy75 '17

7

我总是为此使用相同的功能,通常会生成密码。它易于使用且有用。

function randPass($length, $strength=8) {
    $vowels = 'aeuy';
    $consonants = 'bdghjmnpqrstvz';
    if ($strength >= 1) {
        $consonants .= 'BDGHJLMNPQRSTVWXZ';
    }
    if ($strength >= 2) {
        $vowels .= "AEUY";
    }
    if ($strength >= 4) {
        $consonants .= '23456789';
    }
    if ($strength >= 8) {
        $consonants .= '@#$%';
    }

    $password = '';
    $alt = time() % 2;
    for ($i = 0; $i < $length; $i++) {
        if ($alt == 1) {
            $password .= $consonants[(rand() % strlen($consonants))];
            $alt = 0;
        } else {
            $password .= $vowels[(rand() % strlen($vowels))];
            $alt = 1;
        }
    }
    return $password;
}

好的代码。但是$ alt总是从1变为0。将$ alt随机化会更好吗?
Nico Andrade


3
$str = '';
$str_len = 8;
for($i = 0, $i < $str_len; $i++){
    //97 is ascii code for 'a' and 122 is ascii code for z
    $str .= chr(rand(97, 122));
}
return $str

2

如果您只收到字母AF,那是我的解决方案:

str_pad(dechex(mt_rand(0, 0xFFFFF)), 5, '0', STR_PAD_LEFT);

我相信使用哈希函数对于生成一个随机十六进制数字序列这样的简单任务来说是多余的。dechex+ mt_rand将执行相同的工作,但是没有不必要的加密工作。str_pad保证输出字符串的5个字符的长度(如果随机数小于0x10000)。

重复概率取决于mt_rand的可靠性。Mersenne Twister以高质量的随机性而闻名,因此它应该非常适合这项任务。


2

在想到使用PHP之前,我也不知道该怎么做array。而且我很确定这是用数组生成随机字符串或数字的最简单方法。代码:

function randstr ($len=10, $abc="aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789") {
    $letters = str_split($abc);
    $str = "";
    for ($i=0; $i<=$len; $i++) {
        $str .= $letters[rand(0, count($letters)-1)];
    };
    return $str;
};

您可以像这样使用此功能

randstr(20)     // returns a random 20 letter string
                // Or like this
randstr(5, abc) // returns a random 5 letter string using the letters "abc"

1

Brad Christie的答案类似,但sha1对字符使用alrorithm 0-9a-zA-Z并以随机值作为前缀:

$str = substr(sha1(mt_rand() . microtime()), mt_rand(0,35), 5);

但是,如果您设置了已定义的(允许的)字符:

$validChars = array('0','1','2' /*...*/,'?','-','_','a','b','c' /*...*/);
$validCharsCount = count($validChars);

$str = '';
for ($i=0; $i<5; $i++) {
    $str .= $validChars[rand(0,$validCharsCount - 1)];
}

** 更新 **

正如Archimedix指出的那样,由于给定字符范围的组合数量很少,因此这不能保证返回“复制的可能性最小”。您将需要增加字符数,或在字符串中允许额外的(特殊)字符。我认为,在您的情况下,第一种解决方案会更可取。


使用量time()是可预测性的1百万倍microtime()

还要注意我对Brad答案的评论,更大的问题是,生成的哈希是由16个有效字符组成的十六进制表示形式,因此仅留下1024个变体$str

也许是@Archimedix,但是OP并没有要求安全性,问题被定义为具有由5x26个不同字符组成的字符串生成算法,并避免重复。这可能是在注册过程中确认参考号码(或记账过程),或东西
Yanick罗歇

据我了解,他确实要求复制的可能性最小,这具有0.1%的概率(1024中为1),几乎是十亿分之一。

但是,如果您需要生成5个字符的参考密钥并给您一个客户/客户,则不希望˫§»⁋⅓仅仅因为这样更安全就给他们“ ”,而是将参考密钥增加到7个或更多字符。(顺便说一句:我之前的评论中的更正,是5x36字符)
Yanick Rochon


1

来源:生成随机字符的PHP函数

这个简单的PHP函数为我工作:

function cvf_ps_generate_random_code($length=10) {

   $string = '';
   // You can define your own characters here.
   $characters = "23456789ABCDEFHJKLMNPRTVWXYZabcdefghijklmnopqrstuvwxyz";

   for ($p = 0; $p < $length; $p++) {
       $string .= $characters[mt_rand(0, strlen($characters)-1)];
   }

   return $string;

}

用法:

echo cvf_ps_generate_random_code(5);

1

这是我的random 5 cents...

$random=function($a, $b) {
    return(
        substr(str_shuffle(('\\`)/|@'.
        password_hash(mt_rand(0,999999),
        PASSWORD_DEFAULT).'!*^&~(')),
        $a, $b)
    );
};

echo($random(0,5));

PHP的新功能password_hash()(*> = PHP 5.5)正在完成生成相当长的大小写和数字字符集的工作。

两个连环。password_hash$ random函数之前和之后的字符串都适合更改。

对于Paramteres $random()*($ A,$ b)是实际substr()参数。:)

注意:这不必是一个函数,它也可以是普通变量..作为一个讨厌的单件套,如下所示:

$random=(substr(str_shuffle(('\\`)/|@'.password_hash(mt_rand(0,999999), PASSWORD_DEFAULT).'!*^&~(')), 0, 5));

echo($random);

1
function CaracteresAleatorios( $Tamanno, $Opciones) {
    $Opciones = empty($Opciones) ? array(0, 1, 2) : $Opciones;
    $Tamanno = empty($Tamanno) ? 16 : $Tamanno;
    $Caracteres=array("0123456789","abcdefghijklmnopqrstuvwxyz","ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    $Caracteres= implode("",array_intersect_key($Caracteres, array_flip($Opciones)));
    $CantidadCaracteres=strlen($Caracteres)-1;
    $CaracteresAleatorios='';
    for ($k = 0; $k < $Tamanno; $k++) {
        $CaracteresAleatorios.=$Caracteres[rand(0, $CantidadCaracteres)];
    }
    return $CaracteresAleatorios;
}

专业提示-包括有关您的答案如何解决OP的问题以及为什么它可能与已经提供的其他答案不同的一些说明。
汤姆(Tom),

0

我已经使用此:

<?php function fRand($len) {
    $str = '';
    $a = "abcdefghijklmnopqrstuvwxyz0123456789";
    $b = str_split($a);
    for ($i=1; $i <= $len ; $i++) { 
        $str .= $b[rand(0,strlen($a)-1)];
    }
    return $str;
} ?>

调用时,设置字符串的长度。

<?php echo fRand([LENGHT]); ?>

您还可以更改字符串中可能的字符$a


我看到浪费的时间无所事事地开发了此功能。我用谷歌搜索!@Andrew
LipESprY
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.