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.
-
2do you have a set a specific characters or only `0-9a-zA-Z` ? – Yanick Rochon Mar 25 '11 at 22:35
-
This code golf challenge could be a find: https://codegolf.stackexchange.com/questions/119226/make-me-a-password-generator – Titus May 06 '17 at 08:55
-
Using [`Random::alphanumericString($length)`](https://github.com/delight-im/PHP-Random) you can get strings with 0-9a-zA-Z that are sourced from cryptographically secure random data. – caw Nov 20 '19 at 16:08
17 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 = $now % $base;
$result = $charset[$i] . $result;
$now /= $base;
}
return substr($result, -5);
}
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")

- 100,477
- 16
- 156
- 200
-
6The problem with using `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). – Arc Mar 26 '11 at 02:39
-
3`array_rand($seed, 5)` will return array key, not value, so your code won't work – alumi May 28 '13 at 17:30
-
1I think that using a *cryptographic hash function* to generate random characters is at least inappropriate. – gronostaj Jul 17 '13 at 20:13
-
Is it possible also to include `"`, `'` and backslash in `$charset`? Do I need to use escape sequences to include those characters? – Mai Mar 02 '15 at 01:52
-
1The second snippet does not even use the `$len` input param...did you forget it? – Niki Romagnoli Nov 23 '15 at 17:13
-
@TechNyquist heh, oops. I think copy-paste error. Length is moot given its a hash of time value (length will be determined based on clock), though I suppose you could left pad the value if it were too short. Could also use `-$len` in return too. – Brad Christie Nov 23 '15 at 17:22
If for
loops are on short supply, here's what I like to use:
$s = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", 5)), 0, 5);

- 47,584
- 11
- 86
- 98
-
Interesting solution... very concise, though I wonder about whether this is faster or slower than using for. Can't be bothered to benchmark though :-) – Arc Mar 26 '11 at 02:43
-
-
@user2826057: `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. – Matthew Apr 05 '14 at 00:01
-
@Matthew When running this script second time , It generate the same code as first time – SCC Apr 05 '14 at 05:42
-
2There is a 1/60466176 chance of that happening, assuming the RNG is uniformly distributed. – Matthew Apr 05 '14 at 18:24
-
1This is perfect for our use case of generating voucher codes. We removed confusing chars, like `l`, `i`, `1`, `0`, `O`, etc and out of 500 vouchers got no duplicates. – Luke Cousins Sep 16 '14 at 09:16
-
Chance would decrease more (1/916132832) if you included `A-Z` too. I used it to generate a 22 digit character string. – Muntashir Akon Nov 15 '16 at 06:18
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,958
- 1
- 31
- 45

- 500
- 4
- 5
-
2Can be a little bit make clear with `substr(str_shuffle(implode(range('a', 'z'))), 0, $length)` – Ng Sek Long Sep 15 '22 at 03:46
-
A speedy way is to use the most volatile characters of the uniqid function.
For example:
$rand = substr(uniqid('', true), -5);

- 54,048
- 11
- 129
- 129
-
-
1@gumuruh The question was "…create exact 5 random characters string…", so passing -5 as the offset arg to substr will use the _last_ five characters in the string. As per the PHP docs… "If offset is negative, the returned string will start at the offset'th character from the end of string." – John Parker Dec 07 '21 at 11:06
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];
?>

- 11,143
- 4
- 52
- 75
-
First example more clever with $result .= $characters[mt_rand(0, strlen($characters)-1)] – Hamboy75 Jul 05 '17 at 20:31
-
In that case you should determine the length beforehand and store it in a variable at least. Using `strlen()` in a loop is unnecessary overhead, especially if you already know that the character set is not going to change in the meantime. – Arc Jul 06 '17 at 12:35
-
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);
-
both good up to php t : http://php.net/manual/en/function.substr.php http://php.net/manual/en/function.str-shuffle.php – Jun 22 '17 at 21:09
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;
}

- 2,591
- 3
- 25
- 36
-
Nice code. However $alt always flips from one to 0. Wouldn't it be better to randomize $alt instead? – Nico Andrade Mar 28 '17 at 22:49
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"
$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

- 4,501
- 5
- 31
- 35
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.

- 2,231
- 2
- 23
- 43
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.

- 1
- 1

- 51,409
- 25
- 133
- 214
-
Using `time()` is up to 1 million times more predictable than `microtime()`. – Arc Mar 26 '11 at 00:18
-
Also note my comments to Brad's answer, the bigger issue is that the generated hash is a hexadecimal representation consisting of 16 valid characters, therefore leaving only 1024 variations for `$str`. – Arc Mar 26 '11 at 00:34
-
@Archimedix, perhaps, but the OP didn't ask for security, the question was defined to have string generating algorithm consisting of a combination of 5x26 different characters, and avoiding duplicates. This is probably for a confirmation reference number in a registration process (or billing process), or something – Yanick Rochon Mar 26 '11 at 01:24
-
It was my understanding that he *did* ask for *least possibility of getting duplicated*, and this has 0.1% probability (1 in 1024) which could have been almost 1 in 1 billion. – Arc Mar 26 '11 at 01:38
-
however, if you need to generate a reference key of 5 characters and give that you a client/customer, you don't want to give them "`˫§»⁋⅓`" 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) – Yanick Rochon Mar 26 '11 at 02:09
-
No, but he said that 0 - 9, a - z and A - Z were valid characters, making a set of 62 symbols, i.e. 62^5 possiblities. Oh, and sorry, my calculation was way wrong... it's not 1024 possibilities when using hex digits but 16^5 = 1048576. – Arc Mar 26 '11 at 02:37
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;

- 19
- 2
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);

- 805
- 12
- 24
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);

- 1,235
- 15
- 17
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;
}
-
Pro tip - Include some explanation about how your answer solves the OP's problem, and why it might be different to the other answers already provided. – Tom Mar 24 '17 at 15:57
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
.

- 291
- 2
- 8
-
I see that lost time idly developing this function. I googled little! @Andrew – LipESprY May 11 '16 at 05:25
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{|}~

- 2,690
- 1
- 26
- 51