web-dev-qa-db-fra.com

PHP: Comment générer une chaîne alphanumérique aléatoire, unique?

Comment serait-il possible de générer une chaîne aléatoire unique en utilisant des chiffres et des lettres à utiliser dans un lien de vérification? Par exemple, lorsque vous créez un compte sur un site Web, celui-ci vous envoie un courrier électronique avec un lien. Vous devez cliquer sur ce lien pour vérifier votre compte ... ouais ... l'un d'entre eux.

Comment puis-je générer l'un de ceux qui utilisent PHP?

Mise à jour: Je viens juste de me souvenir de uniqid() . C'est une fonction PHP qui génère un identifiant unique basé sur l'heure actuelle en microsecondes. Je pense que je vais l'utiliser.

347
Andrew

Avis de sécurité : cette solution ne doit pas être utilisée dans des situations où la qualité de votre caractère aléatoire peut affecter la sécurité d'une application. En particulier, Rand() et uniqid() ne sont pas des générateurs de nombres aléatoires sécurisés par cryptographie . Voir réponse de Scott pour une alternative sécurisée.

Si vous n'en avez pas besoin pour être absolument unique dans le temps:

md5(uniqid(Rand(), true))

Sinon (si vous avez déjà déterminé un identifiant unique pour votre utilisateur):

md5(uniqid($your_user_login, true))
281
loletech

Je cherchais simplement à résoudre ce même problème, mais je souhaite également que ma fonction crée un jeton pouvant également être utilisé pour la récupération de mot de passe. Cela signifie que je dois limiter la capacité du jeton à être deviné. Parce que uniqid est basé sur l'heure et, selon php.net, "la valeur de retour est légèrement différente de microtime ()", uniqid ne répond pas aux critères. PHP recommande d'utiliser openssl_random_pseudo_bytes() à la place pour générer des jetons sécurisés de manière cryptographique.

Voici une réponse rapide, brève et pertinente:

bin2hex(openssl_random_pseudo_bytes($bytes))

qui générera une chaîne aléatoire de caractères alphanumériques de longueur = $ bytes * 2. Malheureusement, cela n’a que l’alphabet [a-f][0-9], mais cela fonctionne.


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) fonctionne comme un remplacement instantané de Rand() ou mt_Rand. Il utilise openssl_random_pseudo_bytes pour créer un nombre aléatoire compris entre $ min et $ max.

getToken($length) crée un alphabet à utiliser dans le jeton, puis crée une chaîne de longueur $length.

MODIFIER: J'ai négligé de citer la source - http://us1.php.net/manual/fr/function.openssl-random-pseudo-bytes.php#104322

EDIT (PHP7): Avec la sortie de PHP7, la bibliothèque standard a maintenant deux nouvelles fonctions qui peuvent remplacer/améliorer/simplifier la fonction crypto_Rand_secure ci-dessus. random_bytes($length) et random_int($min, $max)

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

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

Exemple:

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

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

    return $token;
}
460
Scott

Version orientée objet de la solution la plus votée

J'ai créé une solution orientée objet basée sur la réponse 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);
    }
}

Usage

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

Alphabet personnalisé

Vous pouvez utiliser un alphabet personnalisé si nécessaire. Il suffit de transmettre une chaîne avec des caractères pris en charge au constructeur ou au configurateur:

<?php

$customAlphabet = '0123456789ABCDEF';

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

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

Voici les échantillons de sortie

SRniGU2sRQb2K1ylXKnWwZr4HrtdRgrM
q1sRUjNq1K9rG905aneFzyD5IcqD4dlC
I0euIWffrURLKCCJZ5PQFcNUCto6cQfD
AKwPJMEM5ytgJyJyGqoD5FQwxv82YvMr
duoRF6gAawNOEQRICnOUNYmStWmOpEgS
sdHUkEn4565AJoTtkc8EqJ6cC4MLEHUx
eVywMdYXczuZmHaJ50nIVQjOidEVkVna
baJGt7cdLDbIxMctLsEBWgAw5BByP5V0
iqT0B2obq3oerbeXkDVLjZrrLheW4d8f
OUQYCny6tj2TYDlTuu1KsnUyaLkeObwa

J'espère que ça va aider quelqu'un. À votre santé!

86
Slava Fomin II

Je suis en retard mais je suis ici avec de bonnes données de recherche basées sur les fonctions fournies par , la réponse de Scott . J'ai donc mis en place un droplet Digital Ocean uniquement pour ce test automatisé de 5 jours et ai stocké les chaînes uniques générées dans une base de données MySQL.

Au cours de cette période de test, j'ai utilisé 5 longueurs différentes (5, 10, 15, 20, 50) et +/- 0,5 million d'enregistrements ont été insérés pour chaque longueur. Au cours de mon test, seule la longueur 5 a généré +/- 3 000 doublons sur 0,5 million et les longueurs restantes n'ont généré aucun doublon. Nous pouvons donc dire que si nous utilisons une longueur de 15 ou plus avec les fonctions de Scott, nous pouvons générer des chaînes uniques extrêmement fiables. Voici le tableau montrant mes données de recherche:

enter image description here

Mise à jour: j'ai créé une application Heroku simple à l'aide de ces fonctions, qui renvoie le jeton sous forme de réponse JSON. L'application est accessible à l'adresse https://uniquestrings.herokuapp.com/api/token?length=15.

J'espère que ça aide.

33
Rehmat

Cette fonction générera une clé aléatoire en utilisant des chiffres et des lettres:

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

Exemple de sortie:

zsd16xzv3jsytnp87tk7ygv73k8zmr0ekh6ly7mxaeyeh46oe8
30
Rathienth Baskaran

Vous pouvez utiliser UUID (identificateur unique universel), il peut être utilisé pour n'importe quel usage, de la chaîne d'authentification de l'utilisateur à l'identifiant de la transaction de paiement.

Un UUID est un nombre de 16 octets (128 bits). Dans sa forme canonique, un UUID est représenté par 32 chiffres hexadécimaux, affichés en cinq groupes séparés par des traits d'union, sous la forme 8-4-4-4-12 pour un total de 36 caractères (32 caractères alphanumériques et quatre traits d'union).

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

}

// fonction d'appel

$transationID = generate_uuid();

quelques exemples de sorties seront comme:

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

j'espère que ça aidera quelqu'un à l'avenir :)

28
Developer

J'utilise ce one-liner:

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

où longueur est la longueur de la chaîne souhaitée (divisible par 4, sinon elle est arrondie au nombre inférieur divisible par 4)

13
DudeOnRock

Utilisez le code ci-dessous pour générer le nombre aléatoire de 11 caractères ou modifier le nombre selon vos besoins.

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

ou nous pouvons utiliser une fonction personnalisée pour générer le nombre aléatoire

 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);
7
Ramesh Kotkar
  1. Générez un nombre aléatoire à l'aide de votre générateur de nombre aléatoire préféré
  2. Multipliez-le et divisez-le pour obtenir un nombre correspondant au nombre de caractères de votre alphabet de code.
  3. Obtenez l'élément à cet index dans votre alphabet de code.
  4. Répéter de 1) jusqu'à ce que vous ayez la longueur souhaitée

par exemple (en pseudo-code)

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

Voici le générateur d'identifiant unique ultime pour vous. fait par moi.

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

vous pouvez utiliser n'importe quel "var" pour votre identifiant, comme vous le souhaitez. mais $ mdun est préférable, vous pouvez remplacer md5 par sha1 pour obtenir un meilleur code, mais ce sera très long, ce dont vous n’avez peut-être pas besoin.

Je vous remercie.

4
Krishna Torque

Pour des chaînes vraiment aléatoires, vous pouvez utiliser

<?php

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

les sorties :

40a29479ec808ad4bcff288a48a25d5c

ainsi, même si vous essayez de générer une chaîne plusieurs fois au même moment, vous obtiendrez une sortie différente.

3
AMB

Lorsque vous essayez de générer un mot de passe aléatoire, vous essayez de:

  • Tout d'abord générer un ensemble sécurisé d'octets aléatoires cryptographiquement sécurisé

  • Deuxièmement, transformer ces octets aléatoires en une chaîne imprimable

Maintenant, il y a plusieurs façons de générer des octets aléatoires dans php comme:

$length = 32;

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

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

Ensuite, vous voulez transformer ces octets aléatoires en une chaîne imprimable:

Vous pouvez utiliser bin2hex:

$string = bin2hex($bytes);

ou base64_encode:

$string = base64_encode($bytes);

Toutefois, notez que vous ne contrôlez pas la longueur de la chaîne si vous utilisez base64. Vous pouvez utiliser bin2hex pour cela, utiliser 2 octets se transformera en chaîne de 64 caractères. Mais cela ne fonctionnera que dans une chaîne MÊME.

2
Dylan Kas

Voici ce que j'utilise:

md5(time() . Rand());    
// Creates something like 0c947c3b1047334f5bb8a3b7adc1d97b
2
Faraz Kelhini
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
Nidhin

J'aime utiliser les clés de hachage lorsque vous utilisez des liens de vérification. Je recommanderais d'utiliser le microtime et le hachage à l'aide de MD5, car il ne devrait y avoir aucune raison pour que les clés soient identiques, car elles sont basées sur le microtime.

  1. $key = md5(Rand());
  2. $key = md5(microtime());
1
codermjb

Si vous voulez générer une chaîne unique en PHP, essayez de suivre.

md5(uniqid().mt_Rand());

Dans ce,

uniqid() - Il générera une chaîne unique. Cette fonction renvoie l'identifiant unique basé sur l'horodatage sous forme de chaîne.

mt_Rand() - Génère un nombre aléatoire.

md5() - Il générera la chaîne de hachage.

1
akshaypjoshi

après avoir lu les exemples précédents, j'ai trouvé ceci:

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

Je duplique 10 fois le tableau [0-9, AZ] et je mélange les éléments. Après avoir obtenu un point de départ aléatoire pour substr (), il est plus "créatif" :) vous pouvez ajouter [az] et d'autres éléments dans un tableau, dupliquer plus ou moins, soyez plus créatif que moi

1
Luiggi ZAMOL

C'est une fonction simple qui vous permet de générer des chaînes aléatoires contenant des lettres et des chiffres (alphanumériques). Vous pouvez également limiter la longueur de la chaîne. Ces chaînes aléatoires peuvent être utilisées à diverses fins, notamment: code de référence, code promotionnel, code de coupon. La fonction repose sur les fonctions PHP suivantes: 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
Arpit J.
<?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 fonction ci-dessus générera une chaîne aléatoire de 11 caractères.

0

Voici ce que j'utilise sur l'un de mes projets, cela fonctionne très bien et génère un NIQUE RANDOM TOKEN:

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

Veuillez noter que j'ai multiplié l'horodatage par trois pour créer une confusion pour les utilisateurs se demandant peut-être comment ce jeton est généré;)

J'espère que ça aide :)

0
Kaszoni Ferencz

Scott, oui tu es très écrit et bonne solution! Merci.

Je suis également tenu de générer un jeton API unique pour chaque utilisateur. Voici mon approche, j'ai utilisé les informations utilisateur (ID utilisateur et nom d'utilisateur):

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

S'il vous plaît jeter un oeil et laissez-moi savoir si une amélioration que je peux faire. Merci

0
Himanshu Sharma

Je pense que c'est la meilleure méthode à utiliser.

str_shuffle(md5(Rand(0,100000)))
0
Davinder Kumar

nous pouvons utiliser ces deux lignes de code pour générer une chaîne unique ont testé environ 10000000 fois d'itération

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

J'utilise toujours cette fonction pour générer une chaîne alphanumérique aléatoire personnalisée ... J'espère que cela vous aidera.

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

Il génère par exemple: Y1FypdjVbFCFK6Gh9FDJpe6dciwJEfV6MQGpJqAfuijaYSZ86g

Si vous voulez comparer avec une autre chaîne pour être sûr que c'est une séquence unique, vous pouvez utiliser cette astuce ...

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

il génère deux chaînes uniques:

qsBDs4JOoVRfFxyLAOGECYIsWvpcpMzAO9pypwxsqPKeAmYLOi

Ti3kE1WfGgTNxQVXtbNNbhhvvapnaUfGMVJecHkUjHbuCb85pF

J'espère que c'est ce que vous recherchez ...

0
Alessandro