60 votes

Identifiant unique en php

Je veux créer un id unique, mais uniqid() est de donner quelque chose comme '492607b0ee414'. Ce que je voudrais, c'est quelque chose de semblable à ce que tinyurl donne: '64k8ra'. Plus c'est court, mieux c'est. La seule condition est qu'il ne devrait pas avoir un ordre apparent et qu'il devrait regarder de plus beau qu'un ordre apparemment aléatoire de la séquence de nombres. Les lettres sont privilégiées sur les nombres et, idéalement, il ne serait pas le cas mixte. Comme le nombre d'entrées ne seront pas que de nombreux (jusqu'à 10000 ou) le risque de collision n'est pas un facteur énorme.

Toutes les suggestions apprécié.

53voto

lpfavreau Points 5622

Faire une petite fonction qui retourne des lettres aléatoires pour une longueur donnée:

<?php
function generate_random_letters($length) {
  $random = '';
  for ($i = 0; $i < $length; $i++) {
    $random .= chr(rand(ord('a'), ord('z')));
  }
  return $random;
}

Ensuite, vous aurez envie d'appeler jusqu'à ce que celui-ci est unique, en pseudo-code, selon l'endroit où vous vous souhaitez stocker de l'information:

do {
  $unique = generate_random_letters(6);
} while (is_in_table($unique));
add_to_table($unique);

Vous pourriez aussi vous voulez vous assurer que les lettres ne forment pas un mot dans un dictionnaire. Peut-il être l'ensemble de l'anglais dictionnaire ou juste un mauvais mot dictionnaire pour éviter de choses qu'un client pourrait trouver de mauvais goût.

EDIT: je tiens à ajouter ceci n'a de sens que si, comme vous avez l'intention de les utiliser, ce n'est pas pour un grand nombre d'éléments, car cela pourrait être assez lent le plus de collisions que vous obtenez (obtention d'un IDENTIFIANT déjà dans la table). Bien sûr, vous aurez envie d'un tableau indexé, et vous aurez envie de régler le nombre de lettres dans l'ID pour éviter la collision. Dans ce cas, avec 6 lettres, vous auriez 26^6 = 308915776 possible Identifiants uniques (moins de gros mots) qui devrait être suffisant pour votre besoin de 10000.

EDIT: Si vous voulez une combinaison de lettres et de nombres, vous pouvez utiliser le code suivant:

$random .= rand(0, 1) ? rand(0, 9) : chr(rand(ord('a'), ord('z')));

33voto

Corelgott Points 576

@gen_uuid () par gord.

preg_replace a quelques problèmes désagréables avec utf-8, ce qui a parfois pour conséquence de contenir "+" ou "/". Pour résoudre ce problème, vous devez explicitement créer le motif utf-8.

 function gen_uuid($len=8) {

    $hex = md5("yourSaltHere" . uniqid("", true));

    $pack = pack('H*', $hex);
    $tmp =  base64_encode($pack);

    $uid = preg_replace("#(*UTF8)[^A-Za-z0-9]#", "", $tmp);

    $len = max(4, min(128, $len));

    while (strlen($uid) < $len)
        $uid .= gen_uuid(22);

    return substr($uid, 0, $len);
}
 

Il m'a fallu un bon bout de temps pour trouver cela, peut-être que ça éviterait à quelqu'un d'autre un mal de tête

20voto

Chris Points 14136

Il existe deux manières d'obtenir un identifiant unique fiable: le rendre tellement long et variable que les risques de collision sont spectaculairement minimes (comme avec un GUID) ou de stocker tous les identifiants générés dans une table à des fins de recherche (en mémoire ou dans une base de données) ou un fichier) pour vérifier l'unicité lors de la génération.

Si vous demandez vraiment comment vous pouvez générer une clé aussi courte et garantir son unicité sans contrôle en double, la réponse est que vous ne pouvez pas.

13voto

gord Points 81

Voici la routine que j'utilise pour aléatoire base62s de n'importe quelle longueur...

Appelant gen_uuid() rendements des chaînes de caractères comme WJX0u0jV, E9EMaZ3P etc.

Par défaut, ceci renvoie à 8 chiffres, donc un espace de 64^8 soit environ 10^14, c'est assez souvent de faire des collisions assez rare.

Pour une plus grande ou plus petite chaîne, de passer en $len comme souhaité. Pas de limite en longueur, comme je l'ai ajouter jusqu'à satisfaction [jusqu'à la limite de sécurité de 128 caractères, qui peut être supprimé].

Remarque, l'utilisation aléatoire de sel à l'intérieur de l'md5 [ou sha1 si vous préférez], de sorte qu'il ne peut pas facilement être de la rétro-ingénierie.

Je n'ai pas trouvé fiable base62 conversions sur le web, d'où cette approche pour le décapage de caractères à partir de la base64 résultat.

Utiliser librement sous la licence BSD, profiter,

gord

function gen_uuid($len=8)
{
    $hex = md5("your_random_salt_here_31415" . uniqid("", true));

    $pack = pack('H*', $hex);

    $uid = base64_encode($pack);        // max 22 chars

    $uid = ereg_replace("[^A-Za-z0-9]", "", $uid);    // mixed case
    //$uid = ereg_replace("[^A-Z0-9]", "", strtoupper($uid));    // uppercase only

    if ($len<4)
        $len=4;
    if ($len>128)
        $len=128;                       // prevent silliness, can remove

    while (strlen($uid)<$len)
        $uid = $uid . gen_uuid(22);     // append until length achieved

    return substr($uid, 0, $len);
}

12voto

Adcuz Points 81

Solution vraiment simple:

Créez l'identifiant unique avec:

 $id = 100;
base_convert($id, 10, 36);
 

Obtenez à nouveau la valeur d'origine:

 intval($str,36);
 

Je ne peux pas prendre le crédit pour cela car il provient d'une autre page de débordement de pile, mais je pensais que la solution était si élégante et si impressionnante qu'il valait la peine de la copier sur ce fil de discussion pour les personnes y faisant référence.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X