我想要创建一个由5个随机字符组成的字符串,最好的方式是减少出现重复的可能性。请问应该怎么做?谢谢。
$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"
md5()
的问题在于,你会得到一个由16个字符组成的字符串(10个数字和a到f,即每个字符4位)。这对于某些目的来说可能足够了,但对于加密目的来说可能太少了(16个符号中的五个字符= 16 ^ 5 = 20位= 1048576个可能性)。 - Arcarray_rand($seed, 5)
返回的是数组键名而非值,因此你的代码可能无法正常运行。 - alumi$charset
中包含双引号 "
, 单引号 '
和反斜杠 \
是可能的吗?我需要使用转义序列来包含这些字符吗? - Mai$len
输入参数...你忘记它了吗? - Niki Romagnoli-$len
。 - Brad Christie如果缺少for
循环,这是我喜欢使用的方法:
$s = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", 5)), 0, 5);
str_shuffle('ab')
会给出ab
或ba
,但永远不会是aa
。添加str_repeat
可以实现这一点。但话说回来,我提供的解决方案并不是一个真正严肃的方案...虽然它确实有效。 - Matthewl
、i
、1
、0
、O
等等,在 500 张优惠券中没有重复的。 - Luke Cousins您可以简单地尝试如下所示:
$length = 5;
$randomletter = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz"), 0, $length);
substr(str_shuffle(implode(range('a', 'z'))), 0, $length)
。 - Ng Sek Long[+1]
- kapitan以下方法应该提供最小的重复机会(你可能想用更好的随机数源替换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/zero
的常规文件或可预测的东西。 mt_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];
?>
strlen()
是不必要的开销,特别是如果你已经知道字符集在此期间不会发生改变。 - Arc我通常使用同一个函数来生成密码,这个函数非常容易使用且有用。
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;
}
看起来str_shuffle可以很好地应用于此。 使用任何您想要的字符来种子洗牌。
$my_rand_strng = substr(str_shuffle("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), -5);
在我想到使用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"
$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
sha1
算法对字符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()
比 microtime()
更可预测,高达100万倍。 - Arc$str
使用。 - Arc˫§»⁋⅓
"交给他们...您可以将参考密钥增加到7个或更多字符。(顺便说一句:在我之前的评论中有一个更正,它是5x36个字符) - Yanick Rochon
0-9a-zA-Z
? - Yanick RochonRandom::alphanumericString($length)
,您可以获取由加密安全随机数据提供的0-9a-zA-Z字符串。 - caw