Как спрятать ссылки

Как спрятать ссылки

Индекс материала
Как спрятать ссылки
Как спрятать ссылки стр.2
Как спрятать ссылки стр.3
Все страницы

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

Кстати, если вам лень читать статью, или попросту нет времени вникать во всё это, то здесь Я разместил этот скрипт ввиде онлайн инструмента.

Так вот. Роботы пока не научились интерпретировать JavaScript, но по слухам вполне ничего себе так заглядывают в его код. Поэтому конструкции типа:

document.write('<a href="/somedomain.net">ля-ля-тополя...</a>');

похоже прокатывают уже через раз. Народ придумал шифровать ссылки в формат кодовых точек unicode, ну типа того: \u003c\u0061\u0020\u0063 есть онлайн сервисы для подобных операций, но что делать если выводимые ссылки формируются движком динамически? Что - что... читать-понимать принцип кодирования многобайтных кодировок в unicode. Что такое unicode и ASCII спросите у google он должен знатьЕсли у вас сайт в модной нынче кодировке UTF-8 а расширения типа mb_string и iconv вам не доступны (бывает и такое) или просто интересно, как это можно сделать самому, то читайте дальше.

Итак. В unicode существуют так называемые "кодовые точки", которые имеют вид: U+007F или U+0400. После префикса U+ следует шестнадцатиричное число ( предварённое нулями ). Фактически это порядковое шестнадцатиричное число позиции символа: U+006B это 6B в шестнадцатиричной, или 107 в десятичной системе или маленькая латинская буква "k" в соответствии с ASCII.

В диапазоне от U+0000 до U+007F ( это интервал от 0 до 127 в десятичном представлении) число после "U+" совпадает с шестнадцатиричным кодом символа в ASCII. Это диапазон латиницы и других печатных/не печатных символов (типа пробела и пр.) то есть символов для хранения и обработки которых требуется 1 байт. После U+007F - кодовые точки unicode следуют далее по порядку, а вот нормальное их шестнадцатиричное представление символов там уже требует 2 байта, т.е. 4 - шестнадцатиричных цыфры: U+0080 соответствует С2 80 (какой то непечатный символ).

Принцип кодирования многобайтных символов следующий:

Unicode (шестнадцатиричный) Unicode ( двоичный )
0x0000 – 0x007F 0xxxxxxx
0x0080 – 0x07FF 110xxxxx 10xxxxxx
0x0800 – 0xFFFF 1110xxxx 10xxxxxx 10xxxxxx

Вы всё еще здесь? Теперь интересное. В таблице видно что для однобайтного символа двоичное представление начинается с 0, а вот для многобайтного с 1. Причем количество единичек в первом байте (ещё его называют стартовым байтом многобайтовой последовательности ) прямо указывает на количество байт нужных для кодировки данного символа. Далее идут серийные байты которые начинаются с 10, и количество которых определено в стартовом байте. Ну а биты символа unicode упаковываются в "транспортные" биты стартового и серийных байтов, обозначенных выше как "xxxx"


В принципе, поняв весь этот двоично-шестнадцатирично-десятичный коматоз, можно понять как нам кодировать символы средствами PHP. Javascript "понимает" литералы юникода в таком виде: \u0410 т.е. префикс у него свой. Наша задача заключается в том, что нам будет нужно перегнать строку, которая содержит, как кирилицу, латиницу и спец. символы в шестнадцатиричное их представление. Причём каждый символ в отдельности.

Здесь мы постараемся обойтись без всякого рода расширений типа mb_string и iconv (мы же не ищем лёгких путей) а только фунуцией PHP bin2hex() - она вернет шестнадцатиричное представление строки-символа например 'a'. По строке пройдёмся циклом, как по массиву.  И будем работать с каждым символом по отдельности.

Кстати если у вас не прописано в php.ini  mbstring.func_overload=1 и впринципе недоступна mb_string. И если ваш сайт в UTF-8 То код:

  
    echo strlen('один');
  

Выведет число 8! - Почему? Правильно: потому что каждый кирилический символ в юникоде кодируется двумя байтами, вот такие приколы люди и имеют ввиду, когда говорят о сложности работы в PHP с unicode. Фактически функция strlen() - возвращает нам не длину слова в буквах, а длину слова в байтах! И вкоде ниже, в цикле мы фактически будем шагать не по символам слова, а по его байтам! В данном случае нам это как раз на руку. По сути нам интересен интервал от U+0410 до U+044F - интервал кириллицы в юникоде символы здесь представлены двумя байтами. Если взятый ( идём циклом по строке ) байт символов (первый из двух) умещается в диапазоне от D0 до D1 (можете посмотреть таблицу символов unicode), то это значит, что к нему нужно прибавить (здесь я имею ввиду операцию конкатенации ) следующий за ним байт, точнее его шестнадцатиричное представление.

Иначе если взятый байт меньше или равен 7Е то значит нам попался однобайтный символ, к нему просто конкатенируем спереди "\u00" (с дополнительными нулями потому что так Javascript работает)

А совсем в ином случае (если байт не в диапазоне D0-D1 и он больше 7Е) тупо пропускаем то что попалось через PHP функцию htmlentities() .

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

Теперь шестнадцатиричные коды кирилицы нужно перевести в кодовые точки unicode. Для этого смотрим в таблицу unicode и тупо копируем значения в два массива паралельно. В одном будут кодовые точки, а в другом шестнадцатиричные числа, соответсвующие этим точкам. Смотрите не напутайте :)


Осталось только прогнать всё это через функцию str_replace() и вернуть из нашей функции. Ниже приведён полный код функции с массивами сопоставления кодировки и подробными комментариями:

<?php
// На всякий случай проверка:
if(!function_exists('conv'))
{
    function conv($str)
    {
        // Переменная для "накопления" результирующей строки:
        $uot = '';

        // Здесь хранятся кодовые точки unicode 
        // в формате удобном JavaScript:
        $unicodePoints = array( '\u0410','\u0411','\u0412','\u0413',
                                '\u0414','\u0415','\u0416','\u0417',
                                '\u0418','\u0419','\u041A','\u041B',
                                '\u041C','\u041D','\u041E','\u041F',
                                '\u0420','\u0421','\u0422','\u0423',
                                '\u0424','\u0425','\u0426','\u0427',
                                '\u0428','\u0429','\u042A','\u042B',
                                '\u042C','\u042D','\u042E','\u042F',
                                '\u0430','\u0431','\u0432','\u0433',
                                '\u0434','\u0435','\u0436','\u0437',
                                '\u0438','\u0439','\u043A','\u043B',
                                '\u043C','\u043D','\u043E','\u043F',
                                '\u0440','\u0441','\u0442','\u0443',
                                '\u0444','\u0445','\u0446','\u0447',
                                '\u0448','\u0449','\u044A','\u044B',
                                '\u044C','\u044D','\u044E','\u044F');

        // Здесь хранятся шестнадцатиричные представления чисел
        // этот массив сопоставим с массивом сверху по таблице
        // юникод
        $hexView = array(   'd090','d091','d092','d093',
                            'd094','d095','d096','d097',
                            'd098','d099','d09a','d09b',
                            'd09c','d09d','d09e','d09f',
                            'd0a0','d0a1','d0a2','d0a3',
                            'd0a4','d0a5','d0a6','d0a7',
                            'd0a8','d0a9','d0aa','d0ab',
                            'd0ac','d0ad','d0ae','d0af',
                            'd0b0','d0b1','d0b2','d0b3',
                            'd0b4','d0b5','d0b6','d0b7',
                            'd0b8','d0b9','d0ba','d0bb',
                            'd0bc','d0bd','d0be','d0bf',
                            'd180','d181','d182','d183',
                            'd184','d185','d186','d187',
                            'd188','d189','d18a','d18b',
                            'd18c','d18d','d18e','d18f' );

        // Идём по строке как по массиву:
        for($i=0; $i < strlen( $str ); $i++)
        {
            // Если байт начинается с 11xx, то это стартовый 
            // байт многобайтной последовательности
            // Здесь у нас идёт сравнение с шестнадцатиричным 
            // числом: 'd0', в двоичном представлении
            // это будет как раз число 11010000, если это так...
            if(bin2hex($str{$i}) >= 'd0' && bin2hex($str{$i}) <= 'd1')
            { 
            	// то записываем в результирующую стоку этот 
                // байт в шестнадцатиричном представлении 
                // и следующий за ним, так как это будут два 
                // байта одного кирилического символа:
                $uot .= bin2hex($str{$i}).bin2hex($str{$i+1});
                
                // увеличиваем счётчик, что бы проскочить на 
                //следующий итерации уже взятый нами следующий байт:
                $i++;
            }
            // Иначе если шестнадцатиричное представление 
            // байта меньше 7Е, то перед нами однобайтный символ:
            elseif(bin2hex($str{$i}) <= '7e')
            {
                $uot .= '\u00'.bin2hex($str{$i});
            }
            // Иначе перед нами иной символ который просто обрабатываем:
            else $uot .= htmlentities($str{$i},ENT_QUOTES,'UTF-8');
        }
        // Здесь замещаем шестнадцатиричные представления кирилических символов
        // кодовыми точками unicode и возвращаем результат:
        return str_replace($hexView,$unicodePoints, $uot);
    }
}
?>

В итоге получаем кодированную строку примерно такого вида:

\u003c\u0061\u0020\u0063\u006c\u0061\u0073\u0073\u003d\u0022\u0068\u006f

Котую выводим в PHP - скрипте следующей конструкцией:

  echo '<script type="text/javascript">
           document.write("'.conv('<a href="/xxxx">ссылка</a>').'");
        </script>';

Она скроет от роботов лишние ссылки, которые в принципе нужно оставить на странице для удобства пользователей. Что вы кстати можете наблюдать у меня на сайте, если просмотрите исходный код страницы. Уф.. Фсё!

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


Защитный код
Обновить



Кто на сайте
Сейчас 140 гостей онлайн