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.


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


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

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


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

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

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

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.


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"

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.


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


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

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

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

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.


Je vois ce temps perdu à développer cette fonction sans rien faire. J'ai peu googlé! @Andrew
LipESprY
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.