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


380

Comment serait-il possible de générer une chaîne aléatoire unique à l'aide de chiffres et de lettres à utiliser dans un lien de vérification? Comme lorsque vous créez un compte sur un site Web, et il vous envoie un e-mail avec un lien, et vous devez cliquer sur ce lien afin de vérifier votre compte ... ouais ... l'un d'eux.

Comment puis-je en générer un en utilisant PHP?

Mise à jour: Je me souviens juste 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.


Tout ce dont vous avez besoin sont des chaînes et des nombres aléatoires uniformément distribués.
Artelius

10
Hey Andrew, tu devrais choisir Scottla bonne réponse. Scott utilise le générateur de nombres psudo-aléatoires (CSPRNG) cryptographiquement sécurisé d'OpenSSL qui choisira la source d'entropie la plus sécurisée en fonction de votre plateforme.
tour

3
Si vous lisez ceci après 2015, veuillez regarder ici: paragonie.com/blog/2015/07/… La plupart des meilleures réponses sont plus ou moins imparfaites ...
rugk

OpenSSL et ne uniqidsont pas sécurisés. Utilisez quelque chose comme Random::alphanumericString($length)ou Random::alphanumericHumanString($length).
caw

Réponses:


305

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 cryptographiquement . Voir la réponse de Scott pour une alternative sécurisée.

Si vous n'avez pas besoin qu'il soit absolument unique au fil du temps:

md5(uniqid(rand(), true))

Sinon (étant donné que vous avez déjà déterminé une connexion unique pour votre utilisateur):

md5(uniqid($your_user_login, true))

90
Les deux méthodes ne garantissent pas l' unicité - la longueur de l'entrée de la fonction md5 est supérieure à la longueur de sa sortie et selon le principe en.wikipedia.org/wiki/Pigeonhole_principle, la collision est garantie. En revanche, plus la population compte sur les hachages pour obtenir l'identifiant "unique", plus la probabilité de se produire au moins une collision est grande (voir en.wikipedia.org/wiki/Birthday_problem ). La probabilité peut être minime pour la plupart des solutions, mais elle existe toujours.
Dariusz Walczak

12
Ce n'est pas une méthode sûre pour générer des valeurs aléatoires. Voir la réponse de Scott.
tour

4
Pour les confirmations par e-mail qui expirent assez rapidement, je pense que la minuscule possibilité qu'une personne puisse un jour confirmer l'e-mail de quelqu'un d'autre est un risque négligeable. Mais vous pouvez toujours vérifier si le jeton existe déjà dans la base de données après l'avoir créé et en choisir un nouveau si tel est le cas. Cependant, le temps que vous passez à écrire cet extrait de code est probablement perdu, car il ne sera probablement jamais exécuté.
Andrew

Notez que md5 renvoie des valeurs hexadécimales, ce qui signifie que le jeu de caractères est limité à [0-9] et [af].
Thijs Riezebeek

1
md5 peut avoir des collisions, vous venez de ruiner l'avantage
uniqid

507

Je cherchais juste à résoudre ce même problème, mais je veux aussi que ma fonction crée un jeton qui peut é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 uniqidest basé sur l'heure, et selon php.net "la valeur de retour est peu différente de microtime ()", uniqidne répond pas aux critères. PHP recommande d'utiliser à la openssl_random_pseudo_bytes()place pour générer des jetons sécurisés cryptographiquement.

Une réponse rapide, courte et précise est:

bin2hex(openssl_random_pseudo_bytes($bytes))

qui va générer une chaîne aléatoire de caractères alphanumériques de longueur = $ octets * 2. Malheureusement, cela n'a qu'un alphabet [a-f][0-9], mais cela fonctionne.


Ci-dessous se trouve la fonction la plus puissante que j'ai pu faire et qui réponde aux critères (Ceci est une version implémentée de la réponse d'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)fonctionne en remplacement de rand()ou mt_rand. Il utilise openssl_random_pseudo_bytes pour aider à créer un nombre aléatoire entre $ min et $ max.

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

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

EDIT (PHP7): Avec la sortie de PHP7, la bibliothèque standard dispose désormais de deux nouvelles fonctions qui peuvent remplacer / améliorer / simplifier la fonction crypto_rand_secure ci-dessus. random_bytes($length)etrandom_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);

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

    return $token;
}

2
D'accord. Le stockage des mots de passe en clair est horrible! (J'utilise Blowfish.) Mais une fois le jeton généré, il permet au détenteur du jeton de réinitialiser le mot de passe, de sorte que le jeton est équivalent au mot de passe alors qu'il est valide (et est traité comme tel).
Scott

23
Hé, j'ai combiné votre excellent code avec la fonctionnalité pratique de la méthode Kohana Text :: random () et j'ai
raveren

9
Parfait! Je l'ai testé avec 10 caractères comme longueur. 100000 jetons et toujours pas de doublons!
Sharpless512

5
J'ai utilisé ce processus et l'ai trouvé super lent. Avec une longueur de 36, il a expiré sur le serveur de développement. Avec une longueur de 24, cela prenait encore environ 30 secondes. Je ne sais pas ce que j'ai fait de mal mais c'était trop lent pour moi et j'ai opté pour une autre solution.
Shane

5
Vous pouvez également utiliser base64_encodeau lieu de bin2hexpour obtenir une chaîne plus courte avec un alphabet plus grand.
erjiang

91

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. Passez simplement une chaîne avec les caractères pris en charge au constructeur ou au setter:

<?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 cela aidera quelqu'un. À votre santé!


Je suis désolé, mais comment puis-je exécuter cette chose? Je l'ai fait, $obj = new RandomStringGenerator;mais quelle méthode dois-je appeler? Je vous remercie.
sg552

@ sg552, vous devez appeler la generateméthode comme dans l'exemple ci-dessus. Il suffit de lui passer un entier pour spécifier la longueur de la chaîne résultante.
Slava Fomin II

Merci ça marche pour moi mais Custom Alphabetpas. J'ai une sortie vide quand je fais écho. Quoi qu'il en soit, je ne sais même pas à quoi sert le 2ème exemple, Custom Alphabetdonc je pense que je reste avec le premier exemple. Merci.
sg552

1
Agréable, mais assez exagéré dans la plupart des scénarios, à moins que votre projet ne repose fortement sur des codes générés de manière aléatoire
dspacejs

1
oui sympa mais exagéré, d'autant plus qu'il est à peu près obsolète maintenant pour php 5.7
Andrew

39

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 une gouttelette Digital Ocean juste pour ce test automatisé de 5 jours et stocké les chaînes uniques générées dans une base de données MySQL.

Pendant 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 très fiables. Voici le tableau montrant mes données de recherche:

entrez la description de l'image ici

Mise à jour: j'ai créé une application Heroku simple en utilisant ces fonctions qui renvoie le jeton en tant que réponse JSON. L'application est accessible sur https://uniquestrings.herokuapp.com/api/token?length=15

J'espère que ça aide.


33

Vous pouvez utiliser l'UUID (Universally Unique Identifier), il peut être utilisé à toutes fins, de la chaîne d'authentification de l'utilisateur à l'ID de 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 tirets, sous la forme 8-4-4-4-12 pour un total de 36 caractères (32 caractères alphanumériques et quatre tirets).

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

}

// appeler funtion

$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 cela aidera quelqu'un à l'avenir :)


Semble fantastique, ajouté à ma liste!
Mustafa Erdogan du

32

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

6
Après un certain temps, vous obtenez les mêmes numéros
Sharpless512

1
Ce n'est pas entièrement aléatoire car il n'aura jamais le même chacater plus d'une fois.
EricP

16

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 divisible par 4 le plus proche)


6
Il ne renvoie pas toujours uniquement des caractères alphanumériques. Il peut contenir des caractères comme==
user3459110

1
S'il est utilisé dans une URL, base64url_encodepeut être utilisé à la place, voir ici: php.net/manual/en/function.base64-encode.php
Paul

9

Utilisez le code ci-dessous pour générer le nombre aléatoire de 11 caractères ou modifiez 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);

3
Cela ne peut jamais générer la chaîne "aaaaaaaaaaa" ou "aaaaabbbbbb". Il sélectionne simplement une sous-chaîne d'une permutation aléatoire de l'alphabet. La chaîne longue de 11 caractères n'a que V (11,35) = 288 valeurs possibles. Ne l'utilisez pas si vous vous attendez à ce que les cordes soient uniques!
kdojeteri

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

7
  1. Générez un nombre aléatoire en utilisant votre générateur de nombres aléatoires préféré
  2. Multipliez 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étez à partir 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

Théoriquement, cela ne pourrait-il pas potentiellement générer la même chaîne plus d'une fois?
frezq

4

Voici le générateur d'identification 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 faire écho à n'importe quel «var» pour votre identifiant comme vous le souhaitez. mais $ mdun est mieux, vous pouvez remplacer md5 en sha1 pour un meilleur code mais ce sera très long dont vous n'aurez peut-être pas besoin.

Je vous remercie.


7
Dans ce cas, le caractère aléatoire est garanti par un code écrit aléatoire, non?
Daniel Kucal

3
oui, c'est un peu "aléatoire" parce que c'est du code obscur non standard. Cela le rend difficile à prévoir ... mais en réalité, il n'utilise pas de pièces non sécurisées pour générer un nombre aléatoire. donc le résultat n'est techniquement pas aléatoire ou sécurisé.
Philipp

4

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

<?php

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

les sorties :

40a29479ec808ad4bcff288a48a25d5c

donc même si vous essayez de générer plusieurs fois la chaîne en même temps, vous obtiendrez une sortie différente.


4

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

  • Générez d'abord un ensemble d'octets aléatoires cryptographiquement sécurisé

  • La deuxième consiste à transformer ces octets aléatoires en une chaîne imprimable

Maintenant, il existe plusieurs façons de générer des octets aléatoires en php comme:

$length = 32;

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

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

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

Vous pouvez utiliser bin2hex :

$string = bin2hex($bytes);

ou base64_encode :

$string = base64_encode($bytes);

Cependant, notez que vous ne contrôlez pas la longueur de la chaîne si vous utilisez base64. Vous pouvez utiliser bin2hex pour ce faire, l'utilisation de 32 octets se transformera en une chaîne de 64 caractères . Mais cela ne fonctionnera ainsi que dans une chaîne MÊME .

Donc, fondamentalement, vous pouvez simplement faire :

$length = 32;

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

$string = bin2hex($bytes);

3

Voici ce que j'utilise:

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

Il s'agit d'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

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 mélange les éléments, après avoir obtenu un point de départ aléatoire pour que substr () soit plus «créatif» :) vous pouvez ajouter [az] et d'autres éléments au tableau, dupliquer plus ou moins, soyez plus créatif que moi


1

J'aime utiliser des clés de hachage lorsque je traite des liens de vérification. Je recommanderais d'utiliser le microtime et de hacher cela en utilisant MD5 car il ne devrait y avoir aucune raison pour que les clés soient les mêmes car il hache en fonction du microtime.

  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 fonction ci-dessus vous générera une chaîne aléatoire d'une longueur de 11 caractères.


1

Si vous souhaitez 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'identificateur unique basé sur l'horodatage sous forme de chaîne.

mt_rand() - Générez un nombre aléatoire.

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


0

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

Je dois également générer un jeton API unique pour chaque utilisateur. Voici mon approche, j'ai utilisé les informations utilisateur (Userid et Username):

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

Veuillez jeter un coup d'œil et faites-moi savoir si je peux apporter des améliorations Merci


0

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

$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 quiconque se demande peut-être comment ce jeton est généré;)

J'espère que ça aide :)


1
« S'il vous plaît noter que je multipliai l'horodatage par trois pour créer une confusion pour quiconque utilisateur peut se demander comment ce jeton est généré » Sons comme la sécurité par l' obscurcissement stackoverflow.com/questions/533965/...
Harry

Ce n'est pas une «sécurité par obscurcissement» car l'horodatage est ensuite ajouté à une chaîne aléatoire qui a été générée, et c'est la chaîne finale réelle que nous
renvoyons

0

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

str_shuffle(md5(rand(0,100000)))

0

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

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

<?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 vous assurer qu'il s'agit d'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 cherchez ...


0

Une solution simple consiste à convertir la base 64 en caractères alphanumériques en supprimant les caractères non alphanumériques.

Celui-ci utilise random_bytes () pour un résultat cryptographiquement sécurisé.

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

Je crois que le problème avec toutes les idées existantes est qu'elles sont probablement uniques, mais pas définitivement uniques (comme souligné dans la réponse de Dariusz Walczak à loletech). J'ai une solution qui est réellement unique. Cela nécessite que votre script ait une sorte de mémoire. Pour moi, c'est une base de données SQL. Vous pouvez également simplement écrire dans un fichier quelque part. Il existe deux implémentations:

Première méthode: avoir DEUX champs au lieu d'un qui fournissent l'unicité. Le premier champ est un numéro d'identification non aléatoire mais unique (le premier identifiant est 1, le second 2 ...). Si vous utilisez SQL, définissez simplement le champ ID avec la propriété AUTO_INCREMENT. Le deuxième champ n'est pas unique mais aléatoire. Cela peut être généré avec l'une des autres techniques que les gens ont déjà mentionnées. L'idée de Scott était bonne, mais md5 est pratique et probablement assez bonne pour la plupart des usages:

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

Deuxième méthode: Fondamentalement, la même idée, mais choisissez initialement un nombre maximum de chaînes qui seront jamais générées. Cela pourrait juste être un très grand nombre comme un billion. Faites ensuite la même chose, générez un ID, mais mettez-le à zéro afin que tous les ID aient le même nombre de chiffres. Ensuite, concaténez simplement l'ID avec la chaîne aléatoire. Il sera suffisamment aléatoire pour la plupart des utilisations, mais la section ID s'assurera qu'il est également unique.


-1

Vous pouvez utiliser ce code, j'espère qu'il vous sera utile.

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

Détails sur Générateur de code aléatoire en PHP


-2

Simplifier le code Scotts ci-dessus en supprimant les boucles inutiles, ce qui ralentit gravement et ne le rend pas plus sécurisé que d'appeler openssl_random_pseudo_bytes une seule fois

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

Malheureusement, je ne peux pas être d'accord avec vous qu'il s'agit d'une simplification appropriée de la fonction crypto_rand_secure. La boucle est nécessaire pour éviter le biais modulo qui se produit lorsque vous prenez le résultat d'un nombre généré de manière aléatoire, puis le modifiez par un nombre qui divise la plage. en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Modulo_bias . En utilisant une boucle pour rejeter tous les nombres en dehors de la plage et en sélectionnant un nouveau nombre, cela évite ce biais. stackoverflow.com/questions/10984974/…
Scott

@Scott, ce message concerne rand (). Cependant dans ce cas, il est déjà pris en charge par openssl_random_pseudo_bytes donc boucle en inutile.
mabel

1
gist.github.com/anonymous/87e3ae6fd3320447f46b973e75c2ea85 - Veuillez exécuter ce script. Vous verrez que la distribution des résultats n'est pas aléatoire. Les nombres entre 0 et 55 ont une occurrence plus élevée que les nombres entre 56 et 100. openssln'est pas la cause de cela, c'est à cause du biais modulo dans votre déclaration de retour. 100 (plage) ne divise pas 255 (1 octet) également et provoque ces résultats. Mon plus gros problème avec votre réponse est que vous déclarez que la fonction est aussi sécurisée que l'utilisation d'une boucle, ce qui est faux. Votre implémentation de crypto_rand_secure n'est pas sécurisée cryptographiquement et est trompeuse.
Scott

@Scott, nous nous éloignons ici, il ne s'agit pas de la dernière déclaration de retour, elle peut également être calculée progressivement à partir de la valeur de retour de openssl_random_pseudo_bytes sans utiliser modulo. Le point que je fais est que la boucle n'est pas nécessaire une fois que openssl_random_pseudo_bytes renvoie les octets aléatoires. En faisant une boucle, vous ne la rendez pas plus sûre, vous la ralentissez simplement.
mabel

2
Cette réponse propage de mauvaises informations. Vous avez raison de dire que la boucle ne rend pas opensslplus sécurisée, mais plus important encore, elle ne la rend pas moins sécurisée, cette réponse le fait. Le code ci-dessus prend un nombre aléatoire parfaitement bon et le modifie en le biaisant vers des nombres inférieurs. Si vous mettez un avertissement sur votre réponse indiquant qu'elle est plus rapide (en supprimant la boucle) mais qu'il ne s'agit pas d'un CSPRNG, cela résoudrait ce problème. S'il vous plaît, pour l'amour de la cryptographie, faites savoir aux utilisateurs que la sortie de cette fonction pourrait être biaisée et n'est pas une solution équivalente. La boucle n'est pas seulement là pour vous ennuyer.
Scott
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.