Generator losowych ciągów PHP


814

Próbuję utworzyć losowy ciąg w PHP i nie otrzymuję absolutnie żadnych danych wyjściowych z tym:

<?php
    function RandomString()
    {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $randstring = '';
        for ($i = 0; $i < 10; $i++) {
            $randstring = $characters[rand(0, strlen($characters))];
        }
        return $randstring;
    }

    RandomString();
    echo $randstring;

Co ja robię źle?


241
Moje jedno liniowe rozwiązanie do generowania krótkiego ciągu to substr (md5 (rand ()), 0, 7); powodzenia ...
tasmaniski

5
@tasmaniski .. Twoje rozwiązanie jest w porządku .. Ale jest mniej losowe! W twoim przykładzie liczba losowych ciągów, które można wygenerować, jest ograniczona wielkością całkowitą. (2 ^ 32) maksymalnie .. W przypadku innego rozwiązania możesz wygenerować (62 ^ 8) .. W przypadku, gdy chcę większych ciągów, wtedy liczba różnych ciągów pozostaje na maksimum 2 ^ 32, ale w inne rozwiązanie wzrasta do (62 ^ n) ..
Manu

9
Zapomniałeś dodać każdego nowo wygenerowanego znaku do łańcucha. Po prostu go nadpisujesz. Powinny być $ randstring. = $ Znaki ..
Spock

3
@CaptainLightning Czy możesz zamienić zaakceptowaną odpowiedź na jedną z bardziej bezpiecznych? :)
Scott Arciszewski,

2
strlen($characters)=> strlen($characters) - 1- długość łańcucha zaczyna się od 1
Zippp 24.04.17

Odpowiedzi:


1393

Aby odpowiedzieć konkretnie na to pytanie, dwa problemy:

  1. $randstring nie jest objęty zakresem, gdy go echo.
  2. Postacie nie łączą się w pętli.

Oto fragment kodu z poprawkami:

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

Wypisz losowy ciąg za pomocą wywołania poniżej:

// Echo the random string.
// Optionally, you can give it a desired string length.
echo generateRandomString();

Należy pamiętać, że generuje to przewidywalne losowe ciągi. Jeśli chcesz utworzyć bezpieczne tokeny, zapoznaj się z tą odpowiedzią .


34
@FranciscoPresencia, lepiej „zmarnować” dodatkową zmienną, jak wywołać metodę w warunku porównania pętli.
Rico Sonntag,

200
Cała ta praca, dlaczego nie coś takiego substr(str_shuffle(MD5(microtime())), 0, 10);?
SpYk3HH

4
Dzięki za kod, ale zmień rand()na mt_rand(). Kiedyś metodę i przeżył mnóstwo kolizji z nazwami.
Nate

5
@FranciscoPresencia, czy masz pojęcie, jak przerażająco to jest nieefektywne? Sprawdzasz długość ciągu dwa razy na iterację! Strlen wewnątrz pętli powinien być buforowany w zmiennej przed wejściem do pętli.
developerbmw

4
To nie jest dobre rozwiązanie. Ciągi, które to generuje, będą przewidywalne. :(
Scott Arciszewski

370

Uwaga: str_shuffle()zastosowania wewnętrzne rand(), które nie są odpowiednie do celów kryptograficznych (np. Generowanie losowych haseł). Zamiast tego potrzebujesz bezpiecznego generatora liczb losowych . Nie pozwala również na powtarzanie się znaków.

Jeszcze jeden sposób.

AKTUALIZACJA (teraz generuje dowolną długość łańcucha):

function generateRandomString($length = 10) {
    return substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,$length);
}

echo  generateRandomString();  // OR: generateRandomString(24)

Otóż ​​to. :)


64
+1 za najkrótszą odpowiedź :). Ale nie najlepsza odpowiedź dla każdego przypadku użycia. Ten kod wyświetli ciągi, w których każdy znak nie pojawi się więcej niż jeden raz (co osłabia go w przypadku ataków typu brute force) i nie wypisze niczego dłuższego niż 62 znaki.
David

17
Nie rób tego, jest bardzo słaby. Im dłużej tworzysz losowy ciąg, tym będzie on słabszy.
Abhi Beckert

23
Może być słabo, ale jest to szybkie i łatwe. W zależności od przypadku użycia jest w porządku - użyłem go, ponieważ nie potrzebowałem bezpieczeństwa ani siły; tylko szybki los. Piszę test jednostkowy, a to daje mi odpowiednio losowy wkład do przetestowania.
SDC,

23
@FranciscoPresencia powodem, dla którego nie jest bezpieczny, jest to, że nigdy nie używa tego samego znaku dwa razy. To czyni go strasznym generatorem haseł. Proszę, przestańcie głosować w tej sprawie, to jest całkowicie niepewne, nigdy nie wolno jej używać. Gdy hasło się wydłuża, liczba znaków, które musisz przetestować brutalnie, zmniejsza się, ponieważ nie zawracasz sobie głowy testowaniem wcześniej używanych znaków.
Abhi Beckert,

8
@FranciscoPresencia: Popieram twoje komentarze na temat unikania używania tego do losowych haseł. Nie zgadzam się jednak, że ta odpowiedź nie powinna być jednoznaczna. Mam tę opcję dla plus-one, ponieważ jest to skuteczne jedno-liniowe rozwiązanie do generowania losowych ciągów (oryginalny temat tego pytania).
prawy

331

Istnieje wiele odpowiedzi na to pytanie, ale żadna z nich nie wykorzystuje kryptograficznie bezpiecznego generatora liczb pseudolosowych (CSPRNG).

Prostą, bezpieczną i poprawną odpowiedzią jest użycie RandomLib i nie wymyślanie koła na nowo.

Dla tych z was, którzy nalegają na wymyślenie własnego rozwiązania, PHP 7.0.0 zapewni random_int()w tym celu; jeśli nadal korzystasz z PHP 5.x, napisaliśmy polifill dla PHP 5random_int() , abyś mógł korzystać z nowego API nawet przed uaktualnieniem do PHP 7.

Bezpieczne generowanie losowych liczb całkowitych w PHP nie jest łatwym zadaniem. Zawsze powinieneś skonsultować się z ekspertami w dziedzinie kryptografii StackExchange przed wdrożeniem domowego algorytmu w produkcji.

Dzięki bezpiecznemu generatorowi liczb całkowitych generowanie losowego ciągu za pomocą CSPRNG jest spacerkiem po parku.

Tworzenie bezpiecznego, losowego ciągu

/**
 * Generate a random string, using a cryptographically secure 
 * pseudorandom number generator (random_int)
 *
 * This function uses type hints now (PHP 7+ only), but it was originally
 * written for PHP 5 as well.
 * 
 * For PHP 7, random_int is a PHP core function
 * For PHP 5.x, depends on https://github.com/paragonie/random_compat
 * 
 * @param int $length      How many characters do we want?
 * @param string $keyspace A string of all possible characters
 *                         to select from
 * @return string
 */
function random_str(
    int $length = 64,
    string $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
): string {
    if ($length < 1) {
        throw new \RangeException("Length must be a positive integer");
    }
    $pieces = [];
    $max = mb_strlen($keyspace, '8bit') - 1;
    for ($i = 0; $i < $length; ++$i) {
        $pieces []= $keyspace[random_int(0, $max)];
    }
    return implode('', $pieces);
}

Zastosowanie :

$a = random_str(32);
$b = random_str(8, 'abcdefghijklmnopqrstuvwxyz');
$c = random_str();

Demo : https://3v4l.org/IMJGF (Zignoruj ​​awarie PHP 5; wymaga random_compat)


3
Na początku funkcji dodaj $keyspace = str_shuffle($keyspace );dla większego bezpieczeństwa
Jevgenij Dmitrijev

13
Co rozumiesz przez „dla większego bezpieczeństwa”? Używamy już bezpiecznego generatora liczb losowych.
Scott Arciszewski

5
@JGEstiot Tworzenie bezpiecznie losowych ciągów wymaga kryptograficznie bezpiecznej losowości. Ktoś, kto szuka „sposobu generowania losowych ciągów w PHP”, lepiej służy bezpieczna odpowiedź niż niepewna odpowiedź.
Scott Arciszewski

1
@ Scott Arciszewski Nie musisz tworzyć kryptograficznie losowych ciągów za każdym razem, gdy tworzysz losowe ciągi. Pytanie dotyczyło tworzenia losowych ciągów i nie ma to nic wspólnego z bezpieczeństwem. Zakładasz, że łańcuch będzie używany w kontekście wrażliwym na bezpieczeństwo i dodajesz warstwę złożoności, która odstrasza od sedna pytania.
JG Estiot

45
Używanie random_int()zamiast rand()lub mt_rand()nie dodaje złożoności programistom. Jednocześnie zapewnia im większe bezpieczeństwo. Ludzie, którzy przychodzą do StackOverflow w poszukiwaniu szybkich rozwiązań, mogą nie wiedzieć, czy budowana przez nich rzecz musi być bezpieczna, czy nie. Jeśli udzielimy im domyślnie bezpiecznych odpowiedzi, stworzą bezpieczniejszy Internet, nawet jeśli z ich perspektywy jest to całkowicie przypadkowe. Dlaczego miałbyś sprzeciwić się temu celowi, jest dla mnie tajemnicą.
Scott Arciszewski,

155

Spowoduje to utworzenie ciągu szesnastkowego o długości 20 znaków:

$string = bin2hex(openssl_random_pseudo_bytes(10)); // 20 chars

W PHP 7 ( random_bytes () ):

$string = base64_encode(random_bytes(10)); // ~14 characters, includes /=+
// or
$string = substr(str_replace(['+', '/', '='], '', base64_encode(random_bytes(32))), 0, 32); // 32 characters, without /=+
// or
$string = bin2hex(random_bytes(10)); // 20 characters, only 0-9a-f

Zauważ, że openssl_random_pseudo_bytes()nie używał silnego algorytmu kryptograficznego aż do php 5.6. Powiązany błąd: bugs.php.net/bug.php?id=70014
acidtv 08.08.16

Zauważ też, że najmniejszy ciąg, który może wykonać, ma długość 2. Jeśli przekażesz bajt o długości 1 lub mniejszej openssl_random_pseudo_bytes(), nic nie otrzymasz. Zauważ też, że podczas używania, bin2hex(openssl_random_pseudo_bytes($length / 2))ponieważ pracujesz z liczbami całkowitymi, automatycznie usunie to modulo i użyje następnej najniższej wielokrotności 2. Tak więc, $length = 19wygeneruje ciąg długości 18.
Nathan F.

Wniosek do wykorzystania go jako zawartości pliku, który można otworzyć za pomocą fgets($fp, 1024)i każdy edytor plików, który ma problemy z bardzo długich linii: function string_rand($len, $split="\n") { return substr(chunk_split(bin2hex(openssl_random_pseudo_bytes(ceil($len / 2))), 1023, $split), 0, $len); }Zestaw $splitdo nullczy powinien wrócić do jednego-liner. Dzięki temu możesz używać go w obu przypadkach.
mgutt

Naprawdę podoba mi się rozwiązanie random_bytes dla PHP 7, ale jeśli potrzebujesz, aby ciąg znaków zawierał pewną liczbę znaków, czy coś takiego działałoby? $string = substr(base64_encode(random_bytes($size)), 0, $size);
Programster

Jest to absolutnie bez wątpienia najlepsze rozwiązanie. Zajmuje bardzo mało miejsca i jest bardzo łatwy do zrozumienia.
Matthew Campbell,

92

@tasmaniski: twoja odpowiedź zadziałała dla mnie. Miałem ten sam problem i sugerowałbym go tym, którzy kiedykolwiek szukają tej samej odpowiedzi. Oto z @tasmaniski:

<?php 
    $random = substr(md5(mt_rand()), 0, 7);
    echo $random;
?>

Oto film z YouTube pokazujący, jak utworzyć losową liczbę


6
jeśli ciąg jest oparty tylko na losowej liczbie całkowitej, dlaczego po prostu nie użyć losowej liczby całkowitej? ich stóg siana nie zagłębia się przez haszowanie go ... a przez odcięcie twojego hasza zniszczysz małą entropię, od której musiałeś zacząć.
The Surrican,

4
Pamiętaj, md5że spowoduje to ograniczenie do 30 znaków i zawsze małe litery.
fyrye

3
Ponadto rand () nie powinien być używany do kryptografii. Jeśli chcesz wygenerować łańcuch o dobrej jakości kryptograficznej, użyj openssl_random_pseudo_bytes .
mattkgross

md5(rand())oferuje tylko 2 ^ 32 możliwe wartości. Oznacza to, że po średnio 2 ^ 16 losowych ciągach będziesz oczekiwać, że jeden się powtórzy.
Scott Arciszewski,

2
Cóż ... założę się, że OP nie mówi o „bezpiecznie losowych ciągach”. To rozwiązanie jest kompaktowe, łatwe i ładne do zapamiętania, dla odpowiednich przypadków użycia. A jeśli musisz zająć się możliwymi kolizjami, dlaczego nie wstawić / dołączyć znacznik czasu do losowego ciągu? :)
Erenor Paz,

46

W zależności od aplikacji (chciałem generować hasła) możesz użyć

$string = base64_encode(openssl_random_pseudo_bytes(30));

Będąc base64, mogą zawierać =lub- żądane znaki. Możesz wygenerować dłuższy ciąg, a następnie filtrować i przycinać go, aby je usunąć.

openssl_random_pseudo_byteswydaje się być zalecanym sposobem na wygenerowanie odpowiedniej liczby losowej w php. Dlaczego randnie używa? /dev/randomNie wiem.


2
rand nie używa / dev / urandom, ponieważ jest on dostępny tylko w środowiskach takich jak posix i nie jest przenośny.
MacroMan

3
@MacroMan But openssl_random_pseudo_bytes() jest przenośny.
Ja͢ck

Jeśli chcesz usunąć dodatkowe znaki base64, spróbuj tego: gist.github.com/zyphlar/7217f566fc83a9633959
willbradley

3
To nie jest złe, ale radziłbym ostrożność, w jaki sposób odrzucasz niechciane postacie. Zobacz na przykład żądanie ściągnięcia na serwerze OAuth2 ligi ligi PHP .
Scott Arciszewski,

To jedna z najlepszych odpowiedzi. Szkoda, że ​​nie ma większego wsparcia. Polecam jednak edytowanie odpowiedzi, aby lepiej radzić sobie z niechcianymi postaciami.
jcuenod

28

Oto prosty jednowierszowy, który generuje prawdziwy losowy ciąg bez zapętlania poziomu skryptu lub korzystania z bibliotek OpenSSL.

echo substr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', mt_rand(1,10))), 1, 10);

Aby go rozbić, aby parametry były jasne

// Character List to Pick from
$chrList = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

// Minimum/Maximum times to repeat character List to seed from
$chrRepeatMin = 1; // Minimum times to repeat the seed string
$chrRepeatMax = 10; // Maximum times to repeat the seed string

// Length of Random String returned
$chrRandomLength = 10;

// The ONE LINE random command with the above variables.
echo substr(str_shuffle(str_repeat($chrList, mt_rand($chrRepeatMin,$chrRepeatMax))), 1, $chrRandomLength);

Ta metoda polega na losowym powtarzaniu listy znaków, a następnie tasuje połączony ciąg znaków i zwraca określoną liczbę znaków.

Możesz dalej losować to, losując długość zwracanego ciągu, zastępując $chrRandomLengthgo mt_rand(8, 15)(dla losowego ciągu od 8 do 15 znaków).


przykro mi to mówić, ale gdy jedna postać zostanie wybrana, prawdopodobieństwo jej ponownego wystąpienia nie jest tak wysokie, jak pozostałe postacie nadal pozostają w puli. tutaj nie ma prawdziwej przypadkowości ...
The Surrican

@TheSurrican - Byłbyś niepoprawny w tym stwierdzeniu. Wszystkie znaki mają równe prawdopodobieństwo przy użyciu tego algorytmu, a zatem są naprawdę losowe. Jest to zapewnione przez powtórzenie ciągu chrList $ chrRepeatMax, a magia naprawdę dzieje się w str_shuffle, który określa losowość.
Kraang Prime

Wszystkie znaki pojawią się tylko raz i jest bardzo podatny na zgadywanie
siły

@venimus To nieprawda. Ciąg znaków jest zduplikowany dla dowolnej liczby znaków (patrz $chrRepeatMaxi $chrRepeatMin) - więc ciąg znaków 10, może (mało prawdopodobne, ale możliwe) być „aaaaaaaaaa”.
Kraang Prime,

@SanuelJackson Przepraszam, że skomentowałem. Umieściłem komentarz na złą odpowiedź. Masz rację! Właściwie użyłem twojej „sztuczki”, ale nie użyłem mt_rand, ponieważ jest to bezużyteczne IMHO. Nie dodaje się do entropii. Właśnie użyłem const z maksymalną długością.
venimus

25
function generateRandomString($length = 15)
{
    return substr(sha1(rand()), 0, $length);
}

Tada!


Pamiętaj, sha1że spowoduje to ograniczenie do 40 znaków i zawsze małe litery.
fyrye

3
Łańcuchy sha1 nie są losowe, niektóre znaki będą występować częściej niż inne. Byłoby nierozsądnie używać tego w przypadkach, w których naprawdę chcesz losowości, jak w przypadku haseł.
Kit Sunde,

1
@KitSunde - tak, sha nie jest losowy, rand () jest losowy. I sha jest w porządku dla tego, co jest potrzebne tutaj. OP nie potrzebuje poziomu losowości w kryptografii.
Davor

@Uwaga rant()bycia losowym nie ma znaczenia, gdy sha nie jest równomiernie rozłożona. Jeśli wybierzesz losowo z nierównej dystrybucji, otrzymasz dokładnie taką samą nierównomierną dystrybucję. Podkreślam, że nie jest to przypadkowość „poziomu kryptograficznego”, gdyby tak było, nie powinieneś używać rand()żadnego z nich. Wyrywanie z równomiernego rozkładu, jak w zaakceptowanej odpowiedzi, wymaga minimalnego wysiłku i jest tak losowe, jak rand (), co jest rozsądne.
Kit Sunde

@KitSunde - na końcu nie ma dosłownie żadnej różnicy. To jest dokładnie definicja nadinżynierii i złocenia.
Davor,

24

Lepszym sposobem na wdrożenie tej funkcji jest:

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

    $key = "";
    for($i=0; $i < $length; $i++) {
        $key .= $keys[mt_rand(0, count($keys) - 1)];
    }
    return $key;
}

echo RandomString(20);

mt_randjest bardziej losowy zgodnie z tym i tym w PHP 7. randFunkcja jest aliasem mt_rand.


1
Uwaga: mt_randnie generuje bezpiecznych kryptograficznie wartości. Do tego należy użyć PHP7 random_intlub random_bytes.
jchook

18

$randstringzakres funkcji nie jest taki sam jak zakres, w którym go wywołujesz. Musisz przypisać wartość zwracaną do zmiennej.

$randstring = RandomString();
echo $randstring;

Lub po prostu echo zwracanej wartości:

echo RandomString();

Również w swojej funkcji masz mały błąd. W pętli for należy użyć, .=aby każdy znak był dołączany do ciągu. Korzystając z niego =, zastępujesz go każdą nową postacią zamiast dodawać.

$randstring .= $characters[rand(0, strlen($characters))];

14

Najpierw określ alfabet, którego chcesz użyć:

$alphanum = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$special  = '~!@#$%^&*(){}[],./?';
$alphabet = $alphanum . $special;

Następnie użyj openssl_random_pseudo_bytes()do wygenerowania odpowiednich danych losowych:

$len = 12; // length of password
$random = openssl_random_pseudo_bytes($len);

Wreszcie, wykorzystujesz te losowe dane, aby utworzyć hasło. Ponieważ każdy znak $randommoże być chr(0)do chr(255), kod używa reszty po podzieleniu jego wartości porządkowej, $alphabet_lengthaby upewnić się, że wybierane są tylko znaki z alfabetu (pamiętaj, że w ten sposób wpływa to na losowość):

$alphabet_length = strlen($alphabet);
$password = '';
for ($i = 0; $i < $len; ++$i) {
    $password .= $alphabet[ord($random[$i]) % $alphabet_length];
}

Alternatywnie i ogólnie lepiej jest użyć RandomLib i SecurityLib :

use SecurityLib\Strength;

$factory = new RandomLib\Factory;
$generator = $factory->getGenerator(new Strength(Strength::MEDIUM));

$password = $generator->generateString(12, $alphabet);

Zastosowanie operatora modulo %spowoduje stronnicze wyjście. Jednak silne +1 dla RandomLib. Nie wymyślaj koła ponownie.
Scott Arciszewski,

1
Tak, nowa funkcja random_int () jest ładna: D
Ja͢ck

11

Krótkie metody ..

Oto kilka najkrótszych metod generowania losowego ciągu

<?php
echo $my_rand_strng = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), -15); 

echo substr(md5(rand()), 0, 7);

echo str_shuffle(MD5(microtime()));
?>

10

Testowałem tam wydajność najpopularniejszych funkcji, czas potrzebny do wygenerowania 1 000 000 ciągów 32 symboli na moim urządzeniu to:

2.5 $s = substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,32);
1.9 $s = base64_encode(openssl_random_pseudo_bytes(24));
1.68 $s = bin2hex(openssl_random_pseudo_bytes(16));
0.63 $s = base64_encode(random_bytes(24));
0.62 $s = bin2hex(random_bytes(16));
0.37 $s = substr(md5(rand()), 0, 32);
0.37 $s = substr(md5(mt_rand()), 0, 32);

Należy pamiętać, że nie jest ważne, jak naprawdę to było, ale które jest wolniejsze, a które jest szybsze, dzięki czemu można wybrać zgodnie z wymaganiami, w tym gotowość do kryptografii itp.

substr () wokół MD5 został dodany ze względu na dokładność, jeśli potrzebujesz łańcucha, który jest krótszy niż 32 symbole.

W odpowiedzi: ciąg nie został połączony, ale nadpisany, a wynik funkcji nie został zapisany.


Myślę, że to najlepsza odpowiedź. Dzięki!
NSukonny

10

PHP 7+ Generuj kryptograficznie bezpieczne losowe bajty za pomocą funkcji random_bytes .

$bytes = random_bytes(16);
echo bin2hex($bytes);

Możliwe wyjście

da821217e61e33ed4b2dd96f8439056c


PHP 5.3+ Generuj pseudolosowe bajty za pomocą funkcji openssl_random_pseudo_bytes .

$bytes = openssl_random_pseudo_bytes(16);
echo bin2hex($bytes);

Możliwe wyjście

e2d1254506fbb6cd842cd640333214ad


Najlepszy przypadek użycia może być

function getRandomBytes($length = 16)
{
    if (function_exists('random_bytes')) {
        $bytes = random_bytes($length / 2);
    } else {
        $bytes = openssl_random_pseudo_bytes($length / 2);
    }
    return bin2hex($bytes);
}
echo getRandomBytes();

Możliwe wyjście

ba8cc342bdf91143


To nie wygeneruje ciągu o podanej długości
Timberman

@ Timberman wygeneruje teraz dokładną długość.
Madan Sapkota

9

Jednym bardzo szybkim sposobem jest zrobienie czegoś takiego:

substr(md5(rand()),0,10);

To wygeneruje losowy ciąg o długości 10 znaków. Oczywiście, niektórzy mogą powiedzieć, że jest nieco bardziej obciążony po stronie obliczeniowej, ale obecnie procesory są zoptymalizowane do szybkiego uruchamiania algorytmu md5 lub sha256. I oczywiście, jeśli rand()funkcja zwróci tę samą wartość, wynik będzie taki sam, z szansą 1/32767 na bycie takim samym. Jeśli problemem są zabezpieczenia, po prostu zmień rand()namt_rand()


7
function rndStr($len = 64) {
     $randomData = file_get_contents('/dev/urandom', false, null, 0, $len) . uniqid(mt_rand(), true);
     $str = substr(str_replace(array('/','=','+'),'', base64_encode($randomData)),0,$len);
    return $str;
}

4
To nie jest przenośne; jeśli spróbujesz uruchomić to w dowolnym środowisku innym niż posix, spowoduje to błąd krytyczny.
Bryan Agee

7

Ten został pobrany ze źródeł administratora :

/** Get a random string
* @return string 32 hexadecimal characters
*/
function rand_string() {
    return md5(uniqid(mt_rand(), true));
}

Administrator , narzędzie do zarządzania bazami danych napisane w PHP.


6

Funkcja pomocnicza z frameworka Laravel 5

/**
 * Generate a "random" alpha-numeric string.
 *
 * Should not be considered sufficient for cryptography, etc.
 *
 * @param  int  $length
 * @return string
 */
function str_random($length = 16)
{
    $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

    return substr(str_shuffle(str_repeat($pool, $length)), 0, $length);
}

4
„Nie powinno być uważane za wystarczające do kryptografii itp.” Należy to mocno podkreślić.
Scott Arciszewski,


4

Zmodyfikowana wersja funkcji działa dobrze, ale znalazłem tylko jeden problem: użyłeś niewłaściwego znaku do umieszczenia znaków $, więc znak „jest czasem częścią generowanego ciągu losowego.

Aby to naprawić, zmień:

$characters = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ’;

do:

$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

W ten sposób używane są tylko zamknięte znaki, a znak „nigdy nie będzie częścią generowanego ciągu losowego.


4

Kolejna linijka, która generuje losowy ciąg 10 znaków z literami i cyframi. Utworzy tablicę za pomocą range(dostosuje drugi parametr, aby ustawić rozmiar), zapętli tę tablicę i przypisze losowy znak ASCII (zakres 0-9 lub az), a następnie wszczepi tablicę w celu uzyskania łańcucha.

$str = implode('', array_map(function () { return chr(rand(0, 1) ? rand(48, 57) : rand(97, 122)); }, range(0, 9)));

Uwaga: działa to tylko w PHP 5.3 i nowszych


wreszcie naprawdę losowe rozwiązanie, a nie rozdęty skrót 32-bitowej losowej liczby całkowitej lub przetasowany ciąg ...
The Surrican

istnieje tylko jeden problem: liczby są tak samo prawdopodobne, jak postacie, co nie jest tak losowe, jak bym chciał. +1 dla najlepszego rozwiązania na tej stronie. popraw to i jego doskonałe.
The Surrican

poprawiać ... jak to? rand(0, 57-48+122-97)<57-48?...:...? :)
vp_arth

4

Jedna wkładka.

Jest szybki dla ogromnych strun z pewną wyjątkowością.

function random_string($length){
    return substr(str_repeat(md5(rand()), ceil($length/32)), 0, $length);
}

md5(rand())to strasznie niepewny sposób generowania losowej liczby.
Scott Arciszewski,

1
intencją jest łańcuch o długości X i pewnej wyjątkowości. prawdziwa przypadkowość nie jest celem.
Jacob Smith,


3

Podobał mi się ostatni komentarz, który używał openssl_random_pseudo_bytes, ale nie było to dla mnie rozwiązaniem, ponieważ wciąż musiałem usuwać znaki, których nie chciałem, i nie byłem w stanie uzyskać łańcucha o ustalonej długości. Oto moje rozwiązanie ...

function rndStr($len = 20) {
    $rnd='';
    for($i=0;$i<$len;$i++) {
        do {
            $byte = openssl_random_pseudo_bytes(1);
            $asc = chr(base_convert(substr(bin2hex($byte),0,2),16,10));
        } while(!ctype_alnum($asc));
        $rnd .= $asc;
    }
    return $rnd;
}

3
function randomString($length = 5) {
    return substr(str_shuffle(implode(array_merge(range('A','Z'), range('a','z'), range(0,9)))), 0, $length);
}

3

Oto moje proste jednoliniowe rozwiązanie do generowania przyjaznego losowego hasła, z wyłączeniem znaków, które wyglądają podobnie, jak „1” i „l”, „O” i „0” itd.… Tutaj jest 5 znaków, ale możesz łatwo zmień to oczywiście:

$user_password = substr(str_shuffle('abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789'),0,5);

Jest to idealne do tworzenia ciągów losowych identyfikatorów, które będą wywoływane później w jquery. IDK, jeśli jest to dobra praktyka, ale pomogło mi to dużo, bez użycia podobnej odpowiedzi, jak ...
Rodrigo Zuluaga

3

Oto inne rozwiązanie.

function genRandomString($length = 10)
{
    if($length < 1)
        $length = 1;
    return substr(preg_replace("/[^A-Za-z0-9]/", '', base64_encode(openssl_random_pseudo_bytes($length * 2))), 0, $length);
}

PS. Używam PHP 7.2 na Ubuntu.


2

Innym sposobem generowania losowego ciągu w PHP jest:

function RandomString($length) {
    $original_string = array_merge(range(0,9), range('a','z'), range('A', 'Z'));
    $original_string = implode("", $original_string);
    return substr(str_shuffle($original_string), 0, $length);
}
echo RandomString(6);

2

Oto jak to zrobić, aby uzyskać prawdziwy unikalny losowy klucz:

$Length = 10;
$RandomString = substr(str_shuffle(md5(time())), 0, $Length);
echo $RandomString;

Możesz użyć time (), ponieważ jest to uniksowy znacznik czasu i zawsze jest unikalny w porównaniu z innymi losowymi wymienionymi powyżej. Następnie możesz wygenerować sumę md5 i pobrać żądaną długość z wygenerowanego MD5 ciągu . W tym przypadku używam 10 znaków i mógłbym użyć dłuższego łańcucha, jeśli chciałbym, aby był bardziej unikalny.

Mam nadzieję, że to pomoże.


2
Oczywiście, time()jest daleki od unikalności: będzie zwracał tę samą wartość raz za razem, aż skończy się bieżąca sekunda. To, co naprawdę zapewnia pewną losowość, to str_shuffle()reszta kodu ogranicza tylko próbkę do wybierania znaków.
Álvaro González

1
więc to, co właściwie robisz, to tasowanie wokół 32-bitowej liczby całkowitej. nie ma tu wiele entropii ...
The Surrican

2
Atakujący może odgadnąć wartość zwróconą przez time()(to tylko znacznik czasu), jest to słabe źródło losowości.
AL

2

Sparametryzowany jednowierszowy, wykorzystujący tylko natywne funkcje PHP , działający od PHP 5.1.0

str_shuffle(implode('', (array_intersect_key(($map =  array_map('chr', array_merge(array_map('mt_rand', array_fill(0, $length = 25, 48), array_fill(0,$length,57)),array_map('mt_rand', array_fill(0, $length, 65), array_fill(0,$length,90)),array_map('mt_rand', array_fill(0, $length, 97), array_fill(0,$length,122))))), array_flip($keys = array_rand($map, $length))))))
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.