Короткий уникальный идентификатор в php - PullRequest
46 голосов
/ 21 ноября 2008

Я хочу создать уникальный идентификатор, но uniqid() дает что-то вроде '492607b0ee414'. То, что я хотел бы, - это что-то похожее на то, что дает tinyurl: '64k8ra'. Чем короче, тем лучше. Единственные требования - чтобы он не имел очевидного порядка и чтобы он выглядел красивее, чем казалось бы случайная последовательность чисел. Буквы предпочтительнее цифр, и в идеале это не смешанный регистр. Поскольку количество записей не будет таким большим (до 10000 или около того), риск столкновения не является огромным фактором.

Любые предложения приветствуются.

Ответы [ 15 ]

42 голосов
/ 21 ноября 2008

Создайте небольшую функцию, которая возвращает случайные буквы заданной длины:

<?php
function generate_random_letters($length) {
    $random = '';
    for ($i = 0; $i < $length; $i++) {
        $random .= chr(rand(ord('a'), ord('z')));
    }
    return $random;
}

Тогда вы захотите назвать его, пока он не станет уникальным, в псевдокоде, в зависимости от того, где вы будете хранить эту информацию:

do {
    $unique = generate_random_letters(6);
} while (is_in_table($unique));
add_to_table($unique);

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

РЕДАКТИРОВАТЬ: Я также добавил бы, что это имеет смысл, только если, поскольку вы собираетесь использовать его, это не для большого количества элементов, потому что это может быть довольно медленным, чем больше столкновений вы получаете (получение идентификатора уже в таблице) , Конечно, вам понадобится индексированная таблица, и вы захотите изменить количество букв в идентификаторе, чтобы избежать столкновения. В этом случае из 6 букв у вас будет 26 ^ 6 = 308915776 возможных уникальных идентификаторов (минус плохие слова), которых должно хватить на 10000.

EDIT: Если вам нужны комбинации букв и цифр, вы можете использовать следующий код:

$random .= rand(0, 1) ? rand(0, 9) : chr(rand(ord('a'), ord('z')));
27 голосов
/ 21 августа 2010

@ gen_uuid () от gord.

preg_replace получил некоторые неприятные проблемы с utf-8, из-за которых в uid иногда содержатся «+» или «/». Чтобы обойти это, вы должны явно сделать шаблон utf-8

function gen_uuid($len=8) {

    $hex = md5("yourSaltHere" . uniqid("", true));

    $pack = pack('H*', $hex);
    $tmp =  base64_encode($pack);

    $uid = preg_replace("#(*UTF8)[^A-Za-z0-9]#", "", $tmp);

    $len = max(4, min(128, $len));

    while (strlen($uid) < $len)
        $uid .= gen_uuid(22);

    return substr($uid, 0, $len);
}

Мне потребовалось немало времени, чтобы понять, что, возможно, это избавит кого-то еще от головной боли

24 голосов
/ 14 марта 2014

Вы можете достичь этого с меньшим количеством кода:

function gen_uid($l=10){
    return substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyz"), 0, $l);
}

Результат (примеры):

  • cjnp56brdy
  • 9d5uv84zfa
  • ih162lryez
  • ri4ocf6tkj
  • xj04s83egi
17 голосов
/ 21 ноября 2008

Существует два способа получения надежно уникального идентификатора: сделать его настолько длинным и переменным, чтобы шансы на столкновение были невероятно маленькими (как с GUID), или сохранить все сгенерированные идентификаторы в таблице для поиска (либо в памяти, либо в БД или файл) для проверки уникальности при генерации.

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

11 голосов
/ 22 января 2010

Действительно простое решение:

Создайте уникальный идентификатор с помощью:

$id = 100;
base_convert($id, 10, 36);

Получите исходное значение снова:

intval($str,36);

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

11 голосов
/ 04 октября 2009

Вот процедура, которую я использую для случайных base62 любой длины ...

Вызов gen_uuid() возвращает строки типа WJX0u0jV, E9EMaZ3P и т. Д.

По умолчанию это возвращает 8 цифр, следовательно, пробел 64 ^ 8 или примерно 10 ^ 14, этого достаточно, чтобы столкновения происходили довольно редко.

Для большей или меньшей строки передайте $ len по желанию. Никаких ограничений по длине, как я добавляю, пока не будет выполнено [до предела безопасности в 128 символов, который можно удалить].

Обратите внимание, используйте случайную соль внутри md5 [или sha1, если вы предпочитаете], чтобы ее нельзя было легко перепроектировать.

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

Свободно использовать по лицензии BSD, наслаждаться,

Горд

function gen_uuid($len=8)
{
    $hex = md5("your_random_salt_here_31415" . uniqid("", true));

    $pack = pack('H*', $hex);

    $uid = base64_encode($pack);        // max 22 chars

    $uid = ereg_replace("[^A-Za-z0-9]", "", $uid);    // mixed case
    //$uid = ereg_replace("[^A-Z0-9]", "", strtoupper($uid));    // uppercase only

    if ($len<4)
        $len=4;
    if ($len>128)
        $len=128;                       // prevent silliness, can remove

    while (strlen($uid)<$len)
        $uid = $uid . gen_uuid(22);     // append until length achieved

    return substr($uid, 0, $len);
}
4 голосов
/ 08 февраля 2012

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

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

Это python, а не php, но я загрузил код здесь: https://github.com/adecker89/Tiny-Unique-Identifiers

4 голосов
/ 21 ноября 2008

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

function toUId($baseId, $multiplier = 1) {
    return base_convert($baseId * $multiplier, 10, 36);
}
function fromUId($uid, $multiplier = 1) {
    return (int) base_convert($uid, 36, 10) / $multiplier;
}

echo toUId(10000, 11111);
1u5h0w
echo fromUId('1u5h0w', 11111);
10000

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

3 голосов
/ 21 ноября 2008

Буквы красивые, цифры некрасивые. Вы хотите случайные строки, но не хотите "некрасивых" случайных строк?

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

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

Другая альтернатива: используйте uniqid() и избавьтесь от цифр.

function strip_digits_from_string($string) {
    return preg_replace('/[0-9]/', '', $string);
}

Или замените их буквами:

function replace_digits_with_letters($string) {
    return strtr($string, '0123456789', 'abcdefghij');
}
1 голос
/ 20 февраля 2014

Посмотрите на эту статью

Он объясняет, как генерировать короткие уникальные идентификаторы из ваших идентификаторов bdd, как это делает youtube.

На самом деле, функция в статье очень связана с php function base_convert , которая преобразует число из базы в другое (но только до базы 36).

...