Reputation: 21389
I am trying to generate a random password in php.
However I am getting all 'a's and the return type is of type array and I would like it to be a string. Any ideas on how to correct the code?
Thanks.
function randomPassword() {
$alphabet = "abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUWXYZ0123456789";
for ($i = 0; $i < 8; $i++) {
$n = rand(0, count($alphabet)-1);
$pass[$i] = $alphabet[$n];
}
return $pass;
}
Upvotes: 240
Views: 492135
Reputation: 135
I use my method, please have look
public function generatePassword($maxLength)
{
$password = '';
$upper = "ABCDEFGHIJKLMNOPQRSTUWXY";
$lower = "abcdefghijklmnopqrstuwxyz";
$charx = "!@#$%^&*()_+";
while(true)
{
$nRand = rand(0,3);
if($nRand == 0)
{
$password .= $upper[ rand(0, strlen($upper)-1 ) ];
$password .= $lower[ rand(0, strlen($lower)-1 ) ];
$password .= $charx[ rand(0, strlen($charx)-1 ) ];
$password .= rand(0,9);
}
if($nRand == 1)
{
$password .= rand(0,9);
$password .= $upper[ rand(0, strlen($upper)-1 ) ];
$password .= $lower[ rand(0, strlen($lower)-1 ) ];
$password .= $charx[ rand(0, strlen($charx)-1 ) ];
}
if($nRand == 2)
{
$password .= $charx[ rand(0, strlen($charx)-1 ) ];
$password .= rand(0,9);
$password .= $upper[ rand(0, strlen($upper)-1 ) ];
$password .= $lower[ rand(0, strlen($lower)-1 ) ];
}
if($nRand == 3)
{
$password .= $lower[ rand(0, strlen($lower)-1 ) ];
$password .= $charx[ rand(0, strlen($charx)-1 ) ];
$password .= rand(0,9);
$password .= $upper[ rand(0, strlen($upper)-1 ) ];
}
if(strlen($password) >= $maxLength) break;
}
return $password;
}
Upvotes: 0
Reputation: 3076
final readonly class PasswordGenerator
{
private const ALLOWED_PASSWORD_CHARACTERS = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz1234567890!§$%&()=?][#*+-.:><~';
public function generate(int $length = 20): string
{
$allowedPasswordCharacters = self::ALLOWED_PASSWORD_CHARACTERS;
$password = '';
do {
$password .= mb_substr(
$allowedPasswordCharacters,
random_int(0, mb_strlen($allowedPasswordCharacters, 'UTF-8') - 1),
1,
'UTF-8'
);
} while (strlen($password) < $length);
return $password;
}
}
Upvotes: 0
Reputation: 178
private function generatePassword(): string
{
return Arr::join(
Arr::shuffle(
Arr::collapse([
Arr::random(range(0, 9), 3),
Arr::random(range('A', 'Z'), 3),
Arr::random(range('a', 'z'), 3),
Arr::random(['@', '#', '$', '!', '%', '*', '?', '&'], 3)
])
)
, ''
);
}
Upvotes: 1
Reputation: 152
In my case I use uniqid(); it gets a unique prefixed value based on the current time in microseconds. In this way it is very difficult to repeat this value, otherwise you can also use password_hash(), if you need to encrypt the password.
Follow the examples:
public function randowPassWord() : string {
return password_hash(uniqid(), PASSWORD_DEFAULT);
}
Or just use uniqid();
public function randowPassWord() : string {
return uniqid();
}
Useful links:
https://www.php.net/manual/en/function.password-hash.php
https://www.php.net/manual/pt_BR/function.uniqid.php
Upvotes: 2
Reputation: 333
Here is another password generator snippet. Control length, digit and special character count and list.
One issue with the other solutions is that they don't have option to include repeated characters. While below script makes that possible as well.
$length = random_int(30, 40);
$pass = [];
$lowers = range('a', 'z');
$uppers = range('A', 'Z');
$digits = range('0', '9');
$specials = ['.', '-', '_', '^', '#', '(', ')'];
$specialCount = random_int(1, 5);
$digitCount = random_int(1, 9);
for ($i = 0; $i < $length - $specialCount - $digitCount; $i++) {
$pass[] = random_int(1, PHP_INT_MAX) % 2 == 0 ? $uppers[array_rand($uppers)] : $lowers[array_rand($lowers)];
}
for ($i = 0; $i < $specialCount; $i++) {
$pass[] = $specials[array_rand($specials)];
}
for ($i = 0; $i < $digitCount; $i++) {
$pass[] = $digits[array_rand($digits)];
}
shuffle($pass)
$pass = implode('', $pass);
Upvotes: 0
Reputation: 71
There is one short solution (php 8.1):
$dict = array_merge(
...array_map(
fn(array $d): array => range(ord($d[0]), ord($d[1])),
[["0", "9"], ["a", "z"], ["A", "Z"]]
)
);
$f = fn (int $len): string =>
join(
"",
array_map(
fn (): string => chr($dict[random_int(0, count($dict) - 1)]),
range(0, $len)
)
);
echo $f(12) . PHP_EOL;
one-line bash script:
php -r '$dict = array_merge(...array_map(fn(array $d): array => range(ord($d[0]), ord($d[1])), [["0", "9"], ["a", "z"], ["A", "Z"]] )); $f = fn (int $len): string => join("", array_map(fn (): string => chr($dict[random_int(0, count($dict) - 1)]), range(0, $len) )); echo $f(12) . PHP_EOL;'
This is developed idea from https://stackoverflow.com/a/41077923/5599052
Upvotes: 0
Reputation: 1410
A simple code should be like :
function generatePassword($len){
$az = range("a","z");
$AZ = range("A","Z");
$num = range(0,9);
$password = array_merge($az,$AZ,$num);
return substr(str_shuffle(implode("",$password)),0, $len);
}
// testing
$generate = range(8,32);
foreach($generate as $g){
print "Len:{$g} = " . generatePassword($g)."\n";
}
output:
Len:8 = G5uFhPKS
Len:9 = aU9x2NjvI
Len:10 = lJE9kxy3oD
Len:11 = tVh2CmpMdHW
Len:12 = ToXYHCPb58Ar
Len:13 = KIFVoLg5NdDzX
Len:14 = eFUabML28tXhf0
Len:15 = iegDCQcIMaxH0ST
Len:16 = sRvDmPo5IkaMqNO0
Len:17 = T5rwVDs6XGAqSU9KN
Len:18 = QwROWAfh1lpoCSaX0H
Len:19 = HP0trD4B9SQeUkNuAGV
Len:20 = P9Fdwqmu782ARHDiKGZM
Len:21 = 3Gxia9LPmCZM68dwe4YOf
Len:22 = ywFjuA2GDg0Oz8LVnCI94M
Len:23 = 16MiEVUgqPRueahlyvJfBz5
Len:24 = sPt0H9NSu5KrJTYeMXbOFgi7
Len:25 = QFKGTypaZlsMRnHPgNbVfIwxm
Len:26 = hbyJXtV81AEuMazS4GdFTINBUg
Len:27 = H3AiD95S4Z8xwMrz2L71GqUunaW
Len:28 = m8W2geIiO7Phc3H5Kyr1XCAs09Dv
Len:29 = MusNfYgOWnbrI62twRBvj38XEcDdi
Len:30 = VgNeILaRT2wvb4J7hzCMSHsquUBtnA
Len:31 = nhUvCxgOS94dsYjzBtcaTou1WIArMQP
Len:32 = AFSVQqCijuPMp0cGJNdDtzYX78erKB9w
Upvotes: 2
Reputation: 5960
Being a little smarter:
function strand($length){
if($length > 0)
return chr(rand(33, 126)) . strand($length - 1);
}
check it here online.
Upvotes: 14
Reputation: 1137
Here is my password helper
class PasswordHelper
{
/**
* generate a secured random password
*/
public static function generatePassword(
int $lowerCaseCount=8,
int $upperCaseCount=8,
int $numberCount=8,
int $specialCount=4
): string
{
$lowerCase = 'abcdefghijklmnopqrstuvwxyz';
$upperCase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$number = '0123456789';
$special = '!@#$%^&*';
$password = self::getRandom($lowerCase, $lowerCaseCount);
$password .= self::getRandom($upperCase, $upperCaseCount);
$password .= self::getRandom($number, $numberCount);
$password .= self::getRandom($special, $specialCount);
return str_shuffle($password);
}
/**
* get a random string from a set of characters
*/
public static function getRandom($set, $length): string
{
$rand = '';
$setLength = strlen($set);
for ($i = 0; $i < $length; $i++)
{
$rand .= $set[random_int(0, $setLength - 1)];
}
return $rand;
}
}
usage:
PasswordHelper::generatePassword()
or PasswordHelper::generatePassword(2,4,5,3)
Upvotes: 0
Reputation: 2721
Here is my contribution to the list of options.
This function ensures that the password policy is met.
function password_generate($length=8, $min_lowercases=1, $min_uppercases=1, $min_numbers=1, $min_specials=0) {
$lowercases = 'abcdefghijklmnopqrstuvwxyz';
$uppercases = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$numbers = '0123456789';
$specials = '!#%&/(){}[]+-';
$absolutes = '';
if ($min_lowercases && !is_bool($min_lowercases)) $absolutes .= substr(str_shuffle(str_repeat($lowercases, $min_lowercases)), 0, $min_lowercases);
if ($min_uppercases && !is_bool($min_uppercases)) $absolutes .= substr(str_shuffle(str_repeat($uppercases, $min_uppercases)), 0, $min_uppercases);
if ($min_numbers && !is_bool($min_numbers)) $absolutes .= substr(str_shuffle(str_repeat($numbers, $min_numbers)), 0, $min_numbers);
if ($min_specials && !is_bool($min_specials)) $absolutes .= substr(str_shuffle(str_repeat($specials, $min_specials)), 0, $min_specials);
$remaining = $length - strlen($absolutes);
$characters = '';
if ($min_lowercases !== false) $characters .= substr(str_shuffle(str_repeat($lowercases, $remaining)), 0, $remaining);
if ($min_uppercases !== false) $characters .= substr(str_shuffle(str_repeat($uppercases, $remaining)), 0, $remaining);
if ($min_numbers !== false) $characters .= substr(str_shuffle(str_repeat($numbers, $remaining)), 0, $remaining);
if ($min_specials !== false) $characters .= substr(str_shuffle(str_repeat($specials, $remaining)), 0, $remaining);
$password = str_shuffle($absolutes . substr($characters, 0, $remaining));
return $password;
}
The $min_* parameters can have the following values:
It can be used like the following:
echo password_generate(8); // Outputs a random 8 characters long password
A 10 character password with a minimum of 2 charcaters from each set:
echo password_generate(10, 2, 2, 2, 2);
Output 6 random numbers only
echo password_generate(6, false, false, true, false);
Upvotes: 4
Reputation: 6135
Generate random password string
function generate_randompassword($passlength = 8){
$alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#%^*>\$@?/[]=+';
$pass = array(); //remember to declare $pass as an array
$alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
for ($i = 0; $i < $passlength; $i++) {
$n = rand(0, $alphaLength);
$pass[] = $alphabet[$n];
}
return implode($pass); //turn the array into a string
}
Upvotes: 1
Reputation: 60
function password_generate($n, $l, $s)
{
$numbers = '1234567890';
$letters = '1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcefghijklmnopqrstuvwxyz';
$special = '--!=!@@#++%';
return substr(str_shuffle($numbers), 0, $n).substr(str_shuffle($letters), 0, $l).substr(str_shuffle($special), 0, $s);
}
echo password_generate(2,9,1);
Upvotes: -1
Reputation: 146310
Security warning:
rand()
is not a cryptographically secure pseudorandom number generator. Look elsewhere for generating a cryptographically secure pseudorandom string in PHP.
Try this (use strlen
instead of count
, because count
on a string is always 1
):
function randomPassword() {
$alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$pass = array(); //remember to declare $pass as an array
$alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
for ($i = 0; $i < 8; $i++) {
$n = rand(0, $alphaLength);
$pass[] = $alphabet[$n];
}
return implode($pass); //turn the array into a string
}
Upvotes: 317
Reputation: 83
My answer is similar to some of the above, but I removed vowels, numbers 1 and 0, letters i,j, I, l, O,o, Q, q, X,x,Y,y,W,w. The reason is: the first ones are easy to mix up (like l and 1, depending on the font) and the rest (starting with Q) is because they don't exist in my language, so they might be a bit odd for super-end users. The string of characters is still long enough. Also, I know it would be ideal to use some special signs, but they also don't get along with some end-users.
function generatePassword($length = 8) {
$chars = '23456789bcdfhkmnprstvzBCDFHJKLMNPRSTVZ';
$shuffled = str_shuffle($chars);
$result = mb_substr($shuffled, 0, $length);
return $result;
}
Also, in this way, we avoid repeating the same letters and digits (match case not included)
Upvotes: 2
Reputation: 6045
Here's my take at random plain password generation helper.
It ensures that password has numbers, upper and lower case letters as well as a minimum of 3 special characters.
Length of the password will be between 11 and 30.
function plainPassword(): string
{
$numbers = array_rand(range(0, 9), rand(3, 9));
$uppercase = array_rand(array_flip(range('A', 'Z')), rand(2, 8));
$lowercase = array_rand(array_flip(range('a', 'z')), rand(3, 8));
$special = array_rand(array_flip(['@', '#', '$', '!', '%', '*', '?', '&']), rand(3, 5));
$password = array_merge(
$numbers,
$uppercase,
$lowercase,
$special
);
shuffle($password);
return implode($password);
}
Upvotes: 1
Reputation: 6521
//define a function. It is only 3 lines!
function generateRandomPassword($length = 5){
$chars = "0123456789bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ";
return substr(str_shuffle($chars),0,$length);
}
//usage
echo generateRandomPassword(5); //random password legth: 5
echo generateRandomPassword(6); //random password legth: 6
echo generateRandomPassword(7); //random password legth: 7
Upvotes: 1
Reputation: 573
This function will generate a password based on the rules in parameters
function random_password( $length = 8, $characters = true, $numbers = true, $case_sensitive = true, $hash = true ) {
$password = '';
if($characters)
{
$charLength = $length;
if($numbers) $charLength-=2;
if($case_sensitive) $charLength-=2;
if($hash) $charLength-=2;
$chars = "abcdefghijklmnopqrstuvwxyz";
$password.= substr( str_shuffle( $chars ), 0, $charLength );
}
if($numbers)
{
$numbersLength = $length;
if($characters) $numbersLength-=2;
if($case_sensitive) $numbersLength-=2;
if($hash) $numbersLength-=2;
$chars = "0123456789";
$password.= substr( str_shuffle( $chars ), 0, $numbersLength );
}
if($case_sensitive)
{
$UpperCaseLength = $length;
if($characters) $UpperCaseLength-=2;
if($numbers) $UpperCaseLength-=2;
if($hash) $UpperCaseLength-=2;
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$password.= substr( str_shuffle( $chars ), 0, $UpperCaseLength );
}
if($hash)
{
$hashLength = $length;
if($characters) $hashLength-=2;
if($numbers) $hashLength-=2;
if($case_sensitive) $hashLength-=2;
$chars = "!@#$%^&*()_-=+;:,.?";
$password.= substr( str_shuffle( $chars ), 0, $hashLength );
}
$password = str_shuffle( $password );
return $password;
}
Upvotes: 0
Reputation: 777
Generates a strong password of length 8 containing at least one lower case letter, one uppercase letter, one digit, and one special character. You can change the length in the code too.
function checkForCharacterCondition($string) {
return (bool) preg_match('/(?=.*([A-Z]))(?=.*([a-z]))(?=.*([0-9]))(?=.*([~`\!@#\$%\^&\*\(\)_\{\}\[\]]))/', $string);
}
$j = 1;
function generate_pass() {
global $j;
$allowedCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_{}[]';
$pass = '';
$length = 8;
$max = mb_strlen($allowedCharacters, '8bit') - 1;
for ($i = 0; $i < $length; ++$i) {
$pass .= $allowedCharacters[random_int(0, $max)];
}
if (checkForCharacterCondition($pass)){
return '<br><strong>Selected password: </strong>'.$pass;
}else{
echo 'Iteration '.$j.': <strong>'.$pass.'</strong> Rejected<br>';
$j++;
return generate_pass();
}
}
echo generate_pass();
Upvotes: 1
Reputation: 34103
random_int()
and the given random_str()
below.random_int()
, use random_compat.Since you are generating a password, you need to ensure that the password you generate is unpredictable, and the only way to ensure this property is present in your implementation is to use a cryptographically secure pseudorandom number generator (CSPRNG).
The requirement for a CSPRNG can be relaxed for the general case of random strings, but not when security is involved.
The simple, secure, and correct answer to password generation in PHP is to use RandomLib and don't reinvent the wheel. This library has been audited by industry security experts, as well as myself.
For developers who prefer 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 before PHP 7 is released. Using our random_int()
polyfill is probably safer than writing your own implementation.
With a secure random integer generator on hand, generating a secure random string is easier than pie:
<?php
/**
* Generate a random string, using a cryptographically secure
* pseudorandom number generator (random_int)
*
* 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(
$length,
$keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
) {
$str = '';
$max = mb_strlen($keyspace, '8bit') - 1;
if ($max < 1) {
throw new Exception('$keyspace must be at least two characters long');
}
for ($i = 0; $i < $length; ++$i) {
$str .= $keyspace[random_int(0, $max)];
}
return $str;
}
Upvotes: 158
Reputation: 51
I created a more comprehensive and secure password script. This will create a combination of two uppercase, two lowercase, two numbers and two special characters. Total 8 characters.
$char = [range('A','Z'),range('a','z'),range(0,9),['*','%','$','#','@','!','+','?','.']];
$pw = '';
for($a = 0; $a < count($char); $a++)
{
$randomkeys = array_rand($char[$a], 2);
$pw .= $char[$a][$randomkeys[0]].$char[$a][$randomkeys[1]];
}
$userPassword = str_shuffle($pw);
Upvotes: 2
Reputation: 168
Use this simple code for generate med-strong password 12 length
$password_string = '!@#$%*&abcdefghijklmnpqrstuwxyzABCDEFGHJKLMNPQRSTUWXYZ23456789';
$password = substr(str_shuffle($password_string), 0, 12);
Upvotes: 5
Reputation: 1253
Call it like in the comments.
<?php
/**
* @usage :
* include_once($path . '/Password.php');
* $Password = new Password;
* $pwd = $Password->createPassword(10);
* return $pwd;
*
*/
class Password {
public function createPassword($length = 15) {
$response = [];
$response['pwd'] = $this->generate($length);
$response['hashPwd'] = $this->hashPwd( $response['pwd'] );
return $response;
}
private function generate($length = 15) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*(){}/?,><";
return substr(str_shuffle($chars),0,$length);
}
private function hashPwd($pwd) {
return hash('sha256', $pwd);
}
}
?>
Upvotes: 2
Reputation: 5141
This is based off another answer on this page, https://stackoverflow.com/a/21498316/525649
This answer generates just hex characters, 0-9,a-f
. For something that doesn't look like hex, try this:
str_shuffle(
rtrim(
base64_encode(bin2hex(openssl_random_pseudo_bytes(5))),
'='
).
strtoupper(bin2hex(openssl_random_pseudo_bytes(7))).
bin2hex(openssl_random_pseudo_bytes(13))
)
base64_encode
returns a wider spread of alphanumeric charsrtrim
removes the =
sometimes at the end Examples:
32eFVfGDg891Be5e7293e54z1D23110M3ZU3FMjb30Z9a740Ej0jz4
b280R72b48eOm77a25YCj093DE5d9549Gc73Jg8TdD9Z0Nj4b98760
051b33654C0Eg201cfW0e6NA4b9614ze8D2FN49E12Y0zY557aUCb8
y67Q86ffd83G0z00M0Z152f7O2ADcY313gD7a774fc5FF069zdb5b7
This isn't very configurable for creating an interface for users, but for some purposes that's okay. Increase the number of chars to account for the lack of special characters.
Upvotes: 2
Reputation: 331
Quick One. Simple, clean and consistent format if that is what you want
$pw = chr(mt_rand(97,122)).mt_rand(0,9).chr(mt_rand(97,122)).mt_rand(10,99).chr(mt_rand(97,122)).mt_rand(100,999);
Upvotes: 3
Reputation: 534
Try This with Capital Letters, Small Letters, Numeric(s) and Special Characters
function generatePassword($_len) {
$_alphaSmall = 'abcdefghijklmnopqrstuvwxyz'; // small letters
$_alphaCaps = strtoupper($_alphaSmall); // CAPITAL LETTERS
$_numerics = '1234567890'; // numerics
$_specialChars = '`~!@#$%^&*()-_=+]}[{;:,<.>/?\'"\|'; // Special Characters
$_container = $_alphaSmall.$_alphaCaps.$_numerics.$_specialChars; // Contains all characters
$password = ''; // will contain the desired pass
for($i = 0; $i < $_len; $i++) { // Loop till the length mentioned
$_rand = rand(0, strlen($_container) - 1); // Get Randomized Length
$password .= substr($_container, $_rand, 1); // returns part of the string [ high tensile strength ;) ]
}
return $password; // Returns the generated Pass
}
Let's Say we need 10 Digit Pass
echo generatePassword(10);
Example Output(s) :
,IZCQ_IV\7
@wlqsfhT(d
1!8+1\4@uD
Upvotes: 7
Reputation: 3729
I'm going to post an answer because some of the existing answers are close but have one of:
This answer will circumvent the count/strlen
issue as the security of the generated password, at least IMHO, transcends how you're getting there. I'm also going to assume PHP > 5.3.0.
Let's break the problem down into the constituent parts which are:
For the first part, PHP > 5.3.0 provides the function openssl_random_pseudo_bytes
. Note that whilst most systems use a cryptographically strong algorithm, you have to check so we'll use a wrapper:
/**
* @param int $length
*/
function strong_random_bytes($length)
{
$strong = false; // Flag for whether a strong algorithm was used
$bytes = openssl_random_pseudo_bytes($length, $strong);
if ( ! $strong)
{
// System did not use a cryptographically strong algorithm
throw new Exception('Strong algorithm not available for PRNG.');
}
return $bytes;
}
For the second part, we'll use base64_encode
since it takes a byte string and will produce a series of characters that have an alphabet very close to the one specified in the original question. If we didn't mind having +
, /
and =
characters appear in the final string and we want a result at least $n
characters long, we could simply use:
base64_encode(strong_random_bytes(intval(ceil($n * 3 / 4))));
The 3/4
factor is due to the fact that base64 encoding results in a string that has a length at least a third bigger than the byte string. The result will be exact for $n
being a multiple of 4 and up to 3 characters longer otherwise. Since the extra characters are predominantly the padding character =
, if we for some reason had a constraint that the password be an exact length, then we can truncate it to the length we want. This is especially because for a given $n
, all passwords would end with the same number of these, so that an attacker who had access to a result password, would have up to 2 less characters to guess.
For extra credit, if we wanted to meet the exact spec as in the OP's question then we would have to do a little bit more work. I'm going to forgo the base conversion approach here and go with a quick and dirty one. Both need to generate more randomness than will be used in the result anyway because of the 62 entry long alphabet.
For the extra characters in the result, we can simply discard them from the resulting string. If we start off with 8 bytes in our byte-string, then up to about 25% of the base64 characters would be these "undesirable" characters, so that simply discarding these characters results in a string no shorter than the OP wanted. Then we can simply truncate it to get down to the exact length:
$dirty_pass = base64_encode(strong_random_bytes(8)));
$pass = substr(str_replace(['/', '+', '='], ['', '', ''], $dirty_pass, 0, 8);
If you generate longer passwords, the padding character =
forms a smaller and smaller proportion of the intermediate result so that you can implement a leaner approach, if draining the entropy pool used for the PRNG is a concern.
Upvotes: 16
Reputation: 72672
If you are on PHP7 you could use the random_int()
function:
function generate_password($length = 20){
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.
'0123456789`-=~!@#$%^&*()_+,./<>?;:[]{}\|';
$str = '';
$max = strlen($chars) - 1;
for ($i=0; $i < $length; $i++)
$str .= $chars[random_int(0, $max)];
return $str;
}
Old answer below:
function generate_password($length = 20){
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.
'0123456789`-=~!@#$%^&*()_+,./<>?;:[]{}\|';
$str = '';
$max = strlen($chars) - 1;
for ($i=0; $i < $length; $i++)
$str .= $chars[mt_rand(0, $max)];
return $str;
}
Upvotes: 54
Reputation: 11205
base_convert(uniqid('pass', true), 10, 36);
eg. e0m6ngefmj4
EDIT
As I've mentioned in comments, the length means that brute force attacks would work better against it then timing attacks so it's not really relevant to worry about "how secure the random generator was." Security, specifically for this use case, needs to complement usability so the above solution is actually good enough for the required problem.
However, just in case you stumbled upon this answer while searching for a secure random string generator (as I assume some people have based on the responses), for something such as generating tokens, here is how a generator of such codes would look like:
function base64urlEncode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
function secureId($length = 32) {
if (function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes($length);
return rtrim(strtr(base64_encode($bytes), '+/', '0a'), '=');
}
else { // fallback to system bytes
error_log("Missing support for openssl_random_pseudo_bytes");
$pr_bits = '';
$fp = @fopen('/dev/urandom', 'rb');
if ($fp !== false) {
$pr_bits .= @fread($fp, $length);
@fclose($fp);
}
if (strlen($pr_bits) < $length) {
error_log('unable to read /dev/urandom');
throw new \Exception('unable to read /dev/urandom');
}
return base64urlEncode($pr_bits);
}
}
Upvotes: 13
Reputation: 174967
Your best bet is the RandomLib library by ircmaxell.
Usage example:
$factory = new RandomLib\Factory;
$generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
$passwordLength = 8; // Or more
$randomPassword = $generator->generateString($passwordLength);
It produces strings which are more strongly random than the normal randomness functions like shuffle()
and rand()
(which is what you generally want for sensitive information like passwords, salts and keys).
Upvotes: 27
Reputation: 1307
I know you are trying to generate your password in a specific way, but you might want to look at this method as well...
$bytes = openssl_random_pseudo_bytes(2);
$pwd = bin2hex($bytes);
It's taken from the php.net site and it creates a string which is twice the length of the number you put in the openssl_random_pseudo_bytes function. So the above would create a password 4 characters long.
In short...
$pwd = bin2hex(openssl_random_pseudo_bytes(4));
Would create a password 8 characters long.
Note however that the password only contains numbers 0-9 and small cap letters a-f!
Upvotes: 129