Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Общие вопросы > Генерация уникального ID


Автор: taral 20.3.2013, 23:31
На сайте постоянно создаются заказы. На каждый заказ необходимо сгенерировать уникальный id. Он должен быть достаточно простым для восприятия человеком и обязательно не должен повторятся.
Нельзя использовать id  с базы данных и как либо на него ориентироваться.
Пока придумал подвязаться на time() и частично перевести его в цифры. Для лучшей читаемости.
Примерно так
Код

$letters='QWERTYUIOPASDFGHJKLZXCVBNM1234567890';
$count=strlen($letters);
$intval=time();
$result='';

for($i=0;$i<4;$i++) {
    $last=$intval%$count;
    $intval=($intval-$last)/$count;
    $result.=$letters[$last];
}
echo $result.$intval;

в результате получаю примерно такой код WKI0-811
в конец добавляю rand(10,99) для исключения дубляжей в ту же секунду. Получаю такое WKI0-811-45
Длинна и сложность кода устраивает. Не нравится 1. Возможность дубляжей хоть и очень небольшая. 2. Окончание 811 очень редко изменяется. Поскольку это грубо говоря года из time().
Также я уверен что есть более красивые решения. Спасибо за внимание

Автор: Arantir 21.3.2013, 01:18
Можно просто перевести unix-timestamp в 26-ичную систему счисления с буквами английского алфавита в качестве символов.

Время написания данной строки тогда будет выглядеть так: "EKULRDV"
Повторения в пределах секунды исключены. Можно добавить миллисекунды в конец: "EKULRDV903". Теперь повторения почти невозможны физически.

О переводе чисел в K-ичную систему можно почитать где угодно.
К счастью, у меня завалялся пример:
Код

function decimalToKPos($d_number, &$k_number, $dictionary)
{
    $k = count($dictionary);
    $remainder = 0;
    $n = strlen($d_number);
    while ($d_number > 0) {
        $k_number[$n--] = $dictionary[$d_number % $k];
        $d_number = intval($d_number / $k);
    }
}
decimalToKPos(1363821311, $hex, ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']);
echo implode('', array_reverse($hex));


Добавлено через 5 минут и 7 секунд
Словарь можно изменить абсолютно любым угодным вам образом. Далеко не обязательно упорядочивать буквы по алфавиту. Функции перевода все равно.
Если вас беспокоит излишняя "предсказуемость" кода, то просто перемешайте буковки. Можете туда и циферок и циферок в случайные места вставить, и разделять по 3 буквы дефисом (уже после конвертирования), если хотите.
Выйдет что-то вроде UJ2-ЗNK-8
Если не менять словарь, то повторения в пределах секунды по прежнему невозможны.

Автор: baldina 21.3.2013, 09:40
Цитата(taral @  20.3.2013,  23:31 Найти цитируемый пост)
не должен повторятся

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

Автор: skyboy 21.3.2013, 09:53
Цитата(baldina @  21.3.2013,  08:40 Найти цитируемый пост)
чем плоха просто последовательная нумерация в связке с датой?

поддерживаю.
а не то придется выслушивать по телефону объяснения в стиле "«С» как доллар"

Автор: taral 21.3.2013, 11:32
Большое спасибо за ответы. 
Скорее всего буду использовать ваш пример Arantir
baldina я согласен с тем что удобнее сообщать цифры. Но мне поставлены жесткие требования. И с этим ничего не поделать =)

Автор: baldina 21.3.2013, 11:44
закодируйте дату буквами (ДМГ), номер цифрами
день 1-26 - WA-WZ,  27-31 YA-YE
месяц 1-12 - A-L
год 2010-2036 A-Z

счет номер 45 от 21.03.2013 будет WUCD-045

Автор: skyboy 21.3.2013, 12:24
в свете собственных слов про трудность передачи по телефону, особенно людьми, у которых английский последний раз был в школе, советую отобрать буквы, которые легко читаются/понимаются и которые сложно перепутать(из пары "M-N" или "E-I" взять только одну)

Автор: Fortop 21.3.2013, 13:03
skyboy, но даты и цифры читаются вполне нормально учениками старше 3го класса smile
В общем автор юлит в чем-то.

Автор: taral 21.3.2013, 14:54
Цитата(Fortop @ 21.3.2013,  13:03)
skyboy, но даты и цифры читаются вполне нормально учениками старше 3го класса smile
В общем автор юлит в чем-то.

Нет. Просто на сайте используется база данных mongo. Где id 513bb26adffa82cf0a000042. А нужно выводить клиенту id заказа в нормальном виде. Причем заказов может быть очень много. По крайней мере заказчик настаивает на 100% уникальность. По этой причине если взять просто time() . rand(0,999) будет очень много цифр. Получить int по количеству заказов тоже не вариант потому что они могут удалятся. По причине большого кол. цифр выбрали заменить часть их на буквы. Тем более что заказчику нравится когда вначале буквы и дальше цифры. И смысла его переубеждать в этом нет =)

Автор: Fortop 21.3.2013, 16:39
Цитата(taral @  21.3.2013,  14:54 Найти цитируемый пост)
Получить int по количеству заказов тоже не вариант потому что они могут удалятся

В чем прикол?

Автор: Gold Dragon 21.3.2013, 16:58
а может проще использовать во этот формат?
Код

$id = date("ymd-B");

Автор: baldina 21.3.2013, 17:34
идея неплохая, но будут повторы
подошло бы наверно что-то вроде date_format('Symd-siH-u');

Добавлено через 2 минуты и 39 секунд
только оно не работает))))
значит так:
Код

  preg_match ('/0\.(\d{5})/',microtime(), $usec);
  $id = date_format (date_create (), 'Symd-siH-') . $usec[1];


Добавлено через 4 минуты и 30 секунд
лучше наверно
Код

$id = date_format (date_create (), 'Symd-siH-') . substr(microtime(),2,5);


Добавлено через 4 минуты и 40 секунд
http://liveworkspace.org/code/4jkooo$0

Автор: Gold Dragon 21.3.2013, 18:48
Цитата(baldina @  21.3.2013,  18:34 Найти цитируемый пост)
идея неплохая, но будут повторы
это при каких условиях?

Автор: baldina 21.3.2013, 19:22
при условии генерации более одного id в день
http://liveworkspace.org/code/4jkooo$1

Добавлено через 1 минуту и 34 секунды
Цитата(taral @  21.3.2013,  14:54 Найти цитируемый пост)
заказов может быть очень много

365 в год мне кажется не очень большим числом заказов smile

Автор: Gold Dragon 21.3.2013, 20:03
а вообще, задача изначально глупая.. Зачем что-о выдумывать когда есть порядковый номер. Ну если нет возможности использовать ID, ну так сделай отдельное поле.. и при следующем заказе делай запрос MAX(`field`), прибавляй единицу и радуйся. Не нравятся цифры. ну так замени буквами...

Автор: taral 21.3.2013, 21:24
Цитата(baldina @ 21.3.2013,  19:22)
при условии генерации более одного id в день
http://liveworkspace.org/code/4jkooo$1

Добавлено @ 19:24
Цитата(taral @  21.3.2013,  14:54 Найти цитируемый пост)
заказов может быть очень много

365 в год мне кажется не очень большим числом заказов smile

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

Автор: baldina 21.3.2013, 22:28
Цитата(taral @  21.3.2013,  21:24 Найти цитируемый пост)
Когда я говорил про большое число заказов это возможность возникновения нескольких заказов в секунду. 

именно поэтому я и сказал Gold Dragon, что будут повторы, и показал http://liveworkspace.org/code/4jkooo$0без этого недостатка

Автор: Gold Dragon 22.3.2013, 06:19
поэтому я и сказал что нет лучше ID чем простой порядковый номер  smile

Добавлено через 1 минуту и 45 секунд
PS

Цитата(taral @  21.3.2013,  22:24 Найти цитируемый пост)
Когда я говорил про большое число заказов это возможность возникновения нескольких заказов в секунду. 
Это круто, но не верится... Просто если такой оборот у "магазина", то как-то "слабенькая" реализация...  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)