PHP короткий уникальный генерации идентификатора с использованием auto_increment?

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

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

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

EDIT: Я хотел бы начать с 5 символов, и если я удалю 60 миллионов записей, то перейдите к 6 .. так далее и так далее.

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

Сгенерированные строки не должны быть линейными, поэтому простое преобразование идентификатора auto_incremented в base 36 [0-9A-Z] является слишком упрощенным, но функция, подобная той, что я собираюсь сделать с этим.

EDIT: безопасность не является проблемой, так как это не будет использоваться для защиты информации. Это просто ярлык для более длинной строки. Спасибо.

Спасибо за ваши предложения и извините за задержку. Дантист..

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

  • инвертируя некоторые биты (fi, используя XOR, ^ в PHP)
  • заменяя места бит (($ i & 0xc) >> 2 | ($ i & 0x3) << 2) или просто изменяя порядок всех бит
  • добавляя постоянное значение по модулю вашего максимального диапазона (должно быть в два раза, если вы комбинируете это с приведенными выше)

Пример: эта функция преобразует 0, 1, 2, 3, 5, .. в 13, 4, 12, 7, 15, .. для чисел до 15:

 $i=($input+97) & 0xf; $result=((($i&0x1) << 3) + (($i&0xe) >> 1)) ^ 0x5; 

РЕДАКТИРОВАТЬ

Более простой способ – использовать линейный конгруэнтный генератор (LCG, который обычно используется для генерации случайных чисел), который определяется формулой вида:

 X_n+1 = (a * X_n + c) mod m 

Для хороших значений a, c и m последовательность X_0, X_1 .. X_m-1 будет содержать все числа от 0 до m-1 ровно один раз. Теперь вы можете начать с линейно возрастающего индекса и использовать следующее значение в последовательности LCG как ваш секретный ключ.

EDIT2

Реализация: вы можете создавать свои собственные параметры LCG , но если вы ошибетесь, он не будет охватывать весь диапазон (и, следовательно, иметь дубликаты), поэтому я буду использовать опубликованный и испытанный набор параметров из этой статьи :

 a = 16807, c = 0, m = 2147483647 

Это дает вам диапазон 2 ** 31. С пакетом () вы можете получить полученное целое число как строку, base64_encode () делает его читаемой строкой (до 6 значащих символов, 6 бит на каждый байт), так что это может быть ваша функция:

 substr(base64_encode(pack("l", (16807 * $index) % 2147483647)), 0, 6) 

Вероятно, вы могли бы генерировать хеш MD5 текущего времени / случайного числа и обрезать его до необходимой длины (5-8 символов) и сохранить его как поле id.

Если вы используете сохранение этой информации в базе данных, вам не нужно использовать цикл for для проверки на столкновение, но вы можете просто сделать инструкцию select – что-то вроде

 SELECT count(1) c FROM Table WHERE id = :id 

где: id будет вновь созданным id. Если c больше 0, вы знаете, что оно уже существует.

РЕДАКТИРОВАТЬ

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

Думаю, как вы сказали, кодировка base64 уже делает число для преобразования короткой строки. Чтобы избежать проблемы последовательности, у вас может быть некоторое сопоставление между вашим автогенерированным идентификатором с некоторым «случайным» значением (уникальное сопоставление). Затем вы можете base64 кодировать это уникальное значение.

Вы можете сгенерировать это сопоставление следующим образом. Имейте временные значения хранилища таблиц от 1 до 10 000 000. Сортируйте его в произвольном порядке и сохраните в нем таблицу карт.

 INSERT INTO MappingTable (mappedId) SELECT values FROM TemporaryTable ORDER BY RAND() 

Если MappingTable будет иметь 2 идентификатора полей (ваш автоматически сгенерированный идентификатор будет искать против этого) и mappedId (это то, что вы будете генерировать для кодировки base64).

По мере приближения к 10 000 000 вы можете повторно запустить вышеуказанный код и изменить значения во временной таблице с 10 000 001-20 000 000 или что-то в этом роде.

вы можете использовать побитовый XOR для скремблирования некоторых бит:

 select thefield ^ 377 from thetable; +-----+---------+ | a | a ^ 377 | +-----+---------+ | 154 | 483 | | 152 | 481 | | 69 | 316 | | 35 | 346 | | 72 | 305 | | 139 | 498 | | 96 | 281 | | 31 | 358 | | 11 | 370 | | 127 | 262 | +-----+---------+ 

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

MD5 инкрементирующего числа должно быть прекрасным, но я беспокоюсь, что если вы усекаете свой MD5 (который обычно составляет 128 бит) до 5-8 символов, вы почти наверняка будете наносить ущерб его способности действовать как уникальная подпись. ..

Абсолютно верно. Особенно, если вы достигнете 80% вероятности столкновения, усеченный MD5 будет таким же хорошим, как любое случайное число, чтобы гарантировать уникальность сам по себе, то есть бесполезный.

Но так как вы все равно используете базу данных, почему бы просто не использовать UNIQUE INDEX? Таким образом, Uniquness check выполняется (гораздо более эффективным способом, чем использование цикла) самой MySQL. Просто попробуйте сделать INSERT с вашим MD5-сгенерированным ключом, и если он не сработает, попробуйте еще раз …

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

У этого сообщения в блоге есть что-то близкое к тому, что вам нужно.

http://kevin.vanzonneveld.net/techblog/article/create_short_ids_with_php_like_youtube_or_tinyurl/

MD5 инкрементирующего числа должно быть прекрасным, но я беспокоюсь, что если вы усекаете свой MD5 (который обычно составляет 128 бит) до 5-8 символов, вы почти наверняка будете наносить ущерб его способности действовать как уникальная подпись. ..