Krótki unikalny identyfikator w php

Chcę utworzyć unikalny identyfikator, ale uniqid() daje coś w rodzaju '492607b0ee414'. Chciałbym coś podobnego do tego, co daje tinyurl: '64k8ra'. Im krócej, tym lepiej. Jedynym wymogiem jest to, że nie powinien mieć oczywistego porządku i że powinien wyglądać ładniej niż pozornie losowy ciąg liczb. Litery są preferowane niż cyfry i idealnie nie byłoby mieszanych liter. Ponieważ liczba zgłoszeń nie będzie tak duża (do 10000 lub więcej) ryzyko kolizji nie jest ogromne factor.

Wszelkie sugestie mile widziane.
Author: tereško, 2008-11-21

15 answers

Zrób małą funkcję, która zwraca losowe litery dla danej długości:

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

Wtedy będziesz chciał to nazwać, dopóki nie będzie unikalne, w pseudo-kodzie w zależności od tego, gdzie przechowujesz te informacje:

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

Możesz również upewnić się, że litery nie tworzą słowa w słowniku. Niech to będzie cały angielski dictionnary lub po prostu złe słowo dictionnary, aby uniknąć rzeczy, które klient znajdzie złego smaku.

EDIT: dodałbym również, że ma to sens tylko wtedy, gdy, jak zamierzamy go używać, nie jest to dla dużej ilości przedmiotów, ponieważ może to być dość powolne im więcej kolizji otrzymasz(uzyskanie ID już w tabeli). Oczywiście będziesz potrzebował zindeksowanej tabeli i będziesz chciał dostosować liczbę liter w identyfikatorze, aby uniknąć kolizji. W tym przypadku, z 6 literami, masz 26^6 = 308915776 możliwych unikalnych identyfikatorów (minus złe słowa), które powinny wystarczyć na Twoją potrzebę 10000.

Edytuj: Jeśli chcesz kombinację liter i cyfr możesz użyć następujący kod:

$random .= rand(0, 1) ? rand(0, 9) : chr(rand(ord('a'), ord('z')));
 41
Author: lpfavreau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-10 08:05:49

@gen_uuid () by gord.

Preg_replace ma paskudne problemy z utf-8, które powodują czasami, że uid zawiera " + "lub"/". Aby to obejść, musisz jawnie utworzyć wzór 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);
}

Zajęło mi trochę czasu, aby dowiedzieć się, że, być może to oszczędza kogoś innego ból głowy

 25
Author: Corelgott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-21 12:36:05

Możesz to osiągnąć za pomocą mniejszego kodu:

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

Wynik (przykłady):

  • cjnp56brdy
  • 9d5uv84zfa
  • Ih162lryez]}
  • ri4ocf6tkj
  • xj04s83egi
 23
Author: Nico Schefer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-14 15:15:19

Istnieją dwa sposoby uzyskania niezawodnie unikalnego identyfikatora: uczynić go tak długim i zmiennym, że szanse kolizji są spektakularnie małe (jak w przypadku GUID) lub zapisać wszystkie wygenerowane identyfikatory w tabeli do wyszukiwania (w pamięci lub w DB lub pliku)w celu sprawdzenia unikalności podczas generowania.

Jeśli naprawdę pytasz, jak możesz wygenerować tak krótki klucz i zagwarantować jego wyjątkowość bez jakiegoś duplikatu, odpowiedź brzmi: nie możesz.

 17
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-21 01:47:39

Naprawdę proste rozwiązanie:

Stwórz unikalny identyfikator za pomocą:

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

Uzyskaj oryginalną wartość ponownie:

intval($str,36);

Nie mogę wziąć za to uznania, ponieważ jest to z innej strony przepełnienia stosu, ale myślałem, że rozwiązanie było tak eleganckie i niesamowite, że warto skopiować do tego wątku dla osób, które odnoszą się do tego.

 11
Author: Adcuz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-21 22:31:37

Oto procedura, której używam dla losowych base62 o dowolnej długości...

Wywołanie gen_uuid() zwraca łańcuchy takie jak WJX0u0jV, E9EMaZ3P itd.

Domyślnie zwraca 8 cyfr, stąd spacja 64^8 lub mniej więcej 10^14, jest to na tyle często, że kolizje są dość rzadkie.

Dla większego lub mniejszego ciągu, podaj $len zgodnie z życzeniem. Nie ma limitu długości, ponieważ dołączam do momentu spełnienia [do limitu bezpieczeństwa 128 znaków, które można usunąć].

Uwaga, użyj losowej soli wewnątrz md5 [lub sha1, jeśli wolisz], więc nie można go łatwo odwrócić.

Nie znalazłem żadnych wiarygodnych konwersji base62 w sieci, stąd takie podejście do usuwania znaków z wyniku base64.

Swobodnie korzystać na licencji BSD, enjoy,

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
Author: gord,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-04 13:49:14

Możesz użyć Id i po prostu przekonwertować go na numer base-36, jeśli chcesz przekonwertować go tam iz powrotem. Może być stosowany dla dowolnej tabeli o identyfikatorze całkowitym.

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

Mądrzy ludzie mogą prawdopodobnie dowiedzieć się o tym z wystarczającą ilością przykładów id. Nie pozwól, aby ta ciemność zastąpiła bezpieczeństwo.

 4
Author: OIS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-21 09:58:07

Wymyśliłem to, co myślę, że jest całkiem fajne rozwiązanie robiąc to bez sprawdzenia wyjątkowości. Pomyślałem, że podzielę się z przyszłymi gośćmi.

Licznik jest naprawdę łatwym sposobem zagwarantowania wyjątkowości lub jeśli używasz bazy danych klucz podstawowy również gwarantuje wyjątkowość. Problem w tym, że wygląda źle i może być podatny. Więc wziąłem sekwencję i pomieszałem ją za pomocą szyfru. Ponieważ szyfr można odwrócić, wiem, że każdy identyfikator jest unikalny, a jednocześnie pojawia się przypadkowe.

To python nie php, ale wgrałem tutaj Kod: https://github.com/adecker89/Tiny-Unique-Identifiers

 4
Author: AJD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-08 05:15:06

Litery są ładne, cyfry brzydkie. Chcesz losowe struny, ale nie chcesz" brzydkich " losowych strun?

Utwórz losową liczbę i wydrukuj ją w alpha-style (base-26), podobnie jak rezerwacja "numerów", które linie lotnicze podają.

W PHP nie ma wbudowanych funkcji konwersji bazy ogólnego przeznaczenia, o ile wiem, więc sam musisz to zakodować.

Inna alternatywa: użyj uniqid() i pozbądź się cyfr.

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

Lub zastąp je litery:

function replace_digits_with_letters($string) {
    return strtr($string, '0123456789', 'abcdefghij');
}
 3
Author: RJHunter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-28 11:30:13

Możesz też zrobić to jak 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
Author: Aldee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-26 10:08:43

Możesz to zrobić Bez brudnych/kosztownych rzeczy, takich jak pętle, połączenia łańcuchowe lub wiele wywołań rand (), w czysty i łatwy do odczytania sposób. Ponadto, lepiej jest użyć mt_rand():

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

Jeśli chcesz, aby ciąg miał dokładną długość w każdym przypadku, po prostu wpisz liczbę hex z zerami:

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

"teoretyczny backdraw" polega na tym, że ograniczasz się do możliwości PHPs - ale w tym przypadku jest to bardziej filozoficzne zagadnienie ;) przejdźmy przez to anyway:

  • PHP jest ograniczone w tym, co może reprezentować jako liczbę szesnastkową robiąc to w ten sposób. To byłoby $length <= 8 co najmniej na 32-bitowym systemie, gdzie ograniczenie PHPs powinno wynosić 4.294.967.295 .
  • generator liczb losowych PHPs ma również maksimum. Na mt_rand() co najmniej w systemie 32bit powinno być 2.147.483.647
  • Więc teoretycznie jesteś ograniczony do 2.147.483.647 identyfikatorów.

Wracając do tematu-intuicyjny do { (generate ID) } while { (id is not uniqe) } (insert id) ma jedną wadą i jedną możliwą wadą, która może doprowadzić cię prosto do ciemności...

Wada: Walidacja jest pesymistyczna. Robienie tego w ten sposób Zawsze wymaga sprawdzenia w bazie danych. Posiadanie wystarczającej ilości przestrzeni kluczy (na przykład długości 5 dla wpisów 10k) może spowodować kolizje tak często, ponieważ może to być porównywalnie mniej zużywające zasoby, aby po prostu spróbować zapisać dane i spróbować ponownie tylko w przypadku unikalnego błędu klucza.

Wada: Użytkownik a pobiera identyfikator, który zostanie zweryfikowany jako jeszcze nie wzięty. Następnie kod spróbuje wstawić dane. Ale w międzyczasie, użytkownik B wszedł w tę samą pętlę i niestety pobiera tę samą liczbę losową, ponieważ użytkownik A nie jest jeszcze przechowywany i ten identyfikator był nadal wolny. Teraz system przechowuje User B lub User a, a podczas próby przechowywania drugiego Użytkownika, w międzyczasie jest już drugi - o tym samym ID.

You would trzeba obsłużyć ten wyjątek w każdym przypadku i ponownie spróbować wstawiania z nowo utworzonym identyfikatorem. Dodanie tego przy zachowaniu pesymistycznej pętli sprawdzającej (którą trzeba by wprowadzić ponownie) spowoduje, że kod będzie dość brzydki i trudny do naśladowania. na szczęście rozwiązanie tego problemu jest takie samo jak wada: po prostu idź na to w pierwszej kolejności i spróbuj zapisać dane. W przypadku błędu unikalnego klucza po prostu spróbuj ponownie z nowym identyfikatorem.

 1
Author: nico gawenda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-24 17:41:50

Zajrzyj do tego artykułu

Wyjaśnia, jak generować krótkie unikalne identyfikatory z identyfikatorów bdd, tak jak robi to youtube.

Właściwie, funkcja w artykule jest bardzo związana z funkcją php base_convert, która Konwertuje liczbę z bazy na inną (ale tylko do bazy 36).

 1
Author: httpete,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
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
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-15 16:26:06

Jeśli podoba Ci się dłuższa wersja unikalnego identyfikatora użyj tego:
$uniqueid = sha1(md5 (time ()));

 0
Author: Alon Kogan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-07 09:11:28

Najlepsza odpowiedź: najmniejszy unikalny ciąg "Hash Like" podany unikalny identyfikator bazy danych-rozwiązanie PHP, nie wymaga bibliotek stron trzecich.

Oto kod:

<?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
Author: John Erck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-04 19:28:22