Generieren Sie eine zufällige Zeichenfolge mit 5 Zeichen

101

Ich möchte genau 5 zufällige Zeichenfolgen mit der geringsten Wahrscheinlichkeit erstellen, dass sie dupliziert werden. Was wäre der beste Weg, dies zu tun? Vielen Dank.

Peter
quelle
2
Hast du einen bestimmten Charakter oder nur einen Satz 0-9a-zA-Z?
Yanick Rochon
Diese Code Golf Herausforderung könnte ein Fund sein: codegolf.stackexchange.com/questions/119226/…
Titus
Mit Random::alphanumericString($length)können Sie Zeichenfolgen mit 0-9a-zA-Z abrufen, die aus kryptografisch sicheren Zufallsdaten stammen.
Caw

Antworten:

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

Wäre meine beste Vermutung - es sei denn, Sie suchen auch nach Sonderzeichen:

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

Beispiel

Und zum einen basierend auf der Uhr (weniger Kollisionen, da sie inkrementell sind):

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

Hinweis: Inkrementell bedeutet leichter zu erraten. Wenn Sie dies als Salz- oder Verifizierungs-Token verwenden, tun Sie dies nicht. Ein Salz (jetzt) ​​von "WCWyb" bedeutet in 5 Sekunden "WCWyg")

Brad Christie
quelle
6
Das Problem bei der Verwendung ist md5()jedoch, dass Sie eine Zeichenfolge aus einem 16-Zeichen-Satz erhalten (10 Ziffern und abis f, dh 4 Bits pro Zeichenfolge). Dies kann für einige Zwecke ausreichend sein, für kryptografische Zwecke jedoch zu wenig (fünf Zeichen von 16 Symbolen = 16 ^ 5 = 20 Bit = 1048576 Möglichkeiten).
Arc
3
array_rand($seed, 5)wird Array-Schlüssel zurückgeben, nicht Wert, so dass Ihr Code nicht funktioniert
Alumi
1
Ich denke, dass die Verwendung einer kryptografischen Hash-Funktion zum Generieren von zufälligen Zeichen zumindest unangemessen ist.
Gronostaj
Ist es auch möglich ", einen 'Backslash einzubeziehen $charset? Muss ich Escape-Sequenzen verwenden, um diese Zeichen einzuschließen?
Mai
1
Das zweite Snippet verwendet nicht einmal den $lenEingabeparameter ... haben Sie es vergessen?
TechNyquist
76

Wenn forSchleifen knapp sind, verwende ich Folgendes:

$s = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", 5)), 0, 5);
Matthew
quelle
Interessante Lösung ... sehr prägnant, obwohl ich mich frage, ob dies schneller oder langsamer ist als für. Kann nicht die Mühe machen, Benchmarking :-)
Arc
@matthew str_shuffle wird kontinuierlich Duplikate produzieren
SCC
@ user2826057: str_shuffle('ab')würde geben aboder baaber nie aa. Das Hinzufügen der str_repeaterlaubt das. Aber das heißt, die Lösung, die ich gegeben habe, ist nicht wirklich ernst ... obwohl sie funktioniert.
Matthew
2
Es besteht eine Wahrscheinlichkeit von 1/60466176, dass dies geschieht, vorausgesetzt, das RNG ist gleichmäßig verteilt.
Matthew
1
Dies ist perfekt für unseren Anwendungsfall der Generierung von Gutscheincodes. Wir entfernten verwirrend Zeichen, wie l, i, 1, 0, O, etc. und aus 500 Gutscheinen bekommen keine Duplikate.
Luke Cousins
25

Ein schneller Weg besteht darin, die flüchtigsten Zeichen der Uniqid- Funktion zu verwenden.

Beispielsweise:

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

Sie können es einfach so versuchen:

$length = 5;

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

Weitere Details: http://forum.arnlweb.com/viewtopic.php?f=7&t=25

Apurba Pathak
quelle
15

Folgendes sollte die geringste Wahrscheinlichkeit einer Duplizierung bieten (möglicherweise möchten Sie es durch mt_rand()eine bessere Zufallszahlenquelle ersetzen, z. B. von /dev/*randomoder aus GUIDs):

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

EDIT:
Wenn Sie über die Sicherheit betrifft, wirklich, sie nicht verwenden , rand()oder mt_rand(), und stellen Sie sicher , dass Ihre Zufallsdaten Gerät ist eigentlich ein Gerät zu erzeugen zufällige Daten, keine reguläre Datei oder etwas vorhersehbar wie /dev/zero. mt_rand()als schädlich angesehen:
https://spideroak.com/blog/20121205114003-exploit-information-leaks-in-random-numbers-from-python-ruby-and-php

BEARBEITEN: Wenn Sie OpenSSL-Unterstützung in PHP haben, können Sie Folgendes verwenden 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];
?>
Bogen
quelle
Erstes Beispiel klüger mit $ result. = $ Zeichen [mt_rand (0, strlen ($ Zeichen) -1)]
hamboy75
In diesem Fall sollten Sie die Länge vorher bestimmen und mindestens in einer Variablen speichern. Die Verwendung strlen()in einer Schleife ist unnötig, insbesondere wenn Sie bereits wissen, dass sich der Zeichensatz in der Zwischenzeit nicht ändern wird.
Arc
Ich bezweifle es, PHP ist optimiert, es ist sowieso eine Option :)
Hamboy75
7

Ich benutze dafür immer die gleiche Funktion, normalerweise um Passwörter zu generieren. Es ist einfach zu bedienen und nützlich.

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
quelle
Schöner Code. $ Alt wechselt jedoch immer von eins auf 0. Wäre es nicht besser, stattdessen $ alt zu randomisieren?
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
quelle
2

Wenn es in Ordnung ist, dass Sie nur Buchstaben AF erhalten, dann ist hier meine Lösung:

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

Ich glaube, dass die Verwendung von Hash-Funktionen ein Overkill für eine so einfache Aufgabe ist, wie das Erzeugen einer Folge von zufälligen hexadezimalen Ziffern. dechex+ mt_randerledigt den gleichen Job, jedoch ohne unnötige kryptografische Arbeit. str_padgarantiert eine Länge von 5 Zeichen der Ausgabezeichenfolge (wenn die Zufallszahl kleiner als 0x10000 ist).

Die doppelte Wahrscheinlichkeit hängt von mt_randder Zuverlässigkeit ab. Mersenne Twister ist bekannt für hochwertige Zufälligkeit, daher sollte es gut zur Aufgabe passen.

gronostaj
quelle
2

Ich wusste auch nicht, wie ich das machen sollte, bis ich daran dachte, PHPs arrayzu verwenden. Und ich bin mir ziemlich sicher, dass dies der einfachste Weg ist, eine zufällige Zeichenfolge oder Zahl mit Arrays zu generieren. Der 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;
};

Sie können diese Funktion so verwenden

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

quelle
1

Ähnlich wie Brad Christies Antwort, jedoch mit sha1Alrorithmus für Zeichen 0-9a-zA-Zund mit einem zufälligen Wert vorangestellt:

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

Wenn Sie jedoch definierte (zulässige) Zeichen festgelegt haben:

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

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

** UPDATE **

Wie Archimedix hervorhob, garantiert dies nicht die Rückgabe einer "geringsten Möglichkeit der Duplizierung", da die Anzahl der Kombinationen für den angegebenen Zeichenbereich gering ist. Sie müssen entweder die Anzahl der Zeichen erhöhen oder zusätzliche (Sonder-) Zeichen in der Zeichenfolge zulassen. Die erste Lösung wäre in Ihrem Fall meiner Meinung nach vorzuziehen.

Yanick Rochon
quelle
Die Verwendung time()ist bis zu 1 Million Mal vorhersehbarer als microtime().
Arc
Beachten Sie auch meine Kommentare zu Brads Antwort. Das größere Problem ist, dass der generierte Hash eine hexadezimale Darstellung ist, die aus 16 gültigen Zeichen besteht, sodass nur 1024 Variationen für übrig bleiben $str.
Arc
@Archimedix vielleicht, aber das OP hat nicht nach Sicherheit gefragt. Die Frage wurde so definiert, dass sie einen Algorithmus zur Zeichenfolgengenerierung enthält, der aus einer Kombination von 5 x 26 verschiedenen Zeichen besteht und Duplikate vermeidet. Dies ist wahrscheinlich für eine Bestätigungsreferenznummer in einem Registrierungsprozess (oder Abrechnungsprozess) oder so etwas
Yanick Rochon
Es war mein Verständnis , dass er tat fragen dest Möglichkeit, sich vervielfältigt , und dies hat 0,1% Wahrscheinlichkeit (1 in 1024) , die fast 1 waren in 1 Milliarde könnte.
Arc
Wenn Sie jedoch einen Referenzschlüssel mit 5 Zeichen generieren und diesem einen Kunden / Kunden geben müssen, möchten Sie ihn nicht " ˫§»⁋⅓" geben, nur weil er sicherer ist ... Sie erhöhen Ihren Referenzschlüssel auf 7 oder mehr Zeichen . (Übrigens: Korrektur in meinem vorherigen Kommentar, es ist 5x36 Zeichen)
Yanick Rochon
1

funktioniert gut in 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;

Live-Demo

Lyoniel Farase
quelle
1

Quelle: PHP-Funktion, die zufällige Zeichen generiert

Diese einfache PHP-Funktion hat bei mir funktioniert:

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;

}

Verwendung:

echo cvf_ps_generate_random_code(5);
Carl
quelle
1

Hier sind meine 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));

Die neue password_hash()Funktion von PHP (*> = PHP 5.5) erledigt die Aufgabe, einen anständig langen Satz von Groß- und Kleinbuchstaben und -zahlen zu generieren.

Zwei concat. Zeichenfolgen vor und nach der password_hash$ random-Funktion können geändert werden.

Parameter für $random()* ($ a, $ b) sind tatsächlich substr()Parameter. :) :)

HINWEIS: Dies muss keine Funktion sein, es kann auch eine normale Variable sein. Als ein böser Singleliner, wie folgt:

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

echo($random);
Gruslig
quelle
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.
quelle
Pro-Tipp - Geben Sie eine Erklärung an, wie Ihre Antwort das Problem des OP löst und warum sie sich möglicherweise von den anderen bereits bereitgestellten Antworten unterscheidet.
Tom
0

Ich benutze immer das:

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

Wenn Sie es aufrufen, legen Sie die Länge der Zeichenfolge fest.

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

Sie können auch die möglichen Zeichen in der Zeichenfolge ändern $a.

LipESprY
quelle
Ich sehe, dass verlorene Zeit untätig diese Funktion entwickelt. Ich habe wenig gegoogelt! @ Andrew
LipESprY