Алгоритм сокращения URL-адресов PHP

Может ли кто-нибудь порекомендовать предпочтительный алгоритм для сокращения URL-адресов? Я кодирую с помощью PHP. Первоначально я думал о том, чтобы написать что-то, что начиналось бы с символа, такого как «a», и повторяло бы запросы, создавая записи в базе данных и, следовательно, увеличивая символ до b, c, d ... A, B и так далее, как подходящее.

Однако меня осенило, что этот алгоритм может быть довольно тяжелым/неуклюжим, и может быть лучший способ сделать это.

Я немного читал в Google, и некоторые люди, кажется, делают это с базовым преобразованием из столбца идентификатора базы данных. Это не то, с чем я слишком хорошо знаком.

Может ли кто-нибудь уточнить и объяснить мне, как это будет работать? Пара примеров кода тоже не помешала бы.

Я, очевидно, не хочу полного решения, поскольку я хотел бы научиться, делая это сам, но просто объяснение/псевдокод о том, как это будет работать, было бы превосходно.


person George    schedule 18.08.2010    source источник


Ответы (7)


Большинство сервисов сокращения просто используют счетчик, который увеличивается с каждой записью, и преобразуют базу от 10 до 64.

Реализация на PHP может выглядеть так:

function encode($number) {
    return strtr(rtrim(base64_encode(pack('i', $number)), '='), '+/', '-_');
}
function decode($base64) {
    $number = unpack('i', base64_decode(str_pad(strtr($base64, '-_', '+/'), strlen($base64) % 4, '=')));
    return $number[1];
}

$number = mt_rand(0, PHP_INT_MAX);
var_dump(decode(encode($number)) === $number);

Функция encode принимает целое число, преобразует его в байты (pack), кодирует его с помощью кодировки Base-64 ( base64_encode), обрезает конечный отступ = (rtrim) и заменяет символы + и / на - и _ соответственно (strtr). Функция decode является обратной функцией для encode и делает прямо противоположное (за исключением добавления завершающего заполнения).

Дополнительное использование strtr заключается в переводе исходного алфавита Base-64 в < href="http://tools.ietf.org/html/rfc4648#section-5" rel="noreferrer">URL и безопасный алфавит имени файла, поскольку + и / должны быть закодированы с процентным кодированием .

person Gumbo    schedule 18.08.2010
comment
Спасибо за ваши предложения! Много, чтобы получить мои зубы в настоящее время. Поиграюсь с Base64. Спасибо. - person George; 19.08.2010

Вы можете использовать функцию base_convert для базового преобразования от 10 до 36 с идентификаторами базы данных.

<?php
   $id = 315;
   echo base_convert($id, 10, 36), "\n";
?>

Или вы можете повторно использовать некоторые из идей, представленных в комментариях на странице ниже:

http://php.net/manual/en/function.base-convert.php

person hgf    schedule 18.08.2010

Предполагая, что ваш PRIMARY KEY является INT и он автоматически увеличивается, следующий код поможет вам начать работу =).

<?php

    $inSQL = "INSERT INTO short_urls() VALUES();";
    $inResult = mysql_query($inSQL);
    $databaseID = base_convert(mysql_insert_id(), 10, 36);

    // $databaseID is now your short URL

?>

EDIT: включен base_convert из ответа HGF. Я забыл использовать base_convert в исходном сообщении.

person Raphael Caixeta    schedule 18.08.2010
comment
Большое спасибо. Я могу это понять, но, конечно, если вы просто используете идентификатор базы данных, вы ограничены числами от 0 до 9, то есть только Base10? Не лучше ли как-то использовать a-zA-Z0-9? Или у меня очень светлые моменты... - person George; 18.08.2010

Раньше я разбивал идентификатор по алгоритму, аналогичному преобразованию из десятичного в шестнадцатеричный, но он будет использовать 62 символа вместо 16 символов, которые использовались бы в шестнадцатеричном формате.

'0','1','2','3','4','5','6','7','8','9',
'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'

пример: если вы измените ID = 1234567890, вы получите kv7yl1 в качестве ключа.

person Jeg Bagus    schedule 18.08.2010

Я принял «легкое» решение. По запросу пользователя я генерирую уникальный идентификатор (проверка конфликтов в БД) с помощью этого фрагмента кода Python:

url_hash = base64.b64encode(os.urandom(int(math.ceil(0.75*7))))[:6]

и сохранить его в БД.

person Enrico Carlesso    schedule 18.08.2010

Собственный PHP base_convert() хорошо работает для небольших диапазонов чисел, но если вам действительно нужно кодировать большие значения, рассмотрите возможность использования чего-то вроде представленной здесь реализации, которая будет работать с базой 64 и выше, если вы просто предоставите больше допустимых символов для кодирования .

http://af-design.com/blog/2010/08/10/working-with-big-integers-in-php/

person Erik Giberti    schedule 18.08.2010

Вот попробуйте этот метод:

hash_hmac('joaat', "http://www.example.com/long/url/", "secretkey");

Он предоставит вам хеш-значение, подходящее для профессионального сокращения URL, например: «142ecd53».

person AWC    schedule 23.08.2015