PHP « Генерация уникальных кодов
Сайт по продаже билетов, каждый билет - уникальный код.
Вот, думаю, как бы сделать. Может, кто-то уже делал, или просто знает, как лучше?
Спасибо!
UPD:
Желательно, что бы длина ключа была единой. 8 символов, допустим.
1 ответов
Думаю, что бы "действительно" исключить совпадения, следует хранить информацию о ключах.
Рассмотрим ситуацию глубже, и для удобства классифицируем ключи, используя в ключах "префиксы".
К примеру по типам событий:
CL12345 - префикс CL - клубный ключ
EV12345 - префикс EV - ключ для события(выставки)
Конечно, это может оказаться лишним, однако,
вносит некоторое понимание в расшифровку ключа.
Допустим что ключи хранятся в базе данных.
Что бы избежать "совпадений" в базе, элементарно, делаем поле ключа уникальным.
CREATE TABLE `unique_keys` (
`id` int(11) unsigned NOT NULL auto_increment,
`key_value` varchar(8) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `key_value` (`key_value`)
);
То есть добавить в базу данных ключей мы сможем только заведомо уникальный.
Теперь, остается написать некоторую функцию, которая попросту будет генерировать уникальный "номер".
К примеру:
/* Функция генерации уникальной строки
* @var length - длина генерируемой последовательности
* Так как я в своем примере использую префикс в 2 символа,
* то по молчанию длинна основного ключа: +6 символов
* @var chars - набор символов, участвующих в генерации
* в наборе может присутствовать что угодно:
* $chars = 'ABCDEFGHJKLMNOPQRSTUVWXYZ1234567890'
*/
function rand_str($length = 6, $chars = '1234567890') {
// получаем длину строки символов
$chars_length = (strlen($chars) - 1);
// Итак, строчка начинается
$string = $chars{rand(0, $chars_length)};
// Генерируем
for ($i = 1; $i < $length; $i = strlen($string)) {
// Берем случайный элемент из набора символов
$r = $chars{rand(0, $chars_length)};
// Убеждаемся, что соседние символы не совпадают.
if ($r != $string{$i - 1}) $string .= $r;
}
// Вуаля!
return $string;
}
/* функция добавления уникальной записи
* @var prefix - тот самый префикс, о котором я говорил,
* естественно этого параметра можно избежать.
*/
function add_unique_key ($prefix = 'EV') {
// Вбиваем уникальный ключ
while (!mysql_query("INSERT INTO unique_keys (key_value) VALUES ("
. $prefix . rand_str() . ")")) {};
// на выходе мы точно получим уникальную запись.
return mysql_insert_id();
}
Да, коды писались сразу в редактор, поэтому наличие ошибок вполне вероятно.
Я хотел лишь донести смысл из практики.
update:
И да, сюда еще было бы правильней дописать функцию форматированного вывода
ключа. Что бы "читабельность" еще более повысилась.
function getFormattedKey($key) {
// Получаем "CL123456"
list($prefix, $num1, $num2) = sscanf($key, "%s%d{3}%d{3}");
// Возвращаем "CL-123-456"
return $prefix . "-" . $num1 . "-" . $num2;
}
update №2:
Да, есть еще такой ньюанс - если нет "автоматизированной" системы проверки кодов, то для "защиты" используют некий алгоритм генерации кодов.
Самый простой пример - допустим, что сумма каждых следующих двух чисел - целое число. Такая "элементарная защита" от дурака.
Подобными способами защищаются, пожалуй чуть ли не 80% софтверных компаний, пытающихся уйти от злополучных кейгенделов.
У каждого билета новерное есть свой id, не так ли? Что если к этому id добавить любое случайно сгенерированное сочетание символов, которое даже может повторяться и из этой связки сделать хеш :?
В таком случае у нас может быть 13-dha0982e и 142-dha0982e, хоть случайные символы и совпали, то из-за id билета хеш будет различаться.
Добавил вопрос в закладки, самому интересно узнать наилучший вариант ;)
Почитайте про GUID.
А именно про uuid_create(), например.
Или можно написать свою псевдослучайную генерилку GUID'ов, например:
function getGuid(){
mt_srand((double)microtime()*10000);
$charid = strtoupper(md5(uniqid(rand(), true)));
$hyphen = chr(45);
$uuid = substr($charid, 0, 8).$hyphen
.substr($charid, 8, 4).$hyphen
.substr($charid,12, 4).$hyphen
.substr($charid,16, 4).$hyphen
.substr($charid,20,12);
return $uuid;
}
На данном коде было сделано 10 000 000 GUID'ов и повторений при этом не было.