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

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

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

С технической точки зрения реализации на PHP, наиболее удобная 36-ричная система счисления. Во-первых, это максимальное значение параметра $tobase функции base_convert, а во-вторых 36-ричная система счисления включает все цифры 0-9 и латинские буквы a-z в нижнем регистре.

Итак, чтобы сконвертировать десятичный ключ в 32-ричную систему исчисления, воспользуемся следующим кодом:

  echo base_convert(123456, 10, 36); //2n9c

И наоборот:

  echo base_convert('2n9c', 36, 10); //123456

Таким образом после добавления ссылки в таблицу можно легко получить ее идентификатор:

  mysqli_query($conn, 'INSERT INTO `short_links` (`url`) VALUES ("http://domain.com/some-path/")');
  echo base_convert(mysqli_insert_id($conn), 10, 36);

Переменная $conn — это идентификатор соединения с БД, полученный в результате вызова mysqli_connect.

А сделать перенаправление на исходную ссылку по её идентификатору, можно например так:

  $id = base_convert($_GET['id'], 36, 10);
  $db_result = mysqli_query($conn, 'SELECT `url` FROM `short_links` WHERE `id` = '.$id);
  $link = mysqli_fetch_assoc($db_result);
  header('Location: '.$link['url']);

Вот такие размышления на тему, буду рад если кому-то пригодится :).

Рассказать друзьям: