232

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;
}
Scott Arciszewski
  • 33,610
  • 16
  • 89
  • 206
nunos
  • 20,479
  • 50
  • 119
  • 154
  • 9
    None of the answers use a [secure random number generator](http://stackoverflow.com/a/31107425/2224584), which you want for a password. – Scott Arciszewski Jul 04 '15 at 19:08
  • 4
    Visitors should be getting potentially-security-related information from a source that can be updated properly, not a question that's closed to new answers. I'm deleting the answers to this duplicate so that visitors will read the answers to the open question instead. (If this question is ever reopened, answers will be undeleted.) – Jeremy Jul 06 '15 at 05:47
  • 6
    @JeremyBanks Nowhere does the question state a *cryptographically secure* password is required. For some people, the answers using `/dev/random` are enough as the question doesn't ask for a "*secure*" password (and shouldn't be edited to contain that as it would alter the meaning of the original question). Although I'm all for security, I think this carpet bomb wasn't thought through fully. Like using `mysql_*`, the answers are still valid, but should be marked as insecure. Perhaps this is something that SO needs to include as extra software - the ability to *warn* of insecure code? – Jimbo Jul 06 '15 at 07:33
  • 1
    Passwords come with implicit security requirements; namely, unpredictability. You cannot get this property with a weak PRNG, you must use a CSPRNG if you wish to generate one randomly. – Scott Arciszewski Jul 06 '15 at 08:28
  • 2
    Passwords come with different requirements - one person's "extremely complex and confusing" password is another person's secure password. It depends entirely on the use-case (an in-house project that will remain in-house, on a small dev team, won't need *as much* thought put into security to get the software working for them asap). – Jimbo Jul 06 '15 at 08:29
  • "`Passwords come with different requirements - one person's "extremely complex and confusing" password is another person's secure password.`" And my advice for users is to [use a password manager](https://paragonie.com/blog/2015/06/guide-securing-your-business-s-online-presence-for-non-experts) and only bother remembering one "extremely complex and confusing password". – Scott Arciszewski Jul 06 '15 at 08:34
  • 1
    I mean - the security aspects of implementing a secure password may cause the solution become unnecessarily complex - hence why a few of these weren't too bad. Not the password itself. These answers could always have been edited or commented on stating they're not *the best way*. – Jimbo Jul 06 '15 at 08:37
  • @Jimbo The primary purpose of a duplicate question is to act as a signpost to find the target question, where the information is supposed to be. I wouldn't delete all of these answers in another context, but in this case they're not supposed to be the source of information anyway. (Not *all* passwords need to be secure, but many do, and it's important to provide good security advice to the users that do need it.) – Jeremy Jul 06 '15 at 10:18
  • 1
    I still think more people are going to search for random passwords than random strings then - perhaps this could be changed... – Jimbo Jul 06 '15 at 10:45
  • 6
    @JeremyBanks Can you please reinstate the answers to this question? Just because it is a duplicate it does not mean the answers are wrong (I accidentally voted to reopen, I agree it is a duplicate). It makes no sense to delete the answers, Consider instead removing this question and migrating the answers to the other question (I have seen it done before). – Naftali Jul 06 '15 at 12:26
  • 2
    Also @JeremyBanks the answers on the supposed "duplicate" are just as "insecure" – Naftali Jul 06 '15 at 12:31
  • 7
    @JeremyBanks if you want something to not be reopened, lock it. Otherwise 99% people will reopen it and create a whole mess. Personally I totally disagree with deleting highly scored answers just like that, but can't fight you over this – Shadow The GPT Wizard Jul 06 '15 at 12:36
  • @ShadowWizard I don't have any objection to the question being reopened, and didn't don't want to lock it to prevent that. My concern was specifically with the difficulties of updating information on a closed questions, conflicting with the dangers of spreading bad security-related information. If the question is reopened, so newer answers can be added to compete with the existing ones, that concern is eliminated. – Jeremy Jul 06 '15 at 14:30
  • Generate [random string](https://fe-tool.com/en-us/random-password) in different programming languaues. – cwtuan Oct 26 '22 at 15:54

32 Answers32

308

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
}

Demo

Amin Mir
  • 640
  • 8
  • 15
Naftali
  • 144,921
  • 39
  • 244
  • 303
  • 29
    Seems more straightforward to use `$pass .= $alphabet[$n]`. – Matthew May 23 '11 at 19:33
  • @konforce, yes true, but i just went with the array way the op had, there is nothing really wrong with it. – Naftali May 23 '11 at 19:34
  • @KarlLaurentiusRoos I don't understand, why is `[]` enough? Is that statement some kind of implicit append function? – Pat Needham Oct 31 '13 at 03:49
  • @Pat: yes, I'm presuming you're coming from some other language :) `$array[] = ` is the same thing as `$array[count($array)] = ` in PHP. – Karl Laurentius Roos Oct 31 '13 at 13:57
  • 37
    Generating *password* using *rand* is a really bad idea. It's not a secure PRNG. (and no `mt_rand` isn't better either) – CodesInChaos Oct 31 '13 at 16:56
  • @CodesInChaos I was just going off the OP's code. This question has nothing to do with the security of `rand`.... – Naftali Oct 31 '13 at 17:08
  • 19
    The question is about *generating a password*. Code to generate a password clearly needs to use secure random numbers. – CodesInChaos Oct 31 '13 at 17:18
  • @CodesInChaos The title _might_ say that, but the answer is that the OP's code had an error. Whatever ^_^ – Naftali Oct 31 '13 at 17:29
  • Perhaps this alternative would be a more suitable RNG: http://www.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322 – Daniel Perván Nov 04 '13 at 11:43
  • 12
    For the same reason as this is **not** a duplicate question, this answer is incorrect, since the question is about _generating a password_ and **not** a _random string_. This answer provides a terribly insecure approach to generating a password. Please use @user3260409's answer below, where `openssl_random_pseudo_bytes()` is used instead of `rand()` – Sorry-Im-a-N00b Mar 30 '15 at 00:21
  • 1
    This answer is insecure, can you please put a disclaimer on it and direct people to [this answer which uses a CSPRNG](http://stackoverflow.com/a/31107425/2224584)? Thanks :) @CodesInChaos What do you think of the linked answer? – Scott Arciszewski Jul 02 '15 at 20:17
  • 1
    @ScottArciszewski Please do not edit my answer with random updates. If you feel it is incorrect then post your own answer. – Naftali Jul 05 '15 at 13:23
  • 38
    I've seen your insecure code **in production** and want to stop it at the source. You **NEED** cryptographically secure randomness for passwords. – Scott Arciszewski Jul 06 '15 at 04:22
  • 2
    All of these "It's unsafe!!!" screams are solely based on the _assumption_ the attackers knows how you generate your passwords. (If they do, you have bigger problems than those passwords) Just make sure you randomize your input (`$alphabet`), then this is safe enough. – Cerbrus Jul 06 '15 at 13:48
  • 4
    @Cerbrus You're proposing a substitution cipher, trivially breaks under a known-plaintext attack. The attacker simply needs to sign up a couple of times and note both the time of the signup and their password and recovers the permutation from that. – CodesInChaos Jul 06 '15 at 14:04
  • 2
    As the answer is now community wiki community contributions are encouraged so I reinstated Scott's. – Martin Smith Jul 07 '15 at 06:23
  • @MartinSmith the only point in Scott's edit is to promote his post... I am editing ur edit again to remove the needless promotion... – Naftali Jul 07 '15 at 13:17
  • 2
    @Neal No, the only point of my edit was to point people directly towards a secure answer. Which, now that this is a Community-protected question rather than a closed one, I can just supply my own here. – Scott Arciszewski Jul 08 '15 at 06:15
  • 7
    Can someone explain how an attack on this insecure method would work? I know that the numbers produced by rand() are not secure random numbers, but I still have trouble wrapping my head around how someone would exploit this. Does it make any difference if you assume that a potential attacker can not sign up themselves to receive multiple passwords for analysis? – Christian Sep 01 '15 at 10:29
  • 1
    That password is secure enough compared to the user's pet name :) – Heroselohim Mar 02 '16 at 19:24
  • I prefer this method over RandomLib because I am not forced to use Composer. – Adam Sep 27 '16 at 19:29
  • Use `openssl_random_pseudo_bytes()` or `random_byte()` – Jeroen Bellemans Oct 25 '16 at 09:06
  • More flexible if you pass it an int and use `for ($i = 0; $i < $len; $i++)` – Elliott B Jul 28 '18 at 20:09
  • I am not sure what you mean @ElliottB – Naftali Aug 02 '18 at 13:54
  • 1
    If you are using php7+, simply substitute `random_int()` for `rand()` here and it will be cryptographically secure. – But those new buttons though.. Mar 09 '19 at 01:41
  • @CodesInChaos that sounds completely impractical in reality. Surely the 'hacker' would have to know the exact time of the server at the moment of code execution, plus know the exact character set and order of the character set - generally they'd have to see those lines of code AND be clever enough to fathom what 8 chars it would generate at random in immediate succession? Is that actually possible rather than just in theory? – benjaminhull Jul 15 '21 at 15:29
157

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;
}
Scott Arciszewski
  • 33,610
  • 16
  • 89
  • 206
  • 5
    RandomLib has not been updated for over two years now. Using it on a recent PHP build (7.1.25 in my case) throws deprecation warnings for various `mcrypt_*` functions. I can see on [an issue thread](https://github.com/ircmaxell/RandomLib/issues/55) that you have [forked the library](https://github.com/paragonie/RandomLib) due not being able to get a hold of @ircmaxell, but your fork says ‘build failing’ on Travis. Would you care to update this answer (which still shows up quite high on Google)? – Janus Bahs Jacquet Jan 14 '19 at 14:13
  • 3
    Good catch! It needs to be removed. – Scott Arciszewski Jan 21 '19 at 18:59
  • For >=PHP7 you can do `bin2hex(random_bytes($length/2))` but will not include uppercase chars. – gerardnll Jun 20 '23 at 09:00
127

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!

henningda
  • 366
  • 3
  • 7
user3260409
  • 1,287
  • 1
  • 8
  • 2
  • 13
    If you want a password that's uppercase, lowercase, and numbers, try this: https://gist.github.com/zyphlar/7217f566fc83a9633959 – willbradley Dec 20 '14 at 22:35
  • 1
    @زياد Says who? If the generator was using 7-bit bytes I would agree with you, but `openssl_random_pseudo_bytes()` is a powerful full binary byte randomness generator and doesn't need any further shuffling. Also I'll take the chance to point out that it is dangerous to assume stacking multiple encryption methods will make anything more random, in some cases it can in fact be exactly the opposite because of accumulating hashing collisions. – Havenard Aug 07 '18 at 19:34
66

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.

Naftali
  • 144,921
  • 39
  • 244
  • 303
BSQ
  • 945
  • 6
  • 4
  • 24
    Nice, though you won't get any repeated characters using this approach, which might be undesirable. – Hobo Dec 15 '12 at 10:47
  • 14
    This function is terrible for generating long passwords. First, if $length is longer than the $chars string, then you will not receive a string as long as the length you input, but the length of the chars string. Also, you are guaranteed only 1 of each character with no duplicates. It also does not guarantee the use of a capital letter or a number which is quite often a requirement (except of course if your length is more than 26 due to the previous fault) – Programster Oct 05 '13 at 11:59
  • 1
    What about this @Programster and @Hobo ? `substr(str_shuffle(str_repeat($chars,$length)),0,$length);` – Charles-Édouard Coste Sep 21 '17 at 14:40
  • @Charles-EdouardCoste seems to work okay enough (especially if you throw in some special chars). Although it still doesn't *guarantee* at least one of each character type. The only thing that bothers me is repeating the entire character set by the length of the desired password but that ensures the chars in the generated password don't have to be unique and doesn't have a noticeable performance impact in a single use. – Programster Sep 27 '17 at 20:12
  • I concur. It's probably better not to choose an algorithm on its number of lines. By the way, if the main goal is just to generate a temporary password when creating a new user on a website, this would meet the needs, I guess. – Charles-Édouard Coste Sep 28 '17 at 09:05
53

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;
}
PeeHaa
  • 71,436
  • 58
  • 190
  • 262
  • 13
    don't use `mt_rand` to generate a password. – CodesInChaos Oct 31 '13 at 17:00
  • 2
    @CodesInChaos it's better than rand() which is what the above example uses. openssl_random_pseudo_bytes() is preferred according to the PHP manual. – willbradley Dec 20 '14 at 21:58
  • 4
    @willbradley The quality of the seed is just as bad for `mt_rand`, so it's still unsuitable for any security use. – CodesInChaos Jan 14 '15 at 11:30
  • 2
    you see this is what annoys me +ChaosInCodes. You haven't looked at the question, you've just made some generic statements repeated a load of poorly held beliefs. In short: right piece of advice for a totally different question. Random passwords are fine. They are probably "x" use only. Quite honestly if you are designing your system without timed lockouts and DOS detection and "x tries then -> locked" then you are doing it wrong. IT is IMPOSSIBLE to guess a mt_rand password with such measures in place. Conversely using mt_rand will not make it EASIER to brute force a password. It just won't. – Mr Heelis Aug 09 '16 at 15:59
  • 1
    I wouldn't use \ in `$chars` – Pedro Lobito Nov 09 '17 at 02:00
  • Why wouldn't you @PedroLobito? – PeeHaa Nov 09 '17 at 03:13
  • I was using your code to generate passwords to be used as an argument to a shell script, something like: `command 'mypassword'`. If I keept the \, it would break the script if the password ended in \, since \ would escape quote, i.e:`command 'mypassword\'` – Pedro Lobito Nov 09 '17 at 10:52
32

In one line:

substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') , 0 , 10 )
Sandra
  • 1,596
  • 15
  • 22
  • 13
    This prevents re-use of the same letters as they just shuffle around but don't occur more than once. – nickdnk May 07 '15 at 10:36
  • 9
    Needless to say, nobody should be optimizing their password generation function based on line count. Even if the RNG this used were secure (it's not), avoiding repeated characters while generating a 10-character password brings you down from ~52 bits of entropy to ~50 bits of entropy (~4x faster to crack). If you extended this out to 20 characters, the non-repetition would bring you down from ~103 bits to ~94 bits (~512x faster to crack). – Jeremy Jul 11 '15 at 00:47
  • 1
    This method reminds me of the [flaw in the Enigma code](https://www.youtube.com/watch?v=V4V2bpZlqx8) Lol – hatef Jul 11 '15 at 21:23
  • 4
    `substr(str_shuffle(str_repeat($chars,$length)),0,$length);` Entropy restored – Charles-Édouard Coste Sep 21 '17 at 14:43
27

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

Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308
15

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.

jeteon
  • 3,471
  • 27
  • 40
  • 1
    Thanks for this addition. None of the existing answers noted that `openssl_random_pseudo_bytes` could produced a weak result. I didn't realize that was the case. – Jeremy Jul 11 '15 at 17:19
14

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.

phihag
  • 278,196
  • 72
  • 453
  • 469
13

Being a little smarter:

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

check it here online.

Amir Fo
  • 5,163
  • 1
  • 43
  • 51
12

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);
    }
}
srcspider
  • 10,977
  • 5
  • 40
  • 35
  • 1
    PS - this is PHP - just using \ to denote the global namespace. – Bob Gregor Apr 24 '13 at 01:33
  • Except that uniqid is not cryptographically secure. Use rand() instead: base_convert(rand(78364164096, 2821109907455), 10, 36); – Benubird Feb 20 '14 at 12:51
  • 8
    @Benubird rand() is not cryptographically secure either, according to the PHP manual. The manual suggests openssl_random_pseudo_bytes() instead. – willbradley Dec 20 '14 at 21:58
  • For most use cases, specifically where the attacker does not have access to the exact time, this is perfectly fine and produces a nice more-or-less human friendly "temporary" password. If we were to take this to the extreme the length here is far more troublesome then what function was used to generate the random number. – srcspider Jul 08 '15 at 10:44
  • I've added an example for generating fully secure strings, for those interested; but highly do not recommend using this when generating temporary passwords for users. Even using the secure version, the length problem still applies. – srcspider Jul 08 '15 at 10:55
9

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)), "=");
}
Askarel
  • 99
  • 1
  • 1
  • 1
    Reading 1024 bytes to compress into a 128-bit cryptographic hash of the entropy is a little wasteful. Also, `fread()` buffers to 8192 bytes by default, so you're always going to read that many from `/dev/urandom` with the given code. This also won't work on Windows. Kudos for using a CSPRNG, though. – Scott Arciszewski Jul 08 '15 at 09:33
7

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

Sanjeev
  • 534
  • 1
  • 5
  • 16
  • 2
    the `rand` function is not actually cryptographically secure so it might be quite a risk to generate a password using it – jeteon Jul 17 '15 at 22:06
5

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

$password_string = '!@#$%*&abcdefghijklmnpqrstuwxyzABCDEFGHJKLMNPQRSTUWXYZ23456789';
$password = substr(str_shuffle($password_string), 0, 12);
Pablo Martinez
  • 168
  • 1
  • 5
  • 1
    This is actually (very?) wrong. It actually use every char from the alphabet only once, thus severely shrinks space of all possible values (relevant to cracking). – Radoslav Bodó Jun 21 '20 at 09:34
4

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:

  • 1-999 = required
  • true = optional
  • false = disabled

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);
tim
  • 2,530
  • 3
  • 26
  • 45
3

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

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.

Community
  • 1
  • 1
Adam
  • 5,091
  • 5
  • 32
  • 49
2
  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);
        }
    
    }
    
    ?>
    
waz
  • 1,165
  • 16
  • 31
2

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);
monrejames
  • 51
  • 6
2

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)

1
//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
hakki
  • 6,181
  • 6
  • 62
  • 106
  • 2
    This is actually (very?) wrong. It actually use every char from the alphabet only once, thus severely shrinks space of all possible values (relevant to cracking). – Radoslav Bodó Jun 21 '20 at 09:29
1

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();
Zihad Ul Islam
  • 697
  • 2
  • 8
  • 17
1

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);
}
Sebastian Sulinski
  • 5,815
  • 7
  • 39
  • 61
1

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
Bruno Ribeiro
  • 1,280
  • 16
  • 21
0

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;
}
Behiry
  • 575
  • 5
  • 20
0

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
}
Kamlesh
  • 5,233
  • 39
  • 50
0

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)

Williem
  • 1,131
  • 1
  • 12
  • 19
0

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

Sergey Yurich
  • 51
  • 1
  • 4
0

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

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

0
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)
            ])
        )
        , ''
    );
}
Junaid Ali
  • 168
  • 1
  • 4
  • 13
-1
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);
user1942990
  • 60
  • 1
  • 6
  • For password generation purposes, only a secure random generator should be used, such as `random_bytes` or `random_int`. Many other solutions for random value generation, including those involving `time()`, `microtime()`, `uniqid()`, `rand()`, `mt_rand()`, `str_shuffle()`, `array_rand()`, and `shuffle()`, are much more predictable and are unsuitable if the random string will serve as a password or another secret value. See: https://stackoverflow.com/questions/4570980/generating-a-random-code-in-php/64472183#64472183 – Peter O. Apr 05 '21 at 12:01