Domanda

Sto cercando un modo, in particolare in PHP, che mi garantisca di ottenere sempre una chiave univoca.

Ho fatto quanto segue:

strtolower(substr(crypt(time()), 0, 7));

Ma ho scoperto che di tanto in tanto mi ritrovo con una chiave duplicata (raramente, ma abbastanza spesso).

Ho pensato anche di fare:

strtolower(substr(crypt(uniqid(rand(), true)), 0, 7));

Ma secondo il sito web di PHP, uniqid() potrebbe, se uniqid() viene chiamato due volte nello stesso microsecondo, generare la stessa chiave.Penso che l'aggiunta di rand() sarebbe rara, ma comunque possibile.

Dopo le righe sopra menzionate rimuovo anche i caratteri come L e O in modo da creare meno confusione per l'utente.Questo forse è parte della causa dei duplicati, ma è comunque necessario.

Un'opzione a cui ho pensato è creare un sito Web che genererà la chiave, archiviandola in un database, garantendo che sia completamente unica.

Altri pensieri?Ci sono siti web là fuori che già lo fanno che hanno qualche tipo di API o semplicemente restituiscono la chiave.ho trovato http://userident.com ma non sono sicuro che le chiavi saranno completamente uniche.

Questo deve essere eseguito in background senza alcun input da parte dell'utente.

È stato utile?

Soluzione

Esistono solo 3 modi per generare valori univoci, piuttosto che siano password, ID utente, ecc.:

  1. Utilizza un generatore GUID efficace: sono lunghi e non possono essere ridotti.Se usi solo part hai fallito.
  2. Almeno parte del numero viene generata sequenzialmente da una singola sequenza.Puoi aggiungere confusione o codifica per renderlo meno sequenziale.Il vantaggio è che iniziano in breve tempo, lo svantaggio è che richiedono un'unica fonte.La soluzione per la limitazione della singola fonte è avere fonti numerate, quindi includi [sorgente #] + [seq #] e quindi ciascuna fonte può generare la propria sequenza.
  3. Generarli tramite altri mezzi e quindi confrontarli con la singola cronologia dei valori generati in precedenza.

Qualsiasi altro metodo non è garantito.Tieni presente che fondamentalmente stai generando un numero binario (è un computer), ma puoi codificarlo in esadecimale, decimale, Base64 o in un elenco di parole.Scegli una codifica adatta al tuo utilizzo.Di solito per i dati inseriti dall'utente si desidera una variazione di Base32 (a cui hai accennato).

Nota sui GUID:La loro forza di unicità deriva dalla loro lunghezza e dal metodo utilizzato per generarli. Qualunque cosa inferiore a 128 bit non è sicura. Oltre alla generazione di numeri casuali, ci sono caratteristiche che entrano in un GUID per renderlo più univoco.Tieni presente che sono solo praticamente unici, non completamente unici.È possibile, anche se praticamente impossibile, averne un duplicato.

Nota aggiornata sui GUID:Da quando ho scritto questo ho appreso che molti generatori GUID utilizzano un generatore di numeri casuali crittograficamente sicuro (difficile o impossibile prevedere il numero successivo generato e difficilmente ripetibile).In realtà ce ne sono 5 diversi Algoritmi UUID.L'algoritmo 4 è quello che Microsoft attualmente utilizza per l'API di generazione del GUID di Windows.UN GUIDA è l'implementazione di Microsoft dello standard UUID.

Aggiornamento:Se desideri da 7 a 16 caratteri, devi utilizzare il metodo 2 o 3.

Linea di fondo:Francamente non esiste qualcosa di completamente unico.Anche se utilizzassi un generatore sequenziale alla fine esauriresti lo spazio di archiviazione utilizzando tutti gli atomi nell'universo, tornando così su te stesso e ripetendo.La tua unica speranza sarebbe la morte termica dell'universo prima di raggiungere quel punto.

Anche il miglior generatore di numeri casuali ha una possibilità di ripetizione pari alla dimensione totale del numero casuale che stai generando.Prendiamo ad esempio un quarto.È un generatore di bit completamente casuale e le sue probabilità di ripetizione sono 1 su 2.

Quindi tutto si riduce alla tua soglia di unicità.Puoi avere un'unicità del 100% in 8 cifre per 1.099.511.627.776 numeri utilizzando una sequenza e quindi codificandola in base32.Qualsiasi altro metodo che non implica il controllo rispetto a un elenco di numeri passati ha solo probabilità pari a n/1.099.511.627.776 (dove n=numero di numeri precedenti generati) di non essere univoco.

Altri suggerimenti

Qualsiasi algoritmo risulterà in duplicati.

Pertanto, potrei suggerirti di utilizzare l'algoritmo esistente* e controllare semplicemente la presenza di duplicati?

*Piccola aggiunta:Se uniqid() può essere non univoco in base al tempo, includere anche un contatore globale che si incrementa dopo ogni invocazione.In questo modo qualcosa è diverso anche nello stesso microsecondo.

Senza scrivere il codice, la mia logica sarebbe:

Genera una stringa casuale da qualsiasi carattere accettabile tu voglia.
Quindi aggiungi metà del datario (secondi parziali e tutto) in primo piano e l'altra metà alla fine (o da qualche parte al centro, se preferisci).

Resta JOLLY!
H

Se utilizzi il metodo originale, ma aggiungi il nome utente o l'indirizzo e-mail davanti alla password, sarà sempre univoco se ogni utente può avere solo 1 password.

Potrebbe interessarti questo articolo che tratta lo stesso argomento: I GUID sono univoci a livello globale, ma le sottostringhe di GUID non lo sono.

L'obiettivo di questo algoritmo è utilizzare la combinazione di tempo e posizione ("coordinate spazio-temporali" per i fanatici della relatività là fuori) come chiave di unicità.Tuttavia, il cronometraggio non è perfetto, quindi esiste la possibilità che, ad esempio, due GUID vengano generati in rapida successione dalla stessa macchina, così vicini nel tempo che il timestamp sarebbe lo stesso.È qui che entra in gioco l'uniquificatore.

Di solito lo faccio così:

$this->password = '';

for($i=0; $i<10; $i++)
{
    if($i%2 == 0)
        $this->password .= chr(rand(65,90));
    if($i%3 == 0)
        $this->password .= chr(rand(97,122));
    if($i%4 == 0)
        $this->password .= chr(rand(48,57));
}

Suppongo che ci siano alcuni buchi teorici ma non ho mai avuto problemi con la duplicazione.Di solito lo uso per password temporanee (come dopo la reimpostazione della password) e funziona abbastanza bene per questo.

Come ha commentato Frank Kreuger, scegli un generatore GUID.

Come Questo

Non riesco ancora a capire perché le password devono essere univoche?Qual è lo svantaggio se 2 dei tuoi utenti hanno la stessa password?

Ciò presuppone che stiamo parlando di password legate agli ID utente e non solo a identificatori univoci.Se quello è cosa stai cercando, perché non utilizzare i GUID?

Potresti essere interessato all'implementazione estremamente sicura di Steve Gibson di un generatore di password (nessuna fonte, ma ha una descrizione dettagliata di come funziona) su https://www.grc.com/passwords.htm.

Il sito crea enormi password di 64 caratteri ma, poiché sono completamente casuali, potresti facilmente prendere i primi 8 (o comunque molti) caratteri per una password meno sicura ma "il più casuale possibile".

MODIFICARE:dalle tue risposte successive vedo che hai bisogno di qualcosa di più simile a un GUID che a una password, quindi probabilmente non è quello che vuoi...

Credo che parte del tuo problema sia che stai cercando di fornirci una funzione singolare per due usi separati...password e Transaction_ID

si tratta in realtà di due aree problematiche diverse e in realtà non è meglio cercare di affrontarle insieme.

Recentemente volevo una chiave univoca casuale semplice e veloce, quindi ho fatto quanto segue:

$ukey = dechex(time()) . crypt( time() . md5(microtime() + mt_rand(0, 100000)) ); 

Quindi, in pratica, ottengo l'ora unix in secondi e aggiungo una stringa md5 casuale generata da ora + numero casuale.Non è il massimo, ma per le richieste a bassa frequenza è abbastanza buono.È veloce e funziona.

Ho fatto un test in cui generavo migliaia di chiavi e poi cercavo le ripetizioni, e avendo circa 800 chiavi al secondo non c'erano ripetizioni, quindi non male.Immagino che dipenda totalmente da mt_rand()

Lo uso per un tracker di sondaggi in cui otteniamo una velocità di invio di circa 1000 sondaggi al minuto...quindi per ora (incrocia le dita) non ci sono duplicati.Naturalmente, la tariffa non è costante (riceviamo le richieste in determinati orari del giorno), quindi questa non è una prova di fallimento né la soluzione migliore...il suggerimento è utilizzare un valore incrementale come parte della chiave (nel mio caso ho utilizzato time(), ma potrebbe essere migliore).

Inserendo la parte di crittografia che non ha molto a che fare con la creazione di un valore univoco, di solito utilizzo questa:

function GetUniqueValue()
{
   static $counter = 0; //initalized only 1st time function is called
   return strtr(microtime(), array('.' => '', ' ' => '')) . $counter++;
}

Quando viene chiamato nello stesso processo, $counter viene aumentato, quindi il valore è sempre univoco nello stesso processo.

Quando vengono chiamate in processi diversi devi essere davvero sfortunato se ottieni 2 chiamate microtime() con gli stessi valori, pensa che le chiamate microtime() di solito hanno valori diversi anche se chiamate nello stesso script.

Di solito eseguo una sottostringa casuale (rendo in modo casuale il numero di caratteri tra 8 e 32 o meno per comodità dell'utente) o l'MD5 di qualche valore che ho ottenuto, o l'ora, o qualche combinazione.Per maggiore casualità, eseguo MD5 del valore come (diciamo cognome) concatenandolo con l'ora, MD5 di nuovo, quindi prendo la sottostringa casuale.Si tu Potevo ottenere password uguali, ma non è affatto probabile.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top