web-dev-qa-db-fra.com

Comment créer une chaîne aléatoire en utilisant PHP?

Je sais que la fonction Rand dans PHP génère des entiers aléatoires, mais quelle est la meilleure façon de générer une chaîne aléatoire telle que:

chaîne d'origine, 9 caractères

$string = 'abcdefghi';

Exemple de chaîne aléatoire se limitant à 6 caractères

$string = 'ibfeca';

MISE À JOUR: J'ai trouvé des tonnes de ces types de fonctions, essentiellement j'essaie de comprendre la logique derrière chaque étape.

MISE À JOUR: La fonction doit générer autant de caractères que nécessaire.

Veuillez commenter les pièces si vous répondez.

56
Keith Donegan

Eh bien, vous n'avez pas clarifié toutes les questions que j'ai posées dans mon commentaire, mais je suppose que vous voulez une fonction qui peut prendre une chaîne de caractères "possibles" et une longueur de chaîne à renvoyer. Commenté à fond comme demandé, en utilisant plus de variables que je ne le ferais normalement, pour plus de clarté:

function get_random_string($valid_chars, $length)
{
    // start with an empty random string
    $random_string = "";

    // count the number of chars in the valid chars string so we know how many choices we have
    $num_valid_chars = strlen($valid_chars);

    // repeat the steps until we've created a string of the right length
    for ($i = 0; $i < $length; $i++)
    {
        // pick a random number from 1 up to the number of valid chars
        $random_pick = mt_Rand(1, $num_valid_chars);

        // take the random character out of the string of valid chars
        // subtract 1 from $random_pick because strings are indexed starting at 0, and we started picking at 1
        $random_char = $valid_chars[$random_pick-1];

        // add the randomly-chosen char onto the end of our string so far
        $random_string .= $random_char;
    }

    // return our finished random string
    return $random_string;
}

Pour appeler cette fonction avec vos données d'exemple, vous l'appeleriez quelque chose comme:

$original_string = 'abcdefghi';
$random_string = get_random_string($original_string, 6);

Notez que cette fonction ne vérifie pas l'unicité dans les caractères valides qui lui sont transmis. Par exemple, si vous l'avez appelé avec une chaîne de caractères valide de 'AAAB', il serait trois fois plus probable de choisir un A pour chaque lettre comme B. Cela pourrait être considéré comme un bogue ou une fonctionnalité, selon vos besoins.

91
Chad Birch

Si vous souhaitez autoriser des occurrences répétitives de caractères, vous pouvez utiliser cette fonction:

function randString($length, $charset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
{
    $str = '';
    $count = strlen($charset);
    while ($length--) {
        $str .= $charset[mt_Rand(0, $count-1)];
    }
    return $str;
}

L'algorithme de base consiste à générer <longueur> fois un nombre aléatoire entre 0 et <nombre de caractères> - 1 que nous utilisons comme index pour choisir un caractère de notre ensemble et concaténer ces personnages. Les bornes 0 et <nombre de caractères> - 1 représentent les bornes de la chaîne $charset Car le premier caractère est adressé avec $charset[0] Et le dernier avec la fonction $charset[count($charset) - 1].

98
Gumbo

Mon préféré:

 echo substr(md5(Rand()), 0, 7);
52
tasmaniski

Alors, permettez-moi de commencer en disant UTILISER UNE BIBLIOTHÈQUE . Beaucoup existent:

Le cœur du problème est que presque toutes les réponses de cette page sont susceptibles d'être attaquées. mt_Rand(), Rand(), lcg_value() et uniqid() sont tous vulnérables aux attaques .

Un bon système utilisera /dev/urandom À partir du système de fichiers, ou mcrypt_create_iv() (avec MCRYPT_DEV_URANDOM) Ou openssl_pseudo_random_bytes(). Ce que tout ce qui précède fait. PHP 7 viendra avec deux nouvelles fonctionsrandom_bytes($len) et random_int($min, $max) qui sont également sûrs.

Sachez que la plupart de ces fonctions (à l'exception de random_int()) renvoient des "chaînes brutes", ce qui signifie qu'elles peuvent contenir n'importe quel caractère ASCII de 0 - 255. Si vous voulez un chaîne imprimable, je suggère d'exécuter le résultat via base64_encode().

24
ircmaxell
function generate_random_string($name_length = 8) {
    $alpha_numeric = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    return substr(str_shuffle(str_repeat($alpha_numeric, $name_length)), 0, $name_length);
}

Mise à jour du code selon la grande suggestion de mzhang dans les commentaires ci-dessous.

17
nameht

ne version meilleure et mise à jour de l'excellente réponse de @ taskamiski:

Meilleure version, en utilisant mt_Rand() au lieu de Rand():

echo md5(mt_Rand()); // 32 char string = 128bit

Encore mieux, pour des chaînes plus longues, en utilisant la fonction hash() qui permet de sélectionner des algorithmes de hachage:

echo hash('sha256', mt_Rand()); // 64 char string
echo hash('sha512', mt_Rand()); // 128 char string

Si vous voulez réduire le résultat à 50 disons, faites-le comme ceci:

echo substr(hash('sha256', mt_Rand()), 0, 50); // 50 char string
9
Sliq

La jonction de caractères à la fin devrait être plus efficace que la concaténation répétée de chaînes.

Edit # 1: Ajout d'une option pour éviter la répétition des caractères.

Edit # 2: lève une exception pour éviter d'entrer dans une boucle infinie si $ norepeat est sélectionné et $ len est supérieur au jeu de caractères à choisir.

Édition n ° 3: utilise des clés de tableau pour stocker les caractères aléatoires choisis lorsque $ norepeat est sélectionné, car la recherche de clé de tableau associative est plus rapide que la recherche linéaire du tableau.

function Rand_str($len, $norepeat = true)
{
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    $max = strlen($chars) - 1;

    if ($norepeat && len > $max + 1) {
        throw new Exception("Non repetitive random string can't be longer than charset");
    }

    $Rand_chars = array();

    while ($len) {
        $picked = $chars[mt_Rand(0, $max)];

        if ($norepeat) {
            if (!array_key_exists($picked, $Rand_chars)) {
                $Rand_chars[$picked] = true;
                $len--;
            }
        }
        else {
            $Rand_chars[] = $picked;
            $len--;
        }
    }

    return implode('', $norepeat ? array_keys($Rand_chars) : $Rand_chars);   
}
6
Imran

cela générera une chaîne aléatoire

function generateRandomString($length=10) {
    $original_string = array_merge(range(0,9), range('a','z'), range('A', 'Z'));
    $original_string = implode("", $original_string);
    return substr(str_shuffle($original_string), 0, $length);
}
echo generateRandomString(6);
4
Akhilraj N S

La plupart des aspects de cela ont déjà été discutés, mais je recommanderais une légère mise à jour: si vous l'utilisez pour un usage commercial, j'éviterais le domaine ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789

et utilisez plutôt: ABCDEFGHJKMNPQRSTUVWXY3456789

Certes, vous vous retrouvez avec beaucoup moins de caractères, mais cela évite beaucoup de tracas, car les clients ne peuvent pas confondre 0 pour O, ou 1 pour l ou 2 pour Z. En outre, vous pouvez faire un UPPER sur l'entrée et les clients peuvent ensuite entrez des lettres majuscules ou minuscules - ce qui est parfois déroutant car elles peuvent se ressembler.

2
CoderOfTheNight

Je pense que je vais ajouter ma contribution ici aussi.

function random_string($length) {
    $bytes_1 = openssl_random_pseudo_bytes($length);
    $hex_1 = bin2hex($bytes_1);
    $random_numbers = substr(sha1(Rand()), 0, $length);
    $bytes_2 = openssl_random_pseudo_bytes($length);
    $hex_2 = bin2hex($bytes_2);
    $combined_chars = $hex_1 . $random_numbers . $hex_2;
    $chars_crypted = hash('sha512', $combined_chars);

    return $chars_crypted;
}

Merci

2
zeeks

Pourquoi avez-vous besoin d'une chaîne aléatoire?

Est-ce que cela va être utilisé pour quelque chose d'analogue à distance à un mot de passe?

Si votre chaîne aléatoire nécessite des propriétés de sécurité any, vous devez utiliser la fonction random_int() de PHP 7 au lieu de toutes les réponses non sécurisées mt_Rand() dans ce fil.

/**
 * Generate a random string
 * 
 * @link https://paragonie.com/b/JvICXzh_jhLyt4y3
 *
 * @param int $length - How long should our random string be?
 * @param string $charset - A string of all possible characters to choose from
 * @return string
 */
function random_str($length = 32, $charset = 'abcdefghijklmnopqrstuvwxyz')
{
    // Type checks:
    if (!is_numeric($length)) {
        throw new InvalidArgumentException(
            'random_str - Argument 1 - expected an integer'
        );
    }
    if (!is_string($charset)) {
        throw new InvalidArgumentException(
            'random_str - Argument 2 - expected a string'
        );
    }

    if ($length < 1) {
        // Just return an empty string. Any value < 1 is meaningless.
        return '';
    }
    // This is the maximum index for all of the characters in the string $charset
    $charset_max = strlen($charset) - 1;
    if ($charset_max < 1) {
        // Avoid letting users do: random_str($int, 'a'); -> 'aaaaa...'
        throw new LogicException(
            'random_str - Argument 2 - expected a string at least 2 characters long'
        );
    }
    // Now that we have good data, this is the meat of our function:
    $random_str = '';
    for ($i = 0; $i < $length; ++$i) {
        $r = random_int(0, $charset_max);
        $random_str .= $charset[$r];
    }
    return $random_str;
}

Si vous n'êtes pas encore sur PHP 7 (ce qui est probablement le cas, car il n'a pas été publié à ce jour), alors vous voudrez paragonie/random_compat , qui est une implémentation utilisateur de random_bytes() et random_int() pour PHP 5 projets.

Pour les contextes de sécurité, toujours utilisez random_int(), pas Rand(), mt_Rand(), etc. Voir aussi réponse d'ircmaxell également.

2
Scott Arciszewski
// @author http://codeascraft.etsy.com/2012/07/19/better-random-numbers-in-php-using-devurandom/                                                
function devurandom_Rand($min = 0, $max = 0x7FFFFFFF)
{
    $diff = $max - $min;
    if ($diff < 0 || $diff > 0x7FFFFFFF) {
        throw new RuntimeException('Bad range');
    }
    $bytes = mcrypt_create_iv(4, MCRYPT_DEV_URANDOM);
    if ($bytes === false || strlen($bytes) != 4) {
        throw new RuntimeException('Unable to get 4 bytes');
    }
    $ary = unpack('Nint', $bytes);
    $val = $ary['int'] & 0x7FFFFFFF; // 32-bit safe                           
    $fp = (float) $val / 2147483647.0; // convert to [0,1]                          
    return round($fp * $diff) + $min;
}

function build_token($length = 60, $characters_map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
    $map_length = mb_strlen($characters_map)-1;
    $token = '';
    while ($length--) {
        $token .= mb_substr($characters_map, devurandom_Rand(0,$map_length),1);
    }
    return $token;
}

Cela ne fonctionnera que dans un environnement UNIX où PHP est compilé avec mcrypt.

1
Gajus

Voulez-vous créer votre mot de passe par une permutation aléatoire des lettres originales? Doit-il simplement contenir des caractères uniques?

Utilisez Rand pour choisir des lettres aléatoires par index.

0
Dario
echo substr(bin2hex(random_bytes(14)), 0, $length);

ce code obtient un octet aléatoire, qui est converti du binaire en hexadécimal, puis prend une sous-chaîne de cette chaîne hexadécimale, tant que vous mettez dans la variable $ length

0
Oscar Garcia

C'est une vieille question mais je veux essayer de poster ma solution ... J'utilise toujours ma fonction pour générer une chaîne alphanumérique aléatoire personnalisée ...

<?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;
  }
  $test = random_alphanumeric(50); // 50 characters
  echo $test;
?>

test: UFOruSSTCPIqxTRIIMTRkqjOGidcVlhYaS9gtwttxglheVugFM

si vous avez besoin de deux chaînes uniques ou plus, 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;

$ string_1: tMYicqLCHEvENwYbMUUVGTfkROxKIekEB2YXx5FHyVByp3mlJO

$ string_2: XdMNJYpMlFRKFDlF6GhVn6jsBVNQ1BCCevj8yK2niFOgpDI2MU

J'espère que cette aide.

0
Alessandro