Pergunta

Estou procurando uma maneira, especificamente em PHP, de ter a garantia de sempre obter uma chave exclusiva.

Eu fiz o seguinte:

strtolower(substr(crypt(time()), 0, 7));

Mas descobri que de vez em quando acabo com uma chave duplicada (raramente, mas com bastante frequência).

Também pensei em fazer:

strtolower(substr(crypt(uniqid(rand(), true)), 0, 7));

Mas de acordo com o site PHP, uniqid() poderia, se uniqid() for chamado duas vezes no mesmo microssegundo, poderia gerar a mesma chave.Estou pensando que a adição de Rand() raramente aconteceria, mas ainda é possível.

Após as linhas mencionadas acima, também removo caracteres como L e O para que fique menos confuso para o usuário.Isso talvez seja parte da causa das duplicatas, mas ainda é necessário.

Uma opção que pensei é criar um site que irá gerar a chave, armazenando-a em um banco de dados, garantindo que seja totalmente única.

Algum outro pensamento?Existe algum site que já faça isso que tenha algum tipo de API ou apenas retorne a chave.eu encontrei http://userident.com mas não tenho certeza se as chaves serão completamente exclusivas.

Isso precisa ser executado em segundo plano, sem qualquer intervenção do usuário.

Foi útil?

Solução

Existem apenas 3 maneiras de gerar valores exclusivos: senhas, IDs de usuário, etc.:

  1. Use um gerador GUID eficaz - eles são longos e não podem ser reduzidos.Se você usar apenas parte você falhou.
  2. Pelo menos parte do número é gerada sequencialmente a partir de uma única sequência.Você pode adicionar fluff ou codificação para fazer com que pareça menos sequencial.A vantagem é que eles começam curtos - a desvantagem é que exigem uma única fonte.A solução alternativa para a limitação de fonte única é ter fontes numeradas, então você inclui [source #] + [seq #] e então cada fonte pode gerar sua própria sequência.
  3. Gere-os por outros meios e depois compare-os com o histórico único de valores gerados anteriormente.

Qualquer outro método não é garantido.Tenha em mente que fundamentalmente você está gerando um número binário (é um computador), mas então você pode codificá-lo em Hexadecimal, Decimal, Base64 ou em uma lista de palavras.Escolha uma codificação adequada ao seu uso.Normalmente, para os dados inseridos pelo usuário, você deseja alguma variação do Base32 (que você sugeriu).

Nota sobre GUIDS:Eles ganham sua força de singularidade devido ao seu comprimento e ao método usado para gerá-los. Qualquer coisa menor que 128 bits não é segura. Além da geração de números aleatórios, existem características incluídas em um GUID para torná-lo mais exclusivo.Tenha em mente que eles são praticamente únicos, não completamente únicos.É possível, embora praticamente impossível, ter uma segunda via.

Nota atualizada sobre GUIDS:Desde que escrevi isto, aprendi que muitos geradores de GUID usam um gerador de números aleatórios criptograficamente seguro (difícil ou impossível de prever o próximo número gerado e que provavelmente não será repetido).Na verdade, existem 5 diferentes Algoritmos UUID.O Algoritmo 4 é o que a Microsoft usa atualmente para a API de geração de GUID do Windows.A GUIA é a implementação do padrão UUID pela Microsoft.

Atualizar:Se você quiser de 7 a 16 caracteres, precisará usar o método 2 ou 3.

Resultado final:Francamente, não existe algo completamente único.Mesmo se você usasse um gerador sequencial, acabaria ficando sem armazenamento usando todos os átomos do universo, voltando a si mesmo e repetindo.Sua única esperança seria a morte térmica do universo antes de chegar a esse ponto.

Mesmo o melhor gerador de números aleatórios tem a possibilidade de repetir igual ao tamanho total do número aleatório que você está gerando.Pegue um quarto, por exemplo.É um gerador de bits completamente aleatório e suas chances de repetição são de 1 em 2.

Portanto, tudo se resume ao seu limite de singularidade.Você pode ter 100% de exclusividade em 8 dígitos para 1.099.511.627.776 números usando uma sequência e codificando-a em base32.Qualquer outro método que não envolva verificação em uma lista de números anteriores tem apenas probabilidades iguais a n/1.099.511.627.776 (onde n=número de números anteriores gerados) de não ser único.

Outras dicas

Qualquer algoritmo resultará em duplicatas.

Portanto, posso sugerir que você use seu algoritmo* existente e simplesmente verifique se há duplicatas?

*Pequena adição:Se uniqid() pode não ser exclusivo com base no tempo, inclua também um contador global que você incrementa após cada invocação.Dessa forma, algo é diferente mesmo no mesmo microssegundo.

Sem escrever o código, minha lógica seria:

Gere uma string aleatória a partir de quaisquer caracteres aceitáveis ​​que você desejar.
Em seguida, adicione metade do carimbo de data (segundos parciais e tudo) na frente e a outra metade no final (ou em algum lugar no meio, se preferir).

Fique alegre!
H

Se você usar o método original, mas adicionar o nome de usuário ou endereço de e-mail na frente da senha, será sempre único se cada usuário puder ter apenas 1 senha.

Você pode estar interessado neste artigo que trata do mesmo assunto: GUIDs são globalmente exclusivos, mas substrings de GUIDs não são.

O objetivo deste algoritmo é usar a combinação de tempo e localização (“coordenadas de espaço-tempo” para os geeks da relatividade por aí) como a chave de exclusividade.No entanto, a cronometragem não é perfeita, portanto existe a possibilidade de, por exemplo, dois GUIDs serem gerados em rápida sucessão na mesma máquina, tão próximos um do outro no tempo que o carimbo de data/hora seria o mesmo.É aí que entra o uniquificador.

Eu costumo fazer assim:

$this->password = '';

for($i=0; $i<10; $i++)
{
    if($i%2 == 0)
        $this->password .= chr(rand(65,90));
    if($i%3 == 0)
        $this->password .= chr(rand(97,122));
    if($i%4 == 0)
        $this->password .= chr(rand(48,57));
}

Suponho que existam algumas lacunas teóricas, mas nunca tive problemas com duplicação.Eu costumo usá-lo para senhas temporárias (como após uma redefinição de senha) e funciona bem para isso.

Como comentou Frank Kreuger, use um gerador GUID.

Como Este

Ainda não estou entendendo por que as senhas precisam ser exclusivas.Qual é a desvantagem se dois dos seus usuários tiverem a mesma senha?

Isso pressupõe que estamos falando de senhas vinculadas a IDs de usuário, e não apenas a identificadores exclusivos.Se isso é o que você está procurando, por que não usar GUIDs?

Você pode estar interessado na implementação extremamente segura de Steve Gibson de um gerador de senha (sem fonte, mas ele tem uma descrição detalhada de como funciona) em https://www.grc.com/passwords.htm.

O site cria senhas enormes de 64 caracteres, mas, como são completamente aleatórias, você pode facilmente usar os primeiros 8 (ou quantos) caracteres para obter uma senha menos segura, mas “tão aleatória quanto possível”.

EDITAR:pelas suas respostas posteriores, vejo que você precisa de algo mais parecido com um GUID do que com uma senha, então provavelmente não é isso que você deseja ...

Eu acredito que parte do seu problema é que você está tentando nos fornecer uma função singular para dois usos separados...senhas e transaction_id

estas são realmente duas áreas problemáticas diferentes e não é melhor tentar abordá-las em conjunto.

Recentemente, eu queria uma chave aleatória única, rápida e simples, então fiz o seguinte:

$ukey = dechex(time()) . crypt( time() . md5(microtime() + mt_rand(0, 100000)) ); 

Então, basicamente, obtenho o tempo unix em segundos e adiciono uma string md5 aleatória gerada a partir do tempo + número aleatório.Não é o melhor, mas para solicitações de baixa frequência é muito bom.É rápido e funciona.

Fiz um teste onde gerei milhares de chaves e depois procurei por repetições, e tendo cerca de 800 chaves por segundo não houve repetições, então nada mal.Acho que depende totalmente de mt_rand()

Eu o uso para um rastreador de pesquisas onde obtemos uma taxa de envio de cerca de 1.000 pesquisas por minuto...então, por enquanto (cruza os dedos), não há duplicatas.É claro que a taxa não é constante (recebemos os envios em determinados horários do dia), então isso não é à prova de falhas nem é a melhor solução...a dica é usar um valor incremental como parte da chave (no meu caso usei time(), mas poderia ser melhor).

Ingerindo a parte de criptografia que não tem muito a ver com a criação de um valor único, geralmente uso este:

function GetUniqueValue()
{
   static $counter = 0; //initalized only 1st time function is called
   return strtr(microtime(), array('.' => '', ' ' => '')) . $counter++;
}

Quando chamado no mesmo processo, $counter é aumentado para que o valor seja sempre único no mesmo processo.

Quando chamado em processos diferentes, você deve ter muito azar de obter 2 chamadas de microtime() com os mesmos valores, pense que as chamadas de microtime() geralmente têm valores diferentes também quando chamadas no mesmo script.

Normalmente faço uma substring aleatória (randomize quantos caracteres entre 8 e 32 ou menos para conveniência do usuário) ou o MD5 de algum valor que obtive, ou a hora, ou alguma combinação.Para obter mais aleatoriedade, faço o MD5 do valor come (digamos o sobrenome), concateno-o com o tempo, MD5 novamente e, em seguida, pego a substring aleatória.Sim você poderia obter senhas iguais, mas não é muito provável.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top