Вопрос

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

Я сделал следующее:

strtolower(substr(crypt(time()), 0, 7));

Но я обнаружил, что время от времени у меня появляется дубликат ключа (редко, но достаточно часто).

Я также подумал сделать:

strtolower(substr(crypt(uniqid(rand(), true)), 0, 7));

Но, согласно веб-сайту PHP, uniqid() может, если uniqid() вызывается дважды за одну и ту же микросекунду, он может сгенерировать один и тот же ключ.Я думаю, что добавление rand() происходит редко, но все же возможно.

После строк, упомянутых выше, я также удаляю такие символы, как L и O, чтобы пользователь не запутывался.Возможно, это одна из причин появления дубликатов, но все же необходимо.

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

Есть еще мысли?Есть ли какие-либо веб-сайты, которые уже делают это, имеют какой-то API или просто возвращают ключ.я нашел http://userident.com но я не уверен, что ключи будут полностью уникальными.

Это должно работать в фоновом режиме без какого-либо вмешательства пользователя.

Это было полезно?

Решение

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

  1. Используйте эффективный генератор GUID — они длинные и не могут быть сжаты.Если вы используете только часть ты облажался.
  2. По крайней мере, часть числа последовательно генерируется из одной последовательности.Вы можете добавить детализацию или кодировку, чтобы сделать изображение менее последовательным.Преимущество в том, что они начинаются с короткого времени, а недостаток в том, что им требуется один источник.Обход ограничения единственного источника заключается в том, чтобы иметь нумерованные источники, поэтому вы включаете [источник #] + [seq #], и тогда каждый источник может генерировать свою собственную последовательность.
  3. Сгенерируйте их другими способами, а затем сверьте с единой историей ранее сгенерированных значений.

Любой другой метод не гарантируется.Имейте в виду, что по сути вы генерируете двоичное число (это компьютер), но затем вы можете закодировать его в шестнадцатеричном, десятичном формате, Base64 или в виде списка слов.Выберите кодировку, которая подходит для вашего использования.Обычно для вводимых пользователем данных вам нужен какой-то вариант Base32 (на который вы намекнули).

Примечание о GUIDS:Они приобретают свою уникальность благодаря своей длине и методу, используемому для их создания. Все, что меньше 128 бит, небезопасно. Помимо генерации случайных чисел, в GUID есть характеристики, которые делают его более уникальным.Имейте в виду, что они уникальны лишь практически, а не полностью.Иметь дубликат возможно, хотя и практически невозможно.

Обновленное примечание о GUIDS.:С тех пор, как я написал это, я узнал, что многие генераторы GUID используют криптографически безопасный генератор случайных чисел (сложно или невозможно предсказать следующее сгенерированное число и маловероятно, что он повторится).на самом деле их 5 разных Алгоритмы UUID.Алгоритм 4 — это то, что Microsoft в настоящее время использует для API генерации GUID Windows.А ГУИД — это реализация Microsoft стандарта UUID.

Обновлять:Если вам нужно от 7 до 16 символов, вам нужно использовать метод 2 или 3.

Нижняя граница:Честно говоря, не существует такого понятия, как полностью уникальное.Даже если вы воспользуетесь последовательным генератором, у вас в конечном итоге закончится память, используя все атомы во Вселенной, и вы, таким образом, зациклитесь на себе и повторите.Вашей единственной надеждой будет тепловая смерть Вселенной прежде, чем она достигнет этой точки.

Даже самый лучший генератор случайных чисел имеет возможность повторения, равную общему размеру генерируемого вами случайного числа.Возьмем, к примеру, четверть.Это полностью случайный генератор битов, и вероятность его повторения равна 1 к 2.

Так что все сводится к вашему порогу уникальности.Вы можете получить 100% уникальность 8 цифр для 1 099 511 627 776 чисел, используя последовательность, а затем закодировав ее в формате Base32.Любой другой метод, который не включает проверку списка прошлых чисел, имеет только шансы, равные n/1 099 511 627 776 (где n = количество сгенерированных предыдущих чисел), что он не уникален.

Другие советы

Любой алгоритм приведет к дубликату.

Поэтому могу ли я предложить вам использовать существующий алгоритм* и просто проверять наличие дубликатов?

*Небольшое дополнение:Если uniqid() может быть неуникальным в зависимости от времени, также включает глобальный счетчик, который увеличивается после каждого вызова.Таким образом, даже в одну и ту же микросекунду что-то меняется.

Без написания кода моя логика была бы такой:

Создайте случайную строку из любых допустимых символов, которые вам нравятся.
Затем добавьте половину отметки даты (неполные секунды и все такое) вперед, а другую половину — в конец (или где-то посередине, если хотите).

Оставайтесь ВЕСЕЛЫМИ!
ЧАС

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

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

Цель этого алгоритма — использовать комбинацию времени и местоположения («пространственно-временных координат» для фанатов теории относительности) в качестве ключа уникальности.Однако хронометраж не идеален, поэтому существует вероятность того, что, например, два GUID будут сгенерированы в быстрой последовательности на одной и той же машине, настолько близко друг к другу во времени, что временная метка будет одинаковой.Вот тут-то и вступает в силу уникификатор.

Обычно я делаю это так:

$this->password = '';

for($i=0; $i<10; $i++)
{
    if($i%2 == 0)
        $this->password .= chr(rand(65,90));
    if($i%3 == 0)
        $this->password .= chr(rand(97,122));
    if($i%4 == 0)
        $this->password .= chr(rand(48,57));
}

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

Как прокомментировал Фрэнк Крюгер, используйте генератор GUID.

Нравиться Вот этот

Я до сих пор не понимаю, почему пароли должны быть уникальными?В чем проблема, если у двух ваших пользователей одинаковый пароль?

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

Возможно, вас заинтересует сверхзащищенная реализация генератора паролей Стива Гибсона (источника нет, но у него есть подробное описание того, как он работает) на сайте https://www.grc.com/passwords.htm.

Сайт создает огромные 64-значные пароли, но, поскольку они полностью случайны, вы можете легко взять первые 8 (или сколько угодно) символов для менее безопасного, но «насколько возможно случайного» пароля.

РЕДАКТИРОВАТЬ:из ваших более поздних ответов я вижу, что вам нужно что-то больше похожее на GUID, чем на пароль, так что, вероятно, это не то, что вам нужно...

Я уверен, что часть вашей проблемы заключается в том, что вы пытаетесь использовать единую функцию для двух разных целей...пароли и идентификатор транзакции

На самом деле это две разные проблемные области, и не стоит пытаться решать их вместе.

Недавно мне захотелось получить быстрый и простой случайный уникальный ключ, поэтому я сделал следующее:

$ukey = dechex(time()) . crypt( time() . md5(microtime() + mt_rand(0, 100000)) ); 

Итак, по сути, я получаю время unix в секундах и добавляю случайную строку md5, сгенерированную из времени + случайного числа.Он не самый лучший, но для низкочастотных запросов вполне хорош.Это быстро и работает.

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

Я использую его для отслеживания опросов, где мы получаем скорость отправки около 1000 опросов в минуту...так что на данный момент (скрещивает пальцы) дубликатов нет.Конечно, ставка не является постоянной (мы получаем материалы в определенное время дня), так что это не является ни надежным, ни лучшим решением...совет использует инкрементное значение как часть ключа (в моем случае я использовал time(), но могло бы быть лучше).

Рассматривая часть шифрования, которая не имеет особого отношения к созданию уникального значения, я обычно использую этот:

function GetUniqueValue()
{
   static $counter = 0; //initalized only 1st time function is called
   return strtr(microtime(), array('.' => '', ' ' => '')) . $counter++;
}

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

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

Обычно я использую случайную подстроку (рандомизирую количество символов от 8 до 32 или меньше для удобства пользователя) или MD5 некоторого полученного значения, или время, или какую-то комбинацию.Для большей случайности я объединяю MD5 полученного значения (скажем, фамилии) со временем, снова MD5, а затем беру случайную подстроку.Да ты мог получить одинаковые пароли, но это совсем маловероятно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top