2013-05-09 75 views
7

Sto generando un codice a 6 cifre dai seguenti caratteri. Questi saranno usati per stampare su adesivi.
Verranno generati in lotti di 10k o meno (prima della stampa) e non prevedo che ci saranno mai più di 1-2 milioni di totali (probabilmente molto meno).
Dopo aver generato i batch di codici, controllerò il database MySQL dei codici esistenti per garantire che non vi siano duplicati.Generazione di un codice univoco a 6 cifre

// exclude problem chars: B8G6I1l0OQDS5Z2 

$characters = 'ACEFHJKMNPRTUVWXY4937'; 

$string = ''; 

for ($i = 0; $i < 6; $i++) { 
    $string .= $characters[rand(0, strlen($characters) - 1)]; 
} 

return $string; 
  1. E 'questo un approccio solido per la generazione del codice?
  2. quante possibili permute ci sarebbero? (Codice a 6 cifre dal pool di 21 caratteri). matematica Siamo spiacenti, non è il mio punto di forza
+0

ci sono alcuni buoni post qui su vari approcci: http: // StackOverflow. it/questions/1846202/php-how-to-generate-a-random-unique-alfanumerico-string –

+0

Se non hai bisogno di più di 8 milioni di codici e codici brevi e non ambigui è una priorità alta direi che hai un buon modo per farlo – SEngstrom

risposta

11

21^6 = 85766121 possibilità.

L'utilizzo di un DB e la memorizzazione dei valori utilizzati non è corretto. Se si desidera simulare la casualità, è possibile utilizzare quanto segue:

Ridurre a 19 numeri possibili e utilizzare il fatto che i gruppi di ordine p^k dove p è un numero dispari sono sempre ciclici.

Prendere il gruppo di ordine 7^19, utilizzando un generatore co-prime a 7^19 (selezionerò 13^11, è possibile scegliere qualsiasi cosa non divisibile per 7).

Poi le seguenti opere:

$previous = 0; 

function generator($previous) 
{ 

    $generator = pow(13,11); 
    $modulus = pow(7,19); //int might be too small 
    $possibleChars = "ACEFHJKMNPRTUVWXY49"; 

    $previous = ($previous + $generator) % $modulus; 
    $output=''; 
    $temp = $previous; 

    for($i = 0; $i < 6; $i++) { 
    $output += $possibleChars[$temp % 19]; 
    $temp = $temp/19; 
    } 

    return $output; 
} 

, e che scorre attraverso tutti i possibili valori e guardare un po 'a caso a meno che non andare a scavare. Un'alternativa ancora più sicuro sarebbe gruppi moltiplicativi ma ho dimenticato la mia matematica già :(

+1

I codici generati devono essere memorizzati in quanto associati a timbri (prodotti) che avranno informazioni associate con essi. Se generi 10k di codici, poi un mese dopo un altro 10k, ho bisogno di verificare in qualche modo che non ci siano duplicati in questo nuovo lotto 10k. – Quad6

+0

Ho pubblicato come ignorare i duplicati, ma se stai memorizzando informazioni aggiuntive, comunque, trascura questa risposta. –

+2

@ Jean-BernardPellerin ha phpato il tuo codice, spero non ti dispiaccia, controlla se tutto è a posto –

7
  • Ci sono un sacco di combinazione possibile con o senza ripetizione così la logica sarebbe sufficiente
  • collisione sarebbe frequente perché si sta utilizzando rand vedi str_shuffle and randomness.
  • Change rand a mt_rand
  • utilizzare l'archiviazione veloce come memcached o no redis MySQL al momento del check

Possibilità totale

21^6 = 85,766,121 

85,766,121 dovrebbe essere ok, Per aggiungere database per questa generazione prova:

Esempio

$prifix = "stamp."; 

$cache = new Memcache(); 
$cache->addserver("127.0.0.1"); 

$stamp = myRand(6); 
while($cache->get($prifix . $stamp)) { 
    $stamp = myRand(6); 
} 
echo $stamp; 

funzione utilizzata

function myRand($no, $str = "", $chr = 'ACEFHJKMNPRTUVWXY4937') { 
    $length = strlen($chr); 
    while($no --) { 
     $str .= $chr{mt_rand(0, $length- 1)}; 
    } 
    return $str; 
} 
+0

Grazie. 86 mill sono sufficienti. Userò il tuo suggerimento di mt_rand. Non sono sicuro di come si possa usare memcached per verificare che i codici in un batch appena generato non siano già esistenti in MySQL (contenenti tutti i batch di codici generati in precedenza). Per motivi di stampa, immagino di generare 10k o più codici alla volta – Quad6

3

come Baba ha detto che genera una stringa al volo si tradurrà in tonnellate di collisioni. più vicino andrai a 80 milioni già generati più sarà difficile ottenere una stringa disponibile

un'altra soluzione potrebbe essere quella di generare tutte le combinazioni possibili una volta, e memorizzarle tutte nel database già, con qualche colonna booleana campo che segna se una riga/token viene già utilizzato o meno

poi a ottenere uno di loro

SELECT * FROM tokens WHERE tokenIsUsed = 0 ORDER BY RAND() LIMIT 0,1 

e poi segnare come già utilizzato

UPDATE tokens SET tokenIsUsed = 1 WHERE token = ... 
+0

Grazie, avrei pensato che ci sarebbe stato un notevole calo di prestazioni se avessi memorizzato le combinazioni da 80 mill, in termini di query, ecc. Il codice verrà cercato non solo memorizzato come un registro. – Quad6

+2

Penso che potresti combinare questo approccio con la generazione ciclica di @ Jean-Bernard e rendere la tua query molto veloce - riempire il database con tutte le combinazioni in un ordine un po 'casuale, e ogni volta che hai bisogno di nuovi valori puoi afferrarli un tempo. Potrebbe valere la pena, comunque. – Jerry

0

Ho avuto lo stesso problema, e ho trovato molto impressionante soluzione open source:

http://www.hashids.org/php/

Si può prendere e usarlo, anche ne vale la pena di guardare nel suo codice sorgente per capire cosa sta succedendo sotto il cofano .

-1

Oppure ... è possibile codificare nome utente + datetime in MD5 e salvare nel database, questo di sicuro genererà un codice univoco;)

Problemi correlati