PHP: Como gerar uma sequência alfanumérica aleatória, exclusiva?


380

Como seria possível gerar uma sequência aleatória e exclusiva usando números e letras para uso em um link de verificação? Como quando você cria uma conta em um site, e ele envia um e-mail com um link, e você precisa clicar nesse link para verificar sua conta ... sim ... uma delas.

Como posso gerar um usando PHP?

Atualização: Acabei de me lembrar uniqid(). É uma função PHP que gera um identificador exclusivo com base no tempo atual em microssegundos. Eu acho que vou usar isso.


Tudo que você precisa são seqüências de caracteres e números aleatórios distribuídos uniformemente.
Artelius

10
Olá, Andrew, você deve escolher Scottcomo a resposta correta. Scott está usando o gerador de números psudo-aleatórios criptograficamente seguros (CSPRNG) do OpenSSL, que escolherá a fonte mais segura de entropia com base em sua plataforma.
rook

3
Quem ler este depois de 2015, por favor, por favor, veja aqui: paragonie.com/blog/2015/07/... A maioria das respostas principais são falhos mais ou menos ...
rugk

OpenSSL e uniqidsão inseguros. Use algo como Random::alphanumericString($length)ou Random::alphanumericHumanString($length).
caw

Respostas:


305

Aviso de segurança : Esta solução não deve ser usada em situações em que a qualidade de sua aleatoriedade pode afetar a segurança de um aplicativo. Em particular, rand()e uniqid()não são geradores de números aleatórios criptograficamente seguros . Veja a resposta de Scott para uma alternativa segura.

Se você não precisar que seja absolutamente único ao longo do tempo:

md5(uniqid(rand(), true))

Caso contrário (dado que você já determinou um login exclusivo para seu usuário):

md5(uniqid($your_user_login, true))

90
Ambos os métodos não garantem exclusividade - o comprimento da entrada da função md5 é maior que o comprimento de sua saída e de acordo com o en.wikipedia.org/wiki/Pigeonhole_principle, a colisão é garantida. Por outro lado, quanto maior a população que depende de hashes para atingir o ID "único", maior a probabilidade de ocorrer pelo menos uma colisão (consulte en.wikipedia.org/wiki/Birthday_problem ). A probabilidade pode ser pequena para a maioria das soluções, mas ainda existe.
Dariusz Walczak

12
Este não é um método seguro de gerar valores aleatórios. Veja a resposta de Scott.
rook

4
Para confirmações de e-mail que expiram relativamente cedo, acho que a pequena possibilidade de uma pessoa confirmar um dia o e-mail de outra pessoa é um risco insignificante. Mas você sempre pode verificar se o token já existe no banco de dados após criá-lo e escolher um novo, se for o caso. No entanto, o tempo que você gasta escrevendo esse trecho de código provavelmente é desperdiçado, pois provavelmente nunca será executado.
26414 Andrew

Observe que o md5 retorna valores hexadecimais, o que significa que o conjunto de caracteres é limitado a [0-9] e [af].
Thijs Riezebeek

11
md5 pode ter colisões, você acabou de arruinar a vantagem do
uniqid

507

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 ()", uniqidnã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;
}

2
Acordado. O armazenamento de senha em texto sem formatação é horrível! (Eu uso blowfish.) Mas depois que o token é gerado, ele permite que o titular do token redefina a senha; portanto, o token é equivalente a senha enquanto é válido (e é tratado como tal).
8183 Scott

23
Ei, eu combinei sua excelente código com o conveniente Texto Kohana :: random () funcionalidade método e criou esta essência: gist.github.com/raveren/5555297
raveren

9
Perfeito! Eu testei com 10 caracteres como comprimento. 100000 tokens e ainda sem duplicatas!
precisa

5
Eu usei esse processo e achei super lento. Com um comprimento de 36, atingiu o tempo limite no servidor de desenvolvimento. Com um comprimento de 24, ainda demorava cerca de 30 segundos. Não sei o que fiz de errado, mas era muito lento para mim e optei por outra solução.
Shane

5
Você também pode usar em base64_encodevez de bin2hexobter uma sequência mais curta com alfabeto maior.
erjiang

91

Versão orientada a objeto da solução mais votada

Eu criei uma solução orientada a objetos com base na resposta de Scott :

<?php

namespace Utils;

/**
 * Class RandomStringGenerator
 * @package Utils
 *
 * Solution taken from here:
 * http://stackoverflow.com/a/13733588/1056679
 */
class RandomStringGenerator
{
    /** @var string */
    protected $alphabet;

    /** @var int */
    protected $alphabetLength;


    /**
     * @param string $alphabet
     */
    public function __construct($alphabet = '')
    {
        if ('' !== $alphabet) {
            $this->setAlphabet($alphabet);
        } else {
            $this->setAlphabet(
                  implode(range('a', 'z'))
                . implode(range('A', 'Z'))
                . implode(range(0, 9))
            );
        }
    }

    /**
     * @param string $alphabet
     */
    public function setAlphabet($alphabet)
    {
        $this->alphabet = $alphabet;
        $this->alphabetLength = strlen($alphabet);
    }

    /**
     * @param int $length
     * @return string
     */
    public function generate($length)
    {
        $token = '';

        for ($i = 0; $i < $length; $i++) {
            $randomKey = $this->getRandomInteger(0, $this->alphabetLength);
            $token .= $this->alphabet[$randomKey];
        }

        return $token;
    }

    /**
     * @param int $min
     * @param int $max
     * @return int
     */
    protected function getRandomInteger($min, $max)
    {
        $range = ($max - $min);

        if ($range < 0) {
            // Not so random...
            return $min;
        }

        $log = log($range, 2);

        // Length in bytes.
        $bytes = (int) ($log / 8) + 1;

        // Length in bits.
        $bits = (int) $log + 1;

        // Set all lower bits to 1.
        $filter = (int) (1 << $bits) - 1;

        do {
            $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));

            // Discard irrelevant bits.
            $rnd = $rnd & $filter;

        } while ($rnd >= $range);

        return ($min + $rnd);
    }
}

Uso

<?php

use Utils\RandomStringGenerator;

// Create new instance of generator class.
$generator = new RandomStringGenerator;

// Set token length.
$tokenLength = 32;

// Call method to generate random string.
$token = $generator->generate($tokenLength);

Alfabeto personalizado

Você pode usar o alfabeto personalizado, se necessário. Basta passar uma string com caracteres suportados para o construtor ou setter:

<?php

$customAlphabet = '0123456789ABCDEF';

// Set initial alphabet.
$generator = new RandomStringGenerator($customAlphabet);

// Change alphabet whenever needed.
$generator->setAlphabet($customAlphabet);

Aqui estão as amostras de saída

SRniGU2sRQb2K1ylXKnWwZr4HrtdRgrM
q1sRUjNq1K9rG905aneFzyD5IcqD4dlC
I0euIWffrURLKCCJZ5PQFcNUCto6cQfD
AKwPJMEM5ytgJyJyGqoD5FQwxv82YvMr
duoRF6gAawNOEQRICnOUNYmStWmOpEgS
sdHUkEn4565AJoTtkc8EqJ6cC4MLEHUx
eVywMdYXczuZmHaJ50nIVQjOidEVkVna
baJGt7cdLDbIxMctLsEBWgAw5BByP5V0
iqT0B2obq3oerbeXkDVLjZrrLheW4d8f
OUQYCny6tj2TYDlTuu1KsnUyaLkeObwa

Espero que ajude alguém. Felicidades!


Sinto muito, mas como faço para executar essa coisa? Eu fiz, $obj = new RandomStringGenerator;mas qual método devo chamar? Obrigado.
SG552

@ sg552, você deve chamar o generatemétodo como no exemplo acima. Basta passar um número inteiro para ele para especificar o comprimento da string resultante.
Slava Fomin II

Obrigado, funciona para mim, mas Custom Alphabetnão funcionou. Recebi uma saída vazia quando ecoei. Enfim, eu nem tenho certeza do que é o segundo exemplo, Custom Alphabetentão acho que fico com o primeiro exemplo. Obrigado.
SG552

11
Bom, mas muito exagero na maioria dos cenários, a menos que seu projeto depende fortemente de códigos gerados aleatoriamente
dspacejs

11
sim legal, mas um exagero, especialmente considerando que está praticamente obsoleto agora para o php 5.7 #
181 Andrew Andrew

39

Estou atrasado, mas estou aqui com alguns bons dados de pesquisa com base nas funções fornecidas pela resposta de Scott . Então, configurei uma gota do Digital Ocean apenas para esse teste automatizado de cinco dias e armazenei as seqüências exclusivas geradas em um banco de dados MySQL.

Durante esse período de teste, usei 5 comprimentos diferentes (5, 10, 15, 20, 50) e +/- 0,5 milhão de registros foram inseridos para cada comprimento. Durante o meu teste, apenas o comprimento 5 gerou +/- 3K duplicatas em 0,5 milhão e os comprimentos restantes não geraram duplicatas. Portanto, podemos dizer que, se usarmos um comprimento de 15 ou mais com as funções de Scott, poderemos gerar seqüências únicas altamente confiáveis. Aqui está a tabela que mostra meus dados de pesquisa:

insira a descrição da imagem aqui

Atualização: criei um aplicativo Heroku simples usando essas funções que retornam o token como uma resposta JSON. O aplicativo pode ser acessado em https://uniquestrings.herokuapp.com/api/token?length=15

Eu espero que isso ajude.


33

Você pode usar o UUID (Universally Unique Identifier), ele pode ser usado para qualquer finalidade, desde a sequência de autenticação do usuário até a identificação da transação de pagamento.

Um UUID é um número de 16 octetos (128 bits). Em sua forma canônica, um UUID é representado por 32 dígitos hexadecimais, exibidos em cinco grupos separados por hífens, no formato 8-4-4-4-12, para um total de 36 caracteres (32 caracteres alfanuméricos e quatro hífens).

function generate_uuid() {
    return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
        mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
        mt_rand( 0, 0xffff ),
        mt_rand( 0, 0x0C2f ) | 0x4000,
        mt_rand( 0, 0x3fff ) | 0x8000,
        mt_rand( 0, 0x2Aff ), mt_rand( 0, 0xffD3 ), mt_rand( 0, 0xff4B )
    );

}

// chamando função

$transationID = generate_uuid();

alguns exemplos de saídas serão como:

E302D66D-87E3-4450-8CB6-17531895BF14
22D288BC-7289-442B-BEEA-286777D559F2
51B4DE29-3B71-4FD2-9E6C-071703E1FF31
3777C8C6-9FF5-4C78-AAA2-08A47F555E81
54B91C72-2CF4-4501-A6E9-02A60DCBAE4C
60F75C7C-1AE3-417B-82C8-14D456542CD7
8DE0168D-01D3-4502-9E59-10D665CEBCB2

espero que ajude alguém no futuro :)


Parece fantástico, adicionado à minha lista!
Mustafa Erdogan

32

Esta função irá gerar uma chave aleatória usando números e letras:

function random_string($length) {
    $key = '';
    $keys = array_merge(range(0, 9), range('a', 'z'));

    for ($i = 0; $i < $length; $i++) {
        $key .= $keys[array_rand($keys)];
    }

    return $key;
}

echo random_string(50);

Exemplo de saída:

zsd16xzv3jsytnp87tk7ygv73k8zmr0ekh6ly7mxaeyeh46oe8

6
Depois de um tempo você começa aos mesmos números
Sharpless512

11
Isso não é totalmente aleatório, porque nunca terá o mesmo chacater mais de uma vez.
EricP

16

Eu uso este one-liner:

base64_encode(openssl_random_pseudo_bytes(3 * ($length >> 2)));

onde length é o comprimento da string desejada (divisível por 4, caso contrário, ela é arredondada para o número mais próximo divisível por 4)


6
Nem sempre retorna apenas caracteres alfanuméricos. Ele pode conter caracteres como==
user3459110

11
Se usado em um URL, base64url_encodepode ser usado em vez disso, veja aqui: php.net/manual/en/function.base64-encode.php
Paul

9

Use o código abaixo para gerar o número aleatório de 11 caracteres ou altere o número conforme sua exigência.

$randomNum=substr(str_shuffle("0123456789abcdefghijklmnopqrstvwxyz"), 0, 11);

ou podemos usar a função personalizada para gerar o número aleatório

 function randomNumber($length){
     $numbers = range(0,9);
     shuffle($numbers);
     for($i = 0;$i < $length;$i++)
        $digits .= $numbers[$i];
     return $digits;
 }

 //generate random number
 $randomNum=randomNumber(11);

3
Isso nunca pode gerar a sequência "aaaaaaaaaaa" ou "aaaaabbbbbb". Ele apenas escolhe uma substring de uma permutação aleatória do alfabeto. A cadeia longa de 11 caracteres possui apenas V (11,35) = 288 valores possíveis. Não use isso se você espera que as strings sejam únicas!
kdojeteri 5/09

@Peping then dosubstr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstvwxyz', 36)), 0, 11);
Tim Hallman

7
  1. Gere um número aleatório usando seu gerador de números aleatórios favorito
  2. Multiplique e divida para obter um número correspondente ao número de caracteres no alfabeto de código
  3. Obtenha o item nesse índice no seu alfabeto de código.
  4. Repita de 1) até obter o comprimento desejado

por exemplo (em pseudo código)

int myInt = random(0, numcharacters)
char[] codealphabet = 'ABCDEF12345'
char random = codealphabet[i]
repeat until long enough

Teoricamente falando, isso não poderia gerar a mesma string mais de uma vez?
frezq 29/01/19

4

Aqui está o melhor gerador de identificação exclusivo para você. feito por mim.

<?php
$d=date ("d");
$m=date ("m");
$y=date ("Y");
$t=time();
$dmt=$d+$m+$y+$t;    
$ran= rand(0,10000000);
$dmtran= $dmt+$ran;
$un=  uniqid();
$dmtun = $dmt.$un;
$mdun = md5($dmtran.$un);
$sort=substr($mdun, 16); // if you want sort length code.

echo $mdun;
?>

você pode repetir qualquer 'var' do seu ID como desejar. mas $ mdun é melhor, você pode substituir md5 por sha1 para obter um código melhor, mas isso será muito longo, o que talvez você não precise.

Obrigado.


7
Nesse caso, a aleatoriedade é garantida por código escrito aleatório, certo?
Daniel Kucal

3
Sim, isso é meio "aleatório" porque é um código obscuro e não padrão. Isso dificulta a previsão ... mas na verdade não usa partes inseguras para gerar um número aleatório. portanto, o resultado tecnicamente não é aleatório ou seguro.
Philipp

4

Para seqüências realmente aleatórias, você pode usar

<?php

echo md5(microtime(true).mt_Rand());

saídas:

40a29479ec808ad4bcff288a48a25d5c

portanto, mesmo se você tentar gerar string várias vezes ao mesmo tempo, terá uma saída diferente.


4

Ao tentar gerar uma senha aleatória, você está tentando:

  • Primeiro gere um conjunto criptograficamente seguro de bytes aleatórios

  • O segundo é transformar esses bytes aleatórios em uma sequência imprimível

Agora, existem várias maneiras de gerar bytes aleatórios em php como:

$length = 32;

//PHP 7+
$bytes= random_bytes($length);

//PHP < 7
$bytes= openssl_random_pseudo_bytes($length);

Então você deseja transformar esses bytes aleatórios em uma sequência imprimível:

Você pode usar bin2hex :

$string = bin2hex($bytes);

ou base64_encode :

$string = base64_encode($bytes);

No entanto, observe que você não controla o comprimento da sequência se usar o base64. Você pode usar bin2hex para fazer isso, usando 32 bytes se transformará em uma seqüência de caracteres de 64 caracteres . Mas isso só funcionará dessa maneira em uma string EVEN .

Então, basicamente, você pode fazer :

$length = 32;

if(PHP_VERSION>=7){
    $bytes= random_bytes($length);
}else{
    $bytes= openssl_random_pseudo_bytes($length);
} 

$string = bin2hex($bytes);

3

Aqui está o que eu uso:

md5(time() . rand());    
// Creates something like 0c947c3b1047334f5bb8a3b7adc1d97b

2
function random_string($length = 8) {
    $alphabets = range('A','Z');
    $numbers = range('0','9');
    $additional_characters = array('_','=');
    $final_array = array_merge($alphabets,$numbers,$additional_characters);
       while($length--) {
      $key = array_rand($final_array);

      $password .= $final_array[$key];
                        }
  if (preg_match('/[A-Za-z0-9]/', $password))
    {
     return $password;
    }else{
    return  random_string();
    }

 }

2

Essa é uma função simples que permite gerar seqüências aleatórias contendo letras e números (alfanuméricos). Você também pode limitar o comprimento da string. Essas seqüências aleatórias podem ser usadas para vários propósitos, incluindo: Código de referência, Código promocional, Código de cupom. A função depende das seguintes funções do PHP: base_convert, sha1, uniqid, mt_rand

function random_code($length)
{
  return substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, $length);
}

echo random_code(6);

/*sample output
* a7d9e8
* 3klo93
*/

1

depois de ler os exemplos anteriores, vim com isso:

protected static $nonce_length = 32;

public static function getNonce()
{
    $chars = array();
    for ($i = 0; $i < 10; $i++)
        $chars = array_merge($chars, range(0, 9), range('A', 'Z'));
    shuffle($chars);
    $start = mt_rand(0, count($chars) - self::$nonce_length);
    return substr(join('', $chars), $start, self::$nonce_length);
}

Duplico 10 vezes a matriz [0-9, AZ] e embaralha os elementos, depois de obter um ponto de início aleatório para substr () ser mais 'criativo' :) você pode adicionar [az] e outros elementos à matriz, duplicar mais ou menos, seja mais criativo que eu


1

Eu gosto de usar chaves de hash ao lidar com links de verificação. Eu recomendaria usar o microtime e o hash que usem o MD5, pois não deve haver razão para que as chaves sejam as mesmas, pois o hash baseia-se no microtime.

  1. $key = md5(rand());
  2. $key = md5(microtime());

1
<?php
function generateRandomString($length = 11) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;

}

?>

A função acima irá gerar uma sequência aleatória com 11 caracteres.


1

Se você deseja gerar uma string única no PHP, tente seguir.

md5(uniqid().mt_rand());

Nisso,

uniqid()- Ele irá gerar uma string única. Essa função retorna o identificador exclusivo baseado em carimbo de data e hora como uma sequência.

mt_rand() - Gere número aleatório.

md5() - Ele irá gerar a cadeia de hash.


0

Scott, sim, você é muito escritor e boa solução! Obrigado.

Também sou obrigado a gerar um token de API exclusivo para cada usuário. A seguir, minha abordagem, usei informações do usuário (ID do usuário e nome de usuário):

public function generateUniqueToken($userid, $username){

        $rand = mt_rand(100,999);
    $md5 = md5($userid.'!(&^ 532567_465 ///'.$username);

    $md53 = substr($md5,0,3);
    $md5_remaining = substr($md5,3);

    $md5 = $md53. $rand. $userid. $md5_remaining;

    return $md5;
}

Por favor, dê uma olhada e deixe-me saber se alguma melhoria eu posso fazer. obrigado


0

Aqui está o que estou usando em um dos meus projetos: ele está funcionando muito bem e gera um token aleatório exclusivo :

$timestampz=time();

function generateRandomString($length = 60) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;
}


$tokenparta = generateRandomString();


$token = $timestampz*3 . $tokenparta;

echo $token;

Observe que eu multipliquei o carimbo de data / hora por três para criar uma confusão para quem quer que o usuário esteja se perguntando como esse token é gerado;)

Espero que ajude :)


11
"Por favor note que eu multipliquei o timestamp por três para criar uma confusão para quem usuário pode estar se perguntando como isso token é gerado" soa como segurança através de ofuscação stackoverflow.com/questions/533965/...
Harry

Esta não é uma "segurança através da ofuscação", pois o carimbo de data / hora é adicionado a uma sequência aleatória gerada, e essa é a sequência final real que retornamos;)
Kaszoni Ferencz

0

Eu acho que esse é o melhor método para usar.

str_shuffle(md5(rand(0,100000)))

0

podemos usar essas duas linhas de código para gerar uma string única, testamos cerca de 10000000 vezes de iteração

  $sffledStr= str_shuffle('abscdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-+');
    $uniqueString = md5(time().$sffledStr);

0

Eu sempre uso essa minha função para gerar uma seqüência alfanumérica aleatória personalizada ... Espero que ajude.

<?php
  function random_alphanumeric($length) {
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345689';
    $my_string = '';
    for ($i = 0; $i < $length; $i++) {
      $pos = mt_rand(0, strlen($chars) -1);
      $my_string .= substr($chars, $pos, 1);
    }
    return $my_string;
  }
  echo random_alphanumeric(50); // 50 characters
?>

Ele gera, por exemplo: Y1FypdjVbFCFK6Gh9FDJpe6dciwJEfV6MQGpJqAfuijaYSZ86g

Se você deseja comparar com outra string para ter certeza de que é uma sequência única, use este truque ...

$string_1 = random_alphanumeric(50);
$string_2 = random_alphanumeric(50);
while ($string_1 == $string_2) {
  $string_1 = random_alphanumeric(50);
  $string_2 = random_alphanumeric(50);
  if ($string_1 != $string_2) {
     break;
  }
}
echo $string_1;
echo "<br>\n";
echo $string_2;

gera duas seqüências únicas:

qsBDs4JOoVRfFxyLAOGECYIsWvpcpMzAO9pypwxsqPKeAmYLOi

Ti3kE1WfGgTNxQVXtbNNbhhvvapnaUfGMVJecHkUjHbuCb85pF

Espero que seja isso que você está procurando...


0

Uma solução simples é converter a base 64 em alfanumérica, descartando os caracteres não alfanuméricos.

Este usa random_bytes () para um resultado criptograficamente seguro.

function random_alphanumeric(int $length): string
{
    $result='';
    do
    {
        //Base 64 produces 4 characters for each 3 bytes, so most times this will give enough bytes in a single pass
        $bytes=random_bytes(($length+3-strlen($result))*2);
        //Discard non-alhpanumeric characters
        $result.=str_replace(['/','+','='],['','',''],base64_encode($bytes));
        //Keep adding characters until the string is long enough
        //Add a few extra because the last 2 or 3 characters of a base 64 string tend to be less diverse
    }while(strlen($result)<$length+3);
    return substr($result,0,$length);
}


-1

Acredito que o problema com todas as idéias existentes é que elas provavelmente são únicas, mas não definitivamente únicas (como apontado na resposta de Dariusz Walczak ao loletech). Eu tenho uma solução que é realmente única. Requer que seu script tenha algum tipo de memória. Para mim, este é um banco de dados SQL. Você também pode simplesmente gravar em um arquivo em algum lugar. Existem duas implementações:

Primeiro método: tenha DOIS campos em vez de 1 que fornecem exclusividade. O primeiro campo é um número de ID que não é aleatório, mas é único (o primeiro ID é 1, o segundo 2 ...). Se você estiver usando SQL, basta definir o campo ID com a propriedade AUTO_INCREMENT. O segundo campo não é exclusivo, mas é aleatório. Isso pode ser gerado com qualquer uma das outras técnicas que as pessoas já mencionaram. A ideia de Scott foi boa, mas o md5 é conveniente e provavelmente bom o suficiente para a maioria dos propósitos:

$random_token = md5($_SERVER['HTTP_USER_AGENT'] . time());

Segundo método: Basicamente, a mesma ideia, mas escolha inicialmente um número máximo de strings que serão geradas. Este poderia ser um número realmente grande como um trilhão. Em seguida, faça o mesmo, gere um ID, mas coloque zero nele para que todos os IDs tenham o mesmo número de dígitos. Em seguida, concatene o ID com a sequência aleatória. Será aleatório o suficiente para a maioria dos propósitos, mas a seção de ID garantirá que ela também seja exclusiva.


-1

Você pode usar esse código, espero que seja útil para você.

function rand_code($len)
{
 $min_lenght= 0;
 $max_lenght = 100;
 $bigL = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 $smallL = "abcdefghijklmnopqrstuvwxyz";
 $number = "0123456789";
 $bigB = str_shuffle($bigL);
 $smallS = str_shuffle($smallL);
 $numberS = str_shuffle($number);
 $subA = substr($bigB,0,5);
 $subB = substr($bigB,6,5);
 $subC = substr($bigB,10,5);
 $subD = substr($smallS,0,5);
 $subE = substr($smallS,6,5);
 $subF = substr($smallS,10,5);
 $subG = substr($numberS,0,5);
 $subH = substr($numberS,6,5);
 $subI = substr($numberS,10,5);
 $RandCode1 = str_shuffle($subA.$subD.$subB.$subF.$subC.$subE);
 $RandCode2 = str_shuffle($RandCode1);
 $RandCode = $RandCode1.$RandCode2;
 if ($len>$min_lenght && $len<$max_lenght)
 {
 $CodeEX = substr($RandCode,0,$len);
 }
 else
 {
 $CodeEX = $RandCode;
 }
 return $CodeEX;
}

Detalhes sobre o gerador de código aleatório no PHP


-2

Simplificando o código Scotts acima, removendo loops desnecessários que estão desacelerando muito e não o tornam mais seguro do que chamar openssl_random_pseudo_bytes apenas uma vez

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
 $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
 return $min + $rnd%$range;
}

function getToken($length)
{
 return bin2hex(openssl_random_pseudo_bytes($length)
}

Infelizmente, não posso concordar com você que essa é uma simplificação apropriada da função crypto_rand_secure. O loop é necessário para evitar desvios de módulo que ocorrem quando você obtém o resultado de um número gerado aleatoriamente e modifica-o por um número que divide o intervalo. en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Modulo_bias . Ao usar um loop para descartar qualquer número fora do intervalo e selecionar um novo número, evita esse viés. stackoverflow.com/questions/10984974/…
Scott

@ Scott, esse post é sobre rand (). No entanto, neste caso, ele já é tratado por openssl_random_pseudo_bytes, fazendo o loop desnecessário.
Mabel

11
gist.github.com/anonymous/87e3ae6fd3320447f46b973e75c2ea85 - Execute este script. Você verá que a distribuição dos resultados não é aleatória. Os números entre 0 e 55 têm uma ocorrência maior que os números entre 56 e 100. opensslnão está causando isso, é por causa do viés do módulo em sua declaração de retorno. 100 (intervalo) não divide 255 (1 byte) uniformemente e causa esses resultados. Meu maior problema com sua resposta é que você declara que a função é tão segura quanto usar um loop, o que é falso. Sua implementação de crypto_rand_secure não é criptograficamente segura e é enganosa.
Scott

@ Scott, estamos divagando aqui, não se trata da última declaração de retorno, também pode ser calculada progressivamente a partir do valor de retorno de openssl_random_pseudo_bytes sem usar o módulo. O que estou dizendo é que o loop é desnecessário quando o openssl_random_pseudo_bytes retorna os bytes aleatórios. Fazendo loop, você não o torna mais seguro, apenas o torna lento.
Mabel

2
Esta resposta propaga informações ruins. Você está certo de que o loop não torna opensslmais seguro, mas o mais importante é que não o torna menos seguro, essa resposta sim. O código acima pega um número aleatório perfeitamente bom e o manipula enviesando-o para números mais baixos. Se você colocar um aviso de isenção de responsabilidade na sua resposta, afirmando que é mais rápido (removendo o loop), mas não é um CSPRNG, resolveria esse problema. Por favor, pelo amor à criptografia, informe aos usuários que a saída dessa função pode ser tendenciosa e não é uma solução equivalente. O loop não existe apenas para incomodá-lo.
Scott
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.