我知道PHP中的rand函数会生成随机整数,但生成随机字符串的最佳方法是:
原始字符串,9个字符
$string = 'abcdefghi';
示例随机字符串限制为6个字符
$string = 'ibfeca';
更新:我发现了大量这些类型的函数,基本上我正试图理解每一步背后的逻辑。
更新:该函数应根据需要生成任意数量的字符。
如果您回复,请评论部分。
好吧,你没有澄清我在评论中提出的所有问题,但我会假设你想要一个可以带一串“可能”字符和一串字符串返回的函数。为清楚起见,根据要求进行了彻底评论,使用了比我通常更多的变量:
function get_random_string($valid_chars, $length)
{
// start with an empty random string
$random_string = "";
// count the number of chars in the valid chars string so we know how many choices we have
$num_valid_chars = strlen($valid_chars);
// repeat the steps until we've created a string of the right length
for ($i = 0; $i < $length; $i++)
{
// pick a random number from 1 up to the number of valid chars
$random_pick = mt_rand(1, $num_valid_chars);
// take the random character out of the string of valid chars
// subtract 1 from $random_pick because strings are indexed starting at 0, and we started picking at 1
$random_char = $valid_chars[$random_pick-1];
// add the randomly-chosen char onto the end of our string so far
$random_string .= $random_char;
}
// return our finished random string
return $random_string;
}
要使用示例数据调用此函数,您可以将其称为:
$original_string = 'abcdefghi';
$random_string = get_random_string($original_string, 6);
请注意,此函数不会检查传递给它的有效字符的唯一性。例如,如果您使用'AAAB'
的有效字符串字符串调用它,那么为每个字母选择A作为B的可能性是三倍。根据您的需要,可以将其视为错误或功能。
这方面的大多数方面已经讨论过了,但我建议稍作更新:如果您将此用于零售用途,我会避免使用域名ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
而是使用:ABCDEFGHJKMNPQRSTUVWXY3456789
当然,你最终会得到更少的字符,但是它可以节省很多麻烦,因为客户不能将0错误称为O,或者将1错误判断为1或2作为Z.此外,您可以在输入上执行UPPER,然后客户可以输入大写或小写字母 - 这有时也会让人感到困惑,因为它们看起来很相似。
你需要一个随机字符串?
这是否会用于任何远程类似于密码的东西?
如果您的随机字符串完全需要任何安全属性,则应使用PHP 7的random_int()
函数,而不是此线程中所有不安全的mt_rand()
答案。
/**
* Generate a random string
*
* @link https://paragonie.com/b/JvICXzh_jhLyt4y3
*
* @param int $length - How long should our random string be?
* @param string $charset - A string of all possible characters to choose from
* @return string
*/
function random_str($length = 32, $charset = 'abcdefghijklmnopqrstuvwxyz')
{
// Type checks:
if (!is_numeric($length)) {
throw new InvalidArgumentException(
'random_str - Argument 1 - expected an integer'
);
}
if (!is_string($charset)) {
throw new InvalidArgumentException(
'random_str - Argument 2 - expected a string'
);
}
if ($length < 1) {
// Just return an empty string. Any value < 1 is meaningless.
return '';
}
// This is the maximum index for all of the characters in the string $charset
$charset_max = strlen($charset) - 1;
if ($charset_max < 1) {
// Avoid letting users do: random_str($int, 'a'); -> 'aaaaa...'
throw new LogicException(
'random_str - Argument 2 - expected a string at least 2 characters long'
);
}
// Now that we have good data, this is the meat of our function:
$random_str = '';
for ($i = 0; $i < $length; ++$i) {
$r = random_int(0, $charset_max);
$random_str .= $charset[$r];
}
return $random_str;
}
如果您还没有使用PHP 7(可能就是这种情况,因为在撰写本文时尚未发布),那么您将需要paragonie/random_compat,这是用于PHP 5项目的random_bytes()
和random_int()
的用户态实现。
对于安全上下文,请始终使用random_int()
,而不是rand()
,mt_rand()
等。请参阅ircmaxell's answer。
// @author http://codeascraft.etsy.com/2012/07/19/better-random-numbers-in-php-using-devurandom/
function devurandom_rand($min = 0, $max = 0x7FFFFFFF)
{
$diff = $max - $min;
if ($diff < 0 || $diff > 0x7FFFFFFF) {
throw new RuntimeException('Bad range');
}
$bytes = mcrypt_create_iv(4, MCRYPT_DEV_URANDOM);
if ($bytes === false || strlen($bytes) != 4) {
throw new RuntimeException('Unable to get 4 bytes');
}
$ary = unpack('Nint', $bytes);
$val = $ary['int'] & 0x7FFFFFFF; // 32-bit safe
$fp = (float) $val / 2147483647.0; // convert to [0,1]
return round($fp * $diff) + $min;
}
function build_token($length = 60, $characters_map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
$map_length = mb_strlen($characters_map)-1;
$token = '';
while ($length--) {
$token .= mb_substr($characters_map, devurandom_rand(0,$map_length),1);
}
return $token;
}
这仅适用于使用mcrypt
编译PHP的UNIX环境。
您想通过原始字母的随机排列来创建密码吗?它应该只包含独特的字符吗?
使用rand
按索引选择随机字母。
这是一个老问题,但我想尝试发布我的解决方案...我总是用我的函数生成一个自定义的随机字母数字字符串...
<?php
function random_alphanumeric($length) {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345689';
$my_string = '';
for ($i = 0; $i < $length; $i++) {
$pos = mt_rand(0, strlen($chars) -1);
$my_string .= substr($chars, $pos, 1);
}
return $my_string;
}
$test = random_alphanumeric(50); // 50 characters
echo $test;
?>
测试:UFOruSSTCPIqxTRIIMTRkqjOGidcVlhYaS9gtwttxglheVugFM
如果您需要两个或更多独特的字符串,您可以使用此技巧...
$string_1 = random_alphanumeric(50);
$string_2 = random_alphanumeric(50);
while ($string_1 == $string_2) {
$string_1 = random_alphanumeric(50);
$string_2 = random_alphanumeric(50);
if ($string_1 != $string_2) {
break;
}
}
echo $string_1;
echo "<br>\n";
echo $string_2;
$ string_1:tMYicqLCHEvENwYbMUUVGTfkROxKIekEB2YXx5FHyVByp3mlJO
$ string_2:XdMNJYpMlFRKFDlF6GhVn6jsBVNQ1BCCevj8yK2niFOgpDI2MU
我希望这有帮助。
echo substr(bin2hex(random_bytes(14)), 0, $length);
此代码获取一个随机字节,从二进制转换为十六进制,然后获取此十六进制字符串的子字符串,只要您输入$ length变量
您可以创建一个字符数组,然后使用rand()从数组中选取一个字母并将其添加到字符串中。
$letters = array( [0] => 'a' [1] => 'b' [2] => 'c' [3] => 'd' ... [25] = 'z');
$lengthOfString = 10;
$str = '';
while( $lengthOfString-- )
{
$str .= $letters[rand(0,25)];
}
echo $str;
*请注意,这确实允许重复字符
这建立在Gumbo's solution的基础上,通过添加功能来列出要在基本字符集中跳过的一组字符。随机字符串选择$base_charset
中的字符,这些字符也不会出现在$skip_charset
中。
/* Make a random string of length using characters from $charset, excluding $skip_chars.
* @param length (integer) length of return value
* @param skip_chars (string) characters to be excluded from $charset
* @param charset (string) characters of posibilities for characters in return val
* @return (string) random string of length $length */
function rand_string(
$length,
$skip_charset = '',
$base_charset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'){
$skip_len = strlen($skip_charset);
for ($i = 0; $i<$skip_len; $i++){
$base_charset = str_replace($skip_charset[$i], '', $base_charset);
}
cvar_dump($base_charset, '$base_charset after replace');
$str = '';
$count = strlen($base_charset);
while ($length--) {
$str .= $base_charset[mt_rand(0, $count - 1)];
}
return $str;
}
以下是一些使用示例。前两个示例使用$base_charset
的默认值。最后一个示例明确定义了$base_charset
。
echo rand_string(15, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
// 470620078953298
echo rand_string(8, 'abcdefghijklmnopqrstuvwxyz0123456789');
// UKLIHOTFSUZMFPU
echo rand_string(15, 'def', 'abcdef');
// cbcbbccbabccaba
好吧,我正在寻找一个解决方案,而且我使用@Chad Birch的解决方案与@Gumbo的解决方案合并。这就是我想出的:
function get_random_string($length, $valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456790!·$%&/()=?¿¡',.-;:+*`+´ç")
{
$random_string = "";
$num_valid_chars = strlen($valid_chars);
for ($i = 0; $i < $length; $i++, $random_string .= $valid_chars[mt_rand(1, $num_valid_chars)-1]);
return $random_string;
}
我认为评论几乎没有必要,因为我用来构建这个评论的答案已经被彻底评论过了。干杯!
如果您不关心时间,内存或CPU效率,如果您的系统可以处理它,为什么不尝试这个算法?!
function randStr($len, $charset = 'abcdABCD0123') {
$out = '';
$str = array();
for ($i = 0; $i < PHP_INT_MAX; $i++) {
$str[$i] = $charset;
shuffle($str);
$charset .= implode($charset, $str);
$charset = str_shuffle($charset);
}
$str = array_flip($str);
$str = array_keys($str);
for ($i = 0; $i < PHP_INT_MAX; $i++) {
shuffle($str);
}
$str = implode('', $str);
for ($i = 0; $i < strlen($str); $i++) {
$index = mt_rand(1, strlen($str));
$out .= $str[$index - 1];
}
for ($i = 0; $i < PHP_INT_MAX; $i++) {
$out = str_shuffle($out);
}
return substr($out, 0, $len);
}
如果它使用递归,也许这会更好读,但我不确定PHP是否使用尾递归...
如果要允许重复出现字符,可以使用此功能:
function randString($length, $charset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
{
$str = '';
$count = strlen($charset);
while ($length--) {
$str .= $charset[mt_rand(0, $count-1)];
}
return $str;
}
基本算法是生成<length>次0和<字符数之间的随机数> - 1我们用作索引从我们的集合中选择一个字符并连接这些字符。 0和<字符数> - 1个边界表示$charset
字符串的边界,因为第一个字符用$charset[0]
处理,最后一个字符用$charset[count($charset) - 1]
处理。
我的最爱:
echo substr(md5(rand()), 0, 7);
所以,让我先说一下USE A LIBRARY。许多存在:
问题的核心几乎是本页面中的每个答案都容易受到攻击。 mt_rand()
,rand()
,lcg_value()
和uniqid()
都是vulnerable to attack。
一个好的系统将使用文件系统中的/dev/urandom
,或mcrypt_create_iv()
(使用MCRYPT_DEV_URANDOM
)或openssl_pseudo_random_bytes()
。以上所有都做了。 PHP 7 will come with two new functions random_bytes($len)
和random_int($min, $max)
也很安全。
请注意,大多数这些函数(random_int()
除外)都返回“原始字符串”,这意味着它们可以包含来自0 - 255
的任何ASCII字符。如果你想要一个可打印的字符串,我建议你通过base64_encode()
运行结果。
function generate_random_string($name_length = 8) {
$alpha_numeric = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
return substr(str_shuffle(str_repeat($alpha_numeric, $name_length)), 0, $name_length);
}
根据mzhang在下面的评论中的重要建议更新了代码。
@ taskamiski的更好和更新版本的优秀答案:
更好的版本,使用mt_rand()
而不是rand()
:
echo md5(mt_rand()); // 32 char string = 128bit
更好的是,对于更长的字符串,使用允许选择散列算法的hash()
函数:
echo hash('sha256', mt_rand()); // 64 char string
echo hash('sha512', mt_rand()); // 128 char string
如果你想减少结果让我们说50个字符,那就这样做:
echo substr(hash('sha256', mt_rand()), 0, 50); // 50 char string
最后加入字符应该比重复字符串连接更有效。
编辑#1:添加选项以避免字符重复。
编辑#2:如果选择了$ norepeat并且$ len大于要选择的字符集,则抛出异常以避免进入无限循环。
编辑#3:当选择$ norepeat时,使用数组键存储拾取的随机字符,因为关联数组键查找比线性搜索数组更快。
function rand_str($len, $norepeat = true)
{
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$max = strlen($chars) - 1;
if ($norepeat && len > $max + 1) {
throw new Exception("Non repetitive random string can't be longer than charset");
}
$rand_chars = array();
while ($len) {
$picked = $chars[mt_rand(0, $max)];
if ($norepeat) {
if (!array_key_exists($picked, $rand_chars)) {
$rand_chars[$picked] = true;
$len--;
}
}
else {
$rand_chars[] = $picked;
$len--;
}
}
return implode('', $norepeat ? array_keys($rand_chars) : $rand_chars);
}
这将生成随机字符串
function generateRandomString($length=10) {
$original_string = array_merge(range(0,9), range('a','z'), range('A', 'Z'));
$original_string = implode("", $original_string);
return substr(str_shuffle($original_string), 0, $length);
}
echo generateRandomString(6);
我想我也会在这里添加我的贡献。
function random_string($length) {
$bytes_1 = openssl_random_pseudo_bytes($length);
$hex_1 = bin2hex($bytes_1);
$random_numbers = substr(sha1(rand()), 0, $length);
$bytes_2 = openssl_random_pseudo_bytes($length);
$hex_2 = bin2hex($bytes_2);
$combined_chars = $hex_1 . $random_numbers . $hex_2;
$chars_crypted = hash('sha512', $combined_chars);
return $chars_crypted;
}
谢谢