PHP: Как создать случайную уникальную буквенно-цифровую строку?


380

Как можно было бы генерировать случайную уникальную строку, используя цифры и буквы для использования в проверочной ссылке? Например, когда вы создаете учетную запись на веб-сайте, и он отправляет вам электронное письмо со ссылкой, и вам нужно щелкнуть эту ссылку, чтобы подтвердить свой аккаунт ... да ... один из них.

Как я могу создать один из тех, кто использует PHP?

Обновление: только что вспомнил uniqid(). Это функция PHP, которая генерирует уникальный идентификатор на основе текущего времени в микросекундах. Я думаю, что я буду использовать это.


Все, что вам нужно, это строки и равномерно распределенные случайные числа.
Артелиус

10
Привет, Андрей, ты должен выбрать Scottправильный ответ. Скотт использует криптографически безопасный генератор псевдослучайных чисел OpenSSL (CSPRNG), который выберет наиболее безопасный источник энтропии на основе вашей платформы.
Ладья

3
Любой, кто читает это после 2015 года, пожалуйста, посмотрите здесь: paragonie.com/blog/2015/07/… Большинство топовых ответов более или менее ошибочно ...
rugk

OpenSSL и uniqidнебезопасны. Используйте что-то вроде Random::alphanumericString($length)или Random::alphanumericHumanString($length).
каркать

Ответы:


305

Уведомление о безопасности . Это решение не следует использовать в ситуациях, когда качество вашей случайности может повлиять на безопасность приложения. В частности, rand()и uniqid()не криптографически безопасны генераторы случайных чисел . См ответ Скотта для безопасной альтернативы.

Если вам не нужно, чтобы он был абсолютно уникальным со временем:

md5(uniqid(rand(), true))

В противном случае (если вы уже определили уникальный логин для вашего пользователя):

md5(uniqid($your_user_login, true))

90
Оба метода не гарантируют уникальность - длина ввода функции md5 больше длины ее вывода, и в соответствии с en.wikipedia.org/wiki/Pigeonhole_principle коллизия гарантируется. С другой стороны, чем больше население полагается на хеши для получения «уникального» идентификатора, тем выше вероятность возникновения хотя бы одного столкновения (см. En.wikipedia.org/wiki/Birthday_problem ). Вероятность может быть крошечной для большинства решений, но она все еще существует.
Дариуш Вальчак

12
Это не безопасный метод генерации случайных значений. Смотри ответ Скотта.
Ладья

4
Для подтверждений по электронной почте, срок действия которых истекает относительно скоро, я думаю, что крошечная вероятность того, что один человек когда-нибудь подтвердит чужую электронную почту, является незначительным риском. Но вы всегда можете проверить, существует ли токен в БД после его создания, и просто выбрать новый, если это так. Однако время, потраченное на написание этого фрагмента кода, скорее всего, будет потрачено впустую, поскольку, скорее всего, оно никогда не будет выполнено.
Андрей

Обратите внимание, что md5 возвращает шестнадцатеричные значения, то есть набор символов ограничен [0-9] и [af].
Тийс Ризебек

1
У md5 могут быть коллизии, вы только что разрушили преимущество
uniqid

507

Я просто смотрел, как решить эту проблему, но я также хочу, чтобы моя функция создавала токен, который также можно использовать для получения пароля. Это означает, что мне нужно ограничить способность токена угадываться. Потому uniqidчто основан на времени, и согласно php.net "возвращаемое значение мало отличается от microtime ()", uniqidне соответствует критериям. PHP рекомендует использовать openssl_random_pseudo_bytes()вместо этого для создания криптографически безопасных токенов.

Быстрый, короткий и конкретный ответ:

bin2hex(openssl_random_pseudo_bytes($bytes))

который сгенерирует случайную строку буквенно-цифровых символов длиной = $ байтов * 2. К сожалению, это только алфавит [a-f][0-9], но это работает.


Ниже приведена самая сильная функция, которую я мог сделать, которая удовлетворяет критериям (это реализованная версия ответа Эрика).

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)работает как капля в замене rand()или mt_rand. Он использует openssl_random_pseudo_bytes, чтобы помочь создать случайное число между $ min и $ max.

getToken($length)создает алфавит для использования в токене, а затем создает строку длины $length.

РЕДАКТИРОВАТЬ: я не упомянул источник - http://us1.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322

РЕДАКТИРОВАТЬ (PHP7): С выпуском PHP7 стандартная библиотека теперь имеет две новые функции, которые могут заменить / улучшить / упростить функцию crypto_rand_secure, описанную выше. random_bytes($length)а такжеrandom_int($min, $max)

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

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

Пример:

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
Согласовано. Хранение незашифрованного пароля ужасно! (Я использую blowfish.) Но после того, как токен сгенерирован, он позволяет владельцу токена сбросить пароль, поэтому токен эквивалентен паролю, пока он действителен (и рассматривается как таковой).
Скотт

23
Эй, я объединил ваш отличный код с удобной функциональностью метода Kohana Text :: random () и создал этот гист
raveren

9
Отлично! Я проверил это с 10 символами как длина. 100000 токенов и до сих пор без дубликатов!
Sharpless512

5
Я использовал этот процесс и нашел его очень медленным. При длине 36 тайм-аут на сервере разработки. При длине 24 это все равно заняло около 30 секунд. Не уверен, что я сделал неправильно, но это было слишком медленно для меня, и я выбрал другое решение.
Шейн

5
Вы также можете использовать base64_encodeвместо, bin2hexчтобы получить более короткую строку с большим алфавитом.
erjiang

91

Объектно-ориентированная версия решения с наибольшим количеством голосов

Я создал объектно-ориентированное решение на основе ответа Скотта :

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

Применение

<?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);

Пользовательский алфавит

Вы можете использовать пользовательский алфавит, если требуется. Просто передайте строку с поддерживаемыми символами конструктору или установщику:

<?php

$customAlphabet = '0123456789ABCDEF';

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

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

Вот выходные образцы

SRniGU2sRQb2K1ylXKnWwZr4HrtdRgrM
q1sRUjNq1K9rG905aneFzyD5IcqD4dlC
I0euIWffrURLKCCJZ5PQFcNUCto6cQfD
AKwPJMEM5ytgJyJyGqoD5FQwxv82YvMr
duoRF6gAawNOEQRICnOUNYmStWmOpEgS
sdHUkEn4565AJoTtkc8EqJ6cC4MLEHUx
eVywMdYXczuZmHaJ50nIVQjOidEVkVna
baJGt7cdLDbIxMctLsEBWgAw5BByP5V0
iqT0B2obq3oerbeXkDVLjZrrLheW4d8f
OUQYCny6tj2TYDlTuu1KsnUyaLkeObwa

Надеюсь, это кому-нибудь поможет. Ура!


Извините, но как мне запустить эту штуку? Я сделал, $obj = new RandomStringGenerator;но какой метод я должен вызвать? Спасибо.
sg552

@ sg552, вы должны вызвать generateметод, как в примере выше. Просто передайте ему целое число, чтобы указать длину полученной строки.
Слава Фомин II

Спасибо, это работает для меня, но Custom Alphabetне. Я получил пустой вывод, когда я эхо. Во всяком случае, я даже не уверен, что толку во втором примере, Custom Alphabetпоэтому я думаю, что я останусь с первым примером. Спасибо.
sg552

1
Хороший, но довольно излишний в большинстве сценариев, если ваш проект не основан на случайно сгенерированных кодах
dspacejs

1
да, хорошо, но излишне, особенно если учесть, что теперь это не рекомендуется для php 5.7
Эндрю

40

Я опоздал, но я здесь с некоторыми хорошими исследовательскими данными, основанными на функциях, предоставленных ответом Скотта . Поэтому я настроил каплю Digital Ocean только для этого 5-дневного автоматического теста и сохранил сгенерированные уникальные строки в базе данных MySQL.

В течение этого тестового периода я использовал 5 разных длин (5, 10, 15, 20, 50), и для каждой длины было вставлено +/- 0,5 миллиона записей. Во время моего теста только длина 5 генерировала дубликаты +/- 3K из 0,5 миллиона, а оставшиеся длины не генерировали дубликатов. Таким образом, мы можем сказать, что если мы используем длину 15 или выше с функциями Скотта, то мы можем генерировать высоконадежные уникальные строки. Вот таблица с моими данными исследований:

введите описание изображения здесь

Обновление: я создал простое приложение Heroku, используя эти функции, которые возвращают токен как ответ JSON. Доступ к приложению можно получить по адресу https://uniquestrings.herokuapp.com/api/token?length=15.

Надеюсь, это поможет.


33

Вы можете использовать UUID (универсальный уникальный идентификатор), его можно использовать для любых целей, от строки аутентификации пользователя до идентификатора платежной транзакции.

UUID - это 16-октетное (128-битное) число. В своей канонической форме UUID представлен 32 шестнадцатеричными цифрами, отображаемыми в пяти группах, разделенных дефисами, в форме 8-4-4-4-12, в общей сложности 36 символов (32 буквенно-цифровых символа и четыре дефиса).

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

}

// вызов функции

$transationID = generate_uuid();

некоторые примеры выходных данных будут выглядеть так:

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

надеюсь, это поможет кому-то в будущем :)


Выглядит фантастически, добавлено в мой список!
Мустафа Эрдоган

32

Эта функция сгенерирует случайный ключ, используя цифры и буквы:

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

Пример вывода:

zsd16xzv3jsytnp87tk7ygv73k8zmr0ekh6ly7mxaeyeh46oe8

6
Через некоторое время вы попадаете на те же цифры
Sharpless512

1
Это не совсем случайно, потому что у него никогда не будет одного и того же chacater более одного раза.
EricP

16

Я использую этот однострочник:

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

где длина - длина искомой строки (делится на 4, в противном случае она округляется до ближайшего числа, кратного 4)


6
Он не всегда возвращает только буквенно-цифровые символы. Он может содержать такие символы, как==
user3459110

1
Если используется в URL, base64url_encodeможно использовать вместо этого, см. Здесь: php.net/manual/en/function.base64-encode.php
Пол

9

Используйте код ниже, чтобы сгенерировать случайное число из 11 символов или изменить число в соответствии с вашими требованиями.

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

или мы можем использовать пользовательскую функцию для генерации случайного числа

 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
Это никогда не может генерировать строку "aaaaaaaaaaa" или "aaaaabbbbbb". Он просто выбирает подстроку случайной перестановки алфавита. Строка длиной 11 символов имеет только V (11,35) = 288 возможных значений. Не используйте это, если вы ожидаете, что строки будут уникальными!
kdojeteri

@ Пипинг тогда сделайsubstr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstvwxyz', 36)), 0, 11);
Тим Холлман

7
  1. Генерация случайного числа с помощью вашего любимого генератора случайных чисел
  2. Умножьте и разделите его, чтобы получить число, соответствующее количеству символов в вашем алфавите кода
  3. Получить элемент по этому индексу в вашем кодовом алфавите.
  4. Повторите с 1), пока у вас есть длина, которую вы хотите

например (в псевдокоде)

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

Теоретически, не может ли это потенциально генерировать одну и ту же строку более одного раза?
frezq

4

Перед вами уникальный генератор идентификаторов. сделано мной.

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

Вы можете повторить любой «var» для вашего идентификатора, как вам нравится. но $ mdun лучше, вы можете заменить md5 на sha1 для лучшего кода, но это будет очень долго, что может вам не понадобиться.

Спасибо.


7
В этом случае случайность гарантируется случайным написанным кодом, верно?
Даниэль Кукал

3
да, это своего рода «случайный», потому что это нестандартный, неясный код. Это затрудняет прогнозирование ... но на самом деле он не использует небезопасные части для генерации случайного числа. таким образом, результат технически не является случайным или безопасным.
Филипп

4

Для действительно случайных строк вы можете использовать

<?php

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

выходы:

40a29479ec808ad4bcff288a48a25d5c

так что даже если вы попытаетесь сгенерировать строку несколько раз в одно и то же время, вы получите другой вывод.


4

При попытке создать случайный пароль вы пытаетесь:

  • Сначала создайте криптографически безопасный набор случайных байтов

  • Во-вторых, превращение этих случайных байтов в строку для печати

Теперь есть несколько способов генерировать случайные байты в php, например:

$length = 32;

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

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

Затем вы хотите превратить эти случайные байты в печатную строку:

Вы можете использовать bin2hex :

$string = bin2hex($bytes);

или base64_encode :

$string = base64_encode($bytes);

Однако обратите внимание, что вы не контролируете длину строки, если используете base64. Вы можете использовать bin2hex, чтобы сделать это, использование 32 байтов превратится в строку из 64 символов . Но это будет работать только так в строке EVEN .

Так что в основном вы можете просто сделать :

$length = 32;

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

$string = bin2hex($bytes);


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

Это простая функция, которая позволяет генерировать случайные строки, содержащие буквы и цифры (буквенно-цифровые). Вы также можете ограничить длину строки. Эти случайные строки могут быть использованы для различных целей, в том числе: код реферала, промокод, код купона. Функция опирается на следующие функции 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

после прочтения предыдущих примеров я придумал это:

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

Я 10 раз продублирую массив [0-9, AZ] и перетасую элементы, после того как я получаю случайную начальную точку для substr (), чтобы быть более «креативной» :), вы можете добавить [az] и другие элементы в массив, дублировать более или менее, будь более креативным, чем я


1

Мне нравится использовать хеш-ключи при работе с проверочными ссылками. Я бы порекомендовал использовать microtime и использовать хеширование с использованием MD5, поскольку не должно быть никаких причин, по которым ключи должны совпадать, поскольку хэши основаны на микротайме.

  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;

}

?>

Выше функция генерирует случайную строку длиной 11 символов.


1

Если вы хотите сгенерировать уникальную строку в PHP, попробуйте следующее.

md5(uniqid().mt_rand());

В этом,

uniqid()- Он будет генерировать уникальную строку. Эта функция возвращает уникальный идентификатор на основе метки времени в виде строки.

mt_rand() - Генерация случайного числа.

md5() - Он сгенерирует хеш-строку.


0

Скотт, да ты очень пишешь и хорошее решение! Спасибо.

Я также должен создать уникальный токен API для каждого моего пользователя. Вот мой подход, я использовал информацию о пользователе (Userid и Username):

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

Пожалуйста, посмотрите и дайте мне знать, если я смогу улучшить. Спасибо


0

Вот что я использую в одном из своих проектов, он отлично работает и генерирует УНИКАЛЬНЫЙ СЛУЧАЙНЫЙ ЖЕЛЕЗ :

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

Пожалуйста, обратите внимание, что я умножил временную метку на три, чтобы создать путаницу для всех, кому может быть интересно, как генерируется этот токен;)

Я надеюсь, что это помогает :)


1
«Обратите внимание, что я умножил временную метку на три, чтобы создать путаницу для всех, кому может быть интересно, как генерируется этот токен» Звучит как безопасность через обфускацию stackoverflow.com/questions/533965/…
Harry

Это не «защита через обфускацию», поскольку временная метка затем добавляется к случайной строке, которая была сгенерирована, и это фактическая конечная строка, которую мы возвращаем;)
Kaszoni Ferencz


0

мы можем использовать эти две строки кода для генерации уникальной строки, проверенной около 10000000 раз итерации

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

0

Я всегда использую эту функцию для генерации произвольной случайной буквенно-цифровой строки ... Надеюсь, это поможет.

<?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
?>

Он генерирует, например: Y1FypdjVbFCFK6Gh9FDJpe6dciwJEfV6MQGpJqAfuijaYSZ86g

Если вы хотите сравнить с другой строкой, чтобы убедиться, что это уникальная последовательность, вы можете использовать этот трюк ...

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

он генерирует две уникальные строки:

qsBDs4JOoVRfFxyLAOGECYIsWvpcpMzAO9pypwxsqPKeAmYLOi

Ti3kE1WfGgTNxQVXtbNNbhhvvapnaUfGMVJecHkUjHbuCb85pF

Надеюсь, это то, что вы ищете ...


0

Простое решение состоит в том, чтобы преобразовать основание 64 в алфавитно-цифровую, отбрасывая не буквенно-цифровые символы.

Этот использует random_bytes () для криптографически безопасного результата.

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

Я полагаю, что проблема со всеми существующими идеями заключается в том, что они, вероятно, уникальны, но не обязательно уникальны (как указано в ответе Дариуша Вальчака на loletech). У меня есть решение, которое на самом деле является уникальным. Это требует, чтобы у вашего скрипта была какая-то память. Для меня это база данных SQL. Вы также можете просто написать куда-нибудь файл. Есть две реализации:

Первый способ: иметь ДВА поля, а не 1, которые обеспечивают уникальность. Первое поле - это идентификационный номер, который не является случайным, но является уникальным (первый идентификатор - 1, второй - 2 ...). Если вы используете SQL, просто определите поле ID с помощью свойства AUTO_INCREMENT. Второе поле не уникально, но случайно. Это может быть сгенерировано с помощью любой другой техники, о которой люди уже упоминали. Идея Скотта была хорошей, но md5 удобен и, вероятно, достаточно хорош для большинства целей:

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

Второй метод: в основном та же идея, но изначально выбирают максимальное количество строк, которые когда-либо будут сгенерированы. Это может быть очень большое число, например, триллион. Затем сделайте то же самое, сгенерируйте идентификатор, но добавьте ноль, чтобы все идентификаторы имели одинаковое количество цифр. Затем просто объедините идентификатор со случайной строкой. Это будет достаточно случайным для большинства целей, но раздел идентификатора будет гарантировать, что он также уникален.


-1

Вы можете использовать этот код, я надеюсь, он будет вам полезен.

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

Подробности о генераторе случайного кода в PHP


-2

Упрощение кода Скотта, описанного выше, путем удаления ненужных циклов, которые сильно замедляются и не делают его более безопасным, чем вызов openssl_random_pseudo_bytes только один раз

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

К сожалению, я не могу согласиться с вами, что это подходящее упрощение функции crypto_rand_secure. Цикл необходим, чтобы избежать смещения по модулю, которое возникает, когда вы берете результат случайно сгенерированного числа, а затем модифицируете его числом, которое делит диапазон. en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Modulo_bias . Используя цикл для выброса любых чисел вне диапазона и выбора нового числа, это позволяет избежать этого смещения. stackoverflow.com/questions/10984974/…
Скотт

@ Скотт, этот пост о rand (). Тем не менее, в этом случае, openssl_random_pseudo_bytes уже позаботился об этом, так что цикл в ненужном.
mabel

1
gist.github.com/anonymous/87e3ae6fd3320447f46b973e75c2ea85 - Пожалуйста, запустите этот скрипт. Вы увидите, что распределение результатов не случайно. Числа в диапазоне от 0 до 55 встречаются чаще, чем цифры в диапазоне от 56 до 100. opensslэто не является причиной, это из-за смещения по модулю в вашем заявлении возврата. 100 (диапазон) не делит 255 (1 байт) равномерно и вызывает эти результаты. Моя самая большая проблема с вашим ответом состоит в том, что вы заявляете, что функция безопасна, как использование цикла, что неверно. Ваша реализация crypto_rand_secure не криптографически безопасна и вводит в заблуждение.
Скотт

@ Скотт, мы отвлеклись, речь идет не о последнем операторе возврата, его также можно постепенно вычислить из возвращаемого значения openssl_random_pseudo_bytes без использования модуля. Я хочу сказать, что цикл не нужен, когда openssl_random_pseudo_bytes возвращает случайные байты. Делая цикл, вы не делаете его более безопасным, просто делаете его медленным.
mabel

2
Этот ответ распространяет плохую информацию. Вы правы, что цикл не делает opensslболее безопасным, но, что более важно, он не делает его менее безопасным, этот ответ делает. Код выше берет совершенно хорошее случайное число и искажает его, смещая его в сторону меньших чисел. Если вы добавите в свой ответ отказ от ответственности, заявив, что он быстрее (путем удаления цикла), но это не CSPRNG, это решит эту проблему. Пожалуйста, ради любви к криптографии, сообщите пользователям, что выходные данные этой функции могут быть предвзятыми и не являются эквивалентным решением. Цикл не только для того, чтобы раздражать вас.
Скотт
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.