Pergunta

Eu quero criar uma identificação única, mas uniqid() está dando algo como '492607b0ee414'. O que eu gostaria é algo semelhante ao que tinyurl dá: '64k8ra'. Quanto menor, melhor. Os únicos requisitos são que ele não deve ter um fim óbvio e que ele deve olhar mais bonita do que uma seqüência aparentemente aleatória de números. Letras são preferidos sobre os números e, idealmente, não seria caso misto. Como o número de entradas não será que muitos (até 10000 ou assim) o risco de colisão não é um fator enorme.

Todas as sugestões apreciado.

Foi útil?

Solução

Faça uma pequena função que retorna letras aleatórias para um determinado comprimento:

<?php
function generate_random_letters($length) {
    $random = '';
    for ($i = 0; $i < $length; $i++) {
        $random .= chr(rand(ord('a'), ord('z')));
    }
    return $random;
}

Em seguida, você vai querer chamar isso até que seja única, em pseudo-código, dependendo de onde você armazenar essas informações:

do {
    $unique = generate_random_letters(6);
} while (is_in_table($unique));
add_to_table($unique);

Você também pode querer certificar-se as cartas não formam uma palavra em um Dictionnary. Que seja toda a Dictionnary Inglês ou apenas uma má palavra Dictionnary de coisas a evitar um cliente iria encontrar de mau-gosto.

EDIT: Eu também gostaria de acrescentar isso só faz sentido se, como você pretende usá-lo, não é para uma grande quantidade de itens, porque isso poderia ficar muito retardar os mais colisões que você começa (recebendo uma ID já na tabela) . Claro, você vai querer uma tabela indexada e você vai querer ajustar o número de cartas na ID de colisão evitar. Neste caso, com 6 letras, você teria 26 ^ 6 = 308915776 possíveis identificações exclusivas (menos palavrões), que deve ser suficiente para a sua necessidade de 10000.

EDIT: Se você quer uma combinação de letras e números que você pode usar o seguinte código:

$random .= rand(0, 1) ? rand(0, 9) : chr(rand(ord('a'), ord('z')));

Outras dicas

@gen_uuid () por gord.

preg_replace tem alguns problemas desagradáveis ??UTF-8, que faz com que os somtimes uid para conter "+" ou "/". Para contornar este problema, você tem que fazer explicitamente o padrão utf-8

function gen_uuid($len=8) {

    $hex = md5("yourSaltHere" . uniqid("", true));

    $pack = pack('H*', $hex);
    $tmp =  base64_encode($pack);

    $uid = preg_replace("#(*UTF8)[^A-Za-z0-9]#", "", $tmp);

    $len = max(4, min(128, $len));

    while (strlen($uid) < $len)
        $uid .= gen_uuid(22);

    return substr($uid, 0, $len);
}

Levei muito tempo para descobrir que, talvez seja salva alguém uma dor de cabeça

Você pode conseguir isso com menos código:

function gen_uid($l=10){
    return substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyz"), 0, $l);
}

Resultado (exemplos):

  • cjnp56brdy
  • 9d5uv84zfa
  • ih162lryez
  • ri4ocf6tkj
  • xj04s83egi

Existem duas maneiras de obter uma identificação confiável única: Torná-lo tão longa e variável que as chances de uma colisão são espetacularmente pequena (como com um GUID) ou armazenar todos os IDs gerados em uma mesa para pesquisa (seja na memória ou em um DB ou um arquivo) para verificar a singularidade após geração.

Se você está realmente perguntando como você pode gerar uma chave tão curto e garantir a sua singularidade sem algum tipo de verificação de duplicata, a resposta é, você não pode.

Aqui está o uso rotineiro I para base62s aleatórios de qualquer comprimento ...

Chamando gen_uuid() retorna strings como WJX0u0jV, E9EMaZ3P etc.

Por padrão, esta retorna 8 dígitos, portanto, um espaço de 64 ^ 8 ou cerca de 10 ^ 14, esta é muitas vezes suficiente para fazer colisões bastante raro.

Para uma seqüência maior ou menor, passar em $ len como desejado. Não há limite de comprimento, como I acrescentar até satisfeito [até o limite de segurança de 128 caracteres, o qual pode ser removido].

Note, utilizar um sal aleatório dentro o md5 [ou sha1 se você preferir], portanto, não podem ser facilmente engenharia reversa.

Eu não encontrou qualquer conversão base62 confiáveis ??na web, portanto, esta abordagem de descascar caracteres a partir do resultado base64.

Use livremente sob a licença BSD, desfrutar,

gord

function gen_uuid($len=8)
{
    $hex = md5("your_random_salt_here_31415" . uniqid("", true));

    $pack = pack('H*', $hex);

    $uid = base64_encode($pack);        // max 22 chars

    $uid = ereg_replace("[^A-Za-z0-9]", "", $uid);    // mixed case
    //$uid = ereg_replace("[^A-Z0-9]", "", strtoupper($uid));    // uppercase only

    if ($len<4)
        $len=4;
    if ($len>128)
        $len=128;                       // prevent silliness, can remove

    while (strlen($uid)<$len)
        $uid = $uid . gen_uuid(22);     // append until length achieved

    return substr($uid, 0, $len);
}

solução muito simples:

Faça o ID único com:

$id = 100;
base_convert($id, 10, 36);

Obter o valor original novamente:

intval($str,36);

Não é possível levar o crédito por isso, pois é a partir de outra página estouro de pilha, mas eu pensei que a solução era tão elegante e impressionante que valeu a pena copiar até esta discussão para pessoas que fazem referência esta.

Você pode usar o Id e apenas convertê-lo em número de base-36 se você quiser convertê-lo e para trás. Pode ser usado para qualquer tabela com um id inteiro.

function toUId($baseId, $multiplier = 1) {
    return base_convert($baseId * $multiplier, 10, 36);
}
function fromUId($uid, $multiplier = 1) {
    return (int) base_convert($uid, 36, 10) / $multiplier;
}

echo toUId(10000, 11111);
1u5h0w
echo fromUId('1u5h0w', 11111);
10000

As pessoas inteligentes provavelmente pode descobrir isso com exemplos id suficientes. Não deixe esta obscuridade substituir segurança.

Eu vim com o que eu acho que é uma solução legal bastante fazendo isso sem uma verificação de unicidade. Eu pensei que eu iria partilhar por quaisquer futuros visitantes.

Um contador é uma maneira muito fácil de singularidade garantia ou se você estiver usando um banco de dados uma chave primária também garante exclusividade. O problema é que parece ruim e e pode ser vulnerável. Por isso, tomei a sequência e desordenados-lo com uma cifra. Desde a cifra pode ser revertida, eu sei que cada id é única enquanto ainda aparecendo aleatória.

É python não php, mas eu carregado o código aqui: https://github.com/adecker89/Tiny-Unique-Identifiers

As letras são muito, dígitos são feios. Você quer seqüências aleatórias, mas não quer "feio" seqüências aleatórias?

Criar um número aleatório e imprimi-lo em alfa-estilo ( base-26 ), como a reserva "números" que as companhias aéreas dão.

Não há funções de conversão de base de uso geral construídos em PHP, tanto quanto eu sei, então você precisaria código que se mordeu.

Outra alternativa:. uniqid() uso e se livrar dos dígitos

function strip_digits_from_string($string) {
    return preg_replace('/[0-9]/', '', $string);
}

Ou substituí-los com letras:

function replace_digits_with_letters($string) {
    return strtr($string, '0123456789', 'abcdefghij');
}

Você também pode fazê-lo como este:

public static function generateCode($length = 6)
    {
        $az = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $azr = rand(0, 51);
        $azs = substr($az, $azr, 10);
        $stamp = hash('sha256', time());
        $mt = hash('sha256', mt_rand(5, 20));
        $alpha = hash('sha256', $azs);
        $hash = str_shuffle($stamp . $mt . $alpha);
        $code = ucfirst(substr($hash, $azr, $length));
        return $code;
    }

Você pode fazer isso sem material impuro / costy como loops, concatenations corda ou várias chamadas para rand (), em um ambiente limpo e fácil de ler maneira. Além disso, é melhor usar mt_rand():

function createRandomString($length)
{
    $random = mt_rand(0, (1 << ($length << 2)) - 1);
    return dechex($random);
}

Se você precisar a String para ter o comprimento exato em qualquer caso, basta preencher o número hexadecimal com zeros:

function createRandomString($length)
{
    $random = mt_rand(0, (1 << ($length << 2)) - 1);
    $number = dechex($random);
    return str_pad($number, $length, '0', STR_PAD_LEFT);
}

O "backdraw teórica" ??é que você está limitado a recursos do PHP - mas isso é mais uma questão filosófica, nesse caso;) Vamos passar por isso de qualquer maneira:

  • PHP é limitado no que pode representar como um número hexadecimal de fazê-lo assim. Isso seria $length <= 8 , pelo menos em um sistema de 32 bits, onde a limitação do PHP para este deve ser 4.294.967.295.
  • do PHP gerador de números aleatórios também tem um máximo. Para mt_rand() , pelo menos em um sistema de 32 bits, que deve ser 2.147.483.647
  • Assim que você está teoricamente limitado a 2.147.483.647 IDs.

Voltando ao tópico - o do { (generate ID) } while { (id is not uniqe) } (insert id) intuitiva tem uma desvantagem e uma possível falha que pode levá-lo direto para a escuridão ...

Drawback: A validação é pessimista. Fazê-lo como esta sempre requer uma verificação no banco de dados. Tendo keyspace suficiente (por exemplo comprimento de 5 para seus 10k entradas) irá causar colisões bastante improváveis ??como, muitas vezes, como poderia ser comparavelmente menos recursos consumindo apenas tentar para armazenar os dados e tente novamente somente em caso de um UNIQUE KEY erro.

Defeito: Usuário A recupera um ID que será verificado como não tomar ainda. Em seguida, o código irá tentar inserir os dados. Mas, entretanto, Usuário B entrou no mesmo loop e, infelizmente, recupera o mesmo número aleatório, porque Usuário A ainda não está armazenado e este ID ainda estava livre. Agora o sistema armazena tanto Usuário B ou Usuário A , e ao tentar armazenar o segundo usuário, já existe o outro, entretanto -. Ter a mesma ID

Você precisa lidar com essa exceção em qualquer caso e necessidade de re-experimentar a inserção com um ID recém-criado. Adicionando este mantendo o ciclo verificação pessimista (que você precisa para voltar a entrar) irá resultar em muito feio e difícil de seguir código. Felizmente, a solução para isso é o mesmo como o que a desvantagem: Basta ir para ele em primeiro lugar e tentar armazenar os dados. Em caso de um erro de UNIQUE KEY apenas repetir com um novo ID.

Dê uma lookt neste artigo

Ele explica como gerar identificações exclusivas curtas de seus ids bdd, como o YouTube faz.

Na verdade, a função no artigo está muito relacionada com a php função base_convert que converte um número a partir de uma base para outra (mas apenas até base 36).

function rand_str($len = 12, $type = '111', $add = null) {
    $rand = ($type[0] == '1'  ? 'abcdefghijklmnpqrstuvwxyz' : '') .
            ($type[1] == '1'  ? 'ABCDEFGHIJKLMNPQRSTUVWXYZ' : '') .
            ($type[2] == '1'  ? '123456789'                 : '') .
            (strlen($add) > 0 ? $add                        : '');

    if(empty($rand)) $rand = sha1( uniqid(mt_rand(), true) . uniqid( uniqid(mt_rand(), true), true) );

    return substr(str_shuffle( str_repeat($rand, 2) ), 0, $len);
}

Se você gosta de uma versão mais longa de identificação única utilizar este:
$ Uniqueid = sha1 (md5 (time ()));

Melhor resposta ainda: menor único "Hash Como" String Dado único banco de dados ID - solução PHP , nenhum terceiro bibliotecas necessárias.

Aqui está o código:

<?php
/*
THE FOLLOWING CODE WILL PRINT:
A database_id value of 200 maps to 5K
A database_id value of 1 maps to 1
A database_id value of 1987645 maps to 16LOD
*/
$database_id = 200;
$base36value = dec2string($database_id, 36);
echo "A database_id value of 200 maps to $base36value\n";
$database_id = 1;
$base36value = dec2string($database_id, 36);
echo "A database_id value of 1 maps to $base36value\n";
$database_id = 1987645;
$base36value = dec2string($database_id, 36);
echo "A database_id value of 1987645 maps to $base36value\n";

// HERE'S THE FUNCTION THAT DOES THE HEAVY LIFTING...
function dec2string ($decimal, $base)
// convert a decimal number into a string using $base
{
    //DebugBreak();
   global $error;
   $string = null;

   $base = (int)$base;
   if ($base < 2 | $base > 36 | $base == 10) {
      echo 'BASE must be in the range 2-9 or 11-36';
      exit;
   } // if

   // maximum character string is 36 characters
   $charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';

   // strip off excess characters (anything beyond $base)
   $charset = substr($charset, 0, $base);

   if (!ereg('(^[0-9]{1,50}$)', trim($decimal))) {
      $error['dec_input'] = 'Value must be a positive integer with < 50 digits';
      return false;
   } // if

   do {
      // get remainder after dividing by BASE
      $remainder = bcmod($decimal, $base);

      $char      = substr($charset, $remainder, 1);   // get CHAR from array
      $string    = "$char$string";                    // prepend to output

      //$decimal   = ($decimal - $remainder) / $base;
      $decimal   = bcdiv(bcsub($decimal, $remainder), $base);

   } while ($decimal > 0);

   return $string;

}

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