Générer une chaîne aléatoire de 5 caractères

102

Je veux créer une chaîne exacte de 5 caractères aléatoires avec le moins de possibilité de duplication. Quelle serait la meilleure façon de procéder? Merci.

Peter
la source
2
avez-vous un ensemble de caractères spécifiques ou seulement 0-9a-zA-Z?
Yanick Rochon
Ce défi de golf de code pourrait être une trouvaille: codegolf.stackexchange.com/questions/119226/…
Titus
En utilisant, Random::alphanumericString($length)vous pouvez obtenir des chaînes avec 0-9a-zA-Z qui proviennent de données aléatoires sécurisées par cryptographie.
caw

Réponses:

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

Ce serait ma meilleure supposition - À moins que vous ne recherchiez également des caractères spéciaux:

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

Exemple

Et, pour celui basé sur l'horloge (moins de collisions puisque c'est incrémental):

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

Remarque: incrémentiel signifie plus facile à deviner; Si vous l'utilisez comme un sel ou un jeton de vérification, ne le faites pas. Un sel (maintenant) de "WCWyb" signifie que dans 5 secondes c'est "WCWyg")

Brad Christie
la source
6
Le problème avec l'utilisation md5()est cependant que vous obtenez une chaîne composée d'un jeu de 16 caractères (10 chiffres et aà f, c'est- à -dire 4 bits par caractère de chaîne). Cela peut être suffisant à certaines fins, mais peut être insuffisant à des fins cryptographiques (cinq caractères sur 16 symboles = 16 ^ 5 = 20 bits = 1048576 possibilités).
Arc
3
array_rand($seed, 5)renverra une clé de tableau, pas une valeur, donc votre code ne fonctionnera pas
alumi
1
Je pense que l'utilisation d'une fonction de hachage cryptographique pour générer des caractères aléatoires est au moins inappropriée.
gronostaj
Est - il possible aussi d'inclure ", 'et anti - slash $charset? Dois-je utiliser des séquences d'échappement pour inclure ces caractères?
Mai
1
Le deuxième extrait n'utilise même pas le $lenparamètre d'entrée ... l'avez-vous oublié?
TechNyquist
76

Si les forboucles sont rares, voici ce que j'aime utiliser:

$s = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", 5)), 0, 5);
Matthieu
la source
Solution intéressante ... très concise, même si je me demande si c'est plus rapide ou plus lent que d'utiliser pour. Ne peut pas être dérangé par le benchmark cependant :-)
Arc
@matthew str_shuffle produira des doublons en continu
SCC
@ user2826057: str_shuffle('ab')donnerait abou bamais jamais aa. L'ajout du str_repeatpermet pour cela. Mais cela dit, la solution que j'ai donnée n'est pas vraiment sérieuse ... même si elle fonctionne.
Matthew
2
Il y a une chance 1/60466176 que cela se produise, en supposant que le RNG est uniformément distribué.
Matthieu
1
Ceci est parfait pour notre cas d'utilisation de génération de codes promotionnels. Nous avons retiré les caractères confus, comme l, i, 1, 0, O, etc et de 500 bons a obtenu pas de doublons.
Luke Cousins
25

Un moyen rapide consiste à utiliser les caractères les plus volatils de la fonction uniqid .

Par exemple:

$rand = substr(uniqid('', true), -5);
John Parker
la source
22

Vous pouvez l'essayer simplement comme ceci:

$length = 5;

$randomletter = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz"), 0, $length);

plus de détails: http://forum.arnlweb.com/viewtopic.php?f=7&t=25

Apurba Pathak
la source
15

Ce qui suit devrait fournir le moins de chances de duplication (vous voudrez peut-être remplacer mt_rand()par une meilleure source de nombres aléatoires, par exemple à partir /dev/*randomou à partir de GUID):

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

EDIT:
Si vous êtes préoccupé par la sécurité, vraiment, ne pas utiliser rand()ou mt_rand(), et vérifiez que votre appareil de données aléatoires est en fait un dispositif de génération aléatoire de données, pas un fichier régulier ou quelque chose comme prévisible /dev/zero. mt_rand()considéré comme dangereux:
https://spideroak.com/blog/20121205114003-exploit-information-leaks-in-random-numbers-from-python-ruby-and-php

EDIT: Si vous avez le support OpenSSL en PHP, vous pouvez utiliser 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];
?>
Arc
la source
Premier exemple plus intelligent avec $ result. = $ Characters [mt_rand (0, strlen ($ characters) -1)]
hamboy75
Dans ce cas, vous devez déterminer la longueur au préalable et la stocker au moins dans une variable. L'utilisation strlen()en boucle est inutile, surtout si vous savez déjà que le jeu de caractères ne changera pas entre-temps.
Arc
J'en doute, php est optimisé, de toute façon c'est une option :)
hamboy75
7

J'utilise toujours la même fonction pour cela, généralement pour générer des mots de passe. C'est facile à utiliser et utile.

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
la source
Beau code. Cependant, $ alt passe toujours de un à 0. Ne serait-il pas préférable de randomiser $ alt à la place?
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
la source
2

Si c'est bien que vous n'obteniez que des lettres AF, alors voici ma solution:

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

Je pense que l'utilisation des fonctions de hachage est excessive pour une tâche aussi simple que la génération d'une séquence de chiffres hexadécimaux aléatoires. dechex+ mt_randfera le même travail, mais sans travail cryptographique inutile.str_padgarantit la longueur de 5 caractères de la chaîne de sortie (si le nombre aléatoire est inférieur à 0x10000).

La probabilité de duplication dépend de mt_randla fiabilité de. Mersenne Twister est connu pour son caractère aléatoire de haute qualité, il devrait donc bien s'adapter à la tâche.

Gronostaj
la source
2

Je ne savais pas non plus comment faire cela avant de penser à utiliser PHP array. Et je suis presque sûr que c'est le moyen le plus simple de générer une chaîne ou un nombre aléatoire avec des tableaux. Le code:

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

Vous pouvez utiliser cette fonction comme ceci

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

la source
1

Similaire à la réponse de Brad Christie , mais utilisant l' sha1alrorithme pour les caractères 0-9a-zA-Zet précédé d'une valeur aléatoire:

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

Mais si vous avez défini des caractères définis (autorisés):

$validChars = array('0','1','2' /*...*/,'?','-','_','a','b','c' /*...*/);
$validCharsCount = count($validChars);

$str = '';
for ($i=0; $i<5; $i++) {
    $str .= $validChars[rand(0,$validCharsCount - 1)];
}

** MISE À JOUR **

Comme l'a souligné Archimedix , cela ne garantira pas de renvoyer une "moindre possibilité de duplication" car le nombre de combinaisons est faible pour la plage de caractères donnée. Vous devrez soit augmenter le nombre de caractères, soit autoriser des caractères supplémentaires (spéciaux) dans la chaîne. La première solution serait préférable, je pense, dans votre cas.

Yanick Rochon
la source
L'utilisation time()est jusqu'à 1 million de fois plus prévisible que microtime().
Arc
Notez également mes commentaires sur la réponse de Brad, le plus gros problème est que le hachage généré est une représentation hexadécimale composée de 16 caractères valides, ne laissant donc que 1024 variations pour $str.
Arc
@Archimedix, peut-être, mais l'OP n'a pas demandé de sécurité, la question a été définie pour avoir un algorithme de génération de chaîne consistant en une combinaison de 5x26 caractères différents et en évitant les doublons. Il s'agit probablement d'un numéro de référence de confirmation dans un processus d'inscription (ou de facturation), ou quelque chose comme ça
Yanick Rochon
Je crois comprendre qu'il a demandé la moindre possibilité de duplication , et cela a une probabilité de 0,1% (1 sur 1024) qui aurait pu être de près de 1 sur 1 milliard.
Arc
cependant, si vous avez besoin de générer une clé de référence de 5 caractères et de lui donner un client / client, vous ne voulez pas leur donner " ˫§»⁋⅓" simplement parce que c'est plus sécurisé ... vous augmentez votre clé de référence à 7 caractères ou plus . (BTW: correction dans mon commentaire précédent, c'est 5x36 caractères)
Yanick Rochon
1

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

Démo en direct

Lyoniel Farase
la source
1

Source: Fonction PHP qui génère des caractères aléatoires

Cette fonction PHP simple a fonctionné pour moi:

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;

}

Usage:

echo cvf_ps_generate_random_code(5);
Carl
la source
1

Voici mes 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 nouvelle fonction de PHP password_hash()(*> = PHP 5.5) fait le travail pour la génération d'un ensemble décemment long de caractères et de nombres majuscules et minuscules.

Deux concat. les chaînes avant et après password_hashdans la fonction $ random peuvent être modifiées.

Les paramètres pour $random()* ($ a, $ b) sont en fait des substr()paramètres. :)

REMARQUE: cela n'a pas besoin d'être une fonction, cela peut aussi être une variable normale ... comme un méchant singleliner, comme ceci:

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

echo($random);
Effrayant
la source
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;
}
John F
la source
Conseil de pro - Incluez des explications sur la façon dont votre réponse résout le problème du PO et pourquoi elle pourrait être différente des autres réponses déjà fournies.
Tom
0

J'utilise toujours ceci:

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

Lorsque vous l'appelez, définit la longueur de la chaîne.

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

Vous pouvez également modifier les caractères possibles dans la chaîne $a.

LipESprY
la source
Je vois ce temps perdu à développer cette fonction sans rien faire. J'ai peu googlé! @Andrew
LipESprY