How-to create a PHP Password Generator

PHP Password GeneratorDo you need a PHP password generator function for your user registration application or do you have to write a new script for your web application? Than is this PHP tutorial for you. The function in this tutorial is flexible enough to use it during the user registration process or for a password recovery function. The generated password from this function is so safe as you which: Generate alpha-numerical password combined with capital character or with special signs or characters. All used character are based on the number from the ASCII table. In this tutorial we will explain all the important code, find the complete function at the begin of this tutorial. 

The PHP Password Generator code/function

function create_password($pw_length = 8, $use_caps = true, $use_numeric = true, $use_specials = true) {
	$caps = array();
	$numbers = array();
	$num_specials = 0;
	$reg_length = $pw_length;
	$pws = array();
	for ($ch = 97; $ch <= 122; $ch++) $chars[] = $ch; // create a-z
	if ($use_caps) for ($ca = 65; $ca <= 90; $ca++) $caps[] = $ca; // create A-Z
	if ($use_numeric) for ($nu = 48; $nu <= 57; $nu++) $numbers[] = $nu; // create 0-9
	$all = array_merge($chars, $caps, $numbers);
	if ($use_specials) {
		$reg_length =  ceil($pw_length*0.75);
		$num_specials = $pw_length - $reg_length;
		if ($num_specials > 5) $num_specials = 5;
		for ($si = 33; $si <= 47; $si++) $signs[] = $si;
		$rs_keys = array_rand($signs, $num_specials);	
		foreach ($rs_keys as $rs) {
			$pws[] = chr($signs[$rs]);
		}
	} 
	$rand_keys = array_rand($all, $reg_length);
	foreach ($rand_keys as $rand) {
		$pw[] = chr($all[$rand]);
	}	
	$compl = array_merge($pw, $pws);	
	shuffle($compl);
	return implode('', $compl);
}

We create a for loop to build our arrays with characters, while the default characters are always included, we use if statements to include the capital or numeric characters.

	for ($ch = 97; $ch <= 122; $ch++) $chars[] = $ch; // create a-z
	if ($use_caps) for ($ca = 65; $ca <= 90; $ca++) $caps[] = $ca; // create A-Z
	if ($use_numeric) for ($nu = 48; $nu <= 57; $nu++) $numbers[] = $nu; // create 0-9

After this, we merge the three arrays together into one array called $all:

	$all = array_merge($chars, $caps, $numbers);

If the function is configured to use special characters, we use 25% from the password length for these characters. Next we check the number of used special character, if we reach 5 of them (based on the 25% from the password length) we replace the value with 5.

		$reg_length =  ceil($pw_length*0.75);
		$num_specials = $pw_length - $reg_length;
		if ($num_specials > 5) $num_specials = 5;

As before we use a for loop to create the array with special characters. We use the array_rand function to create another array with random keys and the foreach loop will add the values to the array $pws.

		for ($si = 33; $si <= 47; $si++) $signs[] = $si;
		$rs_keys = array_rand($signs, $num_specials);
		foreach ($rs_keys as $rs) {
			$pws[] = chr($signs[$rs]);
		}

With the same method as for the special characters we will build the array $pw using the alpha-numerical array.

	$rand_keys = array_rand($all, $reg_length);
	foreach ($rand_keys as $rand) {
		$pw[] = chr($all[$rand]);
	}	

The next code will merge the two password arrays and after we used the function shuffle before the password is returned as a string (using the implode function).

	$compl = array_merge($pw, $pws);	
	shuffle($compl);
	return implode('', $compl);	

With function it’s very easy to create a random password in your application, just use it this way:

$password = create_password(12, false, true, false); // creates 12 character alpha-numeric password

What do you think what we could do be better in this PHP Password Generator function? Maybe we can segment the amount of numbers or capitals? If you like to use less different characters, just decrease the numbers inside the for loops. Use this ASCII table as your reference. Please post your comments below, thanks.

Published in: PHP Scripts

13 Comments

  1. Good code, but those ‘for’ cycles look like they’re not in place :) For letters, you can use range(‘a’,’z’); and range(‘A’,’Z’);, then for ‘specials’ the cycle could be placed with range(33,47);, same with numbers. They will create array’s with the needed symbols :) It’s more practical, and it looks cleaner, and of course the performance SHOULD be better :)

  2. Hi fosron,

    Thanks for the comment, it’s funny I’m sure that I noticed that function before, but never used it :D

    I don’t think that most of the websites will see a big raise in performance. But for those this is the function in a more “compact” format:

    function create_password($pw_length = 8, $use_caps = true, $use_numeric = true, $use_specials = true) {
    	$caps = array();
    	$numbers = array();
    	$num_specials = 0;
    	$reg_length = $pw_length;
    	$pws = array();
    	$chars = range(97, 122); // create a-z
    	if ($use_caps) $caps = range(65, 90); // create A-Z
    	if ($use_numeric) $numbers = range(48, 57); // create 0-9
    	$all = array_merge($chars, $caps, $numbers);
    	if ($use_specials) {
    		$reg_length =  ceil($pw_length*0.75);
    		$num_specials = $pw_length - $reg_length;
    		if ($num_specials > 5) $num_specials = 5;
    		$signs = range(33, 47);
    		$rs_keys = array_rand($signs, $num_specials);	
    		foreach ($rs_keys as $rs) {
    			$pws[] = chr($signs[$rs]);
    		}
    	} 
    	$rand_keys = array_rand($all, $reg_length);
    	foreach ($rand_keys as $rand) {
    		$pw[] = chr($all[$rand]);
    	}	
    	$compl = array_merge($pw, $pws);	
    	shuffle($compl);
    	return implode('', $compl);
    }
    
  3. Or, simply:
    $ pear install Text_Password
    and then in your code:

    require_once 'Text/Password.php';
    echo Text_Password::create();
  4. Hi Christian,

    sure there are many options. I don’t like PEAR ;)
    Don’t forget many shared hosting provider doesn’t allow pear installs

  5. Correction of some errors I’ve made:
    – it should be “strlen($specialSymbols) – 1”
    – $alphabet instead of $alhpabet in the 1st line of the function
    – there is a “‘” repeated with the $alphabet declaration

  6. You don’t have to have a hosting provider’s permission to use PEAR packages (hint: they work without PEAR installer).
    As for the code, how about something like this:

    function randomString($length = 16) {
        $alhpabet = 'ABCDEFGHIJKLMNOPORRQSTUWVXYZabcdefghijklmnoprqstuwvxyz0123456789!@#$%^&*?';
        $alphabetLenght = strlen($alphabet) - 1;
        $string = '';
        while($length) {
            $string .= $alphabet[mt_rand(0, $alphabetLenght)];
            --$length;
        }
        return $string;
    }
    

    For a “special symbols in 25% of the password” thing you would have to have a separate variable for those special symbols and then in the loop something like this:

    if (mt_rand(0,3)) {
        $string .= $alphabet[mt_rand(0, $alphabetLenght)];
    } else {
        $string .= $specialSymbols[mt_rand(0, strlen($specialSymbols))];
    }
    

    That won’t guarantee you perfect 25% every time, but statistically it should oscillate around that number (gotta love math!) and it’s much more elegant solution I think.

    1. Hallo Tomek,

      First of all, thanks for posting your PHP code examples. :)

      Why not using PEAR?

      Sure your can download all the PHP classes from the PEAR site.
      I think the best is the PEAR distribution system, so why should I use PEAR? Because there are so many old projects? Yes there are several good maintained projects but, how do I know which project is a good one? If I need to use a PHP “library”, is Zend Framework a good choise too.

      About your function, I used this kind of code very often (short and simple), but the function in this PHP tutorial has much more control about which character I can use.

      Don’t forget this tutorial is supposed to show how stuff works ;)

  7. Thanks for sharing a code sample, but please don’t teach people to use bad coding style. Omitting braces is a recipe for disaster here:

    if ($use_caps) for ($ca = 65; $ca <= 90; $ca++) $caps[] = $ca; // create A-Z

    Also, the way of specifying options can get awkward. A bit mask is more elegant here:

    function create_password($options) {
      if ($options & PASSWORD_USE_SPECIALS) {
        /* ... */
      }
    }

    And as said before, don't reinvent the wheel. :-)

    1. Hi Jan,

      Normally I use braces in my code, but for tutorials I try to keep the code as short as possible … :)

      I don’t understand your second comment, do you suggest to use an array for the options? Why do you suggest a constant variable?

  8. Nice script. Thanks

    I have one concern with it (sorry, I’m going to be a little bit blunt), but the syntax you use is atrocious and disgusting:

    if ($use_numeric) for ($nu = 48; $nu <= 57; $nu++) $numbers[] = $nu;

    This is acceptable though:

    if ($use_numeric) $numbers = range(48, 57);

    but this is better:

    if ($use_numeric) 
        $numbers = range(48, 57);

    Code readability is very important...

  9. Hello Aziz,
    you’re right readability is important, but is also about personal “coding style” ;)
    I see a lot of people coding this way:

    if ($val) 
    {
        echo 'Hello!';
    }
    

    This is something I don’t like.
    Right my IF statement with a FOR loop on a single row without using braces is very short, but I can read this very well:
    if ($use_numeric) $numbers = range(48, 57);

    btw. You see that WordPress gives a new format to posted code as well.

  10. Hello Olaf,

    You are right. if we use the single row without using braces like if ($use_numeric) $numbers = range(48, 57);
    is very short. but the beginners can’t able to understood it at first look.

    1. @srisoftwarez,
      I remember me that I had some problems (years ago with notations like:

      $var ($is_true) ? 'cool' : 'not cool';

      But if you need to pass only one value to a variable , it should be fine to use these short notations. If I have 10 statements like this I can choose from 10 rows I need to scroll or 40

Comments are closed.