PHP 7 standard library provides the random_bytes($length) function that generate cryptographically secure pseudo-random bytes.
Example:
$bytes = random_bytes(20);
var_dump(bin2hex($bytes));
The above example will output something similar to:
string(40) "5fe69c95ed70a9869d9f9af7d8400a6673bb9ce9"
More info: http://php.net/manual/en/function.random-bytes.php
PHP 5 (outdated)
I was just looking into how to solve this same problem, but I also want my function to create a token that can be used for password retrieval as well. This means that I need to limit the ability of the token to be guessed. Because uniqid is based on the time, and according to php.net "the return value is little different from microtime()", uniqid does not meet the criteria. PHP recommends using openssl_random_pseudo_bytes() instead to generate cryptographically secure tokens.
A quick, short and to the point answer is:
bin2hex(openssl_random_pseudo_bytes($bytes))
which will generate a random string of alphanumeric characters of length = $bytes * 2. Unfortunately this only has an alphabet of [a-f][0-9], but it works.
Below is the strongest function I could make that satisfies the criteria (This is an implemented version of Erik's answer).
function crypto_rand_secure(
max)
{
$range =
min;
if ($range < 1) return $min; // not so random...
$log = ceil(log($range, 2));
$bytes = (int) ($log / 8) + 1; // length in bytes
$bits = (int) $log + 1; // length in bits
$filter = (int) (1 << $bits) - 1; // set all lower bits to 1
do {
$rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
rnd & $filter; // discard irrelevant bits
} while (
range);
return
rnd;
}
function getToken($length)
{
$token = "";
$codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
$codeAlphabet.= "0123456789";
$max = strlen($codeAlphabet); // edited
for (
i < $length; $i++) {
$token .= $codeAlphabet[crypto_rand_secure(0, $max-1)];
}
return $token;
}
crypto_rand_secure( works as a drop in replacement for max)
rand() or mt_rand. It uses openssl_random_pseudo_bytes to help create a random number between max.
getToken($length) creates an alphabet to use within the token and then creates a string of length $length.
Source: https://www.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322
Answer from Scott on Stack OverflowPHP 7 standard library provides the random_bytes($length) function that generate cryptographically secure pseudo-random bytes.
Example:
$bytes = random_bytes(20);
var_dump(bin2hex($bytes));
The above example will output something similar to:
string(40) "5fe69c95ed70a9869d9f9af7d8400a6673bb9ce9"
More info: http://php.net/manual/en/function.random-bytes.php
PHP 5 (outdated)
I was just looking into how to solve this same problem, but I also want my function to create a token that can be used for password retrieval as well. This means that I need to limit the ability of the token to be guessed. Because uniqid is based on the time, and according to php.net "the return value is little different from microtime()", uniqid does not meet the criteria. PHP recommends using openssl_random_pseudo_bytes() instead to generate cryptographically secure tokens.
A quick, short and to the point answer is:
bin2hex(openssl_random_pseudo_bytes($bytes))
which will generate a random string of alphanumeric characters of length = $bytes * 2. Unfortunately this only has an alphabet of [a-f][0-9], but it works.
Below is the strongest function I could make that satisfies the criteria (This is an implemented version of Erik's answer).
function crypto_rand_secure(
max)
{
$range =
min;
if ($range < 1) return $min; // not so random...
$log = ceil(log($range, 2));
$bytes = (int) ($log / 8) + 1; // length in bytes
$bits = (int) $log + 1; // length in bits
$filter = (int) (1 << $bits) - 1; // set all lower bits to 1
do {
$rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
rnd & $filter; // discard irrelevant bits
} while (
range);
return
rnd;
}
function getToken($length)
{
$token = "";
$codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
$codeAlphabet.= "0123456789";
$max = strlen($codeAlphabet); // edited
for (
i < $length; $i++) {
$token .= $codeAlphabet[crypto_rand_secure(0, $max-1)];
}
return $token;
}
crypto_rand_secure( works as a drop in replacement for max)
rand() or mt_rand. It uses openssl_random_pseudo_bytes to help create a random number between max.
getToken($length) creates an alphabet to use within the token and then creates a string of length $length.
Source: https://www.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322
Security Notice: This solution should not be used in situations where the quality of your randomness can affect the security of an application. In particular,
rand()anduniqid()are not cryptographically secure random number generators. See Scott's answer for a secure alternative.
If you do not need it to be absolutely unique over time:
md5(uniqid(rand(), true))
Otherwise (given you have already determined a unique login for your user):
md5(uniqid($your_user_login, true))
Videos
First make a string with all your possible characters:
$characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
You could also use range() to do this more quickly.
Then, in a loop, choose a random number and use it as the index to the $characters string to get a random character, and append it to your string:
$string = '';
$max = strlen($characters) - 1;
for (
i < $random_string_length; $i++) {
$string .= $characters[mt_rand(0, $max)];
}
$random_string_length is the length of the random string.
I like this function for the job
function randomKey($length) {
$pool = array_merge(range(0,9), range('a', 'z'),range('A', 'Z'));
for(
i < $length; $i++) {
$key .= $pool[mt_rand(0, count($pool) - 1)];
}
return $key;
}
echo randomKey(20);