I want to create exact 5 random characters string with least possibility of getting duplicated. What would be the best way to do it? Thanks.
18 Answers
$rand = substr(md5(microtime()),rand(0,26),5);
Would be my best guess--Unless you're looking for special characters, too:
$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];
And, for one based on the clock (fewer collisions since it's incremental):
function incrementalHash($len = 5){
$charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
$base = strlen($charset);
$result = '';
$now = explode(' ', microtime())[1];
while ($now >= $base){
$i = (int)$now % $base;
$result = $charset[$i] . $result;
$now /= $base;
}
return substr(str_repeat($charset[0], $len) . $result, -$len);
}
Note: incremental means easier to guess; If you're using this as a salt or a verification token, don't. A salt (now) of "WCWyb" means 5 seconds from now it's "WCWyg")
6 Comments
md5() however is that you get a string made of a 16-character set (10 digits and a to f, i.e. 4 bits per string character). This may be enough for some purposes but may be too little for cryptographical purposes (five characters out of 16 symbols = 16^5 = 20 bits = 1048576 possibilities).array_rand($seed, 5) will return array key, not value, so your code won't work", ' and backslash in $charset? Do I need to use escape sequences to include those characters?$len input param...did you forget it?If for loops are on short supply, here's what I like to use:
$s = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", 5)), 0, 5);
9 Comments
str_shuffle('ab') would give ab or ba but never aa. Adding the str_repeat allows for that. But that said, the solution I gave is not really a serious one... although it does work.l, i, 1, 0, O, etc and out of 500 vouchers got no duplicates.You can try it simply like this:
$length = 5;
$randomletter = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz"), 0, $length);
more details: http://forum.arnlweb.com/viewtopic.php?f=7&t=25
2 Comments
substr(str_shuffle(implode(range('a', 'z'))), 0, $length)[+1]A speedy way is to use the most volatile characters of the uniqid function.
For example:
$rand = substr(uniqid('', true), -5);
2 Comments
The following should provide the least chance of duplication (you might want to replace mt_rand() with a better random number source e.g. from /dev/*random or from GUIDs):
<?php
$characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$result = '';
for ($i = 0; $i < 5; $i++)
$result .= $characters[mt_rand(0, 61)];
?>
EDIT:
If you are concerned about security, really, do not use rand() or mt_rand(), and verify that your random data device is actually a device generating random data, not a regular file or something predictable like /dev/zero. mt_rand() considered harmful:
https://spideroak.com/blog/20121205114003-exploit-information-leaks-in-random-numbers-from-python-ruby-and-php
EDIT:
If you have OpenSSL support in PHP, you could use 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];
?>
3 Comments
strlen() in a loop is unnecessary overhead, especially if you already know that the character set is not going to change in the meantime.I always use the same function for this, usually to generate passwords. It's easy to use and useful.
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;
}
1 Comment
It seems like str_shuffle would be a good use for this. Seed the shuffle with whichever characters you want.
$my_rand_strng = substr(str_shuffle("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), -5);
1 Comment
I also did not know how to do this until I thought of using PHP array's. And I am pretty sure this is the simplest way of generating a random string or number with array's. The code:
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;
};
You can use this function like this
randstr(20) // returns a random 20 letter string
// Or like this
randstr(5, abc) // returns a random 5 letter string using the letters "abc"
Comments
Similar to Brad Christie's answer, but using sha1 alrorithm for characters 0-9a-zA-Z and prefixed with a random value :
$str = substr(sha1(mt_rand() . microtime()), mt_rand(0,35), 5);
But if you have set a defined (allowed) characters :
$validChars = array('0','1','2' /*...*/,'?','-','_','a','b','c' /*...*/);
$validCharsCount = count($validChars);
$str = '';
for ($i=0; $i<5; $i++) {
$str .= $validChars[rand(0,$validCharsCount - 1)];
}
** UPDATE **
As Archimedix pointed out, this will not guarantee to return a "least possibility of getting duplicated" as the number of combination is low for the given character range. You will either need to increase the number of characters, or allow extra (special) characters in the string. The first solution would be preferable, I think, in your case.
6 Comments
time() is up to 1 million times more predictable than microtime().$str.˫§»⁋⅓" simply because it's more secure... you increase your reference key to 7 or more characters. (BTW: correction in my previous comment, it's 5x36 characters)If it's fine that you'll get only letters A-F, then here's my solution:
str_pad(dechex(mt_rand(0, 0xFFFFF)), 5, '0', STR_PAD_LEFT);
I believe that using hash functions is an overkill for such a simple task as generating a sequence of random hexadecimal digits. dechex + mt_rand will do the same job, but without unnecessary cryptographic work. str_pad guarantees 5-character length of the output string (if the random number is less than 0x10000).
Duplicate probability depends on mt_rand's reliability. Mersenne Twister is known for high-quality randomness, so it should fit the task well.
Comments
works fine in PHP (php 5.4.4)
$seed = str_split('abcdefghijklmnopqrstuvwxyz');
$rand = array_rand($seed, 5);
$convert = array_map(function($n){
global $seed;
return $seed[$n];
},$rand);
$var = implode('',$convert);
echo $var;
Comments
Source: PHP Function that Generates Random Characters
This simple PHP function worked for me:
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;
}
Usage:
echo cvf_ps_generate_random_code(5);
Comments
Here are my 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's new password_hash() (* >= PHP 5.5) function is doing the job for generation of decently long set of uppercase and lowercase characters and numbers.
Two concat. strings before and after password_hash within $random function are suitable for change.
Paramteres for $random() *($a,$b) are actually substr() parameters. :)
NOTE: this doesn't need to be a function, it can be normal variable as well .. as one nasty singleliner, like this:
$random=(substr(str_shuffle(('\\`)/|@'.password_hash(mt_rand(0,999999), PASSWORD_DEFAULT).'!*^&~(')), 0, 5));
echo($random);
Comments
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;
}
1 Comment
I`ve aways use this:
<?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;
} ?>
When you call it, sets the lenght of string.
<?php echo fRand([LENGHT]); ?>
You can also change the possible characters in the string $a.
1 Comment
Simple one liner which includes special characters:
echo implode("", array_map(function() {return chr(mt_rand(33,126));}, array_fill(0,5,null)));
Basically, it fills an array with length 5 with null values and replaces each value with a random symbol from the ascii-range and as the last, it joins them together t a string.
Use the 2nd array_fill parameter to control the length.
It uses the ASCII Table range of 33 to 126 which includes the following characters:
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
0-9a-zA-Z?Random::alphanumericString($length)you can get strings with 0-9a-zA-Z that are sourced from cryptographically secure random data.