Id unique court en php

je veux créer un id unique mais uniqid() donne quelque chose comme '492607b0ee414' . Ce que je voudrais c'est quelque chose de semblable à ce que donne tinyurl: '64k8ra' . Plus c'est court, mieux c'est. Les seules exigences sont qu'il ne doit pas avoir un ordre évident et qu'il doit paraître plus joli qu'une séquence apparemment aléatoire de nombres. Les lettres sont préférées aux chiffres et idéalement, il ne serait pas cas mixte. Comme le nombre d'entrées ne sera pas que beaucoup (jusqu'à 10000 ou plus) risque de collision n'est pas un facteur énorme.

toute suggestion est appréciée.

46
demandé sur tereško 2008-11-21 04:05:57

15 réponses

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

alors vous voudrez appeler cela jusqu'à ce qu'il soit unique, en pseudo-code selon l'endroit où vous stockez cette information:

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

vous pouvez également vous assurer que les lettres ne forment pas un mot dans un dictionnaire. Qu'il s'agisse du dictionnaire anglais en entier ou simplement d'un dictionnaire de mauvais mots pour éviter les choses qu'un client trouverait de mauvais goût.

EDIT: je voudrais aussi ajouter que cela n'a de sens que si, comme vous avez l'intention de l'utiliser, ce n'est pas pour un grand nombre d'éléments parce que cela pourrait devenir assez lent le plus de collisions que vous obtenez (obtenir un ID déjà dans la table). Bien sûr, vous aurez besoin d'une table indexée et vous voudrez modifier le nombre de lettres dans L'ID pour éviter la collision. Dans ce cas, avec 6 lettres, vous auriez 26^6 = 308915776 identifiants uniques possibles (moins les mauvais mots) qui devraient être suffisants 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')));
41
répondu lpfavreau 2017-08-10 08:05:49

@gen_uuid() par gord.

preg_replace eu une méchante utf-8 problèmes, ce qui provoque l'uid parfois contenir "" + " ou "/". Pour contourner cela, vous devez faire explicitement le modèle 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);
}

m'a pris un certain temps pour constater que, peut-être cela sauve quelqu'un d'autre un mal de tête

25
répondu Corelgott 2010-08-21 12:36:05

vous pouvez y arriver avec moins de code:

function gen_uid($l=10){
    return substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyz"), 0, $l);
}

résultat (exemples):

  • cjnp56brdy
  • 9d5uv84zfa
  • ih162lryez
  • ri4ocf6tkj
  • xj04s83egi
23
répondu Nico Schefer 2014-03-14 15:15:19

il y a deux façons d'obtenir un ID unique fiable: le rendre si long et variable que les chances d'une collision sont extraordinairement petites (comme avec une GUID) ou stocker tous les ID générés dans une table pour la recherche (soit dans la mémoire ou dans un DB ou un fichier) pour vérifier l'unicité sur la génération.

si vous vous demandez vraiment comment vous pouvez générer une clé aussi courte et garantir son unicité sans une sorte de vérification en double, la réponse est, vous ne pouvez pas.

17
répondu Chris 2008-11-21 01:47:39

Vraiment la solution la plus simple:

Faire de l'IDENTIFIANT unique:

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

obtenir la valeur originale de nouveau:

intval($str,36);

ne peut pas prendre le crédit pour cela car il est d'une autre page de débordement de pile, mais j'ai pensé que la solution était si élégante et génial qu'il valait la peine de copier sur ce fil pour les gens se référant à cela.

11
répondu Adcuz 2010-01-21 22:31:37

Voici la routine que j'utilise pour les base62 aléatoires de n'importe quelle longueur...

Appel gen_uuid() renvoie des chaînes comme WJX0u0jV, E9EMaZ3P etc.

par défaut cela renvoie 8 chiffres, donc un espace de 64^8 ou environ 10^14, cela est souvent suffisant pour rendre les collisions assez rares.

pour une plus grande ou plus petite corde, passer dans $len comme désiré. Aucune limite de longueur, car je ajoute jusqu'à ce que satisfait [jusqu'à la limite de sécurité de 128 caractères, qui peut être retiré.]

Note, utilisez un sel aléatoire inside le md5 [ou sha1 si vous préférez], de sorte qu'il ne peut pas être facilement rétro-ingénierie.

Je n'ai pas trouvé de conversions de base62 fiables sur le web, d'où cette approche de retirer les caractères du résultat de base64.

utiliser librement sous licence BSD, profiter de,

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);
}
10
répondu gord 2009-10-04 13:49:14

vous pouvez utiliser L'Id et juste le convertir en base-36 Nombre si vous voulez le convertir d'avant en arrière. Peut être utilisé pour n'importe quelle table avec un entier id.

function toUId($baseId, $multiplier = 1) {
    return base_convert($baseId * $multiplier, 10, 36);
}
function fromUId($uid, $multiplier = 1) {
    return (int) base_convert($uid, 36, 10) / $multiplier;
}

echo toUId(10000, 11111);
1u5h0w
echo fromUId('1u5h0w', 11111);
10000

les gens intelligents peuvent probablement le comprendre avec assez d'exemples d'identification. Ne laissez pas cette obscurité remplacer sécurité.

4
répondu OIS 2008-11-21 09:58:07

j'ai trouvé ce que je pense être une solution assez cool de faire cela sans un contrôle d'unicité. Je pensais partager pour les futurs visiteurs.

un compteur est un moyen vraiment facile de garantir l'unicité ou si vous utilisez une base de données une clé primaire garantit également l'unicité. Le problème est qu'il semble mauvais et et pourrait être vulnérable. Donc j'ai pris la séquence et je l'ai mélangée avec un cryptogramme. Puisque le chiffre peut être inversé, je sais que chaque id est unique apparaissant de façon aléatoire.

c'est python pas php, mais j'ai téléchargé le code ici: https://github.com/adecker89/Tiny-Unique-Identifiers

4
répondu AJD 2012-02-08 05:15:06

les Lettres sont jolies, les chiffres sont moches. Tu veux des cordes au hasard, mais pas des cordes au hasard" moches"?

créer un nombre aléatoire et l'imprimer en alpha-style ( base-26 ), comme les" numéros " de réservation que les compagnies aériennes donnent.

il n'y a pas de fonctions générales de conversion de base intégrées dans PHP, autant que je sache, donc vous devez coder cela vous-même.

un autre alternative: utiliser uniqid() et se débarrasser des chiffres.

function strip_digits_from_string($string) {
    return preg_replace('/[0-9]/', '', $string);
}

ou les remplacer par les lettres:

function replace_digits_with_letters($string) {
    return strtr($string, '0123456789', 'abcdefghij');
}
3
répondu RJHunter 2018-02-28 11:30:13

vous pouvez aussi le faire comme tihs:

public static function generateCode($length = 6)
    {
        $az = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $azr = rand(0, 51);
        $azs = substr($az, $azr, 10);
        $stamp = hash('sha256', time());
        $mt = hash('sha256', mt_rand(5, 20));
        $alpha = hash('sha256', $azs);
        $hash = str_shuffle($stamp . $mt . $alpha);
        $code = ucfirst(substr($hash, $azr, $length));
        return $code;
    }
1
répondu Aldee 2013-02-26 10:08:43

vous pouvez faire que sans des trucs impurs/costauds comme des boucles, des concaténations de chaîne ou des appels multiples à rand(), d'une manière propre et facile à lire. En outre, il est préférable d'utiliser mt_rand() :

function createRandomString($length)
{
    $random = mt_rand(0, (1 << ($length << 2)) - 1);
    return dechex($random);
}

si vous avez besoin de la chaîne pour avoir la longueur exacte dans tous les cas, il suffit de remplir le numéro hexadécimal de zéros:

function createRandomString($length)
{
    $random = mt_rand(0, (1 << ($length << 2)) - 1);
    $number = dechex($random);
    return str_pad($number, $length, '0', STR_PAD_LEFT);
}

Le "théorique backdraw" est, que vous êtes limité à PHPs capacités - mais ce n'est plus un question philosophique dans ce cas ;) allons à travers elle de toute façon:

  • PHP est limité dans ce qu'il peut représenter comme un nombre hexadécimal le faisant comme ceci. Ce serait $length <= 8 au moins sur un système 32 bits, où la limite de PHPs pour cela devrait être 4.294.967.295 .
  • PHPS générateur de nombres aléatoires a également un maximum. Pour mt_rand() au moins sur un système de 32 bits, il devrait être 2.147.483.647
  • donc vous êtes théoriquement limité à 2.147.483.647 IDs.

pour revenir au sujet - l'intuitif do { (generate ID) } while { (id is not uniqe) } (insert id) a un inconvénient et un défaut possible qui pourrait vous conduire directement à l'obscurité...

Inconvénient: La validation est pessimiste. Faire comme ceci toujours nécessite une vérification à la base de données. Avoir assez de place de clé (par exemple longueur de 5 pour vos entrées de 10k) causera très peu de collisions aussi souvent, comme il pourrait être comparable moins de ressources de simplement essayer de stocker les données et de réessayer seulement en cas d'une erreur clé UNIQUE.

défaut: L'Utilisateur a récupère un ID qui est vérifié comme non encore pris. Ensuite, le code essaiera d'insérer les données. Mais en attendant, utilisateur B est entré dans la même boucle et malheureusement récupère le même nombre aléatoire, parce que Utilisateur a n'est pas encore stocké et cet ID était encore libre. Maintenant, le système stocke soit utilisateur B ou Utilisateur a , et en essayant de stocker le deuxième utilisateur, il y a déjà l'autre dans l'intervalle - ayant le même ID.

vous devez gérer cette exception dans tous les cas et vous devez réessayer l'insertion avec un ID nouvellement créé. L'ajout de cette tout en gardant la boucle de vérification pessimiste (que vous auriez besoin de re-entrer) résultera en code assez laid et difficile à suivre. heureusement la solution à cela est la même que celle à l'inconvénient: il suffit d'aller pour elle en premier lieu et essayer de stocker les données. En cas d'erreur clé UNIQUE, réessayez avec un nouvel ID.

1
répondu nico gawenda 2013-09-24 17:41:50

consultez cet article

il explique comment générer de courts identifiants uniques à partir de vos identifiants bdd, comme youtube le fait.

en fait, la fonction dans l'article est très liée à fonction php base_convert qui convertit un nombre d'une base à une autre (mais est seulement jusqu'à la base 36).

1
répondu httpete 2014-02-20 13:39:06
function rand_str($len = 12, $type = '111', $add = null) {
    $rand = ($type[0] == '1'  ? 'abcdefghijklmnpqrstuvwxyz' : '') .
            ($type[1] == '1'  ? 'ABCDEFGHIJKLMNPQRSTUVWXYZ' : '') .
            ($type[2] == '1'  ? '123456789'                 : '') .
            (strlen($add) > 0 ? $add                        : '');

    if(empty($rand)) $rand = sha1( uniqid(mt_rand(), true) . uniqid( uniqid(mt_rand(), true), true) );

    return substr(str_shuffle( str_repeat($rand, 2) ), 0, $len);
}
0
répondu 2008-12-15 16:26:06

si vous aimez une version plus longue de l'ID unique Utilisez ceci:

$uniqueid = sha1 (md5 (time ()));

0
répondu Alon Kogan 2012-08-07 09:11:28

meilleure réponse encore: plus petite chaîne de caractères unique" semblable à du hachage " étant donné L'ID de base de données Unique - Solution PHP, aucune bibliothèque tierce partie nécessaire.

voici le code:

<?php
/*
THE FOLLOWING CODE WILL PRINT:
A database_id value of 200 maps to 5K
A database_id value of 1 maps to 1
A database_id value of 1987645 maps to 16LOD
*/
$database_id = 200;
$base36value = dec2string($database_id, 36);
echo "A database_id value of 200 maps to $base36value\n";
$database_id = 1;
$base36value = dec2string($database_id, 36);
echo "A database_id value of 1 maps to $base36value\n";
$database_id = 1987645;
$base36value = dec2string($database_id, 36);
echo "A database_id value of 1987645 maps to $base36value\n";

// HERE'S THE FUNCTION THAT DOES THE HEAVY LIFTING...
function dec2string ($decimal, $base)
// convert a decimal number into a string using $base
{
    //DebugBreak();
   global $error;
   $string = null;

   $base = (int)$base;
   if ($base < 2 | $base > 36 | $base == 10) {
      echo 'BASE must be in the range 2-9 or 11-36';
      exit;
   } // if

   // maximum character string is 36 characters
   $charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';

   // strip off excess characters (anything beyond $base)
   $charset = substr($charset, 0, $base);

   if (!ereg('(^[0-9]{1,50}$)', trim($decimal))) {
      $error['dec_input'] = 'Value must be a positive integer with < 50 digits';
      return false;
   } // if

   do {
      // get remainder after dividing by BASE
      $remainder = bcmod($decimal, $base);

      $char      = substr($charset, $remainder, 1);   // get CHAR from array
      $string    = "$char$string";                    // prepend to output

      //$decimal   = ($decimal - $remainder) / $base;
      $decimal   = bcdiv(bcsub($decimal, $remainder), $base);

   } while ($decimal > 0);

   return $string;

}

?>
0
répondu John Erck 2014-08-04 19:28:22