Eu estava pensando em como resolver esse mesmo problema, mas também quero que minha função crie um token que também possa ser usado para recuperação de senha. Isso significa que eu preciso limitar a capacidade do token de ser adivinhado. Como uniqid
é baseado no tempo, e de acordo com o php.net "o valor de retorno é um pouco diferente de microtime ()", uniqid
não atende aos critérios. O PHP recomenda o uso openssl_random_pseudo_bytes()
para gerar tokens criptograficamente seguros.
Uma resposta rápida, curta e direta é:
bin2hex(openssl_random_pseudo_bytes($bytes))
que gerará uma sequência aleatória de caracteres alfanuméricos de comprimento = $ bytes * 2. Infelizmente, isso só tem um alfabeto de [a-f][0-9]
, mas funciona.
Abaixo está a função mais forte que eu poderia desempenhar que satisfaz os critérios (esta é uma versão implementada da resposta de Erik).
function crypto_rand_secure($min, $max)
{
$range = $max - $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 = $rnd & $filter; // discard irrelevant bits
} while ($rnd > $range);
return $min + $rnd;
}
function getToken($length)
{
$token = "";
$codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
$codeAlphabet.= "0123456789";
$max = strlen($codeAlphabet); // edited
for ($i=0; $i < $length; $i++) {
$token .= $codeAlphabet[crypto_rand_secure(0, $max-1)];
}
return $token;
}
crypto_rand_secure($min, $max)
funciona como uma gota em substituição a rand()
ou mt_rand
. Ele usa openssl_random_pseudo_bytes para ajudar a criar um número aleatório entre $ min e $ max.
getToken($length)
cria um alfabeto para usar no token e, em seguida, cria uma sequência de comprimento $length
.
EDIT: Eu esqueci de citar a fonte - http://us1.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322
EDIT (PHP7): Com o lançamento do PHP7, a biblioteca padrão agora possui duas novas funções que podem substituir / melhorar / simplificar a função crypto_rand_secure acima. random_bytes($length)
erandom_int($min, $max)
http://php.net/manual/en/function.random-bytes.php
http://php.net/manual/en/function.random-int.php
Exemplo:
function getToken($length){
$token = "";
$codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
$codeAlphabet.= "0123456789";
$max = strlen($codeAlphabet);
for ($i=0; $i < $length; $i++) {
$token .= $codeAlphabet[random_int(0, $max-1)];
}
return $token;
}