Generate random strings (tokens) of variable lengths with selectable characters and output
in text, binary, octal, decimal or hexadecimal.
By default the function uses what I will refer to as standard and special printable ASCII
characters. The standard characters are a-z, A-Z and 0-9. The special characters are
! " # $ % ^ ' ( ) * + , - . / ; ; < = > ? @ [ \ ] ^ _ `
To understand why I did this, here is one of the many articles available
explaining the weaknesses in PHP's randomization functions.
http: phpsecurity.readthedocs.org/en/latest/Insufficient-Entropy-For-Random-Values.html
My solution was simply to rely on the SSH random byte function, converting the returned
random byte into decimal and making sure it falls in my range of desired characters.
This leverages both the added security of the SSH randomization and additionally makes
the amount of loops which will be used to build the string impossible to predict thereby
reducing the chance of any possible successful attack on the token.
You can define the length of the string to return (pre base conversion) or the default is 64.
You can optionally select the base of the output. (If unsure, use False or 5). Valid options
are 1 for Binary, 2 for Octal, 3 for Decimal, 4 for Hexidecimal and 5 or False for normal text.
You can provide an array of characters to use, a single character to use or a string which
the function will split into an array and use (after remove any duplicates).
Examples:
Default: 64 character string using standard and special characters and outputting in text.
Input: randomToken();
Output: #Z=9%|b.S$1\R}cj)rblGAQn_,g=.gM~K{@u=aY&Z1d7HOlP2)kLZIV%{h2gj61[
32 character token using standard and special characters and output text.
Input: randomToken(16);
Output: Ps%X5&:f,9S|F:`8\zSW%(Wldz#siz44
16 character token using standard and special characters and in output base-2 The output length
selected was 16 characters but due to the output being converted to Binary it will actually
be 128 characters (16 * 8).
Input: randomToken(16, 1);
Output: 00111100001110000011101000111101100110001000111011001101111001101111001110110001010001001001111001001100001011100011100100010110100111001
16 character token using standard and special characters and output in base-8 The output length
selected was 16 characters but due to the output being converted to Octal it will actually
be 48 characters (16 * 3).
Input: randomToken(16, 2);
Output: 142074146170166155067050061101173076156162051167
16 character token using standard and special characters and output in base-10 The output length
selected was 16 characters but due to the output being converted to Decimal it will actually
be 32 to 48 characters (16 * 2|3).
Input: randomToken(16, 3);
Output: 834698110507238106124121361177411210470
16 character token using standard and special characters and output in base-16 The output
length selected was 16 characters but due to the output being converted to Hexadecimal it
will actually be 64 characters (16 * 4).
Input: randomToken(16, 4);
Output: 0x5c0x4e0x7a0x380x320x500x640x520x5f0x4f0x760x4d0x440x4a0x630x6d
16 character token using standard and special characters and output in text.
Input: randomToken(16, 5); OR randomToken(16, false);
Output: d2C^.88~7S[!LNHH
32 character token using only special characters and output in text.
Input: randomToken(16, false, false);
Output: +}*|%?"/=`)(~#*`^.+:"[^~^'\,({~'
32 character token using only standard characters and output in text.
Input: randomToken(16, false, true, false);
Output: BAgL1HnYuykKJiMQKH7LBC4Xjr2j22QH
128 character token using only the characters #, $, and @.
Input: randomToken(128, false, false, false, '#$@')); OR randomToken(128, false, false, false, array('#', '$', '@'));
Output: @@#$$@#@$#$@#@@##$#$#@###$@#$@$@$@#$$@##@#$@####@@$@$##$#@$##@$#@$#$$@#$$#@#@##$##@@$$@@$##$#@$@@#$@$@@@$#@$@#$@@@@@@@######$##@
function randomToken($len = 64, $output = 5, $standardChars = true, $specialChars = true, $chars = array()) {
$out = '';
$len = intval($len);
$outputMap = array(1 => 2, 2 => 8, 3 => 10, 4=> 16, 5 => 10);
if (!is_array($chars)) { $chars = array_unique(str_split($chars)); }
if ($standardChars) { $chars = array_merge($chars, range(48, 57),range(65, 90), range(97, 122)); }
if ($specialChars) { $chars = array_merge($chars, range(33, 47),range(58, 64), range(91, 96), range(123, 126)); }
array_walk($chars, function(&$val) { if (!is_int($val)) { $val = ord($val); } });
if (is_int($len)) {
while ($len) {
$tmp = ord(openssl_random_pseudo_bytes(1));
if (in_array($tmp, $chars)) {
if (!$output || !in_array($output, range(1,5)) || $output == 3 || $output == 5) { $out .= ($output == 3) ? $tmp : chr($tmp); }
else {
$based = base_convert($tmp, 10, $outputMap[$output]);
$out .= ((($output == 1) ? '00' : (($output == 4) ? '0x' : '')) . (($output == 2) ? sprintf('%03d', $based) : $based));
}
$len--;
}
}
}
return (empty($out)) ? false : $out;
}
I plan to implement a markdown parser for these descriptions to add more flexibility.