Genera una stringa di 5 caratteri casuale


102

Voglio creare una stringa di 5 caratteri casuali esatti con la minima possibilità di essere duplicata. Quale sarebbe il modo migliore per farlo? Grazie.


2
hai un set di caratteri specifici o solo 0-9a-zA-Z?
Yanick Rochon

Questa sfida di golf in codice potrebbe essere una scoperta: codegolf.stackexchange.com/questions/119226/…
Titus

Usando Random::alphanumericString($length)puoi ottenere stringhe con 0-9a-zA-Z che provengono da dati casuali crittograficamente sicuri.
caw

Risposte:


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

Sarebbe la mia ipotesi migliore, a meno che tu non stia cercando anche caratteri speciali:

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

Esempio

E, per uno basato sull'orologio (meno collisioni poiché è incrementale):

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

Nota: incrementale significa più facile da indovinare; Se lo stai usando come sale o come token di verifica, non farlo. Un sale (ora) di "WCWyb" significa che tra 5 secondi è "WCWyg")


6
Il problema con l'utilizzo, md5()tuttavia, è che si ottiene una stringa composta da un set di 16 caratteri (10 cifre e ato f, cioè 4 bit per carattere stringa). Questo può essere sufficiente per alcuni scopi, ma potrebbe essere troppo piccolo per scopi crittografici (cinque caratteri su 16 simboli = 16 ^ 5 = 20 bit = 1048576 possibilità).
Arco

3
array_rand($seed, 5)restituirà la chiave della matrice, non il valore, quindi il codice non funzionerà
alumi

1
Penso che l'utilizzo di una funzione hash crittografica per generare caratteri casuali sia almeno inappropriato.
gronostaj

E 'possibile anche includere ", 'e backslash $charset? Devo usare sequenze di escape per includere quei caratteri?
maggio

1
Il secondo frammento non usa nemmeno il $lenparametro di input ... l'hai dimenticato?
TechNyquist

76

Se i forloop scarseggiano, ecco cosa mi piace usare:

$s = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", 5)), 0, 5);

Soluzione interessante ... molto concisa, anche se mi chiedo se sia più veloce o più lento dell'uso per. Non posso essere disturbato dal benchmark però :-)
Arc

@matthew str_shuffle produrrà continuamente duplicati
SCC

@ user2826057: str_shuffle('ab')darebbe abo bama mai aa. Aggiungendo i str_repeatpermessi per quello. Ma detto questo, la soluzione che ho dato non è davvero seria ... anche se funziona.
Matteo

2
C'è una probabilità 1/60466176 che ciò accada, assumendo che l'RNG sia distribuito uniformemente.
Matteo

1
Questo è perfetto per il nostro caso d'uso di generazione di codici voucher. Abbiamo rimosso confondendo caratteri, come l, i, 1, 0, O, ecc e di 500 voucher ottenuto duplicati.
Luke Cousins

25

Un modo rapido è utilizzare i caratteri più volatili della funzione uniqid .

Per esempio:

$rand = substr(uniqid('', true), -5);


15

Quanto segue dovrebbe fornire la minima possibilità di duplicazione (potresti voler sostituire mt_rand()con una migliore fonte di numeri casuali, ad esempio da /dev/*randomo da GUID):

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

MODIFICA:
Se sei preoccupato per la sicurezza, davvero, non usare rand()o mt_rand()e verifica che il tuo dispositivo di dati casuali sia effettivamente un dispositivo che genera dati casuali , non un file normale o qualcosa di prevedibile come /dev/zero. mt_rand()considerato dannoso:
https://spideroak.com/blog/20121205114003-exploit-information-leaks-in-random-numbers-from-python-ruby-and-php

EDIT: se hai il supporto OpenSSL in PHP, puoi usare 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];
?>

Primo esempio più intelligente con $ risultato. = $ Caratteri [mt_rand (0, strlen ($ caratteri) -1)]
hamboy75

In tal caso dovresti determinare in anticipo la lunghezza e memorizzarla almeno in una variabile. L'uso strlen()in un ciclo non è necessario sovraccarico, soprattutto se sai già che il set di caratteri non cambierà nel frattempo.
Arco

Ne dubito, php è ottimizzato, comunque è un'opzione :)
hamboy75

7

Uso sempre la stessa funzione per questo, di solito per generare password. È facile da usare e 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;
}

Bel codice. Tuttavia $ alt cambia sempre da uno a 0. Non sarebbe meglio invece randomizzare $ alt?
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

Se va bene che riceverai solo lettere AF, allora ecco la mia soluzione:

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

Credo che l'utilizzo di funzioni hash sia eccessivo per un'attività così semplice come la generazione di una sequenza di cifre esadecimali casuali. dechex+ mt_randfarà lo stesso lavoro, ma senza lavoro crittografico non necessario. str_padgarantisce la lunghezza di 5 caratteri della stringa di output (se il numero casuale è inferiore a 0x10000).

La probabilità duplicata dipende mt_randdall'affidabilità di. Mersenne Twister è noto per la casualità di alta qualità, quindi dovrebbe adattarsi bene al compito.


2

Inoltre non sapevo come farlo finché non ho pensato di utilizzare PHP array. E sono abbastanza sicuro che questo sia il modo più semplice per generare una stringa o un numero casuale con array. Il codice:

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

Puoi usare questa funzione in questo modo

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

Simile alla risposta di Brad Christie , ma utilizzando l' sha1alroritmo per i caratteri 0-9a-zA-Ze preceduto da un valore casuale:

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

Ma se hai impostato un carattere definito (consentito):

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

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

** AGGIORNAMENTO **

Come sottolineato da Archimedix , ciò non garantirà di restituire una "minima possibilità di essere duplicato" poiché il numero di combinazioni è basso per il dato intervallo di caratteri. Dovrai aumentare il numero di caratteri o consentire caratteri extra (speciali) nella stringa. La prima soluzione sarebbe preferibile, credo, nel tuo caso.


L'utilizzo time()è fino a 1 milione di volte più prevedibile di microtime().
Arco

Notare anche i miei commenti alla risposta di Brad, il problema più grande è che l'hash generato è una rappresentazione esadecimale composta da 16 caratteri validi, quindi lasciando solo 1024 varianti per $str.
Arco

@Archimedix, forse, ma l'OP non ha chiesto sicurezza, la domanda è stata definita per avere un algoritmo di generazione di stringhe costituito da una combinazione di 5x26 caratteri diversi ed evitare duplicati. Questo è probabilmente per un numero di riferimento di conferma in un processo di registrazione (o processo di fatturazione), o qualcosa del genere
Yanick Rochon

E 'stata la mia comprensione che egli ha fatto chiedere almeno la possibilità di ottenere duplicati , e questo ha lo 0,1% di probabilità (1 nel 1024), che avrebbe potuto essere quasi 1 a 1 miliardo.
Arco

tuttavia, se devi generare una chiave di riferimento di 5 caratteri e darti un cliente / cliente, non vuoi fornire " ˫§»⁋⅓" semplicemente perché è più sicuro ... aumenti la tua chiave di riferimento a 7 o più caratteri . (BTW: correzione nel mio commento precedente, sono 5x36 caratteri)
Yanick Rochon

1

funziona bene 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;

Dimostrazione dal vivo


1

Fonte: funzione PHP che genera caratteri casuali

Questa semplice funzione PHP ha funzionato per me:

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;

}

Utilizzo:

echo cvf_ps_generate_random_code(5);

1

Ecco i miei 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 nuova funzione di PHP password_hash()(*> = PHP 5.5) sta facendo il lavoro per la generazione di una serie di numeri e caratteri maiuscoli e minuscoli abbastanza lunghi.

Due concat. le stringhe prima e dopo password_hashall'interno della funzione $ random sono adatte per il cambiamento.

I parametri per $random()* ($ a, $ b) sono in realtà substr()parametri. :)

NOTA: questa non deve essere una funzione, può essere anche una normale variabile .. come un brutto singleliner, come questo:

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

Suggerimento professionale: includi alcune spiegazioni su come la tua risposta risolve il problema dell'OP e perché potrebbe essere diversa dalle altre risposte già fornite.
Tom

0

Uso questo:

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

Quando lo chiami, imposta la lunghezza della stringa.

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

È inoltre possibile modificare i possibili caratteri nella stringa $a.


Vedo che il tempo perso nello sviluppare pigramente questa funzione. Ho cercato su Google poco! @Andrew
LipESprY
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.