Blog. Just Blog

Как сделать свой сервис коротких ссылок

Версия для печати Добавить в Избранное Отправить на E-Mail 02.06.2011 | Категория: Web-мастеру и не только | Автор: ManHunter
С ростом популярности социальных сетей типа Twitter, где длина сообщения ограничена, возникла необходимость в специальных сервисах для сокращения длинных ссылок. В результате появилось много сайтов, где вы можете ввести длинную ссылку и вместо нее получить короткую. При переходе по такой ссылке вы сперва попадаете на сайт-редиректор, а уже с него выполняется автоматический переход на нужную ссылку. Я даже встречал такие сокращенные ссылки в печатных изданиях, а не только в интернете. Ничего сложного в реализации такого сервиса нет, и сейчас мы сделаем что-нибудь подобное.

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

А дальше нам надо продумать структуру базы данных, в которой будут храниться короткие ссылки и их соответствия. Поскольку мы делаем сейчас самый простейший сервис, то пусть структура базы будет такой:

CREATE TABLE IF NOT EXISTS `redirector_links` (
`link_id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'ID ссылки в базе',
`link_hash` VARCHAR(32) COMMENT 'Хэш ссылки',
`link_url` TEXT COMMENT 'Адрес ссылки',
PRIMARY KEY (`link_id`),
KEY `link_hash` (`link_hash`)
) ENGINE=MyISAM

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

Следующий шаг - выбор формата коротких ссылок. Оптимально, чтобы они имели вид "http://site/id", где id - это индекс ссылки в нашей базе, по которой будет выполнен переход. Можно использовать привычную числовую систему, а можно сэкономить еще несколько байт в ссылке за счет использования других символов кроме цифр. Например, возьмем все буквы английского алфавита, причем строчные и прописные будут считаться различными "цифрами". Вместе с десятичными цифрами получится 62 символа. Но традиционными средствами PHP с такими "числами" работать нельзя. Для этого нам потребуются две вспомогательные функции для преобразования числа из десятичной системы счисления в 62-ричную и обратно:
  1. // Функция получения кода ссылки из индекса
  2. function dec2link($id) {
  3.     $digits='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  4.     $link='';
  5.     do {
  6.         $dig=$id%62;
  7.         $link=$digits[$dig].$link;
  8.         $id=floor($id/62);
  9.     } while($id!=0);
  10.     return $link;
  11. }
  1. // Функция получения индекса из кода ссылки
  2. function link2dec($link) {
  3.     $digits=Array('0'=>0,  '1'=>1,  '2'=>2,  '3'=>3,  '4'=>4,  '5'=>5,  '6'=>6,
  4.                   '7'=>7,  '8'=>8,  '9'=>9,  'a'=>10'b'=>11'c'=>12'd'=>13,
  5.                   'e'=>14'f'=>15'g'=>16'h'=>17'i'=>18'j'=>19'k'=>20,
  6.                   'l'=>21'm'=>22'n'=>23'o'=>24'p'=>25'q'=>26'r'=>27,
  7.                   's'=>28't'=>29'u'=>30'v'=>31'w'=>32'x'=>33'y'=>34,
  8.                   'z'=>35'A'=>36'B'=>37'C'=>38'D'=>39'E'=>40'F'=>41,
  9.                   'G'=>42'H'=>43'I'=>44'J'=>45'K'=>46'L'=>47'M'=>48,
  10.                   'N'=>49'O'=>50'P'=>51'Q'=>52'R'=>53'S'=>54'T'=>55,
  11.                   'U'=>56'V'=>57'W'=>58'X'=>59'Y'=>60'Z'=>61);
  12.     $id=0;
  13.     for ($i=0$i<strlen($link); $i++) {
  14.         $id+=$digits[$link[(strlen($link)-$i-1)]]*pow(62,$i);
  15.     }
  16.     return $id;
  17. }
Что нам это дает? Ну, например, семизначное десятичное число 2906248 преобразуется в четырехзначное число "cc2Y", экономия в три символа налицо. Можно подумать, что это "экономия на спичках", но мы же пишем сервис КОРОТКИХ ссылок. Теперь нам надо настроить сервер, чтобы он мог обрабатывать переходы по коротким ссылкам. Это делается через файл .htaccess примерно следующим образом:

DirectoryIndex index.php

RewriteEngine on
Options +FollowSymlinks
RewriteBase /

RewriteRule ^([0-9a-z]+)$ /index.php?link=$1 [NE]

Теперь при переходе по короткой ссылке ее идентификатор будет передан скрипту index.php, затем идентификатор преобразуется из нашей 62-ричной системы счисления в обычное десятичное число и по этому ID выбирается соответствующая запись в базе. Если запись есть - выполняется переадресация на соответствующую ссылку, если записи нет - выводится сообщение об ошибке. На переадресации остановлюсь поподробнее. Ее лучше сделать одновременно несколькими способами, а именно сперва через заголовок сервера "Status: 301 Moved Permanently" и "Location: URL", затем на странице выполняется автоматическая переадресация средствами HTML через тег <meta http-equiv=Refresh content='0; url=URL'>, там же выполняется скрипт JavaScript document.location.href='URL'; и для совсем уже клинических случаев выводится обычная ссылка вида "нажмите сюда, чтобы перейти". Такое решение позволит выполнить переход в любом браузере, независимо от того, поддерживает ли он скрипты, обрабатывает ли заголовки и т.п. Получается что-то вроде такого:
  1. // Ссылка для перехода
  2. $link='http://www.manhunter.ru';
  3.  
  4. // Переадресация заголовками
  5. Header('Status: 301 Moved Permanently');
  6. Header('Location: '.$link);
  7.  
  8. // Переадресация HTML
  9. echo '<meta http-equiv="Refresh" content="0; url='.htmlspecialchars($link).'">';
  10.  
  11. // Переадресация JavaScript
  12. echo '<script type="text/javascript">';
  13. echo 'document.location.href=unescape("'.rawurlencode($link).'");';
  14. echo '</script>';
  15.  
  16. // Ручной переход
  17. echo '<a href="'.htmlspecialchars($link).'">';
  18. echo 'Нажмите сюда для перехода по запрошенной ссылке</a>';
Переходим к добавлению ссылок в базу. Здесь алгоритм следующий: пользователь вводит длинную ссылку, сервис заносит ее в базу и возвращает короткую ссылку вида http://site/id, сформированную на основании ее ID, переведенного в 62-ричную систему счисления. Если такая ссылка уже есть в базе, то новая запись не добавляется, а берется ID ранее добавленной записи. Для проверки уникальности проще всего использовать какой-нибудь хэш типа MD5 (поле link_hash в таблице).

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

В приложении мой скрипт Re:Director 1.0, который представляет собой готовый сервис коротких ссылок. Исходник прокомментирован, можете использовать его совершенно бесплатно при условии сохранения ссылки на сайт и информации об авторе.

Re:Director 1.0Re:Director 1.0

Re.Director.1.0-PCL.zip (3,648 bytes)


Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на Я.ру Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Поделиться ссылкой на Friendfeed Добавить в Яндекс.Закладки Добавить в закладки Memori Добавить в закладки Google
Просмотров: 2056 | Комментариев: 10

Комментарии

Отзывы посетителей сайта о статье
ManHunter (16.07.2011 в 14:35):
Ок. Вопрос закрыт. Я не проповедник, чтобы кого-то в чем-то убеждать. Нравится кому-то register_globals=on - хорошо, нравятся warnings - прекрасно, нравится еще что-то - замечательно.
Жека (16.07.2011 в 14:30):
ожидал от тебя слов которые меня убедят использовать флаг E_ALL, указав на плюсы, но видно не судьба.
ManHunter (16.07.2011 в 14:22):
Некритичных ошибок нет, есть состояние БЕЗ ошибок и состояние с ошибками. По остальному делай так, как считаешь правильным.
Жека (16.07.2011 в 13:54):
про error_reporting = E_ALL знаю, но не знаю зачем прописывать.
что бы показало что эта проверка if($_POST['do']) не верна?!, не вижу я большого смысла накидывать isset и  empty ради E_ALL, оно и так работает, ошибка не критична, если только не окажется что if(isset($_POST['do'])) быстрее чем if($_POST['do'])

так же искать ссылку по хэшу считаю равнозначным что и искать напрямую.

а в 153 строчке где идёт проверка на существование ссылки в базе, ты вытаскиваешь 'link_id', после вызываешь функцию dec2link...можно избавиться от её вызова добавив в таблицу поле для хранения коротких ссылок( короткие ссылки имхо выгоднее хэша держать, символов то меньше :-D ), задействован будет один и тот же запрос, к тому же на один вызов этой функции станет меньше, и соответственно пропадёт смысл в ф-ции link2dec....хотя это ты наверно и сам знаешь))
ManHunter (16.07.2011 в 13:08):
Скрытое поле 'do' запускает обработчик сабмита формы. Конкретно в этом случае в форме только одно поле, так как это минимальный пример, поэтому и кажется, что в коде есть избыточность. В реальных проектах полей может быть больше, и каджое из них будет проверяться внутри обработчика формы.

А по поводу "бессмысленно проверять существование", так пропиши у себя в php.ini параметр error_reporting = E_ALL и многое поймешь.
Жека (16.07.2011 в 03:05):
мне показалось что значение скрытого поля "do" всегда "add", $_POST['do']=='add' - бессмысленно, проверять существование элемента массива isset($_POST['do']) ....., а не проще просто if($_POST['do']), да и вообще в чём смысл этого поля?, зачем эта проверка если следующим шагом проверяется поле "url" которое куда важнее?
ManHunter (16.07.2011 в 01:04):
А тебе какой смысл нужен? Проверка скрытого поля, подтверждающего отправку формы.
Жека (16.07.2011 в 00:54):
в чём смысл этой строки?
if(isset($_POST['do']) && $_POST['do']=='add')
ManHunter (02.06.2011 в 08:11):
Я надеюсь, что до сплойтов дело не дойдет :)
AyTkACT (02.06.2011 в 02:40):
>>>>>> а всякие мудаки могут даже показывать принудительную рекламу на странице переадресации.

А конченые мудаки могут добавить вредоносные элементы (скрипты, эксплоит-паки, etc.)...


з.ы. Простенько. Со вкусом. Занимательно!

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п. будут удаляться. Злостным нарушителям доступ к сайту может быть заблокирован.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2012
При использовании материалов ссылка на сайт обязательна
Время генерации: 0,14 сек. / MySQL: 2 (0,001 сек.) / Память: 3,5 Mb
Наверх