Уникальное генерирование ключей

Я ищу способ, в частности, на 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. Создайте их с помощью некоторых других средств, а затем проверьте их на одну историю ранее созданных значений.

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

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

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

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

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

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

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

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

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

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

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

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

Оставайтесь JOLLY!
ЧАС

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

Вы можете быть заинтересованы в этой статье, которая касается одной и той же проблемы: идентификаторы 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.

Как этот

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

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

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

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

EDIT: из ваших более поздних ответов я вижу, что вам нужно что-то большее, чем 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 снова, затем возьмите случайную подстроку. Да, вы можете получить одинаковые пароли, но это совсем не так.