[php] Generating a random password in php

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;
}

This question is related to php security random passwords

The answer is


Being a little smarter:

function strand($length){
  if($length > 0)
    return chr(rand(33, 126)) . strand($length - 1);
}

check it here.


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;
}

In one line:

substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') , 0 , 10 )

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 chars
  • rtrim 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.


Another one (linux only)

function randompassword()
{
    $fp = fopen ("/dev/urandom", 'r');
    if (!$fp) { die ("Can't access /dev/urandom to get random data. Aborting."); }
    $random = fread ($fp, 1024); # 1024 bytes should be enough
    fclose ($fp);
    return trim (base64_encode ( md5 ($random, true)), "=");
}

I'm going to post an answer because some of the existing answers are close but have one of:

  • a smaller character space than you wanted so that either brute-forcing is easier or the password must be longer for the same entropy
  • a RNG that isn't considered cryptographically secure
  • a requirement for some 3rd party library and I thought it might be interesting to show what it might take to do it yourself

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:

  1. use some secure source of randomness to get random data
  2. use that data and represent it as some printable string

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.


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).


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

You want strlen($alphabet), not count of the constant alphabet (equivalent to 'alphabet').

However, rand is not a suitable random function for this purpose. Its output can easily be predicted as it is implicitly seeded with the current time. Additionally, rand is not cryptographically secure; it is therefore relatively easy to determine its internal state from output.

Instead, read from /dev/urandom to get cryptographically random data.


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();

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);
}

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

//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

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!


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);
    }
}

TL;DR:

  • Use random_int() and the given random_str() below.
  • If you don't have random_int(), use random_compat.

Explanation:

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;
}

Tiny code with 2 line.

demo: http://codepad.org/5rHMHwnH

function rand_string( $length ) {

    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    return substr(str_shuffle($chars),0,$length);

}

echo rand_string(8);

with rand_string you can define how much character will be create.


Use this simple code for generate med-strong password 12 length

$password_string = '!@#$%*&abcdefghijklmnpqrstuwxyzABCDEFGHJKLMNPQRSTUWXYZ23456789';
$password = substr(str_shuffle($password_string), 0, 12);

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


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)


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;
}

  1. Create a file with this code in it.
  2. 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);
        }
    
    }
    
    ?>
    

Examples related to php

I am receiving warning in Facebook Application using PHP SDK Pass PDO prepared statement to variables Parse error: syntax error, unexpected [ Preg_match backtrack error Removing "http://" from a string How do I hide the PHP explode delimiter from submitted form results? Problems with installation of Google App Engine SDK for php in OS X Laravel 4 with Sentry 2 add user to a group on Registration php & mysql query not echoing in html with tags? How do I show a message in the foreach loop?

Examples related to security

Monitoring the Full Disclosure mailinglist Two Page Login with Spring Security 3.2.x How to prevent a browser from storing passwords JWT authentication for ASP.NET Web API How to use a client certificate to authenticate and authorize in a Web API Disable-web-security in Chrome 48+ When you use 'badidea' or 'thisisunsafe' to bypass a Chrome certificate/HSTS error, does it only apply for the current site? How does Content Security Policy (CSP) work? How to prevent Screen Capture in Android Default SecurityProtocol in .NET 4.5

Examples related to random

How can I get a random number in Kotlin? scikit-learn random state in splitting dataset Random number between 0 and 1 in python In python, what is the difference between random.uniform() and random.random()? Generate random colors (RGB) Random state (Pseudo-random number) in Scikit learn How does one generate a random number in Apple's Swift language? How to generate a random string of a fixed length in Go? Generate 'n' unique random numbers within a range What does random.sample() method in python do?

Examples related to passwords

Your password does not satisfy the current policy requirements Laravel Password & Password_Confirmation Validation Default password of mysql in ubuntu server 16.04 mcrypt is deprecated, what is the alternative? What is the default root pasword for MySQL 5.7 MySQL user DB does not have password columns - Installing MySQL on OSX Changing an AIX password via script? Hide password with "•••••••" in a textField How to create a laravel hashed password Enter export password to generate a P12 certificate