Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Ещё о защите e-mail адресов на веб-страницах

Автор: fox++
http://foxweb.net.ru/
9 августа 2005 года

Оригинальная защита e-mail адресов от сканирования спам-роботами. Мы не будем кодировать адреса, мы будем их… рисовать!

О защите e-mail адресов от сканирования спам-роботами в Интернете писалось немало. Скорее наоборот, очень много. Однако все способы сводятся в основном к одному – кодирование адресов таким образом, чтобы спам-роботы не смогли его распознать, а для человека это не составило бы труда. Чаще всего мне встречались такие варианты: name[at]server.ru, name(a)server.ru и даже name(Shift+2)server.ru. Вариант, конечно, тоже хороший, но спам-роботы быстро «учатся». Опытный интернетчик догадается, что [at] нужно заменить на «@», но некоторые люди копируют адрес name[at]server.ru прямо в почтовую программу, а потом удивляются – почему письма не доходят :) Вначале проблема спама не так беспокоила меня, пока однажды горы рекламных писем не посыпались на мой ящик. В этот же день нашёл простой выход: «собачку» можно показывать как картинку, всё остальное – как символы. Внешне – обычный e-mail, а скопировать не получится.

Предлагаю вашему вниманию простой и доступный способ публикации e-mail адресов без опасения, что его просканирует спам-робот. Хотя, возможно, и просканирует, но для этого он должен обладать искусственным интеллектом :) Требования: наличие PHP с библиотекой GD. Многие наверно догадались, что мы будем делать с адресами. Мы будем их… рисовать! Назовём наш скрипт email.php. Алгоритм достаточно прост:

  1. Одним из способов скрипт получает на вход е-mail адрес:
    1. Получим адрес автора из базы данных, указав например id статьи или записи в гостевой книге (каталоге файлов, ссылок и т.д.).
    2. Передадим адрес скрипту в явном виде: email. php?adr=name@server.ru (но это чревато тем, что e-mail всё-таки «засвечен»). Такая защита равносильна её отсутсвию.
    3. Передадим адрес скрипту в неявном виде: email. php?name=name&server=server. ru
    4. Передадим адрес скрипту в зашифрованном виде: email.php?adr=anzr@freire.eh (воспользовавшись функцией str_rot13() , которая смещает коды всех латинских букв вверх на 13).
  2. Скрипт расшифровывает данные, генерирует картинку с изображением адреса и возвращает её браузеру.

Для начала рассмотрим процесс «рисования», так как он впоследствии останется неизменным:

$size = 2; 
$im = imagecreate(imagefontwidth($size)*strlen($adr), imagefontheight($size)); 

Здесь нет ничего особенного. Исходные данные: $adr – адрес, который надо «нарисовать», $size – размер шрифта на картинке (легко подбирается по размеру и «жирности», внешне похож на Tahoma, Verdana, Arial). Функция imagecreate() создаёт картинку и помещает указатель на неё в переменную $im. Однако для этого вычислим размеры будущей картинки, исходя из размера шрифта и количества символов в строке.

imagefontwidth($size) – определяет ширину одного символа при размере $size. Умножим её на длину строки strlen($adr) и получим ширину будущей картинки. Высота картинки вычисляется функцией imagefontheight($size). Добавляем в палитру изображения цвета фона и надписи (соответственно белый и красный)

$bg = imagecolorallocate($im, 255, 255, 255); 
$black = imagecolorallocate($im, 0x00, 0x00, 0x00);

Если цвет фона вашего сайта не белый, сделаем так:

imagecolortransparent($im,$bg); 

Цвет $bg в палитре станет прозрачным, поэтому $bg может быть любым цветом. Цвет символов задаётся в соответствии с вашими потребностями.

Делаем надпись:

imagestring($im, $size, 0, 0, $adr, $black); 

И выводим картинку :

header('Content-type: image/png'); 
imagepng($im); 

Теперь рассмотрим, какими способами можно получить e-mail для обработки. В таблице помещены варианты адресации и соответствующие фрагменты кода.

Извлечение e-mail из базы данных MySQL.

email.php?id=1

 mysql_connect("localhost", "username", "password");
 mysql_select_db("database");
 $id = abs(intval($id));
 $query = "SELECT email FROM table WHERE table_id='$id'";
 $result = mysql_query ($query);
 $f = mysql_fetch_array($result);
 if (empty($f[email])) $adr = "n/a";
  else $adr = $f[email]; 

Прямая передача адреса

email. php?adr=name@server.ru

дополнительный код не нужен

Раздельная передача адреса

email.php?name=name&
server=server.ru

 $adr = $name.”@”.$server 

Передача закодированного адреса

email. php?adr=anzr@freire.eh

(адрес был закодирован функцией str_ rot13(), она же раскодирует его, потому что букв в латинском алфавите всего 26, а смещение каждый раз на 13)

 $adr = str_rot13($adr); 

Вот весь скрипт целиком (добавьте нужный вам способ получения адреса):

<?php 
$size = 2; 
$im = imagecreate(imagefontwidth($size)*strlen($adr), imagefontheight($size)); 
$bg = imagecolorallocate($im, 255, 255, 255); 
$black = imagecolorallocate($im, 0x00, 0x00, 0x00); 
imagecolortransparent($im,$bg); 
imagestring($im, $size, 0, 0, $adr, $black); 
header('Content-type: image/png'); 
imagepng($im); 
?> 

Вывод картинки вместо реального e-mail делается примерно так:

Ваш e-mail: <a href="mailto:name@server.ru">name@server.ru&lt/a>
Ваш e-mail: <img src="email.php?adr=name@server.ru">

Теперь, когда мы знаем, как заменять e-mail адреса, можно написать функцию, которая будет производить такие замены в заданном тексте при помощи регулярных выражений. Это может потребоваться при тотальной фильтрации всего вывода, пакетной обработке HTML-файлов, выводе информации из БД.

Разделим адрес на 3 части:

(Имя)@(Домен).(Зона) 

И того уже имеем паттерн типа:

(.*)@(.*).(.*) 

Под эту формулу подойдут миллиарды выражений, но мы идём дальше по спецификации e-mail адреса. Имя пользователя должно состоять из "a-z", "A-Z", "0-9", а также ".", "_" и "-". Если не ошибаюсь, строгих правил по этому поводу никогда не было, где-то разрешены и другие символы, это основа. "A-Z" добавлено на случай если пользователь любит прописывать своё мыло "покруче". Длина имени от 2-х до 256-ти символов (см. RFC). Дальше домен, тоже самое – "a-z", "A-Z", "0-9", ".", "-" и всё! Длина доменного имени та же, единственная загвоздка – если мыло находится не в домене второго уровня, а, скажем, третьего или даже четвёртого. Тут снова в RFC кидаться надо, поскольку и сама служба DNS не лишена "ответа" типа HTTP 414 :). Длина домена не может превышать 256 символов, но вот входят ли в это число поддомены – не помню. Зона – здесь просто "a-z", "A-Z" от 2-х до 4-х символов.

В итоге получается что-то такое:

([a-zA-Z0-9|.|-|_]{2,256})@(([a-zA-Z0-9|.|-]{2,256}).([a-z]{2,4})) 

Можно проверить, не начинаются ли (или заканчиваются) подвыражения \\1, \\2 символами типа "." или "-", дальше – на что фантазии хватает. Используя вычисленное регулярное выражение (невольно вспоминаются лекции по матанализу), напишем функцию, которая будет заменять все адреса e-mail в строке на тэг IMG и возвращать изменённую строку. В качестве функции замены я использовал preg_replace() с синтаксисом Perl RegExp.

email_ replace. php

<?php 

// функция замены e-mail адресов 
function email_replace($text) 
{ 
$exp = '/([a-zA-Z0-9|.|-|_]{2,256})@(([a-zA-Z0-9|.|-]{2,256}).([a-z]{2,4}))/';
return preg_replace($exp, '<img src=email.php?name=\\1&server=\\2 border=0>', $text); 
} 

// исходная строка со множеством e-mail адресов
$text =<<<END 
По всем вопросам пишите на мои e-mail: 
f_mulder@list.ru, 
fox58@list.ru, 
admin@foxweb.net.ru, 
kurepin@sura.ru, 
fox58@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com 
(это реальный адрес!!!)"; 
END;

echo $text; // исходная строка 
echo "<br>"; 
echo email_replace($text); // изменённая строка

?>

Если вы нашли в этой статье спорные или непонятные моменты, жду ваших комментариев. Протестировать и скачать все варианты скриптов можно здесь: http://foxweb.net.ru/test/email/.

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
27K
26 февраля 2007 года
kipnisad
0 / / 26.02.2007
+1 / -0
Мне нравитсяМне не нравится
26 февраля 2007, 16:13:59
2foxweb

обрати внимание на программу gocr, бесплатная никсовая прога для распознавания текста

с примером из этой статьи сработает на 99%

намного практичнее пример с яваскриптом...
но роботы учатся и яваскрипты выполнять
почему бы не написать простейший сканер под винду на Delphi на основе ядра IE?
2.
Аноним
+1 / -0
Мне нравитсяМне не нравится
22 декабря 2005, 04:19:26
Вот еще более красивый и эффективный способ кодирования

<?php
function antispam_mail($mail)
{
$mail=split("@",$mail);
$user=$mail[0];
eregi("\.[a-z]{2,3}$", $mail[1], $regs);
$serv=str_replace ($regs[0], "", $mail[1]);
$domain=str_replace (".", "", $regs[0]);

$code="qwertyuiopasdfghjklzxcvbnm1234567890";

for ($i=0; $i<7; $i++) {

$a[$i]=$code[mt_rand (0, 25)];

for ($j=0; $j<mt_rand(1,5); $j++) {
$a[$i].=$code[mt_rand (0, 35)];
}
}

$antispam="<script language=JavaScript><!--\n";
$antispam.=$a[0]."=\"a h\"; ".$a[1]."=\"ref='mai\"; ".$a[2]."=\"lto:\"; ".$a[3]."=\"".$user."\"; ".$a[4]."=\"".$serv."&#46;".$domain."\"; ".$a[5]."=\"<\"+".$a[0]."+".$a[1]."+".$a[2]."; ".$a[6]."=".$a[3]."+\"@\"+".$a[4]."; document.write(".$a[5]."+".$a[6]."+\"'>\"+".$a[6]."+\"</a>\");\n";
$antispam.="//--></script><noscript>".$user."&reg;".$serv."&cedil;".$domain."</noscript>\n";
return $antispam;

print antispam_mail("user@domain.com");

?>

Адрес user@domain.com сохраняет свою работоспособность (при включеном ява-скрипте), но в исходном коде совершенно неподлежит сканированию (частично меняется с каждым адресом):
<script language=JavaScript><!--
ew6="a h"; uwj3="ref='mai"; pbwd="lto:"; oxx="user"; bm6="domain&#46;com"; h3r="<"+ew6+uwj3+pbwd; b15os=oxx+"@"+bm6; document.write(h3r+b15os+"'>"+b15os+"</a>");
//--></script><noscript>user&reg;domain&cedil;com</noscript>
3.
Аноним
+0 / -1
Мне нравитсяМне не нравится
19 октября 2005, 04:40:36
а не проще ли сделать так:
e-mail: <script language=javascript>var sobachka="@";document.write ("<a id=link title=написать href=mailto:redcoder"+sobachka+"mail.ru>redcoder"+sobachka+"mail.ru</a>")</script>

4.
Аноним
Мне нравитсяМне не нравится
11 сентября 2005, 16:52:54
А свои-то e-mail почему не закодровал 8-)))
5.
Аноним
Мне нравитсяМне не нравится
25 августа 2005, 18:24:02
2 tapin13:
Присылай это чудо программерской мысли на admin(at)foxweb.net.ru :)
6.
Аноним
Мне нравитсяМне не нравится
25 августа 2005, 14:52:59
>>не разу не видел таких роботов, штоб значит ещё и буквы на картинке угадывали.

Xex, a ia videl, moi znakomii napisal :)
Pravda tam reshenie problemi v lob, no o4en' horosho ugadival.
7.
Аноним
Мне нравитсяМне не нравится
23 августа 2005, 15:29:21
<blockquote><small>Цитата:<hr size=1>Теперь, когда мы знаем, как заменять e-mail адреса, можно написать функцию, которая будет производить такие замены в заданном тексте при помощи регулярных выражений. Это может потребоваться при тотальной фильтрации всего вывода, пакетной обработке HTML-файлов, выводе информации из БД.[/quote]
8.
Аноним
Мне нравитсяМне не нравится
23 августа 2005, 15:26:56
Хорошие предложения!

Времени не хватает до ума довести.

Замечание:
preg_replace() не нужна при вытаскивании из базы. Она нужна для выискивания мыл в выводимых текстах.

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

Спасибо за конструктивную критику!
9.
Аноним
Мне нравитсяМне не нравится
22 августа 2005, 11:45:50
Рисование рисование...
Оно хорошо, например, когда картинки на сайт для препросмотра пересобираешь.
А вот если надо спрятать почтовый адрес от скан-робота...
Давайте задумаемся. Мы собираемся выставлять почтовые адреса своих пользователей? Думаю что большая половина пользователей незахочет, чтобы их адреса были видны каждому встечному (даже нероботу).
Если же пользователь соизволит показывать свой адрес, то думаю таких будет немного.
В таки случаях (порядка 150 адресов на крупном сайте) создаем отдельное место на веб сервере и туда складваем готовые картинки с адресами пользователей типа (00010.jpg), так же ведем базу типа vasya@pupkin.ru -> 00010.jpg а на страничке выкладываем где надо ссылку на картинку.
В идеале картинки лежат на отдельном сервере для статики.

В таком варианте будут отрабатывать кеши браузеров и проксей, а если мы будем постоянно генерировать картинки почтовых адресов, то генерированные картинки в кеш непопадут и мы потеряем в скорости отображения/загрузки странички.
10.
Аноним
Мне нравитсяМне не нравится
22 августа 2005, 10:37:47
Ну и зачем при каждом отображении странички вызывать небыструю функцию preg_replace(), если данные берутся из базы?!
Лучше при вставке данных в базу один раз проверить, а потом просто вычитывать.
11.
Аноним
Мне нравитсяМне не нравится
13 августа 2005, 18:08:00
не разу не видел таких роботов, штоб значит ещё и буквы на картинке угадывали. тогда берём шрифты TTF добавляем шум (как в "секретной картинке" в этой форме)
12.
Аноним
Мне нравитсяМне не нравится
13 августа 2005, 13:27:23
а как на счет того что роботы сканируют и картинки? по крайней мере такие - запросто. Усложить надо - добавить шрифты, красивый знак @
13.
Аноним
Мне нравитсяМне не нравится
11 августа 2005, 01:03:55
Слушь, Армивит, у меня четырёх-буквенные зоны (.info) воспринимались почему то как ..nfo Ну я в паттерне объединил имя сервера и зону. Вроде заработало. и мне пофигу насчёт 100% правильности совпадений, главное штоб задачу мою решал. А он и решает :) Спасибо!

2 S4gHY:

А у вас они каким методом?
14.
Аноним
Мне нравитсяМне не нравится
11 августа 2005, 00:58:08
Там недочёт есть, перечисленные выражения в доменной зоне это - "a-z", "A-Z", а в самом паттерне только "a-z", - недолглядел =)), исправляюсь...
email_replace.php at line 6.
Код:
$exp = "/([a-zA-Z0-9|.|-|_]{2,256})\x40(([a-zA-Z0-9|.|-]{2,256})\x2E([a-zA-Z]{2,4}))/";
15.
Аноним
Мне нравитсяМне не нравится
10 августа 2005, 19:22:42
давно на своём сайте влепил картинку с нарисованым мылом
16.
Аноним
Мне нравитсяМне не нравится
9 августа 2005, 13:02:37
P.S. - Выражаю огромную благодарность тов. ARMIVIT'у за помощь в составлении регулярного выражения для функции email_replace().
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог