Generar cadena aleatoria de 5 caracteres

102

Quiero crear una cadena exacta de 5 caracteres aleatorios con la menor posibilidad de duplicación. ¿Cuál sería la mejor forma de hacerlo? Gracias.

Pedro
fuente
2
¿Tienes un conjunto de personajes específicos o solo 0-9a-zA-Z?
Yanick Rochon
Este desafío de código de golf podría ser un hallazgo: codegolf.stackexchange.com/questions/119226/…
Titus
Al Random::alphanumericString($length)usarlo, puede obtener cadenas con 0-9a-zA-Z que se obtienen a partir de datos aleatorios criptográficamente seguros.
caw

Respuestas:

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

Sería mi mejor suposición, a menos que también estés buscando caracteres especiales:

$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];

Ejemplo

Y, para uno basado en el reloj (menos colisiones ya que es 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 más fácil de adivinar; Si está usando esto como una sal o un token de verificación, no lo haga. Una sal (ahora) de "WCWyb" significa que dentro de 5 segundos es "WCWyg")

Brad Christie
fuente
6
md5()Sin embargo, el problema con el uso es que se obtiene una cadena formada por un conjunto de 16 caracteres (10 dígitos y ahasta f, es decir, 4 bits por carácter de cadena). Esto puede ser suficiente para algunos propósitos, pero puede ser muy poco para propósitos criptográficos (cinco caracteres de 16 símbolos = 16 ^ 5 = 20 bits = 1048576 posibilidades).
Arco
3
array_rand($seed, 5)devolverá la clave de la matriz, no el valor, por lo que su código no funcionará
alumi
1
Creo que usar una función hash criptográfica para generar caracteres aleatorios es al menos inapropiado.
gronostaj
¿Es posible también incluir ", 'como la barra inversa en $charset? ¿Necesito usar secuencias de escape para incluir esos caracteres?
mayo
1
El segundo fragmento ni siquiera usa el $lenparámetro de entrada ... ¿lo olvidó?
TechNyquist
76

Si forhay escasez de bucles, esto es lo que me gusta usar:

$s = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", 5)), 0, 5);
Mateo
fuente
Solución interesante ... muy concisa, aunque me pregunto si esto es más rápido o más lento que usar for. Sin embargo, no puedo molestarme en realizar una evaluación comparativa :-)
Arc
@matthew str_shuffle producirá duplicados continuamente
SCC
@ user2826057: str_shuffle('ab')daría abo bapero nunca aa. Agregar el str_repeatpermite eso. Pero dicho esto, la solución que di no es realmente seria ... aunque funciona.
Matthew
2
Existe una posibilidad de 1/60466176 de que eso suceda, asumiendo que el RNG se distribuye uniformemente.
Mateo
1
Esto es perfecto para nuestro caso de uso de generar códigos de cupón. Hemos eliminado confundir caracteres, como l, i, 1, 0, O, etc, y de 500 vales conseguido sin duplicados.
Luke Cousins
25

Una forma rápida es utilizar los caracteres más volátiles del uniqid función .

Por ejemplo:

$rand = substr(uniqid('', true), -5);
John Parker
fuente
15

Lo siguiente debería proporcionar la menor posibilidad de duplicación (es posible que desee reemplazar mt_rand()con una mejor fuente de números aleatorios, por ejemplo, desde /dev/*randomo desde GUID):

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

EDITAR:
Si le preocupa la seguridad, en realidad, no use rand()o mt_rand(), y verifique que su dispositivo de datos aleatorios sea en realidad un dispositivo que genera datos aleatorios , no un archivo normal o algo predecible como /dev/zero. mt_rand()considerado dañino:
https://spideroak.com/blog/20121205114003-exploit-information-leaks-in-random-numbers-from-python-ruby-and-php

EDITAR: Si tiene soporte para OpenSSL en PHP, puede 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
fuente
Primer ejemplo más inteligente con $ resultado. = $ Caracteres [mt_rand (0, strlen ($ caracteres) -1)]
hamboy75
En ese caso, debe determinar la longitud de antemano y almacenarla en una variable al menos. Usar strlen()en un bucle es una sobrecarga innecesaria, especialmente si ya sabe que el conjunto de caracteres no va a cambiar mientras tanto.
Arco
Lo dudo, php está optimizado, de todos modos es una opción :)
hamboy75
7

Siempre uso la misma función para esto, generalmente para generar contraseñas. Es fácil de usar y ú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
fuente
Buen código. Sin embargo, $ alt siempre cambia de uno a 0. ¿No sería mejor aleatorizar $ 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
fuente
2

Si está bien que solo obtenga letras AF, aquí está mi solución:

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

Creo que usar funciones hash es una exageración para una tarea tan simple como generar una secuencia de dígitos hexadecimales aleatorios. dechex+ mt_randhará el mismo trabajo, pero sin trabajo criptográfico innecesario. str_padgarantiza una longitud de 5 caracteres de la cadena de salida (si el número aleatorio es menor que 0x10000).

La probabilidad duplicada depende de mt_randla confiabilidad de. Mersenne Twister es conocido por su aleatoriedad de alta calidad, por lo que debería adaptarse bien a la tarea.

gronostaj
fuente
2

Tampoco supe cómo hacer esto hasta que pensé en usar PHP array. Y estoy bastante seguro de que esta es la forma más sencilla de generar una cadena o número aleatorio con matrices. El 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;
};

Puedes usar esta función así

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

fuente
1

Similar a la respuesta de Brad Christie , pero usando un sha1algoritmo para los caracteres 0-9a-zA-Zy prefijado con un valor aleatorio:

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

Pero si ha establecido caracteres definidos (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)];
}

** ACTUALIZAR **

Como señaló Archimedix , esto no garantizará la devolución de una "mínima posibilidad de duplicación", ya que el número de combinaciones es bajo para el rango de caracteres dado. Deberá aumentar el número de caracteres o permitir caracteres adicionales (especiales) en la cadena. Creo que la primera solución sería preferible en su caso.

Yanick Rochon
fuente
El uso time()es hasta 1 millón de veces más predecible que microtime().
Arco
También tenga en cuenta mis comentarios a la respuesta de Brad, el problema más grande es que el hash generado es una representación hexadecimal que consta de 16 caracteres válidos, por lo que solo deja 1024 variaciones para $str.
Arco
@Archimedix, tal vez, pero el OP no pidió seguridad, la pregunta se definió para tener un algoritmo de generación de cadenas que consta de una combinación de 5x26 caracteres diferentes y evita los duplicados. Esto probablemente sea para un número de referencia de confirmación en un proceso de registro (o proceso de facturación), o algo así
Yanick Rochon
Tenía entendido que él hizo pedir menos posibilidad de ser duplicado , y esto tiene un 0,1% de probabilidad (1 en 1024) que podría haber sido casi 1 de 1 mil millones.
Arco
sin embargo, si necesita generar una clave de referencia de 5 caracteres y darle un cliente / cliente, no quiere darles " ˫§»⁋⅓" simplemente porque es más seguro ... aumenta su clave de referencia a 7 o más caracteres . (Por cierto: corrección en mi comentario anterior, son 5x36 caracteres)
Yanick Rochon
1

funciona bien en 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;

Demo en vivo

Lyoniel Farase
fuente
1

Fuente: Función PHP que genera caracteres aleatorios

Esta sencilla función de PHP funcionó para mí:

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
fuente
1

Aquí están mis 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));

La nueva función de PHP password_hash()(*> = PHP 5.5) está haciendo el trabajo para la generación de un conjunto de números y caracteres en mayúsculas y minúsculas decentemente largo.

Dos concat. las cadenas antes y después password_hashde la función $ random son adecuadas para el cambio.

Los parámetros para $random()* ($ a, $ b) son en realidad substr()parámetros. :)

NOTA: esto no necesita ser una función, también puede ser una variable normal ... como un singleliner desagradable, como este:

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

echo($random);
Escalofriante
fuente
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;
}
Juan F
fuente
Consejo profesional: incluya una explicación sobre cómo su respuesta resuelve el problema del OP y por qué podría ser diferente a las otras respuestas ya proporcionadas.
Tom
0

Siempre he usado esto:

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

Cuando lo llama, establece la longitud de la cuerda.

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

También puede cambiar los posibles caracteres de la cadena $a.

LabiosprY
fuente
Veo ese tiempo perdido desarrollando ociosamente esta función. ¡Busqué en Google un poco! @Andrew
LipESprY