Pregunta

Quiero crear una id única, pero uniqid() está dando algo como '492607b0ee414'.Lo que me gustaría es algo similar a lo que tinyurl da: '64k8ra'.Cuanto más corto, mejor.Los únicos requisitos son que no debe tener un orden aparente y que debe verse más bonita que un aparentemente aleatorio de la secuencia de números.Las letras son preferibles a los números y lo ideal no sería del caso mixto.Como el número de entradas no se que muchos (hasta 10000 o así) el riesgo de colisión no es un gran factor.

Cualquier sugerencia apreciado.

¿Fue útil?

Solución

Realiza una pequeña función que devuelve letras aleatorias para una longitud determinada:

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

Entonces querrá llamar a eso hasta que sea único, en pseudocódigo dependiendo de dónde almacenaría esa información:

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

También es posible que desee asegurarse de que las letras no formen una palabra en un diccionario. Puede ser todo el diccionario inglés o simplemente un diccionario de malas palabras para evitar cosas que un cliente encontraría de mal gusto.

EDITAR: También agregaría esto solo tiene sentido si, como pretendes usarlo, no es para una gran cantidad de artículos porque esto podría ser bastante lento cuanto más colisiones obtengas (obteniendo una ID ya en la tabla) . Por supuesto, querrá una tabla indexada y deberá ajustar el número de letras en la ID para evitar colisiones. En este caso, con 6 letras, tendría 26 ^ 6 = 308915776 posibles ID únicos (menos malas palabras) que deberían ser suficientes para su necesidad de 10000.

EDITAR: Si desea una combinación de letras y números, puede usar el siguiente código:

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

Otros consejos

@gen_uuid () por gord.

preg_replace tiene algunos problemas desagradables de utf-8, lo que hace que el uid a veces contenga " + " o " / " ;. Para evitar esto, debe hacer explícitamente el patrón 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);
}

Me tomó bastante tiempo encontrar eso, tal vez esto le ahorre a alguien más un dolor de cabeza

Puede lograr eso con menos código:

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

Resultado (ejemplos):

  • cjnp56brdy
  • 9d5uv84zfa
  • ih162lryez
  • ri4ocf6tkj
  • xj04s83egi

Hay dos formas de obtener una identificación única confiable: hacerla tan larga y variable que las posibilidades de una colisión sean espectacularmente pequeñas (como con un GUID) o almacenar todas las ID generadas en una tabla para buscarlas (ya sea en la memoria o en una base de datos o un archivo) para verificar la unicidad tras la generación.

Si realmente está preguntando cómo puede generar una clave tan breve y garantizar su singularidad sin algún tipo de verificación duplicada, la respuesta es que no puede.

Aquí está la rutina que uso para bases62s al azar de cualquier longitud ...

Llamar a gen_uuid() devuelve cadenas como WJX0u0jV, E9EMaZ3P etc.

Por defecto, esto devuelve 8 dígitos, por lo tanto, un espacio de 64 ^ 8 o aproximadamente 10 ^ 14, esto suele ser suficiente para hacer que las colisiones sean bastante raras.

Para una cadena más grande o más pequeña, pase $ len como desee. Sin límite de longitud, como agrego hasta que esté satisfecho [hasta el límite de seguridad de 128 caracteres, que se pueden eliminar].

Nota, use una sal aleatoria dentro del md5 [o sha1 si lo prefiere], por lo que no se puede realizar ingeniería inversa fácilmente.

No encontré ninguna conversión confiable de base62 en la web, de ahí este enfoque de eliminar caracteres del resultado de base64.

Usar libremente bajo licencia BSD, disfruta

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);
}

Solución realmente simple:

Cree la ID única con:

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

Obtenga el valor original nuevamente:

intval($str,36);

No puedo dar crédito por esto ya que es de otra página de desbordamiento de pila, pero pensé que la solución era tan elegante e increíble que valía la pena copiarla en este hilo para las personas que hacían referencia a esto.

Puede usar el Id y simplemente convertirlo al número base 36 si desea convertirlo de un lado a otro. Se puede usar para cualquier tabla con una identificación de entero.

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

Las personas inteligentes probablemente puedan resolverlo con suficientes ejemplos de identificación. No permita que esta oscuridad reemplace a la seguridad.

Se me ocurrió lo que creo que es una solución genial haciendo esto sin una verificación de singularidad. Pensé en compartir para futuros visitantes.

Un contador es una forma realmente fácil de garantizar la unicidad o si está utilizando una base de datos, una clave primaria también garantiza la unicidad. El problema es que se ve mal y puede ser vulnerable. Así que tomé la secuencia y la revolví con una cifra. Dado que el cifrado se puede revertir, sé que cada identificación es única y al mismo tiempo parece aleatoria.

Es python, no php, pero cargué el código aquí: https://github.com/adecker89/Tiny-Unique-Identifiers

Las letras son bastante, los dígitos son feos.Desea aleatoria de las cadenas, pero no quieren "feo" al azar cadenas?

Crear un número aleatorio y de impresión en alfa-estilo (base-26), como la reserva de los "números" de que las compañías aéreas que dar.

No hay ningún propósito general de la base de las funciones de conversión construido en PHP, por lo que yo sé, por lo que había necesidad de código que poco a ti mismo.

Otra alternativa:uso uniqid() y deshacerse de los dígitos.

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

O reemplazarlos con las letras:

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

También puedes hacerlo así:

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;
    }

Puede hacer eso sin cosas impuras / costosas como bucles, concatenaciones de cadenas o llamadas múltiples a rand (), de una manera limpia y fácil de leer. Además, es mejor usar mt_rand():

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

Si necesita que la cadena tenga la longitud exacta en cualquier caso, simplemente rellene el número hexadecimal con ceros:

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

El " backdraw teórico " es decir, que está limitado a las capacidades de PHP, pero este es más un problema filosófico en ese caso;) Vamos a verlo de todos modos:

  • PHP está limitado en lo que puede representar como un número hexadecimal haciéndolo así. Esto sería $length <= 8 al menos en un sistema de 32 bits, donde la limitación de PHP para esto debería ser 4.294.967.295.
  • El generador de números aleatorios de PHP también tiene un máximo. Para do { (generate ID) } while { (id is not uniqe) } (insert id) al menos en un sistema de 32 bits, debe ser 2.147.483.647
  • Entonces, teóricamente, estás limitado a 2.147.483.647 ID.

Volviendo al tema: el intuitivo <=> tiene un inconveniente y un posible defecto que puede llevarlo directamente a la oscuridad ...

Inconveniente: la validación es pesimista. Hacerlo así siempre requiere una verificación en la base de datos. Tener suficiente espacio de teclas (por ejemplo, una longitud de 5 para sus 10k entradas) causará colisiones con tanta frecuencia, ya que podría ser comparablemente menos consumo de recursos para tratar de almacenar los datos y volver a intentarlo solo en caso de un error CLAVE ÚNICO.

Defecto: Usuario A recupera una identificación que se verifica como aún no tomada. Entonces el código intentará insertar los datos. Pero mientras tanto, Usuario B ingresó al mismo bucle y desafortunadamente recupera el mismo número aleatorio, porque Usuario A aún no está almacenado y esta ID todavía estaba libre. Ahora el sistema almacena Usuario B o Usuario A , y cuando intenta almacenar el segundo Usuario, mientras tanto, ya existe el otro, que tiene la misma ID.

Debería manejar esa excepción en cualquier caso y volver a intentar la inserción con una ID recién creada. Agregar esto mientras se mantiene el ciclo de verificación pesimista (que necesitaría volver a ingresar) dará como resultado un código bastante feo y difícil de seguir. Afortunadamente, la solución a esto es la misma que la del inconveniente: Simplemente, hazlo en primer lugar e intenta almacenar los datos. En caso de un error de CLAVE ÚNICA, vuelva a intentarlo con una nueva ID.

Echa un vistazo a este artículo

Explica cómo generar identificadores únicos cortos a partir de sus identificadores bdd, como lo hace YouTube.

En realidad, la función en el artículo está muy relacionada con php function base_convert que convierte un número de una base a otra (pero solo es hasta la 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);
}

Si te gusta una versión más larga de Id único, usa esto:
$ uniqueid = sha1 (md5 (time ()));

Mejor respuesta: Más pequeño único " Hash Like " Cadena con ID de base de datos única: solución PHP, no se requieren bibliotecas de terceros.

Aquí está el 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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top