Introduction


Figure 1Often one of the first things a new PHP programmer wants to do is create a user system. They want to build something they can login to. I remember the first time I built such a system. When I first logged on my eyes got big and I said to myself "that's cool!".

One of the prerequisites of such a system are session ids, which are unique, usually alpha-numeric tokens a web application can use to uniquely identify users and present them with a personalized experience inside the application.

There are many uses for tokens, for example, when a new user registers on ITNewb they're sent a welcome email that contains an "account activation" link. This link contains a sufficiently unique and private token used to identify which new user is trying to activate their account and validate their registration (as they knew what the code was). So first up I'm going to cover generating these tokens, followed by generating random passwords.

Generating Tokens


The following function genToken accepts 2 parameters: integer $len and boolean $md5. Use the $len parameter to indicate the desired length of the token to be returned, and $md5 to indicate whether you want the generated token run through the MD5 one-way hashing function. I'll walk you through the function down below.

  1. function genToken( $len = 32, $md5 = true ) {
  2.  
  3.     # Seed random number generator
  4.     # Only needed for PHP versions prior to 4.2
  5.     mt_srand( (double)microtime()*1000000 );
  6.  
  7.     # Array of characters, adjust as desired
  8.     $chars = array(
  9.         'Q', '@', '8', 'y', '%', '^', '5', 'Z', '(', 'G', '_', 'O', '`',
  10.         'S', '-', 'N', '<', 'D', '{', '}', '[', ']', 'h', ';', 'W', '.',
  11.         '/', '|', ':', '1', 'E', 'L', '4', '&', '6', '7', '#', '9', 'a',
  12.         'A', 'b', 'B', '~', 'C', 'd', '>', 'e', '2', 'f', 'P', 'g', ')',
  13.         '?', 'H', 'i', 'X', 'U', 'J', 'k', 'r', 'l', '3', 't', 'M', 'n',
  14.         '=', 'o', '+', 'p', 'F', 'q', '!', 'K', 'R', 's', 'c', 'm', 'T',
  15.         'v', 'j', 'u', 'V', 'w', ',', 'x', 'I', '$', 'Y', 'z', '*'
  16.     );
  17.  
  18.     # Array indice friendly number of chars; empty token string
  19.     $numChars = count($chars) - 1; $token = '';
  20.  
  21.     # Create random token at the specified length
  22.     for ( $i=0; $i<$len; $i++ )
  23.         $token .= $chars[ mt_rand(0, $numChars) ];
  24.  
  25.     # Should token be run through md5?
  26.     if ( $md5 ) {
  27.  
  28.         # Number of 32 char chunks
  29.         $chunks = ceil( strlen($token) / 32 ); $md5token = '';
  30.  
  31.         # Run each chunk through md5
  32.         for ( $i=1; $i<=$chunks; $i++ )
  33.             $md5token .= md5( substr($token, $i * 32 - 32, 32) );
  34.  
  35.         # Trim the token
  36.         $token = substr($md5token, 0, $len);
  37.  
  38.     } return $token;
  39. }


Usage Example


Here are two examples: the first uses the default options ($len 32, md5 true) and the second sets $len to 39 and $md5 to false.

Figure 2

genToken


genToken starts out be seeding the random number generator. As commented, this is only necessary in PHP versions prior to 4.2, as after that this is done automatically.

  1. mt_srand( (double)microtime()*1000000 );


An array of randomly positioned alpha, numeric and special characters is then created. We'll randomly select characters from this array to build our token. Feel free to add and/or remove characters from this array. If you do add or remove something, the rest of the code will still function properly without any other changes to the code.

  1. $chars = array(
  2.     'Q', '@', '8', 'y', '%', '^', '5', 'Z', '(', 'G', '_', 'O', '`',
  3.     'S', '-', 'N', '<', 'D', '{', '}', '[', ']', 'h', ';', 'W', '.',
  4.     '/', '|', ':', '1', 'E', 'L', '4', '&', '6', '7', '#', '9', 'a',
  5.     'A', 'b', 'B', '~', 'C', 'd', '>', 'e', '2', 'f', 'P', 'g', ')',
  6.     '?', 'H', 'i', 'X', 'U', 'J', 'k', 'r', 'l', '3', 't', 'M', 'n',
  7.     '=', 'o', '+', 'p', 'F', 'q', '!', 'K', 'R', 's', 'c', 'm', 'T',
  8.     'v', 'j', 'u', 'V', 'w', ',', 'x', 'I', '$', 'Y', 'z', '*'
  9. );


Next an array indice friendly number of characters variable is set, which we'll use when randomly selecting characters from $chars without exceeding the character range. Also, to prevent PHP undefined variable notices $token is set to an empty string.

  1. $numChars = count($chars) - 1;
  2. $token = '';


Now we're ready to create the token. Using a for loop, a random character is selected from the $chars array and appended to the $token string. Notice I'm using mt_rand instead of rand because mt_rand generates better random numbers than rand.

  1. for ( $i=0; $i<$len; $i++ )
  2.     $token .= $chars[ mt_rand(0, $numChars) ];


At this point, we'll have a token containing alpha, numeric and special characters. Some of these characters may need to be URL encoded if the token will be used in a URL. You can use the PHP functions urlencode and urldecode to handle encoding. Another option, if you don't want to mess with encoding is to run the generated token chunk(s) through md5, which produces a 32 character hexadecimal number derived from the randomly generated token that's URL friendly as-is.

  1. if ( $md5 ) {
  2.  
  3.     # Number of 32 char chunks; $md5token empty string
  4.     $chunks = ceil( strlen($token) / 32 ); $md5token = '';
  5.  
  6.     # Run each chunk through md5
  7.     for ( $i=1; $i<=$chunks; $i++ )
  8.         $md5token .= md5( substr($token, $i * 32 - 32, 32) );
  9.  
  10.     # Trim the token
  11.     $token = substr($md5token, 0, $len);
  12.  
  13. }


Finally, genToken returns the $token;

Generating Passwords


Next up is the genPasswd function which accepts 2 parameters: integer $len and boolean $special. Use the $len parameter to indicate the desired length of the password to be returned, and $special to indicate whether special characters should be permitted in the password. I'll walk you through the function down below.

  1. function genPasswd( $len = 8, $special = true ) {
  2.  
  3.     # Seed random number generator
  4.     # Only needed for PHP versions prior to 4.2
  5.     mt_srand( (double)microtime()*1000000 );
  6.  
  7.     # Array of digits, lower and upper characters; empty passwd string
  8.     $passwd = '';
  9.     $chars = array(
  10.         'digits' => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
  11.         'lower' => array(
  12.             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  13.             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
  14.         ),
  15.         'upper' => array(
  16.             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  17.             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
  18.         )
  19.     );
  20.  
  21.     # Add special chars to array, if permitted; adjust as desired
  22.     if ( $special ) $chars['special'] = array(
  23.         '!', '@', '#', '$', '%', '^', '&', '*', '_', '+'
  24.     );
  25.  
  26.     # Array indices (ei- digits, lower, upper)
  27.     $charTypes = array_keys($chars);
  28.     # Array indice friendly number of char types
  29.     $numTypes = count($charTypes) - 1;
  30.  
  31.     # Create random password
  32.     for ( $i=0; $i<$len; $i++ ) {
  33.  
  34.         # Random char type
  35.         $charType = $charTypes[ mt_rand(0, $numTypes) ];
  36.         # Append random char to $passwd
  37.         $passwd .= $chars[$charType][
  38.             mt_rand(0, count( $chars[$charType] ) - 1 )
  39.         ];
  40.  
  41.     } return $passwd;
  42. }


Usage Example


Here are two examples: the first uses the default options ($len 8, $special true) and the second sets $len to 10 and $special to false.

Figure 3

genPasswd


Just like genToken, the first thing genPasswd does is seed the random number generator. Next an array of available char types and characters is created. If $special is true, an array of special chars is also added. Feel free to add and/or remove special chars from the special chars array.

  1. mt_srand( (double)microtime()*1000000 );
  2.  
  3. # Array of digits, lower and upper characters; empty passwd string
  4. $passwd = '';
  5. $chars = array(
  6.     'digits' => array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
  7.     'lower' => array(
  8.         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  9.         'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
  10.     ),
  11.     'upper' => array(
  12.         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  13.         'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
  14.     )
  15. );
  16.  
  17. # Add special chars to array, if permitted; adjust as desired
  18. if ( $special ) $chars['special'] = array(
  19.     '!', '@', '#', '$', '%', '^', '&', '*', '_', '+'
  20. );


Next an array is created that holds numeric indice to char type string indices as well as a variable to hold the number of permitted char types.

  1. # Array indices (ei- digits, lower, upper)
  2. $charTypes = array_keys($chars);
  3.  
  4. # Array indice friendly number of char types
  5. $numTypes = count($charTypes) - 1;


Finally, the password is generated and returned. On each iteration of the for loop, a char type (digit, lower, upper or special) is randomly chosen followed by the random selection of a character in that char type group which is then appended to the $passwd string.

  1. # Create random password
  2. for ( $i=0; $i<$len; $i++ ) {
  3.  
  4.     # Random char type
  5.     $charType = $charTypes[ mt_rand(0, $numTypes) ];
  6.     # Append random char to $passwd
  7.     $passwd .= $chars[$charType][
  8.         mt_rand(0, count( $chars[$charType] ) - 1 )
  9.     ];
  10.  
  11. } return $passwd;


And that's it! I hope these functions help you, and if you derive your own functions I hope you'll share them with us in the comments.