Создавая свои проекты, веб-проекты, многие программисты и веб-мастера зачастую сталкиваются с проблемой внешних ссылок в теле сайта. Наличие внешних ссылок неблагоприятно сказывается как на рейтинге сайта (бесплатно отдавать свой ТИЦ и PR другим никто не хочет), так и на его стоимости в случае продажи ссылок.
Устранение внешних ссылок — занятие простое. Даже очень. Достаточно внести в свою систему достаточно простой код.
Для начала, уточню, что поиск внешних ссылок в теле сайта легко делается регулярным выражением высотой менее трёх этажей. Хабровцы могут со мной поспорить, но это именно так.
Чтобы найти все ссылки на сайте, можно применить следующее регулярное выражение:
/<a (.*?)href=[\"\']([a-z0-9]+)\:\/\/(.*?)\/(.*?)[\"\'](.*?)>(.*?)<\/a>/i
Единственный его минус — это выражение находит все ссылки, как внешние, так и внутренние. Мы можем слегка доработать его в рамках php и добавить распознавание хоста:
$pattern = '/<a (.*?)href=[\"\']([a-z0-9]+)\:\/\/(?!'.$host.')(.*?)\/?(.*?)[\"\'](.*?)>(.*?)<\/a>/i';
В данном случае, $host содержит в себе (о да!) имя хоста, на котором расположен сайт, например, www.av13.ru. Получить его можно любым способом, например, какой-либо мифической системной функцией get_my_host_name или просто через $_SERVER[‘HTTP_HOST’]. Далее, все ссылки нам требуется заменить на внутренние. Для замены мы пользуемся регулярным выражением, описанным выше. В итоге, выходит такая фот функция:
function unurl( $text ) { $host = strtr($_SERVER['HTTP_HOST'], array('.' => '\.')); $pattern = '/<a (.*?)href=[\"\']([a-z0-9]+)\:\/\/(?!'.$host.')(.*?)\/?(.*?)[\"\'](.*?)>(.*?)<\/a>/i'; if ( defined('USER_FRIENDLY_URL') ) { $text = preg_replace_callback( $pattern, 'text_unurl', $text ); } else $text = preg_replace_callback( $pattern, 'text_unurl_bad', $text ); return $text; }
Как видно из кода, мы используем константу USER_FRIENDLY_URL. Предполагается, что она установлена, если наша система поддерживает ЧПУ, и не установлена, если все ссылки по прежнему работают как ?foo=bar. В зависимости от этого, выбирается одна из функций преобразования:
function text_unurl( $text ) { return '<a ' . $text[1] . 'href="/goto/' . $text[2] . '/' . $text[3] . '/' . $text[4] . '"' . $text[5] . '>' . $text[6] . '</a>'; } function text_unurl_bad( $text ) { return '<a ' . $text[1] . 'href="/?goto=' . $text[2] . '://' . $text[3] . '/' . $text[4] . '"' . $text[5] . '>' . $text[6] . '</a>'; }
Первая функция делает ссылки вида http://www.av13.ru/goto/http/vodki.net/pivo/, второй вариант предпочитает ссылки старого образца с прямой передачей параметров, как например http://www.av13.ru/?goto=http://vodki.net/pivo/ — оба варианта будут работать.
После того, как эта функция создана, мы должны доработать ещё два файла в системе. Это наш index.php и .htaccess, на пречи которых будет возложена «сложнейшая» задача трансляции адресов.
Добавим в наш .htaccess:
RewriteEngine On RewriteRule ^goto/([a-z0-9]+)/(.*)$ $1://$2 [L,R=301]
Добавим в index.php перед основным кодом:
if ($goto = validurl($_GET['goto'])) { header( "Location: $goto" ); die(); }
Конечно, в случае с index.php желательно добавить ещё и некоторую функцию проверки url-а на валидность — validurl.
function validurl ( $url ) { if ( $url ) { $urlregex = "^(https?|ftp)\:\/\/([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)*(\:[0-9]{2,5})?(\/([a-z0-9+\$_-]\.?)+)*\/?(\?[a-z+&\$_.-][a-z0-9;:@/&%=+\$_.-]*)?(#[a-z_.-][a-z0-9+\$_.-]*)?\$"; return (eregi($urlregex, $url)) ? $url : ''; } else return ''; }
Вот и всё — таким после этого остаётся просто выводить весь текст сайта не просто через echo $text, а через echo unurl($text). Но, если лень, можно выполнить такую доработку в системы.
В самом начале (после добавленного редиректа) вставляем вот такую штучку:
ob_start(); ob_implicit_flush(0);
И после завершения всего вывода нашего скрипта, добавим следующее:
$html = ob_get_contents(); ob_end_clean(); echo unurl( $html );
Вот и всё =) Таким образом, скрипт будет сохранять весь вывод, а потом проверять его ururl-ом. Сказать честно, простая проверка намного лучше этого варианта, но увы — лень сподвигнет и не на такое.
Пользователи WordPress могут не заниматься такими изращениями, а просто поставить себе плагин WP No External Links — он сам сделает всё за вас.