Создание уникальных id

121
10 апреля 2019, 06:50

В коде, в цикле я задаю уникальные id. Но они начинаются повторяться в БД, из-за неверных функций. Подскажите, как сделать правильно, но и красиво. В виде: "6bqF5zh9WiZo". md5() и sha1() - не дают формат с верхним регистром

Плохой код:

            $blocks = array('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',
                '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',
                '1','2','3','4','5','6','7','8','9','0');
            shuffle($blocks);
            $randKeys = array_rand($blocks, 12);
            foreach ($randKeys as $key) {
                $uid .= $blocks[$key];
            }
Answer 1

Когда-то писал для себя генератор паролей. Возможно вам пригодится. Пример тут.

$characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
$lenght = 15;
$uppers = 3;
$password = "";
$what = -1;
$a = 0;
$b = 0;
srand((double)microtime()*1000003);
while (strlen($password) < $lenght)
{
    $pos = rand(0, strlen($characters) - 1);
    $char = substr($characters, $pos, 1);
    if ($pos < 26)
        $current = 1;
    else if ($pos < 52)
        $current = 2;
    else
        $current = 3;
    if (substr_count($password, $char) > 0 || $current == $what || ($a >= $uppers && $current == 1))
    {
        $i = $i - 1;
        continue;
    }
    else if ($a == 1 && $current == 1 && strlen($password) < 4)
    {
        $i = $i - 1;
        continue;
    }
    else if ($a == 2 && $current == 1 && strlen($password) < 8)
    {
        $i = $i - 1;
        continue;
    }
    else if ($a == 3 && $current == 1 && strlen($password) < 12)
    {
        $i = $i - 1;
        continue;
    }
    else if ($a == 4 && $current == 1 && strlen($password) < 16)
    {
        $i = $i - 1;
        continue;
    }
    else if ($b == 1 && $current == 3 && strlen($password) < 4)
    {
        $i = $i - 1;
        continue;
    }
    else if ($b == 2 && $current == 3 && strlen($password) < 8)
    {
        $i = $i - 1;
        continue;
    }
    if ($current == 1)
        $a++;
    $what = $current;
    $password = $password.$char;
}
Answer 2

Можно сделать свою собственную функцию.

function unique($length = 32)
{
    $a = uniqid(rand(0, 1000), true);
    $b = uniqid(rand(1000, 10000), true);
    $c = uniqid($a . $b);
    $d = md5($a . $b . $c);
    $e = str_split($d);
    $f = '';
    foreach ($e as $l)
        if (is_numeric($l))
            $f .= $l;
        else
            if(rand(0,1))
                $f .= strtoupper($l);
            else
                $f .= $l;
    $r = substr($f, 0, $length);
    return $r;
}

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

echo unique(12) // 1eEf590C0e91 (максимальная длинна 32 символа) 
Answer 3

В твоем коде каждый символ используется только один раз, что на порядки снижает количество вариантов хэша. Мой вариант:

$arr = array_merge( range('a','z'), range('A','Z'), range('0','9') );
$arr = array_flip($arr);
for($i=0; $i<10; $i++){
    $uid .= array_rand($arr,1);  // 10 - меняем на нужную длину
}
echo $uid;

другой вариант

$uid = array_map( function($v){ 
              return rand(0,1)==1 ? $v : strtoupper($v) ; 
          }, str_split(uniqid()) );
echo substr(implode('',$uid),0,10);
Answer 4

Можно использовать 16 bit, как вариант:

function guid() { 
  function s4() { 
    return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); 
  } 
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); 
} 
 
console.log(guid());

Answer 5

Один раз на бэке сгенерите криптостойкий хэш (например, sha256) от случайного значения. Запомните результат. Каждый раз когда требуется следующее значение, генерите его из предыдущего хэша и запоминайте его вместо прошлого. Такая генерация "следующего из предыдущего" будет весьма равномерно гонять вас по всем числам диапазона в котором работает выбранная функция хэширования.

Вам останется только полученные биты привести к системе счисления согласно вашему словарю. Как это сделать (букво-цифровой код из числа) можно почитать, например, тут Create Youtube-Like IDs With PHP/Python/Javascript/Java/SQL (найдено на просторах сети в статье Генерация ID как на YouTube: зачем это надо и как это сделать?).

Хорошая статья по теме: Генерируем псевдослучайные ID а-ля Youtube.

Чуть больше математики в этой про Генераторы непрерывно распределенных случайных величин.

READ ALSO
Как отлавливать warning в PHP?

Как отлавливать warning в PHP?

Есть код, который отрабатывает ответы на запросы к API и там есть такой участок:

132
Ошибка в админке wordpress &#171;failed to open stream: No such file or directory&#187; — как исправить?

Ошибка в админке wordpress «failed to open stream: No such file or directory» — как исправить?

Есть сайт на wordpress с установленным плагином WP Hide PostЕсть необходимость переноса сайта на новый хостинг, но решил перестраховаться и проверить...

118
1C Soap Web Service

1C Soap Web Service

Необходимо запустить проект, где есть 1С на СУБД postgreSQL на северной части, и должно быть клиентское, мобильное приложение Android, которое при...

135