Автоматизируем защиту e-mail адресов от спамеров

Как уже многие знают, одним из методов получения базы e-mail адресов для спам-рассылок является обход сайтов роботами спамеров в поисках адресов.
Предотвратить это можно простым способом: закодировать e-mail адреса на странице так, чтобы для пользователя всё отображалось в обычном виде, но в исходном коде в открытом виде адресов не было. Об этом уже много чего написано и есть хорошая статья на хабре: habrahabr.ru/post/22549/

Далее рассмотрим, как можно автоматизировать процесс кодирования, чтобы на всех страницах e-mail адреса были всегда закодированы.

Суть метода состоит в поиске всех адресов с помощью регулярных выражений и их кодирования тем или иным способом. В настоящее время мы у себя используем кодирование адресов с помощью JavaScript.

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

<code class="php">    $tags = array("a", "area");
    // 1 вариант - теги закрыты: <a>...</a>
    preg_match_all("/\<(".implode("|", $tags).")\s{1}([^<]*?)href=[\'|\"]mailto\:(".self::getMailPattern(false, false).")[\'|\"]{1}([^\>]*)\>(.*?)\<\/(".implode("|", $tags).")\>/iu", $htmlSrc, $matches, PREG_SET_ORDER);
    $htmlSrc = self::processMatchesEmail($htmlSrc, $matches);

    // Разновидность 1 варианта - на случай, если теги не закрыты
    preg_match_all("/\<(".implode("|", $tags).")\s{1}([^<]*?)href=[\'|\"]mailto\:(".self::getMailPattern(false, false).")[\'|\"]{1}([^\>\/]*)\>/i", $htmlSrc, $matches, PREG_SET_ORDER);
    $htmlSrc = self::processMatchesEmail($htmlSrc, $matches);

    // 2 вариант - теги пустые, но закрыты: <area />
    preg_match_all("/\<(".implode("|", $tags).")\s{1}([^<]*?)href=[\'|\"]mailto\:(".self::getMailPattern(false, false).")[\'|\"]{1}([^\>]*)\/\>/i", $htmlSrc, $matches, PREG_SET_ORDER);
    $htmlSrc = self::processMatchesEmail($htmlSrc, $matches);

    // 3 вариант - mail вне тегов.
    $htmlSrc = self::processEmailInText($htmlSrc);
</code>

Найденные совпадения перебираем и кодируем. Например так:

<code class="php">  public static function getJsEmail($mail) {
    $len = strlen($mail);
    $res = '';
    for ($i = 0; $i < $len; $i++) {
      $char = $mail{$i};
      if ($char == '@') {
        $res .= "' + '&' + '#6' + '4;' + '";
      } else {
        if ($i % 2 == 0) {
          $res .= htmlentities($char, ENT_QUOTES, 'utf-8');
        } else {
          $res .= $char;
        }
      }
    }
    $res = "'".$res."'";
    return $res;
  }
</code>

Нюансы:
1. Это не будет работать если e-mail адреса находятся в JavaScript блоке. Но на своей практике пока такого не встречал.
2. Это можно применить если движком сайта можно получить исходный код сгенерированной страницы.
Например, на yii это можно организовать в методе контроллера processOutput:
<code class="php">    public function processOutput($output) {
      $output = parent::processOutput($output);
      return HEmailEncode::encodeHtmlSource($output);
    }
</code>
3. Желательно организовать кэширование страниц, обработанных с помощью этой штуки, чтобы на каждый хит не было однообразной работы. В таком случае, кодировать надо html у кэшируемых блоков, а в шаблоне страницы адреса закодировать вручную:
<code class="php">echo HEmailEncode::getJsEmailEx('test@test.ru');
</code>
Но на небольших сайтах можно и забить.

Исходники: github.com/cvek/EncodeEmail


0 комментариев

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.