Gerar sequência de 5 caracteres aleatórios

102

Eu quero criar uma seqüência exata de 5 caracteres aleatórios com a menor possibilidade de ser duplicado. Qual seria a melhor forma de o fazer? Obrigado.

Peter
fonte
2
você tem um conjunto de caracteres específicos ou apenas 0-9a-zA-Z?
Yanick Rochon,
Este desafio de golfe de código pode ser um achado: codegolf.stackexchange.com/questions/119226/…
Tito
Usando Random::alphanumericString($length)você pode obter strings com 0-9a-zA-Z que são originadas de dados aleatórios criptograficamente seguros.
caw de

Respostas:

162
$rand = substr(md5(microtime()),rand(0,26),5);

Seria meu melhor palpite - a menos que você também esteja procurando por caracteres especiais:

$seed = str_split('abcdefghijklmnopqrstuvwxyz'
                 .'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                 .'0123456789!@#$%^&*()'); // and any other characters
shuffle($seed); // probably optional since array_is randomized; this may be redundant
$rand = '';
foreach (array_rand($seed, 5) as $k) $rand .= $seed[$k];

Exemplo

E, para um baseado no relógio (menos colisões, pois é incremental):

function incrementalHash($len = 5){
  $charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  $base = strlen($charset);
  $result = '';

  $now = explode(' ', microtime())[1];
  while ($now >= $base){
    $i = $now % $base;
    $result = $charset[$i] . $result;
    $now /= $base;
  }
  return substr($result, -5);
}

Nota: incremental significa mais fácil de adivinhar; Se você estiver usando isso como um salt ou um token de verificação, não faça isso. Um salt (agora) de "WCWyb" significa que daqui a 5 segundos é "WCWyg")

Brad Christie
fonte
6
O problema de usar, md5()entretanto, é que você obtém uma string composta de um conjunto de 16 caracteres (10 dígitos e aaté f, ou seja, 4 bits por caractere da string). Isso pode ser suficiente para alguns fins, mas pode ser muito pouco para fins criptográficos (cinco caracteres de 16 símbolos = 16 ^ 5 = 20 bits = 1048576 possibilidades).
Arco de
3
array_rand($seed, 5)retornará a chave da matriz, não o valor, então seu código não funcionará
alumi
1
Eu acho que usar uma função hash criptográfica para gerar caracteres aleatórios é pelo menos inapropriado.
gronostaj
É possível também incluir ", 'e barra invertida $charset? Preciso usar sequências de escape para incluir esses caracteres?
Mai,
1
O segundo trecho nem usa o $lenparâmetro de entrada ... você esqueceu?
TechNyquist
76

Se os forloops estiverem faltando, aqui está o que eu gosto de usar:

$s = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", 5)), 0, 5);
Mateus
fonte
Solução interessante ... muito concisa, embora eu me pergunte se isso é mais rápido ou mais lento do que usar para. No entanto, não posso ser incomodado para fazer o benchmark :-)
Arco
@matthew str_shuffle produzirá duplicatas continuamente
SCC
@ user2826057: str_shuffle('ab')daria abou bamas nunca aa. Adicionar o str_repeatpermite isso. Dito isso, a solução que dei não é realmente séria ... embora funcione.
Mateus
2
Há 1/60466176 de chance de isso acontecer, assumindo que o RNG esteja uniformemente distribuído.
Mateus,
1
Isso é perfeito para nosso caso de uso de geração de códigos de voucher. Nós removemos confundindo caracteres, como l, i, 1, 0, O, etc e fora de 500 vales não tenho duplicatas.
Luke Cousins
25

Uma maneira rápida é usar os caracteres mais voláteis da função uniqid .

Por exemplo:

$rand = substr(uniqid('', true), -5);
John Parker
fonte
22

Você pode tentar simplesmente assim:

$length = 5;

$randomletter = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz"), 0, $length);

mais detalhes: http://forum.arnlweb.com/viewtopic.php?f=7&t=25

Apurba Pathak
fonte
15

O seguinte deve fornecer a menor chance de duplicação (você pode querer substituir mt_rand()por uma fonte de número aleatório melhor, por exemplo, de /dev/*randomou de GUIDs):

<?php
    $characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    $result = '';
    for ($i = 0; $i < 5; $i++)
        $result .= $characters[mt_rand(0, 61)];
?>

EDIT:
Se você está preocupado com a segurança, realmente, não use rand()ou mt_rand(), e verifique se o seu dispositivo de dados aleatórios é na verdade um dispositivo que gera dados aleatórios , não um arquivo regular ou algo previsível como /dev/zero. mt_rand()considerado prejudicial:
https://spideroak.com/blog/20121205114003-exploit-information-leaks-in-random-numbers-from-python-ruby-and-php

EDITAR: Se você tiver suporte a OpenSSL em PHP, poderá usar openssl_random_pseudo_bytes():

<?php
    $length = 5;
    $randomBytes = openssl_random_pseudo_bytes($length);
    $characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    $charactersLength = strlen($characters);
    $result = '';
    for ($i = 0; $i < $length; $i++)
        $result .= $characters[ord($randomBytes[$i]) % $charactersLength];
?>
Arco
fonte
Primeiro exemplo mais inteligente com $ result. = $ Characters [mt_rand (0, strlen ($ characters) -1)]
hamboy75
Nesse caso, você deve determinar o comprimento de antemão e armazená-lo em uma variável, pelo menos. Usar strlen()em um loop é uma sobrecarga desnecessária, especialmente se você já sabe que o conjunto de caracteres não mudará nesse meio tempo.
Arco de
Eu duvido, php é otimizado, de qualquer forma é uma opção :)
hamboy75
7

Sempre uso a mesma função para isso, geralmente para gerar senhas. É fácil de usar e útil.

function randPass($length, $strength=8) {
    $vowels = 'aeuy';
    $consonants = 'bdghjmnpqrstvz';
    if ($strength >= 1) {
        $consonants .= 'BDGHJLMNPQRSTVWXZ';
    }
    if ($strength >= 2) {
        $vowels .= "AEUY";
    }
    if ($strength >= 4) {
        $consonants .= '23456789';
    }
    if ($strength >= 8) {
        $consonants .= '@#$%';
    }

    $password = '';
    $alt = time() % 2;
    for ($i = 0; $i < $length; $i++) {
        if ($alt == 1) {
            $password .= $consonants[(rand() % strlen($consonants))];
            $alt = 0;
        } else {
            $password .= $vowels[(rand() % strlen($vowels))];
            $alt = 1;
        }
    }
    return $password;
}
Kristoffer la Cour
fonte
Belo código. No entanto, $ alt sempre muda de um para 0. Não seria melhor randomizar $ alt?
Nico Andrade
3
$str = '';
$str_len = 8;
for($i = 0, $i < $str_len; $i++){
    //97 is ascii code for 'a' and 122 is ascii code for z
    $str .= chr(rand(97, 122));
}
return $str
edrian
fonte
2

Se não houver problema em receber apenas letras AF, aqui está minha solução:

str_pad(dechex(mt_rand(0, 0xFFFFF)), 5, '0', STR_PAD_LEFT);

Eu acredito que usar funções hash é um exagero para uma tarefa tão simples como gerar uma sequência de dígitos hexadecimais aleatórios. dechex+ mt_randfará o mesmo trabalho, mas sem trabalho criptográfico desnecessário. str_padgarante um comprimento de 5 caracteres da string de saída (se o número aleatório for menor que 0x10000).

A probabilidade duplicada depende mt_randda confiabilidade de. Mersenne Twister é conhecido por sua aleatoriedade de alta qualidade, então deve se encaixar bem na tarefa.

Gronostaj
fonte
2

Eu também não sabia fazer isso até que pensei em usar PHP array. E tenho certeza de que essa é a maneira mais simples de gerar uma string ou número aleatório com array. O código:

function randstr ($len=10, $abc="aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789") {
    $letters = str_split($abc);
    $str = "";
    for ($i=0; $i<=$len; $i++) {
        $str .= $letters[rand(0, count($letters)-1)];
    };
    return $str;
};

Você pode usar esta função assim

randstr(20)     // returns a random 20 letter string
                // Or like this
randstr(5, abc) // returns a random 5 letter string using the letters "abc"

fonte
1

Semelhante à resposta de Brad Christie , mas usando sha1alroritmo para caracteres 0-9a-zA-Ze prefixado com um valor aleatório:

$str = substr(sha1(mt_rand() . microtime()), mt_rand(0,35), 5);

Mas se você definiu caracteres (permitidos):

$validChars = array('0','1','2' /*...*/,'?','-','_','a','b','c' /*...*/);
$validCharsCount = count($validChars);

$str = '';
for ($i=0; $i<5; $i++) {
    $str .= $validChars[rand(0,$validCharsCount - 1)];
}

** ATUALIZAÇÃO **

Como Archimedix apontou, isso não garante o retorno da "menor possibilidade de duplicação", pois o número de combinações é baixo para o intervalo de caracteres fornecido. Você precisará aumentar o número de caracteres ou permitir caracteres extras (especiais) na string. A primeira solução seria preferível, eu acho, no seu caso.

Yanick Rochon
fonte
Usar time()é até 1 milhão de vezes mais previsível do que microtime().
Arco de
Observe também meus comentários à resposta de Brad, o maior problema é que o hash gerado é uma representação hexadecimal que consiste em 16 caracteres válidos, deixando apenas 1.024 variações para $str.
Arco de
@Archimedix, talvez, mas o OP não pediu segurança, a questão foi definida para ter um algoritmo gerador de string consistindo de uma combinação de 5x26 caracteres diferentes, evitando duplicatas. Provavelmente é para um número de referência de confirmação em um processo de registro (ou processo de faturamento) ou algo assim
Yanick Rochon
Foi o meu entendimento de que ele fez pedir menos possibilidade de ser duplicada , e isso tem 0,1% de probabilidade (1 em 1024) que poderia ter sido quase 1 em 1 bilhão.
Arco de
no entanto, se você precisa gerar uma chave de referência de 5 caracteres e dar-lhe um cliente / cliente, você não deseja dar a eles " ˫§»⁋⅓" simplesmente porque é mais seguro ... você aumenta sua chave de referência para 7 ou mais caracteres . (BTW: correção em meu comentário anterior, é 5x36 caracteres)
Yanick Rochon
1

funciona bem em PHP (php 5.4.4)

$seed = str_split('abcdefghijklmnopqrstuvwxyz');
$rand = array_rand($seed, 5);
$convert = array_map(function($n){
    global $seed;
    return $seed[$n];
},$rand);

$var = implode('',$convert);
echo $var;

Demonstração ao vivo

Lyoniel Farase
fonte
1

Fonte: Função PHP que Gera Caracteres Aleatórios

Esta função PHP simples funcionou para mim:

function cvf_ps_generate_random_code($length=10) {

   $string = '';
   // You can define your own characters here.
   $characters = "23456789ABCDEFHJKLMNPRTVWXYZabcdefghijklmnopqrstuvwxyz";

   for ($p = 0; $p < $length; $p++) {
       $string .= $characters[mt_rand(0, strlen($characters)-1)];
   }

   return $string;

}

Uso:

echo cvf_ps_generate_random_code(5);
Carl
fonte
1

Aqui estão meus random 5 cents...

$random=function($a, $b) {
    return(
        substr(str_shuffle(('\\`)/|@'.
        password_hash(mt_rand(0,999999),
        PASSWORD_DEFAULT).'!*^&~(')),
        $a, $b)
    );
};

echo($random(0,5));

A nova função do PHP password_hash()(*> = PHP 5.5) está fazendo o trabalho para a geração de conjuntos decentemente longos de letras maiúsculas e minúsculas e números.

Dois concat. strings antes e depois da password_hashfunção $ random são adequadas para alteração.

Os parâmetros para $random()* ($ a, $ b) são na verdade substr()parâmetros. :)

NOTA: isso não precisa ser uma função, pode ser uma variável normal também .. como um singleliner desagradável, como este:

$random=(substr(str_shuffle(('\\`)/|@'.password_hash(mt_rand(0,999999), PASSWORD_DEFAULT).'!*^&~(')), 0, 5));

echo($random);
Assustador
fonte
1
function CaracteresAleatorios( $Tamanno, $Opciones) {
    $Opciones = empty($Opciones) ? array(0, 1, 2) : $Opciones;
    $Tamanno = empty($Tamanno) ? 16 : $Tamanno;
    $Caracteres=array("0123456789","abcdefghijklmnopqrstuvwxyz","ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    $Caracteres= implode("",array_intersect_key($Caracteres, array_flip($Opciones)));
    $CantidadCaracteres=strlen($Caracteres)-1;
    $CaracteresAleatorios='';
    for ($k = 0; $k < $Tamanno; $k++) {
        $CaracteresAleatorios.=$Caracteres[rand(0, $CantidadCaracteres)];
    }
    return $CaracteresAleatorios;
}
John F
fonte
Dica profissional - inclua alguma explicação sobre como sua resposta resolve o problema do OP e por que ela pode ser diferente das outras respostas já fornecidas.
Tom,
0

Eu sempre uso isso:

<?php function fRand($len) {
    $str = '';
    $a = "abcdefghijklmnopqrstuvwxyz0123456789";
    $b = str_split($a);
    for ($i=1; $i <= $len ; $i++) { 
        $str .= $b[rand(0,strlen($a)-1)];
    }
    return $str;
} ?>

Ao chamá-lo, define o comprimento da corda.

<?php echo fRand([LENGHT]); ?>

Você também pode alterar os caracteres possíveis na string $a.

LipESprY
fonte
Vejo que perdi tempo desenvolvendo ociosamente essa função. Eu pesquisei pouco! @Andrew
LipESprY