Generating a random password in php

2019-01-02 19:09发布

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

22条回答
裙下三千臣
2楼-- · 2019-01-02 19:46

Being a little smarter:

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

check it here.

查看更多
回忆,回不去的记忆
3楼-- · 2019-01-02 19:47

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.

查看更多
初与友歌
4楼-- · 2019-01-02 19:49

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);
查看更多
旧时光的记忆
5楼-- · 2019-01-02 19:49

I've been meaning to try implementing my own "secure" and "random" password generator.

I thought it would be interesting and more flexible to provide a length and type parameter to the function.

Here is a function that performs a few checks to make sure the length is not too short or long (also allowing variable length). It also allows the ability to choose your password charset in the type parameter.

It returns null if the length or type are invalid and uses PHP's mt_rand() function which is more "random" than rand().

<?php

/**
* Generates a random password with the given length and of the given type.
*
* @param int $length
* @param string $type 
* @return string | null
*/
function random_password($length=8, $type='alpha_numeric') {

    if ($length < 1 || $length > 1024) return null;

    $lower = 'abcdefghijklmnopqrstuvwxy';
    $upper = strtoupper($lower);
    $numbers = '1234567890';
    $dash = '-';
    $underscore = '_';
    $symbols = '`~!@#$%^&*()+=[]\\{}|:";\'<>?,./';

    switch ($type) {
        case 'lower':
            $chars = $lower;
            break;
        case 'upper':
            $chars = $upper;
            break;
        case 'numeric':
            $chars = $numbers;
            break;
        case 'alpha':
            $chars = $lower . $upper;
            break;
        case 'symbol':
            $chars = $symbols . $dash . $underscore;
            break;
        case 'alpha_numeric':
            $chars = $lower . $upper . $numbers;
            break;
        case 'alpha_numeric_dash':
            $chars = $lower . $upper . $numbers . $dash;
            break;
        case 'alpha_numeric_underscore':
            $chars = $lower . $upper . $numbers . $underscore;
            break;
        case 'alpha_numeric_dash_underscore':
            $chars = $lower . $upper . $numbers . $underscore . $dash;
            break;
        case 'all':
            $chars = $lower . $upper . $numbers . $underscore . $dash . $symbols;
            break;
        default:
            return null;
    }

    $min = 0;
    $max = strlen($chars) - 1;

    $password = '';

    for ($i = 0; $i < $length; $i++) {
        $random = mt_rand($min, $max);
        $char = substr($chars, $random, 1);
        $password .= $char;
    }

    return $password;
}
查看更多
永恒的永恒
6楼-- · 2019-01-02 19:50

This is basically the same as the much simpler substr(md5(uniqid()), 0, 8);

查看更多
余生无你
7楼-- · 2019-01-02 19:50

If you want 8 characters with 1 uppercase and 1 number.

  $p_lc_letters = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz'), 0, 6); // Generate 6 lowercase letters
  $p_uc_letters = substr(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 1); // Generate 1 uppercase letter
  $p_numbers = substr(str_shuffle('0123456789'), 0, 1); // Generate 1 number

  echo $password = substr(str_shuffle($p_lc_letters.''.$p_uc_letters.''.$p_numbers), 0, 8);
查看更多
登录 后发表回答