Question

Je cherche un moyen, spécifiquement en PHP, d'être assuré de toujours obtenir une clé unique.

J'ai fait ce qui suit :

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

Mais j'ai constaté que de temps en temps, je me retrouvais avec une clé en double (rarement, mais assez souvent).

J'ai aussi pensé à faire :

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

Mais selon le site Web PHP, uniqid() pourrait, si uniqid() est appelé deux fois dans la même microseconde, générer la même clé.Je pense que l'ajout de rand() serait rarement le cas, mais toujours possible.

Après les lignes mentionnées ci-dessus, je supprime également les caractères tels que L et O afin que ce soit moins déroutant pour l'utilisateur.Cela peut être en partie responsable des doublons, mais cela reste nécessaire.

Une option à laquelle j'ai pensé consiste à créer un site Web qui générera la clé, la stockera dans une base de données, garantissant ainsi qu'elle est complètement unique.

D'autres idées ?Existe-t-il des sites Web qui font déjà cela et qui disposent d'une sorte d'API ou renvoient simplement la clé.j'ai trouvé http://userident.com mais je ne sais pas si les clés seront complètement uniques.

Cela doit s'exécuter en arrière-plan sans aucune intervention de l'utilisateur.

Était-ce utile?

La solution

Il n'y a que 3 façons de générer des valeurs uniques, il s'agit plutôt de mots de passe, d'identifiants utilisateur, etc. :

  1. Utilisez un générateur de GUID efficace : ils sont longs et ne peuvent pas être réduits.Si vous n'utilisez qu'une partie vous échouez.
  2. Au moins une partie du nombre est générée séquentiellement à partir d’une seule séquence.Vous pouvez ajouter du fluff ou un encodage pour lui donner un aspect moins séquentiel.L'avantage est qu'ils commencent à court terme - l'inconvénient est qu'ils nécessitent une source unique.La solution pour la limitation d'une source unique consiste à avoir des sources numérotées, vous incluez donc le [source #] + [seq #] et chaque source peut ensuite générer sa propre séquence.
  3. Générez-les via d'autres moyens, puis vérifiez-les par rapport à l'historique unique des valeurs générées précédemment.

Toute autre méthode n’est pas garantie.Gardez à l'esprit qu'en principe, vous générez un nombre binaire (c'est un ordinateur), mais vous pouvez ensuite l'encoder en hexadécimal, décimal, Base64 ou dans une liste de mots.Choisissez un encodage adapté à votre utilisation.Habituellement, pour les données saisies par l'utilisateur, vous souhaitez une variante de Base32 (à laquelle vous avez fait allusion).

Remarque sur les GUIDS:Ils tirent leur force d’unicité de leur longueur et de la méthode utilisée pour les générer. Tout ce qui est inférieur à 128 bits n'est pas sécurisé. Au-delà de la génération de nombres aléatoires, certaines caractéristiques entrent dans un GUID pour le rendre plus unique.Gardez à l’esprit qu’ils ne sont que pratiquement uniques, pas complètement uniques.Il est possible, bien que pratiquement impossible, d'en avoir un duplicata.

Note mise à jour sur les GUIDS:Depuis que j'écris ceci, j'ai appris que de nombreux générateurs de GUID utilisent un générateur de nombres aléatoires cryptographiquement sécurisé (difficile ou impossible de prédire le prochain nombre généré, et peu susceptible de se répéter).Il y en a en fait 5 différents Algorithmes UUID.L'algorithme 4 est celui que Microsoft utilise actuellement pour l'API de génération de GUID Windows.UN GUID est l'implémentation par Microsoft de la norme UUID.

Mise à jour:Si vous voulez 7 à 16 caractères, vous devez utiliser la méthode 2 ou 3.

Conclusion:Franchement, il n’existe pas de chose complètement unique.Même si vous optiez pour un générateur séquentiel, vous finiriez par manquer de stockage en utilisant tous les atomes de l'univers, revenant ainsi sur vous-même et répétant.Votre seul espoir serait la mort thermique de l’univers avant d’atteindre ce point.

Même le meilleur générateur de nombres aléatoires a une possibilité de répétition égale à la taille totale du nombre aléatoire que vous générez.Prenons un quart par exemple.Il s'agit d'un générateur de bits complètement aléatoire et ses chances de répétition sont de 1 sur 2.

Tout dépend donc de votre seuil d’unicité.Vous pouvez avoir 100 % d'unicité sur 8 chiffres pour 1 099 511 627 776 nombres en utilisant une séquence puis en la codant en base32.Toute autre méthode qui n'implique pas de vérification par rapport à une liste de numéros passés a uniquement des chances égales à n/1 099 511 627 776 (où n = nombre de numéros précédents générés) de ne pas être unique.

Autres conseils

Tout algorithme entraînera des doublons.

Par conséquent, puis-je vous suggérer d’utiliser votre algorithme existant* et de simplement vérifier les doublons ?

*Léger ajout :Si uniqid() peut être non unique en fonction du temps, inclure également un compteur global que vous incrémentez après chaque appel.De cette façon, quelque chose est différent même dans la même microseconde.

Sans écrire le code, ma logique serait :

Générez une chaîne aléatoire à partir des caractères acceptables que vous aimez.
Ajoutez ensuite la moitié du timbre à date (secondes partielles et tout) au début et l'autre moitié à la fin (ou quelque part au milieu si vous préférez).

Restez JOLLY !
H

Si vous utilisez votre méthode d'origine, mais ajoutez le nom d'utilisateur ou l'adresse e-mail devant le mot de passe, celui-ci sera toujours unique si chaque utilisateur ne peut avoir qu'un seul mot de passe.

Vous pourriez être intéressé par cet article qui traite de la même problématique : Les GUID sont globalement uniques, mais les sous-chaînes des GUID ne le sont pas.

Le but de cet algorithme est d'utiliser la combinaison du temps et du lieu (« coordonnées spatio-temporelles » pour les connaisseurs de la relativité) comme clé d'unicité.Cependant, le chronométrage n'est pas parfait et il est donc possible que, par exemple, deux GUID soient générés en succession rapide à partir de la même machine, si proches l'un de l'autre dans le temps que l'horodatage serait le même.C'est là qu'intervient l'uniquificateur.

Je fais habituellement comme ceci :

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

Je suppose qu'il y a quelques lacunes théoriques mais je n'ai jamais eu de problème de duplication.Je l'utilise habituellement pour les mots de passe temporaires (comme après une réinitialisation de mot de passe) et cela fonctionne assez bien pour cela.

Comme l'a commenté Frank Kreuger, optez pour un générateur de GUID.

Comme celui-ci

Je ne comprends toujours pas pourquoi les mots de passe doivent être uniques ?Quel est l'inconvénient si 2 de vos utilisateurs ont le même mot de passe ?

Cela suppose que nous parlons de mots de passe liés aux identifiants utilisateur, et pas seulement d'identifiants uniques.Si c'est ce que vous recherchez, pourquoi ne pas utiliser des GUID ?

Vous pourriez être intéressé par l'implémentation ultra-sécurisée d'un générateur de mots de passe par Steve Gibson (pas de source, mais il a une description détaillée de son fonctionnement) sur https://www.grc.com/passwords.htm.

Le site crée d'énormes mots de passe de 64 caractères mais, comme ils sont complètement aléatoires, vous pouvez facilement prendre les 8 premiers caractères (ou autant) pour un mot de passe moins sécurisé mais "aussi aléatoire que possible".

MODIFIER:d'après vos réponses ultérieures, je vois que vous avez besoin de quelque chose qui ressemble plus à un GUID qu'à un mot de passe, donc ce n'est probablement pas ce que vous voulez...

Je crois qu'une partie de votre problème est que vous essayez de nous proposer une fonction unique pour deux utilisations distinctes...mots de passe et transaction_id

ce sont en réalité deux domaines problématiques différents et il n’est vraiment pas préférable d’essayer de les résoudre ensemble.

Je voulais récemment une clé unique aléatoire rapide et simple, j'ai donc fait ce qui suit :

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

Donc, fondamentalement, j'obtiens l'heure Unix en secondes et j'ajoute une chaîne md5 aléatoire générée à partir de l'heure + un nombre aléatoire.Ce n'est pas le meilleur, mais pour les requêtes basse fréquence, c'est plutôt bien.C'est rapide et ça marche.

J'ai fait un test où je générais des milliers de clés, puis recherchais des répétitions, et avec environ 800 clés par seconde, il n'y avait pas de répétitions, donc pas mal.Je suppose que cela dépend totalement de mt_rand()

Je l'utilise pour un tracker d'enquêtes où nous obtenons un taux de soumission d'environ 1000 enquêtes par minute...donc pour l'instant (croise les doigts) il n'y a pas de doublons.Bien entendu, le tarif n'est pas constant (nous recevons les soumissions à certains moments de la journée) ce n'est donc pas une solution infaillible ni la meilleure solution...l'astuce consiste à utiliser une valeur incrémentielle dans le cadre de la clé (dans mon cas, j'ai utilisé time(), mais cela pourrait être mieux).

Pour intégrer la partie cryptage qui n'a pas grand chose à voir avec la création d'une valeur unique, j'utilise habituellement celle-ci :

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

Lorsqu'il est appelé dans le même processus, $counter est augmenté afin que la valeur soit toujours unique dans le même processus.

Lorsqu'il est appelé dans différents processus, vous devez être vraiment malchanceux pour obtenir 2 appels microtime() avec les mêmes valeurs, pensez que les appels microtime() ont généralement des valeurs différentes également lorsqu'ils sont appelés dans le même script.

Je fais habituellement une sous-chaîne aléatoire (randomiser le nombre de caractères entre 8 et 32, ou moins pour la commodité de l'utilisateur) ou le MD5 d'une valeur que j'ai entrée, ou l'heure, ou une combinaison.Pour plus de caractère aléatoire, je fais MD5 de la valeur come (disons le nom de famille), concatène cela avec le temps, MD5 à nouveau, puis prends la sous-chaîne aléatoire.Oui toi pourrait obtenez des mots de passe égaux, mais ce n'est pas très probable du tout.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top