Blog. Just Blog
Как сделать свой сервис коротких ссылок
С ростом популярности социальных сетей типа 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-ричную и обратно:
Code (PHP) : Убрать нумерацию
- // Функция получения кода ссылки из индекса
- function dec2link($id) {
- $digits='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
- $link='';
- do {
- $dig=$id%62;
- $link=$digits[$dig].$link;
- $id=floor($id/62);
- } while($id!=0);
- return $link;
- }
Code (PHP) : Убрать нумерацию
- // Функция получения индекса из кода ссылки
- function link2dec($link) {
- $digits=Array('0'=>0, '1'=>1, '2'=>2, '3'=>3, '4'=>4, '5'=>5, '6'=>6,
- '7'=>7, '8'=>8, '9'=>9, 'a'=>10, 'b'=>11, 'c'=>12, 'd'=>13,
- 'e'=>14, 'f'=>15, 'g'=>16, 'h'=>17, 'i'=>18, 'j'=>19, 'k'=>20,
- 'l'=>21, 'm'=>22, 'n'=>23, 'o'=>24, 'p'=>25, 'q'=>26, 'r'=>27,
- 's'=>28, 't'=>29, 'u'=>30, 'v'=>31, 'w'=>32, 'x'=>33, 'y'=>34,
- 'z'=>35, 'A'=>36, 'B'=>37, 'C'=>38, 'D'=>39, 'E'=>40, 'F'=>41,
- 'G'=>42, 'H'=>43, 'I'=>44, 'J'=>45, 'K'=>46, 'L'=>47, 'M'=>48,
- 'N'=>49, 'O'=>50, 'P'=>51, 'Q'=>52, 'R'=>53, 'S'=>54, 'T'=>55,
- 'U'=>56, 'V'=>57, 'W'=>58, 'X'=>59, 'Y'=>60, 'Z'=>61);
- $id=0;
- for ($i=0; $i<strlen($link); $i++) {
- $id+=$digits[$link[(strlen($link)-$i-1)]]*pow(62,$i);
- }
- return $id;
- }
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'; и для совсем уже клинических случаев выводится обычная ссылка вида "нажмите сюда, чтобы перейти". Такое решение позволит выполнить переход в любом браузере, независимо от того, поддерживает ли он скрипты, обрабатывает ли заголовки и т.п. Получается что-то вроде такого:
Code (PHP) : Убрать нумерацию
- // Ссылка для перехода
- $link='http://www.manhunter.ru';
- // Переадресация заголовками
- Header('Status: 301 Moved Permanently');
- Header('Location: '.$link);
- // Переадресация HTML
- echo '<meta http-equiv="Refresh" content="0; url='.htmlspecialchars($link).'">';
- // Переадресация JavaScript
- echo '<script type="text/javascript">';
- echo 'document.location.href=unescape("'.rawurlencode($link).'");';
- echo '</script>';
- // Ручной переход
- echo '<a href="'.htmlspecialchars($link).'">';
- echo 'Нажмите сюда для перехода по запрошенной ссылке</a>';
Вот, в принципе, и все. Осталось собрать все перечисленное в один скрипт. Вы также можете расширить функционал сервиса, например, как я уже говорил в начале статьи, добавить счетчик переходов, личный кабинет пользователя с его подборкой ссылок, а всякие мудаки могут даже показывать принудительную рекламу на странице переадресации.
В приложении мой скрипт Re:Director 1.0, который представляет собой готовый сервис коротких ссылок. Исходник прокомментирован, можете использовать его совершенно бесплатно при условии сохранения ссылки на сайт и информации об авторе.
Просмотров: 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....хотя это ты наверно и сам знаешь))
что бы показало что эта проверка 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 и многое поймешь.
А по поводу "бессмысленно проверять существование", так пропиши у себя в 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')
if(isset($_POST['do']) && $_POST['do']=='add')
ManHunter
(02.06.2011 в 08:11):
Я надеюсь, что до сплойтов дело не дойдет :)
AyTkACT
(02.06.2011 в 02:40):
>>>>>> а всякие мудаки могут даже показывать принудительную рекламу на странице переадресации.
А конченые мудаки могут добавить вредоносные элементы (скрипты, эксплоит-паки, etc.)...
з.ы. Простенько. Со вкусом. Занимательно!
А конченые мудаки могут добавить вредоносные элементы (скрипты, эксплоит-паки, etc.)...
з.ы. Простенько. Со вкусом. Занимательно!
Добавить комментарий
Заполните форму для добавления комментария
Re:Director 1.0