PHP: Jak wygenerować losowy, unikalny ciąg alfanumeryczny?


380

Jak byłoby możliwe wygenerowanie losowego, unikalnego ciągu przy użyciu cyfr i liter do użycia w łączu weryfikacyjnym? Podobnie jak w przypadku tworzenia konta w witrynie internetowej, która wysyła wiadomość e-mail z linkiem, a użytkownik musi kliknąć ten link, aby zweryfikować swoje konto ... tak ... jeden z nich.

Jak mogę wygenerować jedną z tych przy użyciu PHP?

Aktualizacja: Właśnie zapamiętałem uniqid(). Jest to funkcja PHP, która generuje unikalny identyfikator na podstawie bieżącego czasu w mikrosekundach. Myślę, że użyję tego.


Wszystko czego potrzebujesz to ciągi znaków i jednolicie rozmieszczone liczby losowe.
Artelius,

10
Hej Andrew, powinieneś wybrać Scottwłaściwą odpowiedź. Scott używa kryptograficznie bezpiecznego generatora liczb psudo-losowych OpenSSL (CSPRNG), który wybierze najbezpieczniejsze źródło entropii w oparciu o twoją platformę.
wieża

3
Każdy, kto czyta to po 2015 roku, proszę spojrzeć tutaj: paragonie.com/blog/2015/07/... Większość najlepszych odpowiedzi jest wadliwych mniej więcej ...
rugk

OpenSSL i uniqidsą niepewne. Użyj czegoś takiego jak Random::alphanumericString($length)lub Random::alphanumericHumanString($length).
caw

Odpowiedzi:


305

Uwaga dotycząca bezpieczeństwa : tego rozwiązania nie należy używać w sytuacjach, w których jakość Twojej losowości może wpłynąć na bezpieczeństwo aplikacji. W szczególności rand()i uniqid()nie są kryptograficznie bezpiecznymi generatorami liczb losowych . Zobacz odpowiedź Scotta na bezpieczną alternatywę.

Jeśli nie musisz być absolutnie wyjątkowy w czasie:

md5(uniqid(rand(), true))

W przeciwnym razie (pod warunkiem, że określiłeś już unikalny login dla swojego użytkownika):

md5(uniqid($your_user_login, true))

90
Obie metody nie gwarantują wyjątkowości - długość danych wejściowych funkcji md5 jest większa niż długość danych wyjściowych i zgodnie z en.wikipedia.org/wiki/Pigeonhole_principle kolizja jest gwarantowana. Z drugiej strony, im większa populacja opiera się na haszach, aby osiągnąć „unikalny” identyfikator, tym większe prawdopodobieństwo wystąpienia co najmniej jednego zderzenia (patrz en.wikipedia.org/wiki/Birthday_problem ). Prawdopodobieństwo może być niewielkie w przypadku większości rozwiązań, ale nadal istnieje.
Dariusz Walczak

12
To nie jest bezpieczna metoda generowania losowych wartości. Zobacz odpowiedź Scotta.
wieża

4
W przypadku potwierdzeń e-mail, które wkrótce wygasają, myślę, że niewielka możliwość, że jedna osoba może pewnego dnia potwierdzić, że e-mail innej osoby stanowi znikome ryzyko. Ale zawsze możesz sprawdzić, czy token już istnieje w bazie danych po jego utworzeniu i po prostu wybrać nowy, jeśli tak jest. Jednak czas spędzony na pisaniu tego fragmentu kodu jest prawdopodobnie zmarnowany, ponieważ najprawdopodobniej nigdy nie zostanie uruchomiony.
Andrew

Zauważ, że md5 zwraca wartości szesnastkowe, co oznacza, że ​​zestaw znaków jest ograniczony do [0–9] i [af].
Thijs Riezebeek

1
md5 może mieć kolizje, właśnie zrujnowałeś unikalną przewagę
użytkownik151496

507

Właśnie zastanawiałem się, jak rozwiązać ten sam problem, ale chcę również, aby moja funkcja utworzyła token, którego można również użyć do odzyskiwania hasła. Oznacza to, że muszę ograniczyć możliwość odgadnięcia tokena. Ponieważ uniqidjest oparty na czasie i według php.net „zwracana wartość niewiele różni się od microtime ()”, uniqidnie spełnia kryteriów. PHP zaleca używanie openssl_random_pseudo_bytes()zamiast tego do generowania bezpiecznych kryptograficznie tokenów.

Szybka, krótka i konkretna odpowiedź brzmi:

bin2hex(openssl_random_pseudo_bytes($bytes))

który wygeneruje losowy ciąg znaków alfanumerycznych o długości = $ bajtów * 2. Niestety ma to tylko alfabet [a-f][0-9], ale działa.


Poniżej znajduje się najsilniejsza funkcja, jaką mogę wykonać, która spełnia kryteria (Jest to zaimplementowana wersja odpowiedzi Erika).

function crypto_rand_secure($min, $max)
{
    $range = $max - $min;
    if ($range < 1) return $min; // not so random...
    $log = ceil(log($range, 2));
    $bytes = (int) ($log / 8) + 1; // length in bytes
    $bits = (int) $log + 1; // length in bits
    $filter = (int) (1 << $bits) - 1; // set all lower bits to 1
    do {
        $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
        $rnd = $rnd & $filter; // discard irrelevant bits
    } while ($rnd > $range);
    return $min + $rnd;
}

function getToken($length)
{
    $token = "";
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
    $codeAlphabet.= "0123456789";
    $max = strlen($codeAlphabet); // edited

    for ($i=0; $i < $length; $i++) {
        $token .= $codeAlphabet[crypto_rand_secure(0, $max-1)];
    }

    return $token;
}

crypto_rand_secure($min, $max)działa jako kropla zastępująca dla rand()lub mt_rand. Używa openssl_random_pseudo_bytes, aby pomóc utworzyć losową liczbę między $ min a $ max.

getToken($length)tworzy alfabet do użycia w tokenie, a następnie tworzy ciąg długości $length.

EDYCJA: Zaniedbałem cytować źródło - http://us1.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322

EDYCJA (PHP7): Wraz z wydaniem PHP7 biblioteka standardowa ma teraz dwie nowe funkcje, które mogą zastąpić / ulepszyć / uprościć powyższą funkcję crypto_rand_secure. random_bytes($length)irandom_int($min, $max)

http://php.net/manual/en/function.random-bytes.php

http://php.net/manual/en/function.random-int.php

Przykład:

function getToken($length){
    $token = "";
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
    $codeAlphabet.= "0123456789";
    $max = strlen($codeAlphabet);

    for ($i=0; $i < $length; $i++) {
        $token .= $codeAlphabet[random_int(0, $max-1)];
    }

    return $token;
}

2
Zgoda. Przechowywanie haseł w postaci zwykłego tekstu jest okropne! (Używam blowfish.) Ale po wygenerowaniu tokena pozwala jego właścicielowi zresetować hasło, więc token jest równoważny hasłu, dopóki jest ważny (i jest traktowany jako taki).
Scott

23
Hej, połączyłem Twój doskonały kod z wygodną funkcjonalnością metody Kohana Text :: random () i stworzyłem tę treść: gist.github.com/raveren/5555297
raveren

9
Doskonały! Testowałem to z 10 znakami jako długością. 100000 żetonów i nadal nie ma duplikatów!
Sharpless512,

5
Użyłem tego procesu i okazało się, że jest on bardzo wolny. Przy długości 36 upłynął limit czasu na serwerze deweloperskim. Przy długości 24 nadal zajęło to około 30 sekund. Nie jestem pewien, co zrobiłem źle, ale było to dla mnie zbyt wolne i wybrałem inne rozwiązanie.
Shane

5
Możesz także użyć base64_encodezamiast, bin2hexaby uzyskać krótszy ciąg z większym alfabetem.
erjiang

91

Zorientowana obiektowo wersja najlepiej ocenianego rozwiązania

Stworzyłem rozwiązanie obiektowe oparte na odpowiedzi Scotta :

<?php

namespace Utils;

/**
 * Class RandomStringGenerator
 * @package Utils
 *
 * Solution taken from here:
 * http://stackoverflow.com/a/13733588/1056679
 */
class RandomStringGenerator
{
    /** @var string */
    protected $alphabet;

    /** @var int */
    protected $alphabetLength;


    /**
     * @param string $alphabet
     */
    public function __construct($alphabet = '')
    {
        if ('' !== $alphabet) {
            $this->setAlphabet($alphabet);
        } else {
            $this->setAlphabet(
                  implode(range('a', 'z'))
                . implode(range('A', 'Z'))
                . implode(range(0, 9))
            );
        }
    }

    /**
     * @param string $alphabet
     */
    public function setAlphabet($alphabet)
    {
        $this->alphabet = $alphabet;
        $this->alphabetLength = strlen($alphabet);
    }

    /**
     * @param int $length
     * @return string
     */
    public function generate($length)
    {
        $token = '';

        for ($i = 0; $i < $length; $i++) {
            $randomKey = $this->getRandomInteger(0, $this->alphabetLength);
            $token .= $this->alphabet[$randomKey];
        }

        return $token;
    }

    /**
     * @param int $min
     * @param int $max
     * @return int
     */
    protected function getRandomInteger($min, $max)
    {
        $range = ($max - $min);

        if ($range < 0) {
            // Not so random...
            return $min;
        }

        $log = log($range, 2);

        // Length in bytes.
        $bytes = (int) ($log / 8) + 1;

        // Length in bits.
        $bits = (int) $log + 1;

        // Set all lower bits to 1.
        $filter = (int) (1 << $bits) - 1;

        do {
            $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));

            // Discard irrelevant bits.
            $rnd = $rnd & $filter;

        } while ($rnd >= $range);

        return ($min + $rnd);
    }
}

Stosowanie

<?php

use Utils\RandomStringGenerator;

// Create new instance of generator class.
$generator = new RandomStringGenerator;

// Set token length.
$tokenLength = 32;

// Call method to generate random string.
$token = $generator->generate($tokenLength);

Niestandardowy alfabet

W razie potrzeby możesz użyć niestandardowego alfabetu. Po prostu przekaż ciąg znaków z obsługiwanymi znakami do konstruktora lub setera:

<?php

$customAlphabet = '0123456789ABCDEF';

// Set initial alphabet.
$generator = new RandomStringGenerator($customAlphabet);

// Change alphabet whenever needed.
$generator->setAlphabet($customAlphabet);

Oto próbki wyjściowe

SRniGU2sRQb2K1ylXKnWwZr4HrtdRgrM
q1sRUjNq1K9rG905aneFzyD5IcqD4dlC
I0euIWffrURLKCCJZ5PQFcNUCto6cQfD
AKwPJMEM5ytgJyJyGqoD5FQwxv82YvMr
duoRF6gAawNOEQRICnOUNYmStWmOpEgS
sdHUkEn4565AJoTtkc8EqJ6cC4MLEHUx
eVywMdYXczuZmHaJ50nIVQjOidEVkVna
baJGt7cdLDbIxMctLsEBWgAw5BByP5V0
iqT0B2obq3oerbeXkDVLjZrrLheW4d8f
OUQYCny6tj2TYDlTuu1KsnUyaLkeObwa

Mam nadzieję, że to komuś pomoże. Twoje zdrowie!


Przepraszam, ale jak mam to uruchomić? Zrobiłem, $obj = new RandomStringGenerator;ale którą metodę powinienem wywołać? Dziękuję Ci.
sg552

@ sg552, powinieneś wywołać generatemetodę jak w powyższym przykładzie. Wystarczy podać liczbę całkowitą, aby określić długość wynikowego ciągu.
Slava Fomin II,

Dzięki, to działa dla mnie, ale Custom Alphabetnie zadziałało. Otrzymałem pusty sygnał wyjściowy, gdy echo. W każdym razie nie jestem nawet pewien, jaki jest pożytek z drugiego przykładu, Custom Alphabetwięc myślę, że pozostanę przy pierwszym przykładzie. Dzięki.
sg552

1
Fajna, ale dość przesadna w większości scenariuszy, chyba że twój projekt w dużej mierze opiera się na losowo generowanych kodach
dspacejs

1
tak fajnie, ale przesada, szczególnie biorąc pod uwagę, że jest to obecnie bardzo przestarzałe dla php 5.7
Andrew

39

Jestem spóźniony, ale jestem tutaj z kilkoma dobrymi danymi badawczymi opartymi na funkcjach dostarczonych przez odpowiedź Scotta . Tak więc skonfigurowałem kroplę Digital Ocean tylko na ten 5-dniowy automatyczny test i zapisałem wygenerowane unikalne ciągi w bazie danych MySQL.

Podczas tego okresu testowego użyłem 5 różnych długości (5, 10, 15, 20, 50) i dla każdej długości wstawiono +/- 0,5 miliona rekordów. Podczas mojego testu tylko 5 wygenerowało +/- 3K duplikatów z 0,5 miliona, a pozostałe długości nie wygenerowały żadnych duplikatów. Możemy więc powiedzieć, że jeśli użyjemy długości 15 lub więcej z funkcjami Scotta, możemy wygenerować wysoce niezawodne unikalne ciągi. Oto tabela z moimi danymi badawczymi:

wprowadź opis zdjęcia tutaj

Aktualizacja: Utworzyłem prostą aplikację Heroku przy użyciu tych funkcji, która zwraca token jako odpowiedź JSON. Dostęp do aplikacji można uzyskać na stronie https://uniquestrings.herokuapp.com/api/token?length=15

Mam nadzieję, że to pomoże.


33

Możesz użyć UUID (uniwersalnie unikalny identyfikator), można go użyć do dowolnego celu, od ciągu uwierzytelniającego użytkownika do identyfikatora transakcji płatniczej.

UUID to liczba 16-oktetowa (128-bitowa). W swojej postaci kanonicznej UUID jest reprezentowany przez 32 cyfry szesnastkowe, wyświetlane w pięciu grupach oddzielonych łącznikami, w postaci 8-4-4-4-12 dla łącznie 36 znaków (32 znaki alfanumeryczne i cztery łączniki).

function generate_uuid() {
    return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
        mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
        mt_rand( 0, 0xffff ),
        mt_rand( 0, 0x0C2f ) | 0x4000,
        mt_rand( 0, 0x3fff ) | 0x8000,
        mt_rand( 0, 0x2Aff ), mt_rand( 0, 0xffD3 ), mt_rand( 0, 0xff4B )
    );

}

// wywołanie funkcji

$transationID = generate_uuid();

niektóre przykładowe dane wyjściowe będą takie jak:

E302D66D-87E3-4450-8CB6-17531895BF14
22D288BC-7289-442B-BEEA-286777D559F2
51B4DE29-3B71-4FD2-9E6C-071703E1FF31
3777C8C6-9FF5-4C78-AAA2-08A47F555E81
54B91C72-2CF4-4501-A6E9-02A60DCBAE4C
60F75C7C-1AE3-417B-82C8-14D456542CD7
8DE0168D-01D3-4502-9E59-10D665CEBCB2

mam nadzieję, że pomoże komuś w przyszłości :)


Wygląda fantastycznie, dodano do mojej listy!
Mustafa Erdogan

32

Ta funkcja wygeneruje losowy klucz przy użyciu cyfr i liter:

function random_string($length) {
    $key = '';
    $keys = array_merge(range(0, 9), range('a', 'z'));

    for ($i = 0; $i < $length; $i++) {
        $key .= $keys[array_rand($keys)];
    }

    return $key;
}

echo random_string(50);

Przykładowe dane wyjściowe:

zsd16xzv3jsytnp87tk7ygv73k8zmr0ekh6ly7mxaeyeh46oe8

6
Po chwili dochodzisz do tych samych liczb
Sharpless512

1
To nie jest w pełni losowe, ponieważ nigdy nie będzie miało tego samego chacater więcej niż raz.
EricP,

16

Używam tego jednowarstwowego:

base64_encode(openssl_random_pseudo_bytes(3 * ($length >> 2)));

gdzie długość jest długością pożądanego ciągu (podzielny przez 4, w przeciwnym razie zostanie zaokrąglony w dół do najbliższej liczby podzielnej przez 4)


6
Nie zawsze zwraca tylko znaki alfanumeryczne. Może zawierać znaki takie jak==
user3459110,

1
Jeśli zostanie użyty w adresie URL, base64url_encodemoże być użyty zamiast tego, patrz tutaj: php.net/manual/en/function.base64-encode.php
Paul

9

Użyj poniższego kodu, aby wygenerować losową liczbę 11 znaków lub zmień liczbę zgodnie z wymaganiami.

$randomNum=substr(str_shuffle("0123456789abcdefghijklmnopqrstvwxyz"), 0, 11);

lub możemy użyć funkcji niestandardowej do wygenerowania liczby losowej

 function randomNumber($length){
     $numbers = range(0,9);
     shuffle($numbers);
     for($i = 0;$i < $length;$i++)
        $digits .= $numbers[$i];
     return $digits;
 }

 //generate random number
 $randomNum=randomNumber(11);

3
To nigdy nie może wygenerować ciągu „aaaaaaaaaaa” lub „aaaaabbbbbb”. Po prostu wybiera podciąg przypadkowej permutacji alfabetu. Łańcuch o długości 11 znaków ma tylko V (11,35) = 288 możliwych wartości. Nie używaj tego, jeśli oczekujesz, że łańcuchy będą unikalne!
kdojeteri

@Pping następnie zróbsubstr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstvwxyz', 36)), 0, 11);
Tim Hallman,

7
  1. Wygeneruj liczbę losową za pomocą swojego ulubionego generatora liczb losowych
  2. Pomnóż i podziel go, aby uzyskać liczbę odpowiadającą liczbie znaków w alfabecie kodu
  3. Uzyskaj pozycję o tym indeksie w swoim alfabecie kodu.
  4. Powtarzaj od 1), aż uzyskasz żądaną długość

np. (w pseudo kodzie)

int myInt = random(0, numcharacters)
char[] codealphabet = 'ABCDEF12345'
char random = codealphabet[i]
repeat until long enough

Teoretycznie nie może to wygenerować tego samego ciągu więcej niż jeden raz?
frezq

4

Oto najlepszy unikalny generator identyfikatorów dla Ciebie. zrobione przeze mnie.

<?php
$d=date ("d");
$m=date ("m");
$y=date ("Y");
$t=time();
$dmt=$d+$m+$y+$t;    
$ran= rand(0,10000000);
$dmtran= $dmt+$ran;
$un=  uniqid();
$dmtun = $dmt.$un;
$mdun = md5($dmtran.$un);
$sort=substr($mdun, 16); // if you want sort length code.

echo $mdun;
?>

możesz powtórzyć dowolne „var” dla swojego identyfikatora, jak chcesz. ale $ mdun jest lepszy, możesz zamienić md5 na sha1, aby uzyskać lepszy kod, ale będzie on bardzo długi, co może nie być potrzebne.

Dziękuję Ci.


7
W takim przypadku losowość jest gwarantowana przez losowy kod, prawda?
Daniel Kucal

3
tak, jest to rodzaj „losowy”, ponieważ jest to niestandardowy, niejasny kod. Utrudnia to przewidywanie ... ale tak naprawdę nie wykorzystuje niepewnych części do generowania liczb losowych. więc technicznie wynik nie jest losowy ani bezpieczny.
Philipp

4

Do naprawdę losowych ciągów możesz użyć

<?php

echo md5(microtime(true).mt_Rand());

wyjścia:

40a29479ec808ad4bcff288a48a25d5c

więc nawet jeśli spróbujesz wygenerować ciąg wiele razy dokładnie w tym samym czasie, otrzymasz inną wydajność.


4

Podczas próby wygenerowania losowego hasła próbujesz:

  • Najpierw wygeneruj kryptograficznie bezpieczny zestaw losowych bajtów

  • Drugi polega na zamianie losowych bajtów w ciąg znaków do wydrukowania

Teraz istnieje wiele sposobów generowania losowych bajtów w php, takich jak:

$length = 32;

//PHP 7+
$bytes= random_bytes($length);

//PHP < 7
$bytes= openssl_random_pseudo_bytes($length);

Następnie chcesz zamienić te losowe bajty na ciąg znaków do wydrukowania:

Możesz użyć bin2hex :

$string = bin2hex($bytes);

lub base64_encode :

$string = base64_encode($bytes);

Pamiętaj jednak, że nie kontrolujesz długości łańcucha, jeśli używasz base64. Aby to zrobić, możesz użyć bin2hex, użycie 32 bajtów zamieni się w ciąg znaków o długości 64 znaków . Ale tak to będzie działać tylko w łańcuchu NAWET .

Zasadniczo możesz po prostu zrobić :

$length = 32;

if(PHP_VERSION>=7){
    $bytes= random_bytes($length);
}else{
    $bytes= openssl_random_pseudo_bytes($length);
} 

$string = bin2hex($bytes);

3

Oto czego używam:

md5(time() . rand());    
// Creates something like 0c947c3b1047334f5bb8a3b7adc1d97b

2
function random_string($length = 8) {
    $alphabets = range('A','Z');
    $numbers = range('0','9');
    $additional_characters = array('_','=');
    $final_array = array_merge($alphabets,$numbers,$additional_characters);
       while($length--) {
      $key = array_rand($final_array);

      $password .= $final_array[$key];
                        }
  if (preg_match('/[A-Za-z0-9]/', $password))
    {
     return $password;
    }else{
    return  random_string();
    }

 }

2

Jest to prosta funkcja, która pozwala generować losowe ciągi znaków zawierające litery i cyfry (alfanumeryczne). Możesz także ograniczyć długość łańcucha. Te losowe ciągi znaków mogą być wykorzystywane do różnych celów, w tym: Kod polecający, Kod promocyjny, Kod kuponu. Funkcja opiera się na następujących funkcjach PHP: base_convert, sha1, uniqid, mt_rand

function random_code($length)
{
  return substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, $length);
}

echo random_code(6);

/*sample output
* a7d9e8
* 3klo93
*/

1

po przeczytaniu poprzednich przykładów wpadłem na to:

protected static $nonce_length = 32;

public static function getNonce()
{
    $chars = array();
    for ($i = 0; $i < 10; $i++)
        $chars = array_merge($chars, range(0, 9), range('A', 'Z'));
    shuffle($chars);
    $start = mt_rand(0, count($chars) - self::$nonce_length);
    return substr(join('', $chars), $start, self::$nonce_length);
}

Powielam 10 razy tablicę [0-9, AZ] i tasuję elementy, po tym jak otrzymam losowy punkt początkowy dla substr (), aby być bardziej „kreatywnym” :) możesz dodać [az] i inne elementy do tablicy, powielić mniej więcej bądź bardziej kreatywny ode mnie


1

Podczas korzystania z linków weryfikacyjnych lubię używać kluczy skrótów. Poleciłbym użycie mikrotimu i zaszyfrowanie tego przy użyciu MD5, ponieważ nie powinno być żadnego powodu, dla którego klucze powinny być takie same, ponieważ hashy oparte na mikrotimie.

  1. $key = md5(rand());
  2. $key = md5(microtime());

1
<?php
function generateRandomString($length = 11) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;

}

?>

powyższa funkcja wygeneruje losowy ciąg znaków o długości 11 znaków.


1

Jeśli chcesz wygenerować unikalny ciąg znaków w PHP, spróbuj wykonać następujące czynności.

md5(uniqid().mt_rand());

W tym,

uniqid()- Wygeneruje unikalny ciąg. Ta funkcja zwraca unikalny identyfikator oparty na sygnaturze czasowej jako ciąg.

mt_rand() - Wygeneruj losową liczbę.

md5() - Wygeneruje ciąg skrótu.


0

Scott, tak, bardzo piszesz i dobre rozwiązanie! Dzięki.

Muszę również wygenerować unikalny token API dla każdego użytkownika. Oto moje podejście, wykorzystałem informacje o użytkowniku (identyfikator użytkownika i nazwa użytkownika):

public function generateUniqueToken($userid, $username){

        $rand = mt_rand(100,999);
    $md5 = md5($userid.'!(&^ 532567_465 ///'.$username);

    $md53 = substr($md5,0,3);
    $md5_remaining = substr($md5,3);

    $md5 = $md53. $rand. $userid. $md5_remaining;

    return $md5;
}

Proszę spojrzeć i dać mi znać, czy mogę coś ulepszyć. Dzięki


0

Oto, czego używam w jednym z moich projektów, działa świetnie i generuje UNIKALNY RÓŻOWY TOKEN :

$timestampz=time();

function generateRandomString($length = 60) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;
}


$tokenparta = generateRandomString();


$token = $timestampz*3 . $tokenparta;

echo $token;

Pamiętaj, że pomnożyłem znacznik czasu przez trzy, aby wprowadzić zamieszanie dla każdego, kto może zastanawiać się, jak wygenerowany jest ten token;)

Mam nadzieję, że to pomoże :)


1
„Pamiętaj, że pomnożyłem znacznik czasu przez trzy, aby wprowadzić zamieszanie dla każdego, kto może zastanawiać się, w jaki sposób generowany jest ten token” Brzmi jak bezpieczeństwo poprzez zaciemnianie stosoverflow.com/questions/533965/…
Harry

Nie jest to „zabezpieczenie przez zaciemnianie”, ponieważ znacznik czasu jest następnie dodawany do losowego ciągu, który został wygenerowany, i to jest właśnie ostatni ciąg, który zwracamy;)
Kaszoni Ferencz


0

możemy użyć tego dwóch wierszy kodu do wygenerowania unikalnego ciągu, który przetestowano około 10000000 razy iteracji

  $sffledStr= str_shuffle('abscdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-+');
    $uniqueString = md5(time().$sffledStr);

0

Zawsze używam tej funkcji do generowania niestandardowego losowego ciągu alfanumerycznego ... Mam nadzieję, że ta pomoc.

<?php
  function random_alphanumeric($length) {
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345689';
    $my_string = '';
    for ($i = 0; $i < $length; $i++) {
      $pos = mt_rand(0, strlen($chars) -1);
      $my_string .= substr($chars, $pos, 1);
    }
    return $my_string;
  }
  echo random_alphanumeric(50); // 50 characters
?>

Generuje na przykład: Y1FypdjVbFCFK6Gh9FDJpe6dciwJEfV6MQGpJqAfuijaYSZ86g

Jeśli chcesz porównać z innym ciągiem, aby upewnić się, że jest to unikalna sekwencja, możesz użyć tej sztuczki ...

$string_1 = random_alphanumeric(50);
$string_2 = random_alphanumeric(50);
while ($string_1 == $string_2) {
  $string_1 = random_alphanumeric(50);
  $string_2 = random_alphanumeric(50);
  if ($string_1 != $string_2) {
     break;
  }
}
echo $string_1;
echo "<br>\n";
echo $string_2;

generuje dwa unikalne ciągi:

qsBDs4JOoVRfFxyLAOGECYIsWvpcpMzAO9pypwxsqPKeAmYLOi

Ti3kE1WfGgTNxQVXtbNNbhhvvapnaUfGMVJecHkUjHbuCb85pF

Mam nadzieję, że tego właśnie szukasz ...


0

Prostym rozwiązaniem jest konwersja podstawy 64 na alfanumeryczną poprzez odrzucenie znaków innych niż alfanumeryczne.

Ten używa random_bytes () dla kryptograficznie bezpiecznego wyniku.

function random_alphanumeric(int $length): string
{
    $result='';
    do
    {
        //Base 64 produces 4 characters for each 3 bytes, so most times this will give enough bytes in a single pass
        $bytes=random_bytes(($length+3-strlen($result))*2);
        //Discard non-alhpanumeric characters
        $result.=str_replace(['/','+','='],['','',''],base64_encode($bytes));
        //Keep adding characters until the string is long enough
        //Add a few extra because the last 2 or 3 characters of a base 64 string tend to be less diverse
    }while(strlen($result)<$length+3);
    return substr($result,0,$length);
}


-1

Uważam, że problemem wszystkich istniejących pomysłów jest to, że są one prawdopodobnie wyjątkowe, ale nie na pewno wyjątkowe (jak wskazano w odpowiedzi Dariusza Walczaka na loletech). Mam rozwiązanie, które jest naprawdę wyjątkowe. Wymaga, aby twój skrypt miał jakąś pamięć. Dla mnie jest to baza danych SQL. Możesz także po prostu zapisać gdzieś plik. Istnieją dwie implementacje:

Pierwsza metoda: mają DWA pola zamiast 1, które zapewniają wyjątkowość. Pierwsze pole to numer identyfikacyjny, który nie jest losowy, ale jest unikalny (pierwszy identyfikator to 1, drugi 2 ...). Jeśli używasz SQL, po prostu zdefiniuj pole ID za pomocą właściwości AUTO_INCREMENT. Drugie pole nie jest unikalne, ale jest losowe. Można to wygenerować za pomocą dowolnej innej techniki, o której wspominali ludzie. Pomysł Scotta był dobry, ale md5 jest wygodny i prawdopodobnie wystarczający do większości celów:

$random_token = md5($_SERVER['HTTP_USER_AGENT'] . time());

Druga metoda: Zasadniczo ten sam pomysł, ale początkowo wybierz maksymalną liczbę ciągów, które kiedykolwiek zostaną wygenerowane. To może być naprawdę duża liczba jak bilion. Następnie zrób to samo, wygeneruj identyfikator, ale zeruj go, aby wszystkie identyfikatory miały tę samą liczbę cyfr. Następnie po prostu połącz identyfikator z losowym ciągiem. Dla większości celów będzie wystarczająco losowy, ale sekcja ID zapewni, że będzie on również unikalny.


-1

Możesz użyć tego kodu, mam nadzieję, że będzie on dla ciebie pomocny.

function rand_code($len)
{
 $min_lenght= 0;
 $max_lenght = 100;
 $bigL = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 $smallL = "abcdefghijklmnopqrstuvwxyz";
 $number = "0123456789";
 $bigB = str_shuffle($bigL);
 $smallS = str_shuffle($smallL);
 $numberS = str_shuffle($number);
 $subA = substr($bigB,0,5);
 $subB = substr($bigB,6,5);
 $subC = substr($bigB,10,5);
 $subD = substr($smallS,0,5);
 $subE = substr($smallS,6,5);
 $subF = substr($smallS,10,5);
 $subG = substr($numberS,0,5);
 $subH = substr($numberS,6,5);
 $subI = substr($numberS,10,5);
 $RandCode1 = str_shuffle($subA.$subD.$subB.$subF.$subC.$subE);
 $RandCode2 = str_shuffle($RandCode1);
 $RandCode = $RandCode1.$RandCode2;
 if ($len>$min_lenght && $len<$max_lenght)
 {
 $CodeEX = substr($RandCode,0,$len);
 }
 else
 {
 $CodeEX = $RandCode;
 }
 return $CodeEX;
}

Szczegóły na temat generatora kodów losowych w PHP


-2

Uproszczenie powyższego kodu Scotts poprzez usunięcie niepotrzebnych pętli, które bardzo spowalnia i nie czyni go bardziej bezpiecznym niż wywoływanie openssl_random_pseudo_bytes tylko raz

function crypto_rand_secure($min, $max)
{
 $range = $max - $min;
 if ($range < 1) return $min; // not so random...
 $log = ceil(log($range, 2));
 $bytes = (int) ($log / 8) + 1; // length in bytes
 $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
 return $min + $rnd%$range;
}

function getToken($length)
{
 return bin2hex(openssl_random_pseudo_bytes($length)
}

Niestety nie mogę się z tobą zgodzić, że jest to odpowiednie uproszczenie funkcji crypto_rand_secure. Pętla jest niezbędna, aby uniknąć błędu modulo, który występuje, gdy weźmiesz wynik losowo wygenerowanej liczby, a następnie zmodyfikujesz ją o liczbę, która dzieli zakres. en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Modulo_bias . Używając pętli do wyrzucania dowolnych liczb spoza zakresu i wybierając nową liczbę, pozwala uniknąć tego błędu. stackoverflow.com/questions/10984974/…
Scott,

@Scott, ten post dotyczy rand (). Jednak w tym przypadku jest już zajęty przez openssl_random_pseudo_bytes, więc zapętlenie jest niepotrzebne.
mabel

1
gist.github.com/anonymous/87e3ae6fd3320447f46b973e75c2ea85 - Uruchom ten skrypt. Przekonasz się, że rozkład wyników nie jest przypadkowy. Liczby od 0 do 55 występują częściej niż liczby od 56 do 100. opensslnie powoduje tego, to z powodu błędu modulo w instrukcji return. 100 (zakres) nie dzieli równomiernie 255 (1 bajt) i powoduje te wyniki. Moim największym problemem z twoją odpowiedzią jest to, że stwierdzasz, że funkcja jest tak bezpieczna jak używanie pętli, co jest fałszem. Twoja implementacja crypto_rand_secure nie jest kryptograficznie bezpieczna i wprowadza w błąd.
Scott

@Scott, dygresujemy tutaj, nie chodzi o ostatnią instrukcję zwrotną, można ją również stopniowo obliczać na podstawie wartości zwracanej openssl_random_pseudo_bytes bez użycia modulo. Chodzi mi o to, że pętla jest niepotrzebna, gdy openssl_random_pseudo_bytes zwraca losowe bajty. Tworząc pętlę, nie czynisz jej bardziej bezpiecznym, tylko spowalniasz.
mabel

2
Ta odpowiedź propaguje złe informacje. Masz rację, że pętla nie czyni opensslbezpieczniejszej, ale co ważniejsze, nie czyni jej mniej bezpieczną, ta odpowiedź robi. Powyższy kod przyjmuje całkowicie dobrą liczbę losową i zmienia ją, przesuwając w kierunku niższych liczb. Jeśli umieścisz zastrzeżenie w odpowiedzi, stwierdzając, że jest ono szybsze (poprzez usunięcie pętli), ale nie jest to CSPRNG, rozwiązałoby to ten problem. Z miłości do kryptografii proszę poinformować użytkowników, że wyniki tej funkcji mogą być stronnicze i nie jest równoważnym rozwiązaniem. Pętla jest nie tylko po to, aby cię drażnić.
Scott
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.