Reputation: 10753
I'm trying to create a randomized string in PHP, and I get absolutely no output with this:
<?php
function RandomString()
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randstring = '';
for ($i = 0; $i < 10; $i++) {
$randstring = $characters[rand(0, strlen($characters))];
}
return $randstring;
}
RandomString();
echo $randstring;
What am I doing wrong?
Upvotes: 1026
Views: 1861959
Reputation: 623
One-liner for PHP 7+ with $length
being the desired result string length
substr(bin2hex(random_bytes(intval(ceil($length / 2.0)))), 0, $length)
Upvotes: 0
Reputation: 25765
To answer this question specifically, two problems:
$randstring
is not in scope when you echo it.Here's a code snippet with the corrections:
function generateRandomString($length = 10) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[random_int(0, $charactersLength - 1)];
}
return $randomString;
}
Output the random string with the call below:
// Echo the random string.
echo generateRandomString();
// Optionally, you can give it a desired string length.
echo generateRandomString(64);
Please note that previous version of this answer used
rand()
instead ofrandom_int()
and therefore generated predictable random strings. So it was changed to be more secure, following advice from this answer.
Upvotes: 1690
Reputation: 894
Here's my simple one line solution to generate a use friendly random password, excluding the characters that lookalike such as "1" and "l", "O" and "0", "5" and "S", etc... this example generates 5 characters string but you can easily change it by modifyling the last variable:
$user_password = substr(str_shuffle('abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRTUVWXYZ2346789'),0,5);
It's obviously not the most secure solution as it has a limited amount of different characters and each can only be used once in the output, but a 5 character long string will still allow over 311 million combinations, and a 7 character long over 674 billion combinations, etc, so it's still an elegent, user-friendly, super light and easy to use method for non-critical uses.
Upvotes: 19
Reputation: 21620
Starting from php8.3 you can do this:
$rng = new Random\Randomizer();
$crockfordAlphabet = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
$rng->getBytesFromString($crockfordAlphabet, 10); // "5YH837JSJT"
Upvotes: 8
Reputation: 898
Please, try this my function to generate a custom random alphanumeric string:
<?php
function random_alphanumeric($length) {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345689';
$my_string = '';
for ($i = 0; $i < $length; $i++) {
$pos = random_int(0, strlen($chars) -1);
$my_string .= substr($chars, $pos, 1);
}
return $my_string;
}
?>
You can adjust the result by passing the length of the string to the function like below:
$test_with_50_items = random_alphanumeric(50); // 50 characters
echo $test_with_50_items;
Example (test_with_50_items): Y1FypdjVbFCFK6Gh9FDJpe6dciwJEfV6MQGpJqAfuijaYSZ86
If you need more than 50 chars or less simply call the function how you like:
$test_with_27_items = random_alphanumeric(27); // 27 characters
echo $test_with_27_items;
If you need two or more unique strings you can do by loop using while
so you are sure to get two unique strings... you can do the same with more strings, the only limit is your fantasy...
$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: KkvUwia8rbDEV2aChWqm3AgeUZqyrRbUx2AxVhx5s4TSJ2VwA4
$string_2: XraO85YfxBBCInafvwipSOJwLmk6JMWiuWOxYQDnXohcn2D8K6
According to PHP 8.3 random_int() is "secure by default"
Upvotes: 0
Reputation: 359
I wanted pseudorandom strings of specific characters and a preset length. I wanted the highest quality pseudorandomness practically possible for the current version of PHP, at this time it could be v5, v6, v7, or v8, and it could be using default configuration or special. To tame this chaos, I sampled several of the other answers here and included function availability conditionals.
Usage. To use it globally assign $VALID_ID_CHARS
with whatever characters you want and then call it:
$VALID_ID_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
$myNewRandomId = makeId(6);
function makeId($desiredLen)
{
global $VALID_ID_CHARS;
if ($desiredLen < 1) {
throw new \RangeException("Length must be a positive integer");
}
$vLen = 0;
if (function_exists('mb_strlen')) {
$vLen = mb_strlen($VALID_ID_CHARS, '8bit') - 1;
} else {
$vLen = strlen($VALID_ID_CHARS) - 1;
}
if (function_exists('random_int')) {
$pieces = [];
for ($i = 0; $i < $desiredLen; ++$i) {
$pieces[] = $VALID_ID_CHARS[random_int(0, $vLen)];
}
return implode('', $pieces);
}
if (function_exists('openssl_random_pseudo_bytes')) {
$random = openssl_random_pseudo_bytes($desiredLen);
$id = '';
for ($i = 0; $i < $desiredLen; ++$i) {
$id .= $VALID_ID_CHARS[ord($random[$i]) % $vLen];
}
return $id;
}
http_response_code(500);
die('random id generation failed. either random_int or openssl_random_pseudo_bytes is needed');
}
Upvotes: 0
Reputation: 329
recursive solution:
public static function _random(string $set , int $length): string
{
$setLength = strlen($set);
$randomKey = random_int(0, $setLength - 1);
$firstPiece = substr($set, 0, $randomKey);
$secondPiece = substr($set, $randomKey, $setLength - $randomKey);
$removedCharacter = $firstPiece[strlen($firstPiece) - 1] ?? null;
if(null === $removedCharacter || $length === 0) {
return '';
}
$firstPieceWithoutTheLastChar = substr($firstPiece, 0, -1);
return $removedCharacter . self::_random($firstPieceWithoutTheLastChar . $secondPiece, $length - 1);
}
nice performance , https://3v4l.org/aXaJ6/perf
Upvotes: 0
Reputation: 111
Laravel solution: If you are using Laravel Framework, you can use its StringHelper like this.
use Illuminate\Support\Str;
Str::random($strlentgh = 16)
Upvotes: 0
Reputation: 763
function gen_uid($l=5){
return substr(str_shuffle("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), 10, $l);
}
echo gen_uid();
Default Value[5]: WvPJz
echo gen_uid(30);
Value[30]: cAiGgtf1lDpFWoVwjykNKXxv6SC4Q2
Upvotes: 14
Reputation: 836
A full solution (class plus test), partly based on some suggestions above...
class TokenFactory
{
private const LENGTH = 12;
private const ALLOWED = '123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ~!@#$%^&*{}';
private const MIN_NUMBER_OF_DIGITS = 1;
private const MIN_NUMBER_OF_CAPS = 1;
private const MIN_NUMBER_OF_SPECIALS = 1;
private const MIN_NUMBER_OF_LETTERS = 1;
/**
* @return string
* @throws \Exception
*/
public function make(): string
{
$pass = $this->generateToken();
if ($this->isTokenValid($pass)) {
return $pass;
} else {
return $this->make();
}
}
/**
* @return string
* @throws \Exception
*/
private function generateToken(): string
{
$allowedCharacters = self::ALLOWED;
$token = '';
$max = mb_strlen($allowedCharacters, '8bit') - 1;
for ($i = 0; $i < self::LENGTH; ++$i) {
$token .= $allowedCharacters[random_int(0, $max)];
}
return $token;
}
/**
* @param $token
* @return bool
*/
private function isTokenValid($token): bool
{
$numberOfDigits = preg_match_all("/[0-9]/", $token);
$numberOfCaps = preg_match_all("/[A-Z]/", $token);
$numberOfSpecials = preg_match_all("/[~!@#\$%^&*{}]/", $token);
$numberOfLetters = preg_match_all("/[a-z]/", $token);
return
$numberOfDigits > self::MIN_NUMBER_OF_DIGITS
&& $numberOfCaps > self::MIN_NUMBER_OF_CAPS
&& $numberOfSpecials > self::MIN_NUMBER_OF_SPECIALS
&& $numberOfLetters > self::MIN_NUMBER_OF_LETTERS
;
}
}
class TokenFactoryTest
{
public function test_correct_syntax()
{
/**
* Arrange
*/
$length = 12;
$numberOfChecks = 1000;
/**
* Act & Assert
*/
$class = new TokenFactory();
$i = 0;
while ($i < $numberOfChecks) {
$generatedToken = $class->make();
$numberOfDigits = preg_match_all( "/[0-9]/", $generatedToken );
$numberOfCaps = preg_match_all( "/[A-Z]/", $generatedToken );
$numberOfSpecials = preg_match_all("/[~!@#\$%^&*{}]/", $generatedToken);
$numberOfLetters = preg_match_all("/[a-z]/", $generatedToken);
Assert::assertEquals($length, strlen($generatedToken));
Assert::assertTrue($numberOfDigits >= 1, 'Digit error: ' . $generatedToken);
Assert::assertTrue($numberOfCaps >= 1, 'Caps error: ' . $generatedToken);
Assert::assertTrue($numberOfSpecials >= 1, 'Specials error: ' . $generatedToken);
Assert::assertTrue($numberOfLetters >= 1, 'Letters error: ' . $generatedToken);
$i++;
}
}
}
BTW make sure to catch that exception somewhere where it suits your needs!
Upvotes: 0
Reputation: 2032
//generateRandomString http://stackoverflow.com/questions/4356289/php-random-string-generator
function randomString($length = 32, $string= "0123456789abcdefghijklmnopqrstuvwxyz" ) {
//$string can be:
//0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
//0123456789abcdefghijklmnopqrstuvwxyz
return substr(str_shuffle( $string), 0, $length);
}
Upvotes: 3
Reputation: 313
function generateRandomString($length = 10, $hasNumber = true, $hasLowercase = true, $hasUppercase = true): string
{
$string = '';
if ($hasNumber)
$string .= '0123456789';
if ($hasLowercase)
$string .= 'abcdefghijklmnopqrstuvwxyz';
if ($hasUppercase)
$string .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
return substr(str_shuffle(str_repeat($x = $string, ceil($length / strlen($x)))), 1, $length);
}
and use:
echo generateRandomString(32);
Upvotes: 4
Reputation: 14974
Here's a one-liner. You'll get at least one lower-case, one upper-case, one number, and one symbol. Uses random_int
which is supposed to cyrptographically secure. I do not claim this to be secure, though. I am not a security expert.
To copy+Paste: (just change $len
to your desired length.)
$len=26;for ($chars = array('0123456789','abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ','!@#$%^&*()_+-='),$randomString="",$i=0;$i<$len;$i++)$randomString .= substr($chars[$i%4], random_int(0,strlen($chars[$i%4])), 1);
echo $randomString;
And a little more broken down:
for (
$chars = array('0123456789','abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ','!@#$%^&*()_+-='),
$randomString="",
$i=0;
$i<12;$i++)
$randomString .=
substr($chars[$i%4],
random_int(0, strlen($chars[$i%4])), 1);
I use $chars[$i%4]
in the loop to choose which set of characters to get a random from. It guarantees multiple characters from each set of chars in the array.
It could definitely be improved (randomizing how many of each char set there is), but it's good enough for my purposes.
Upvotes: 2
Reputation: 109
from the yii2 framework
/**
* Generates a random string of specified length.
* The string generated matches [A-Za-z0-9_-]+ and is transparent to URL-encoding.
*
* @param int $length the length of the key in characters
* @return string the generated random key
*/
function generateRandomString($length = 10) {
$bytes = random_bytes($length);
return substr(strtr(base64_encode($bytes), '+/', '-_'), 0, $length);
}
Upvotes: 9
Reputation: 89
This code will help:
This function will return random string with length between $maxLength
and $minLength
.
NOTE: Function random_bytes
works since PHP 7.
If you need specific length, so $maxLength
and $minLength
must be same.
function getRandomString($maxLength = 20, $minLength = 10)
{
$minLength = $maxLength < $minLength ? $maxLength : $minLength;
$halfMin = ceil($minLength / 2);
$halfMax = ceil($maxLength / 2);
$bytes = random_bytes(rand($halfMin, $halfMax));
$randomString = bin2hex($bytes);
$randomString = strlen($randomString) > $maxLength ? substr($randomString, 0, -1) : $randomString;
return $randomString;
}
Upvotes: 0
Reputation: 107
Try this, it can generate up to length of master. but its simple and fit for small string.
$master="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$master_array = str_split($master);
shuffle($master_array);
print_r(implode("",array_slice($master_array,0,10)));
Upvotes: 1
Reputation: 347
IF YOUR ARE USING PHP 7 +
public function generateRandom(){
$string = bin2hex(openssl_random_pseudo_bytes(10)); // 20 chars
// OR
$string = base64_encode(random_bytes(10)); // ~14 characters, includes /=+
// or
$string = substr(str_replace(['+', '/', '='], '', base64_encode(random_bytes(32))), 0, 32); // 32 characters, without /=+
// or
$string = bin2hex(random_bytes(10)); // 20 characters, only 0-9a-f
}
Upvotes: 0
Reputation: 26071
PHP 7+ Generate cryptographically secure random bytes using random_bytes function.
$bytes = random_bytes(16);
echo bin2hex($bytes);
Possible output
da821217e61e33ed4b2dd96f8439056c
PHP 5.3+ Generate pseudo-random bytes using openssl_random_pseudo_bytes function.
$bytes = openssl_random_pseudo_bytes(16);
echo bin2hex($bytes);
Possible output
e2d1254506fbb6cd842cd640333214ad
The best use case could be
function getRandomBytes($length = 16)
{
if (function_exists('random_bytes')) {
$bytes = random_bytes($length / 2);
} else {
$bytes = openssl_random_pseudo_bytes($length / 2);
}
return bin2hex($bytes);
}
echo getRandomBytes();
Possible output
ba8cc342bdf91143
Upvotes: 42
Reputation: 1752
Here is another solution.
function genRandomString($length = 10)
{
if($length < 1)
$length = 1;
return substr(preg_replace("/[^A-Za-z0-9]/", '', base64_encode(openssl_random_pseudo_bytes($length * 2))), 0, $length);
}
PS. I am using PHP 7.2 on Ubuntu.
Upvotes: 2
Reputation: 310
Since php7, there is the random_bytes functions. https://www.php.net/manual/ru/function.random-bytes.php So you can generate a random string like that
<?php
$bytes = random_bytes(5);
var_dump(bin2hex($bytes));
?>
Upvotes: 9
Reputation: 34093
There are a lot of answers to this question, but none of them leverage a Cryptographically Secure Pseudo-Random Number Generator (CSPRNG).
The simple, secure, and correct answer is to use RandomLib and don't reinvent the wheel.
For those of you who insist on inventing your own solution, PHP 7.0.0 will provide random_int()
for this purpose; if you're still on PHP 5.x, we wrote a PHP 5 polyfill for random_int()
so you can use the new API even before you upgrade to PHP 7.
Safely generating random integers in PHP isn't a trivial task. You should always check with your resident StackExchange cryptography experts before you deploy a home-grown algorithm in production.
With a secure integer generator in place, generating a random string with a CSPRNG is a walk in the park.
/**
* Generate a random string, using a cryptographically secure
* pseudorandom number generator (random_int)
*
* This function uses type hints now (PHP 7+ only), but it was originally
* written for PHP 5 as well.
*
* For PHP 7, random_int is a PHP core function
* For PHP 5.x, depends on https://github.com/paragonie/random_compat
*
* @param int $length How many characters do we want?
* @param string $keyspace A string of all possible characters
* to select from
* @return string
*/
function random_str(
int $length = 64,
string $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
): string {
if ($length < 1) {
throw new \RangeException("Length must be a positive integer");
}
$pieces = [];
$max = mb_strlen($keyspace, '8bit') - 1;
for ($i = 0; $i < $length; ++$i) {
$pieces []= $keyspace[random_int(0, $max)];
}
return implode('', $pieces);
}
Usage:
$a = random_str(32);
$b = random_str(8, 'abcdefghijklmnopqrstuvwxyz');
$c = random_str();
Demo: https://3v4l.org/IMJGF (Ignore the PHP 5 failures; it needs random_compat)
Upvotes: 436
Reputation: 500
You can try this:
<?php
function random($len){
$char = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
// ----------------------------------------------
// Number of possible combinations
// ----------------------------------------------
$pos = strlen($char);
$pos = pow($pos, $len);
echo $pos.'<br>';
// ----------------------------------------------
$total = strlen($char)-1;
$text = "";
for ($i=0; $i<$len; $i++){
$text = $text.$char[rand(0, $total)];
}
return $text;
}
$string = random(15);
echo $string;
?>
You can also use md5 on time but be careful.
You need to use microtime()
and not time()
function, because if multiple threads run within the same second, you need to get different string for all of them.
<?php
$string = md5(microtime());
echo $string;
?>
Upvotes: 3
Reputation: 754
A class with some of the functions from the discussions above.
$options['numeric'] = true;
$options['uppercase'] = true;
$options['lowercase'] = true;
$new = new RandomString($options);
class RandomString
{
/**
* @var array
*/
private $default = ['numeric' => true, 'uppercase' => true, 'lowercase' => true];
/**
* @var array
*/
private $options;
/**
* array
*/
private $whitelist = ['numeric', 'uppercase', 'lowercase'];
/**
* RandomString constructor.
*
* @param array $options
*/
public function __construct(array $options = [])
{
$this->options = $this->default;
if(!empty($options))
{
$options = array_intersect_key($options, array_flip($this->whitelist));
if(empty($options))
{
$this->options = $this->default;
}else
{
$this->options = $options;
}
}
}
/**
* @return string
*/
private function returnCharacters(){
$options = $this->options;
$numbers = '0123456789';
$uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$lowercase = "abcdefghijklmnopqrstuvwxyz";
$characters = '';
if(isset($options['numeric']) && $options['numeric'] === true){
$characters .= $numbers;
}
if(isset($options['uppercase']) && $options['uppercase'] === true){
$characters .= $uppercase;
}
if(isset($options['lowercase']) && $options['lowercase'] === true){
$characters .= $lowercase;
}
return $characters;
}
/**
* @param $length
* @param $quantity
* @return string
*/
public function randomString($length, $quantity) {
$string = '';
$characters = $this->returnCharacters();
for ($j = 0; $j < $quantity; $j++) {
for($i = 0; $i < $length; $i++){
$string .= $characters[mt_rand(0, strlen($characters) - 1)];
}
$string .= "\n";
}
return $string;
}
/**
* @return array
*/
public function getOptions()
{
return $this->options;
}
/**
* @return mixed
*/
public function getWhitelist()
{
return $this->whitelist;
}
Upvotes: 1
Reputation: 610
Finally I have found a solution to get random and unique values.
My solution is:
substr(md5(time()), 0, 12)
time
always return a timestamp, and it is always unique. You can use it with MD5 to make it better.
Upvotes: 1
Reputation: 2158
function randomString($length = 5) {
return substr(str_shuffle(implode(array_merge(range('A','Z'), range('a','z'), range(0,9)))), 0, $length);
}
Upvotes: 5
Reputation: 331
There is simple code:
echo implode("",array_map(create_function('$s','return substr($s,mt_rand(0,strlen($s)),1);'),array_fill(0,16,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")));
There is a simple guide:
16
to another value, only.Upvotes: 2
Reputation: 2653
To get it in a single line, try this:
$str = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 5)), 0, $length);
Upvotes: -1
Reputation: 89
One liner.
It is fast for huge strings with some uniqueness.
function random_string($length){
return substr(str_repeat(md5(rand()), ceil($length/32)), 0, $length);
}
Upvotes: 5
Reputation: 53821
This creates a 20 character long hexadecimal string:
$string = bin2hex(openssl_random_pseudo_bytes(10)); // 20 chars
In PHP 7 (random_bytes()):
$string = base64_encode(random_bytes(10)); // ~14 characters, includes /=+
// or
$string = substr(str_replace(['+', '/', '='], '', base64_encode(random_bytes(32))), 0, 32); // 32 characters, without /=+
// or
$string = bin2hex(random_bytes(10)); // 20 characters, only 0-9a-f
Upvotes: 229
Reputation: 1554
Another one-liner, which generates a random string of 10 characters with letters and numbers. It will create an array with range
(adjust the second parameter to set the size), loops over this array and assigns a random ASCII character (range 0-9 or a-z), then implodes the array to get a string.
$str = implode('', array_map(function () { return chr(rand(0, 1) ? rand(48, 57) : rand(97, 122)); }, range(0, 9)));
Note: this only works in PHP 5.3 and later
Upvotes: 5