PHP: ¿Cómo generar una cadena alfanumérica aleatoria, única?


380

¿Cómo sería posible generar una cadena aleatoria y única usando números y letras para usar en un enlace de verificación? Al igual que cuando crea una cuenta en un sitio web, y le envía un correo electrónico con un enlace, y tiene que hacer clic en ese enlace para verificar su cuenta ... sí ... uno de esos.

¿Cómo puedo generar uno de esos usando PHP?

Actualización: Acabo de recordar sobre uniqid(). Es una función PHP que genera un identificador único basado en el tiempo actual en microsegundos. Creo que usaré eso.


Todo lo que necesitas son cadenas y números aleatorios distribuidos uniformemente.
Artelius el

10
Hola Andrew, deberías elegir Scottla respuesta correcta. Scott está utilizando el generador de números psudoaleatorios criptográficamente seguros de OpenSSL (CSPRNG) que elegirá la fuente de entropía más segura en función de su plataforma.
torre el

3
Cualquiera que lea esto después de 2015, por favor, mire aquí: paragonie.com/blog/2015/07/… La mayoría de las respuestas principales tienen fallas más o menos ...
rugk

OpenSSL y uniqidson inseguros. Usa algo como Random::alphanumericString($length)o Random::alphanumericHumanString($length).
caw

Respuestas:


305

Aviso de seguridad : esta solución no debe usarse en situaciones en las que la calidad de su aleatoriedad puede afectar la seguridad de una aplicación. En particular, rand()y uniqid()no son criptográficamente seguros generadores de números aleatorios . Vea la respuesta de Scott para una alternativa segura.

Si no necesita que sea absolutamente único con el tiempo:

md5(uniqid(rand(), true))

De lo contrario (dado que ya ha determinado un inicio de sesión único para su usuario):

md5(uniqid($your_user_login, true))

90
Ambos métodos no garantizan la unicidad: la longitud de la entrada de la función md5 es mayor que la longitud de su salida y, según en.wikipedia.org/wiki/Pigeonhole_principle, la colisión está garantizada. Por otro lado, cuanto mayor sea la población que depende de hashes para lograr la identificación "única", mayor será la probabilidad de que ocurra al menos una colisión (ver en.wikipedia.org/wiki/Birthday_problem ). La probabilidad puede ser pequeña para la mayoría de las soluciones, pero aún existe.
Dariusz Walczak

12
Este no es un método seguro para generar valores aleatorios. Ver la respuesta de Scott.
torre el

44
Para las confirmaciones por correo electrónico que vencen relativamente pronto, creo que la pequeña posibilidad de que una persona pueda algún día confirmar el correo electrónico de otra persona es un riesgo insignificante. Pero siempre puede verificar si el token ya existe en la base de datos después de crearlo y simplemente elegir uno nuevo si ese es el caso. Sin embargo, el tiempo que pasa escribiendo ese fragmento de código probablemente se desperdicia, ya que lo más probable es que nunca se ejecute.
Andrew

Tenga en cuenta que md5 devuelve valores hexadecimales, lo que significa que el conjunto de caracteres está limitado a [0-9] y [af].
Thijs Riezebeek

1
md5 puede tener colisiones, acaba de arruinar una ventaja
única

507

Estaba buscando cómo resolver este mismo problema, pero también quiero que mi función cree un token que también se pueda usar para recuperar la contraseña. Esto significa que necesito limitar la capacidad del token para ser adivinado. Debido a que uniqidse basa en el tiempo, y de acuerdo con php.net "el valor de retorno es un poco diferente de microtime ()", uniqidno cumple con los criterios. PHP recomienda usar en su openssl_random_pseudo_bytes()lugar para generar tokens criptográficamente seguros.

Una respuesta rápida, breve y directa es:

bin2hex(openssl_random_pseudo_bytes($bytes))

que generará una cadena aleatoria de caracteres alfanuméricos de longitud = $ bytes * 2. Desafortunadamente, esto solo tiene un alfabeto de [a-f][0-9], pero funciona.


A continuación se muestra la función más potente que podría hacer que satisfaga los criterios (esta es una versión implementada de la respuesta de Erik)

function crypto_rand_secure($min, $max)
{
    $range = $max - $min;
    if ($range < 1) return $min; // not so random...
    $log = ceil(log($range, 2));
    $bytes = (int) ($log / 8) + 1; // length in bytes
    $bits = (int) $log + 1; // length in bits
    $filter = (int) (1 << $bits) - 1; // set all lower bits to 1
    do {
        $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
        $rnd = $rnd & $filter; // discard irrelevant bits
    } while ($rnd > $range);
    return $min + $rnd;
}

function getToken($length)
{
    $token = "";
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
    $codeAlphabet.= "0123456789";
    $max = strlen($codeAlphabet); // edited

    for ($i=0; $i < $length; $i++) {
        $token .= $codeAlphabet[crypto_rand_secure(0, $max-1)];
    }

    return $token;
}

crypto_rand_secure($min, $max)funciona como una caída en reemplazo de rand()o mt_rand. Utiliza openssl_random_pseudo_bytes para ayudar a crear un número aleatorio entre $ min y $ max.

getToken($length)crea un alfabeto para usar dentro del token y luego crea una cadena de longitud $length.

EDITAR: Olvidé citar la fuente: http://us1.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322

EDITAR (PHP7): con el lanzamiento de PHP7, la biblioteca estándar ahora tiene dos nuevas funciones que pueden reemplazar / mejorar / simplificar la función crypto_rand_secure anterior. random_bytes($length)yrandom_int($min, $max)

http://php.net/manual/en/function.random-bytes.php

http://php.net/manual/en/function.random-int.php

Ejemplo:

function getToken($length){
    $token = "";
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
    $codeAlphabet.= "0123456789";
    $max = strlen($codeAlphabet);

    for ($i=0; $i < $length; $i++) {
        $token .= $codeAlphabet[random_int(0, $max-1)];
    }

    return $token;
}

2
Convenido. ¡El almacenamiento de contraseñas en texto plano es horrible! (Yo uso blowfish.) Pero después de que se genera el token, le permite al titular del token restablecer la contraseña, por lo que el token es equivalente a la contraseña mientras es válido (y se trata como tal).
Scott,

23
Hola, combiné tu excelente código con la conveniente funcionalidad del método Kohana Text :: random () y creé esta esencia: gist.github.com/raveren/5555297
raveren

99
¡Perfecto! Lo probé con 10 caracteres como longitud. ¡100000 tokens y aún no hay duplicados!
Sharpless512

55
Usé este proceso y lo encontré súper lento. Con una longitud de 36, se agotó el tiempo de espera en el servidor de desarrollo. Con una longitud de 24 todavía tomó alrededor de 30 segundos. No estoy seguro de qué hice mal, pero fue demasiado lento para mí y opté por otra solución.
Shane

55
También puede usar en base64_encodelugar de bin2hexobtener una cadena más corta con un alfabeto más grande.
erjiang

91

Versión orientada a objetos de la solución más votada

He creado una solución orientada a objetos basada en la respuesta de Scott :

<?php

namespace Utils;

/**
 * Class RandomStringGenerator
 * @package Utils
 *
 * Solution taken from here:
 * http://stackoverflow.com/a/13733588/1056679
 */
class RandomStringGenerator
{
    /** @var string */
    protected $alphabet;

    /** @var int */
    protected $alphabetLength;


    /**
     * @param string $alphabet
     */
    public function __construct($alphabet = '')
    {
        if ('' !== $alphabet) {
            $this->setAlphabet($alphabet);
        } else {
            $this->setAlphabet(
                  implode(range('a', 'z'))
                . implode(range('A', 'Z'))
                . implode(range(0, 9))
            );
        }
    }

    /**
     * @param string $alphabet
     */
    public function setAlphabet($alphabet)
    {
        $this->alphabet = $alphabet;
        $this->alphabetLength = strlen($alphabet);
    }

    /**
     * @param int $length
     * @return string
     */
    public function generate($length)
    {
        $token = '';

        for ($i = 0; $i < $length; $i++) {
            $randomKey = $this->getRandomInteger(0, $this->alphabetLength);
            $token .= $this->alphabet[$randomKey];
        }

        return $token;
    }

    /**
     * @param int $min
     * @param int $max
     * @return int
     */
    protected function getRandomInteger($min, $max)
    {
        $range = ($max - $min);

        if ($range < 0) {
            // Not so random...
            return $min;
        }

        $log = log($range, 2);

        // Length in bytes.
        $bytes = (int) ($log / 8) + 1;

        // Length in bits.
        $bits = (int) $log + 1;

        // Set all lower bits to 1.
        $filter = (int) (1 << $bits) - 1;

        do {
            $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));

            // Discard irrelevant bits.
            $rnd = $rnd & $filter;

        } while ($rnd >= $range);

        return ($min + $rnd);
    }
}

Uso

<?php

use Utils\RandomStringGenerator;

// Create new instance of generator class.
$generator = new RandomStringGenerator;

// Set token length.
$tokenLength = 32;

// Call method to generate random string.
$token = $generator->generate($tokenLength);

Alfabeto personalizado

Puede usar un alfabeto personalizado si es necesario. Simplemente pase una cadena con caracteres compatibles al constructor o setter:

<?php

$customAlphabet = '0123456789ABCDEF';

// Set initial alphabet.
$generator = new RandomStringGenerator($customAlphabet);

// Change alphabet whenever needed.
$generator->setAlphabet($customAlphabet);

Aquí están las muestras de salida

SRniGU2sRQb2K1ylXKnWwZr4HrtdRgrM
q1sRUjNq1K9rG905aneFzyD5IcqD4dlC
I0euIWffrURLKCCJZ5PQFcNUCto6cQfD
AKwPJMEM5ytgJyJyGqoD5FQwxv82YvMr
duoRF6gAawNOEQRICnOUNYmStWmOpEgS
sdHUkEn4565AJoTtkc8EqJ6cC4MLEHUx
eVywMdYXczuZmHaJ50nIVQjOidEVkVna
baJGt7cdLDbIxMctLsEBWgAw5BByP5V0
iqT0B2obq3oerbeXkDVLjZrrLheW4d8f
OUQYCny6tj2TYDlTuu1KsnUyaLkeObwa

Espero que ayude a alguien. ¡Salud!


Lo siento, pero ¿cómo ejecuto esto? Lo hice $obj = new RandomStringGenerator;pero ¿a qué método debería llamar? Gracias.
sg552

@ sg552, debe llamar al generatemétodo como en el ejemplo anterior. Simplemente pase un número entero para especificar la longitud de la cadena resultante.
Slava Fomin II

Gracias, funciona para mí, pero Custom Alphabetno lo hizo. Obtuve salida vacía cuando echo. De todos modos, ni siquiera estoy seguro de cuál es el uso del segundo ejemplo, Custom Alphabetasí que creo que me quedo con el primer ejemplo. Gracias.
sg552

1
Agradable, pero bastante exagerado en la mayoría de los escenarios, a menos que su proyecto se base en gran medida en códigos generados aleatoriamente
Dspacejs

1
sí agradable pero excesivo, especialmente teniendo en cuenta que ahora está bastante obsoleto para php 5.7
Andrew

39

Llego tarde pero estoy aquí con algunos buenos datos de investigación basados ​​en las funciones proporcionadas por la respuesta de Scott . Así que configuré una gota Digital Ocean solo para esta prueba automatizada de 5 días y almacené las cadenas únicas generadas en una base de datos MySQL.

Durante este período de prueba, utilicé 5 longitudes diferentes (5, 10, 15, 20, 50) y se insertaron +/- 0.5 millones de registros para cada longitud. Durante mi prueba, solo la longitud 5 generó +/- 3K duplicados de 0.5 millones y las longitudes restantes no generaron duplicados. Entonces podemos decir que si usamos una longitud de 15 o más con las funciones de Scott, entonces podemos generar cadenas únicas altamente confiables. Aquí está la tabla que muestra mis datos de investigación:

ingrese la descripción de la imagen aquí

Actualización: creé una aplicación Heroku simple usando estas funciones que devuelve el token como una respuesta JSON. Se puede acceder a la aplicación en https://uniquestrings.herokuapp.com/api/token?length=15

Espero que esto ayude.


33

Puede usar UUID (Identificador único universal), puede usarse para cualquier propósito, desde la cadena de autenticación del usuario hasta la identificación de la transacción de pago.

Un UUID es un número de 16 octetos (128 bits). En su forma canónica, un UUID está representado por 32 dígitos hexadecimales, que se muestran en cinco grupos separados por guiones, en la forma 8-4-4-4-12 para un total de 36 caracteres (32 caracteres alfanuméricos y cuatro guiones).

function generate_uuid() {
    return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
        mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
        mt_rand( 0, 0xffff ),
        mt_rand( 0, 0x0C2f ) | 0x4000,
        mt_rand( 0, 0x3fff ) | 0x8000,
        mt_rand( 0, 0x2Aff ), mt_rand( 0, 0xffD3 ), mt_rand( 0, 0xff4B )
    );

}

// llamando a la función

$transationID = generate_uuid();

algunos resultados de ejemplo serán como:

E302D66D-87E3-4450-8CB6-17531895BF14
22D288BC-7289-442B-BEEA-286777D559F2
51B4DE29-3B71-4FD2-9E6C-071703E1FF31
3777C8C6-9FF5-4C78-AAA2-08A47F555E81
54B91C72-2CF4-4501-A6E9-02A60DCBAE4C
60F75C7C-1AE3-417B-82C8-14D456542CD7
8DE0168D-01D3-4502-9E59-10D665CEBCB2

Espero que ayude a alguien en el futuro :)


¡Se ve fantástico, agregado a mi lista!
Mustafa Erdogan

32

Esta función generará una clave aleatoria usando números y letras:

function random_string($length) {
    $key = '';
    $keys = array_merge(range(0, 9), range('a', 'z'));

    for ($i = 0; $i < $length; $i++) {
        $key .= $keys[array_rand($keys)];
    }

    return $key;
}

echo random_string(50);

Salida de ejemplo:

zsd16xzv3jsytnp87tk7ygv73k8zmr0ekh6ly7mxaeyeh46oe8

66
Después de un tiempo, llega a los mismos números
Sharpless512

1
Esto no es completamente aleatorio porque nunca tendrá el mismo personaje más de una vez.
EricP

16

Yo uso este one-liner:

base64_encode(openssl_random_pseudo_bytes(3 * ($length >> 2)));

donde longitud es la longitud de la cadena deseada (divisible por 4, de lo contrario se redondea al número más cercano divisible por 4)


66
No siempre devuelve solo caracteres alfanuméricos. Puede contener caracteres como==
user3459110

1
Si se usa en una URL, base64url_encodepuede usarse en su lugar, ver aquí: php.net/manual/en/function.base64-encode.php
Paul

9

Utilice el siguiente código para generar el número aleatorio de 11 caracteres o cambie el número según sus requisitos.

$randomNum=substr(str_shuffle("0123456789abcdefghijklmnopqrstvwxyz"), 0, 11);

o podemos usar una función personalizada para generar el número aleatorio

 function randomNumber($length){
     $numbers = range(0,9);
     shuffle($numbers);
     for($i = 0;$i < $length;$i++)
        $digits .= $numbers[$i];
     return $digits;
 }

 //generate random number
 $randomNum=randomNumber(11);

3
Esto nunca puede generar la cadena "aaaaaaaaaaa" o "aaaaabbbbbb". Simplemente selecciona una subcadena de una permutación aleatoria del alfabeto. La cadena larga de 11 caracteres solo tiene V (11,35) = 288 valores posibles. ¡No use esto si espera que las cuerdas sean únicas!
kdojeteri

@Peping luego hazlosubstr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstvwxyz', 36)), 0, 11);
Tim Hallman

7
  1. Genere un número aleatorio usando su generador de números aleatorios favorito
  2. Multiplique y divídalo para obtener un número que coincida con el número de caracteres en su código alfabético
  3. Obtenga el artículo en ese índice en el alfabeto de su código.
  4. Repita desde 1) hasta que tenga la longitud que desea

por ejemplo (en pseudocódigo)

int myInt = random(0, numcharacters)
char[] codealphabet = 'ABCDEF12345'
char random = codealphabet[i]
repeat until long enough

Teóricamente hablando, ¿no podría esto potencialmente generar la misma cadena más de una vez?
Frezq

4

Aquí está el último generador de identificación único para usted. hecho por mi.

<?php
$d=date ("d");
$m=date ("m");
$y=date ("Y");
$t=time();
$dmt=$d+$m+$y+$t;    
$ran= rand(0,10000000);
$dmtran= $dmt+$ran;
$un=  uniqid();
$dmtun = $dmt.$un;
$mdun = md5($dmtran.$un);
$sort=substr($mdun, 16); // if you want sort length code.

echo $mdun;
?>

puedes hacer eco de cualquier 'var' para tu identificación como quieras. pero $ mdun es mejor, puede reemplazar md5 a sha1 para obtener un código mejor, pero eso será muy largo y es posible que no lo necesite.

Gracias.


77
En este caso, la aleatoriedad está garantizada por un código escrito al azar, ¿verdad?
Daniel Kucal

3
Sí, esto es algo "aleatorio" porque no es un código oscuro estándar. Esto hace que sea difícil de predecir ... pero en realidad no usa partes inseguras para generar un número aleatorio. por lo que el resultado no es técnicamente aleatorio ni seguro.
Philipp

4

Para cadenas realmente aleatorias, puede usar

<?php

echo md5(microtime(true).mt_Rand());

salidas:

40a29479ec808ad4bcff288a48a25d5c

así que incluso si intentas generar cadenas varias veces al mismo tiempo, obtendrás resultados diferentes.


4

Cuando intentas generar una contraseña aleatoria, intentas:

  • Primero genere un conjunto criptográficamente seguro de bytes aleatorios

  • El segundo es convertir esos bytes aleatorios en una cadena imprimible

Ahora, hay múltiples formas de generar bytes aleatorios en php como:

$length = 32;

//PHP 7+
$bytes= random_bytes($length);

//PHP < 7
$bytes= openssl_random_pseudo_bytes($length);

Luego, desea convertir estos bytes aleatorios en una cadena imprimible:

Puedes usar bin2hex :

$string = bin2hex($bytes);

o base64_encode :

$string = base64_encode($bytes);

Sin embargo, tenga en cuenta que no controla la longitud de la cadena si usa base64. Puede usar bin2hex para hacer eso, usar 32 bytes se convertirá en una cadena de 64 caracteres . Pero solo funcionará así en una cadena INCLUSO .

Entonces básicamente puedes hacer :

$length = 32;

if(PHP_VERSION>=7){
    $bytes= random_bytes($length);
}else{
    $bytes= openssl_random_pseudo_bytes($length);
} 

$string = bin2hex($bytes);

3

Esto es lo que uso:

md5(time() . rand());    
// Creates something like 0c947c3b1047334f5bb8a3b7adc1d97b

2
function random_string($length = 8) {
    $alphabets = range('A','Z');
    $numbers = range('0','9');
    $additional_characters = array('_','=');
    $final_array = array_merge($alphabets,$numbers,$additional_characters);
       while($length--) {
      $key = array_rand($final_array);

      $password .= $final_array[$key];
                        }
  if (preg_match('/[A-Za-z0-9]/', $password))
    {
     return $password;
    }else{
    return  random_string();
    }

 }

2

Esta es una función simple que le permite generar cadenas aleatorias que contienen letras y números (alfanuméricos). También puede limitar la longitud de la cadena. Estas cadenas aleatorias se pueden utilizar para diversos fines, que incluyen: Código de referencia, Código promocional, Código de cupón. La función se basa en las siguientes funciones de PHP: base_convert, sha1, uniqid, mt_rand

function random_code($length)
{
  return substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, $length);
}

echo random_code(6);

/*sample output
* a7d9e8
* 3klo93
*/

1

Después de leer ejemplos anteriores se me ocurrió esto:

protected static $nonce_length = 32;

public static function getNonce()
{
    $chars = array();
    for ($i = 0; $i < 10; $i++)
        $chars = array_merge($chars, range(0, 9), range('A', 'Z'));
    shuffle($chars);
    $start = mt_rand(0, count($chars) - self::$nonce_length);
    return substr(join('', $chars), $start, self::$nonce_length);
}

Duplico 10 veces la matriz [0-9, AZ] y barajo los elementos, después de obtener un punto de inicio aleatorio para que substr () sea más 'creativo' :) puedes agregar [az] y otros elementos a la matriz, duplicar más o menos, sé más creativo que yo


1

Me gusta usar claves hash cuando trato con enlaces de verificación. Recomendaría usar el microtiempo y el hash que usando MD5 ya que no debería haber ninguna razón por la cual las teclas deberían ser las mismas ya que se basa en el microtiempo.

  1. $key = md5(rand());
  2. $key = md5(microtime());

1
<?php
function generateRandomString($length = 11) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;

}

?>

la función anterior generará una cadena aleatoria que tiene una longitud de 11 caracteres.


1

Si desea generar una cadena única en PHP, intente lo siguiente.

md5(uniqid().mt_rand());

En esto,

uniqid()- Generará una cadena única. Esta función devuelve un identificador único basado en marca de tiempo como una cadena.

mt_rand() - Generar número aleatorio.

md5() - Generará la cadena hash.


0

Scott, sí, eres muy escritor y una buena solución. Gracias.

También debo generar un token API único para cada usuario. El siguiente es mi enfoque, utilicé información de usuario (ID de usuario y nombre de usuario):

public function generateUniqueToken($userid, $username){

        $rand = mt_rand(100,999);
    $md5 = md5($userid.'!(&^ 532567_465 ///'.$username);

    $md53 = substr($md5,0,3);
    $md5_remaining = substr($md5,3);

    $md5 = $md53. $rand. $userid. $md5_remaining;

    return $md5;
}

Eche un vistazo y avíseme si puedo hacer alguna mejora. Gracias


0

Esto es lo que estoy usando en uno de mis proyectos, está funcionando muy bien y genera un TOQUE RANDOM ÚNICO :

$timestampz=time();

function generateRandomString($length = 60) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;
}


$tokenparta = generateRandomString();


$token = $timestampz*3 . $tokenparta;

echo $token;

Tenga en cuenta que multipliqué la marca de tiempo por tres para crear una confusión para quien sea que el usuario se pregunte cómo se genera este token;)

Espero que ayude :)


1
"Tenga en cuenta que multipliqué la marca de tiempo por tres para crear una confusión para el usuario que se pregunte cómo se genera este token" Suena como seguridad a través de la ofuscación stackoverflow.com/questions/533965/…
Harry

Esto no es una "seguridad a través de la ofuscación", ya que la marca de tiempo se agrega a una cadena aleatoria que se generó, y esa es la cadena final real que devolvemos;)
Kaszoni Ferencz


0

podemos usar estas dos líneas de código para generar cadenas únicas que han probado alrededor de 10000000 veces de iteración

  $sffledStr= str_shuffle('abscdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-+');
    $uniqueString = md5(time().$sffledStr);

0

Siempre uso esta función para generar una cadena alfanumérica aleatoria personalizada ... Espero que esto sea de ayuda.

<?php
  function random_alphanumeric($length) {
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345689';
    $my_string = '';
    for ($i = 0; $i < $length; $i++) {
      $pos = mt_rand(0, strlen($chars) -1);
      $my_string .= substr($chars, $pos, 1);
    }
    return $my_string;
  }
  echo random_alphanumeric(50); // 50 characters
?>

Genera, por ejemplo: Y1FypdjVbFCFK6Gh9FDJpe6dciwJEfV6MQGpJqAfuijaYSZ86g

Si desea comparar con otra cadena para asegurarse de que es una secuencia única, puede usar este truco ...

$string_1 = random_alphanumeric(50);
$string_2 = random_alphanumeric(50);
while ($string_1 == $string_2) {
  $string_1 = random_alphanumeric(50);
  $string_2 = random_alphanumeric(50);
  if ($string_1 != $string_2) {
     break;
  }
}
echo $string_1;
echo "<br>\n";
echo $string_2;

genera dos cadenas únicas:

qsBDs4JOoVRfFxyLAOGECYIsWvpcpMzAO9pypwxsqPKeAmYLOi

Ti3kE1WfGgTNxQVXtbNNbhhvvapnaUfGMVJecHkUjHbuCb85pF

Espero que esto sea lo que estás buscando ...


0

Una solución simple es convertir la base 64 a alfanumérica descartando los caracteres no alfanuméricos.

Este usa random_bytes () para un resultado criptográficamente seguro.

function random_alphanumeric(int $length): string
{
    $result='';
    do
    {
        //Base 64 produces 4 characters for each 3 bytes, so most times this will give enough bytes in a single pass
        $bytes=random_bytes(($length+3-strlen($result))*2);
        //Discard non-alhpanumeric characters
        $result.=str_replace(['/','+','='],['','',''],base64_encode($bytes));
        //Keep adding characters until the string is long enough
        //Add a few extra because the last 2 or 3 characters of a base 64 string tend to be less diverse
    }while(strlen($result)<$length+3);
    return substr($result,0,$length);
}


-1

Creo que el problema con todas las ideas existentes es que probablemente sean únicas, pero no definitivamente únicas (como se señala en la respuesta de Dariusz Walczak al loletech). Tengo una solución que en realidad es única. Requiere que su script tenga algún tipo de memoria. Para mí esta es una base de datos SQL. También podría simplemente escribir en un archivo en alguna parte. Hay dos implementaciones:

Primer método: tener DOS campos en lugar de 1 que proporcionan unicidad. El primer campo es un número de ID que no es aleatorio pero es único (el primer ID es 1, el segundo 2 ...). Si está utilizando SQL, simplemente defina el campo ID con la propiedad AUTO_INCREMENT. El segundo campo no es único pero es aleatorio. Esto se puede generar con cualquiera de las otras técnicas que la gente ya ha mencionado. La idea de Scott era buena, pero md5 es conveniente y probablemente lo suficientemente buena para la mayoría de los propósitos:

$random_token = md5($_SERVER['HTTP_USER_AGENT'] . time());

Segundo método: Básicamente, la misma idea, pero inicialmente elige un número máximo de cadenas que se generarán. Esto podría ser un número realmente grande como un billón. Luego haga lo mismo, genere una ID, pero rellene con cero para que todas las ID tengan el mismo número de dígitos. Luego solo concatena la ID con la cadena aleatoria. Será lo suficientemente aleatorio para la mayoría de los propósitos, pero la sección de ID se asegurará de que también sea único.


-1

Puedes usar este código, espero que te sea útil.

function rand_code($len)
{
 $min_lenght= 0;
 $max_lenght = 100;
 $bigL = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 $smallL = "abcdefghijklmnopqrstuvwxyz";
 $number = "0123456789";
 $bigB = str_shuffle($bigL);
 $smallS = str_shuffle($smallL);
 $numberS = str_shuffle($number);
 $subA = substr($bigB,0,5);
 $subB = substr($bigB,6,5);
 $subC = substr($bigB,10,5);
 $subD = substr($smallS,0,5);
 $subE = substr($smallS,6,5);
 $subF = substr($smallS,10,5);
 $subG = substr($numberS,0,5);
 $subH = substr($numberS,6,5);
 $subI = substr($numberS,10,5);
 $RandCode1 = str_shuffle($subA.$subD.$subB.$subF.$subC.$subE);
 $RandCode2 = str_shuffle($RandCode1);
 $RandCode = $RandCode1.$RandCode2;
 if ($len>$min_lenght && $len<$max_lenght)
 {
 $CodeEX = substr($RandCode,0,$len);
 }
 else
 {
 $CodeEX = $RandCode;
 }
 return $CodeEX;
}

Detalles sobre el generador de código aleatorio en PHP


-2

Simplificando el código de Scotts anterior eliminando bucles innecesarios que se ralentizan mucho y no lo hacen más seguro que llamar a openssl_random_pseudo_bytes solo una vez

function crypto_rand_secure($min, $max)
{
 $range = $max - $min;
 if ($range < 1) return $min; // not so random...
 $log = ceil(log($range, 2));
 $bytes = (int) ($log / 8) + 1; // length in bytes
 $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
 return $min + $rnd%$range;
}

function getToken($length)
{
 return bin2hex(openssl_random_pseudo_bytes($length)
}

Desafortunadamente, no puedo estar de acuerdo con usted en que esta es una simplificación apropiada de la función crypto_rand_secure. El bucle es necesario para evitar el sesgo de módulo que ocurre cuando tomas el resultado de un número generado aleatoriamente y luego lo modificas por un número que divide el rango. en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Modulo_bias . Al usar un bucle para arrojar cualquier número fuera del rango y seleccionar un nuevo número, se evita este sesgo. stackoverflow.com/questions/10984974/…
Scott

@ Scott, esa publicación es sobre rand (). Sin embargo, en este caso, ya está cuidado por openssl_random_pseudo_bytes, por lo que es innecesario.
mabel

1
gist.github.com/anonymous/87e3ae6fd3320447f46b973e75c2ea85 - Ejecute este script. Verá que la distribución de los resultados no es aleatoria. Los números entre 0-55 tienen una mayor incidencia que los números entre 56-100. opensslno está causando esto, es debido al sesgo de módulo en su declaración de devolución. 100 (rango) no divide 255 (1 byte) de manera uniforme y causa estos resultados. Mi mayor problema con su respuesta es que usted declara que la función es tan segura como usar un bucle, que es falso. Su implementación de crypto_rand_secure no es criptográficamente segura y es engañosa.
Scott

@ Scott, estamos divagando aquí, no se trata de la última declaración de retorno, también se puede calcular progresivamente a partir del valor de retorno de openssl_random_pseudo_bytes sin usar el módulo. El punto que estoy señalando es que el ciclo es innecesario una vez que openssl_random_pseudo_bytes devuelve los bytes aleatorios. Al hacer un bucle, no lo está haciendo más seguro, solo lo está haciendo más lento.
mabel

2
Esta respuesta propaga mala información. Tiene razón en que el ciclo no es opensslmás seguro, pero lo más importante es que no lo hace menos seguro, esta respuesta sí. El código anterior toma un número aleatorio perfectamente bueno y lo manipula sesgándolo hacia números más bajos. Si pone un descargo de responsabilidad en su respuesta indicando que es más rápido (al eliminar el bucle) pero no es un CSPRNG, resolvería este problema. Por amor a la criptografía, informe a los usuarios que la salida de esta función podría estar sesgada y no es una solución equivalente. El bucle no solo está ahí para molestarte.
Scott
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.