То, что я пытаюсь сделать, создают 12 символьных идентификаторов для статей о моем веб-сайте, подобном тому, как YouTube обрабатывает их видео идентификатор (http://www.youtube.com/watch?v=53iddd5IcSU). Прямо сейчас я генерирую хеш MD5 и затем захватываю 12 символов его как это:
$ArticleId = substr(MD5("Article".$currentID),10,12)
где $currentID является числовым идентификатором от базы данных (например, 144)
Я немного параноик, что я столкнусь с дублирующимся $ArticleId, но реалистично каковы возможности, что это произойдет? И также, будучи, что столбец в моей базе данных уникален, как я могу обработать этот редкий сценарий, не бросая ужасную ошибку?
P.S. Я сделал маленький сценарий для проверки на дубликаты в первых 5 000$ArticleId's и не было ни одного.
Править: Мне не нравится путь взгляд хешей base64_encode, таким образом, я сделал это:
function retryAID($currentID)
{
$AID = substr(MD5("Article".$currentID*2),10,12);
$setAID = "UPDATE `table` SET `artID` = '$AID' WHERE `id` = $currentID ";
mysql_query($setLID) or retryAID($currentID);
}
$AID = substr(MD5("Article".$currentID),10,12);
$setAID = "UPDATE `table` SET `artID` = '$AID' WHERE `id` = $currentID ";
mysql_query($setAID) or retryAID($currentID);
Так как столбец AID уникален, mysql_query бросит ошибку, и функция retryAID найдет уникальный идентификатор...
<?php
function get_id()
{
$max = 1679615; // pow(36, 4) - 1;
$id = '';
for ($i = 0; $i < 3; ++$i)
{
$r = mt_rand(0, $max);
$id .= str_pad(base_convert($r, 10, 36), 4, "0", STR_PAD_LEFT);
}
return $id;
}
?>
Возвращает 12-значное число в базе 36, что дает 4 738 381 338 321 616 896 возможных вариантов.(Вероятность коллизии зависит от распределения генератора случайных чисел.)
Чтобы гарантировать отсутствие коллизий, вам понадобится цикл:
<?php
do {
$id = get_id();
} while ( !update_id($id) );
?>
Что плохого в использовании последовательного идентификатора? База данных сделает это за вас.
Кроме того, 12 символов по-прежнему остаются 96 битами. 2 96 = 79228162514264337593543950336 возможных хешей. Хотя известно, что MD5 имеет уязвимости к коллизиям, существует огромная разница между вероятностью коллизии и вероятностью того, чтобы ее увидеть.
Исходя из возвращаемого значения функции PHP md5 , которую вы используете, мои цифры выше не совсем верны.
Возвращает хеш в виде 32-значного шестнадцатеричного числа.
Поскольку вы берете 12 символов из 32-значного шестнадцатеричного числа (а не 12 байтов из 128-битного хэша), фактическое количество возможных хэшей, которые вы можете получить, составляет 16 12 = 281474976710656. Еще немало.
Нет, не очень уникальный.
Почему бы не закодировать его в base64, если он вам нужен короче?