Автоматизация веб-проектов через электронную почту::Журнал СА 4.2004
www.samag.ru
Льготная подписка для студентов      
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
О журнале
Журнал «БИТ»
Наука и технологии
Подписка
Где купить
Авторам
Рекламодателям
Магазин
Архив номеров
Вакансии
Контакты
   

Jobsora


  Опросы

Какие курсы вы бы выбрали для себя?  

Очные
Онлайновые
Платные
Бесплатные
Я и так все знаю

 Читать далее...

  Статьи

Вектор роста  

Особенности сертификаций по этичному хакингу

В современном мире информационных технологий знания о них настолько широки и многообразны,

 Читать далее...

1001 и 1 книга  
04.12.2019г.
Просмотров: 125
Комментарии: 0
Особенности сертификаций по этичному хакингу

 Читать далее...

28.05.2019г.
Просмотров: 2646
Комментарии: 2
Анализ вредоносных программ

 Читать далее...

28.05.2019г.
Просмотров: 2649
Комментарии: 1
Микросервисы и контейнеры Docker

 Читать далее...

28.05.2019г.
Просмотров: 2124
Комментарии: 0
Django 2 в примерах

 Читать далее...

28.05.2019г.
Просмотров: 1702
Комментарии: 0
Введение в анализ алгоритмов

 Читать далее...

Друзья сайта  

Форум системных администраторов  

sysadmins.ru

 Автоматизация веб-проектов через электронную почту

Архив номеров / 2004 / Выпуск №4 (17) / Автоматизация веб-проектов через электронную почту

Рубрика: Веб /  Веб

Игорь Тетерин

Автоматизация веб-проектов через электронную почту

Если взглянуть на мир со стороны, становится абсолютно не понятно, кто и как управляет сайтами. Информации на этот счет крайне мало, хотя, думаю, существует достаточное количество интересных решений. Более-менее развитые движки сайтов предоставляют веб-интерфейс управления контентом, если, конечно, это не считается принципиальным аппендиксом. Про то, что я буду описывать, лично мне нигде пока слышать не доводилось.

Сразу же уточним, чего мы хотим добиться. Наша задача – сделать как можно более удобный и доступный интерфейс для наполнения сайта контентом, то есть переложить часть рутины на скрипты и сотрудников. Значит, нам предстоит заняться автоматизацией этого процесса.

Иногда дело доходит до смешного. Есть у человека свой проект, и даже есть свой движок. Но для каждого нового динамического раздела он пишет и рисует формы, пишет обработчики, вставляет проверки. Появляется новый раздел – берем шаблон предыдущего, корректируем, правим, редизайним, проверяем и выкладываем. И еще раз проверяем.

Такой вот обьем работы ради того, чтобы добавить один раздел. А кто-то ведь еще работает и делает это через dial-up. Любой, кто занимался этим, поймет – эта работа для орков. Мы же – программисты.

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

Новый принцип автоматизации. Основы. Сравнения

Как-то давно, когда я писал ret 0.8 (ядро для интернет-сайтов), мой друг заметил, что было бы весьма удобно, если бы сайтом можно было управлять через электронную почту. Тогда мы не уделили этому вопросу должного внимания. Позднее – только вспоминали про эту технологию. И вот, наконец, я решил испробовать это на одном разделе своего сайта http://revda.biz.

Написал простой скрипт, который читает почту из рассылки и публикует все, что попадет, на сайт. И тут я понял, что это очень удобно! Люди, которые писали в рассылку, просто переписывались, при этом страница сайта была в постоянном движении. Те, кто заходил на эту страницу, знали и понимали – за новой информацией туда можно заходить каждый день. Да, пока это больше похоже на обычный интернет-трэд, но все же!

Как все это выглядит? Наша задача – обрабатывать письма, которые мы будем брать с заранее созданного почтового ящика. Этот же ящик мы можем подписать на рассылки или нечто подобное, дело даже не только в рассылках. Мы можем дать адрес ящика нужным нам людям для того, чтобы они присылали туда новую информацию почтой, и не приучать их пользоваться для этого каким-либо веб-интерфейсом. Кроме того, наш сайт может брать что-то из сети Интернет, а результат пересылать на тот же почтовый ящик.

Грубо говоря, наш почтовый ящик стал централизованным источником информации. Этого обычно не скажешь о веб-интерфейсе, где приходится (по большей части) кого-то напрягать, заставлять или самому работать ручками. Более того – мы можем автоматически обрабатывать не один ящик, а несколько, закрепив за каждым свою тематику.

Этот подход также решает вопрос вашего присутствия в Интернете. Так как мы работаем с почтовым ящиком, то для того, чтобы обработать материал, ответить кому-то или сделать что-то еще, нам достаточно просто скачать почту, поработать с ней и отослать ответы.

Пока все выглядит очень красиво. Однако, чтобы создать нечто подобное в реальности, нам придется ввязаться в битву с одним, а может, и двумя, самыми запутанными стандартами: MIME и HTML.

Победить в битве с HTML достаточно трудно – это довольно противоречивый и очень динамичный стандарт. Тут придется не один раз приложить и руки, и голову. В рамках нашей задачи мы коснемся его только слегка.

Выбор платформы, языка и оценка задачи

На чем будет работать наш обработчик почты? Ответ очевиден, если предположить, что все должно работать и на Windows, и на UNIX-платформах. Мы не станем ограничивать себя чем-то одним, поэтому после разработки обработчика сможем использовать его и там, и там. А это весьма удобно.

На чем будем писать? Немного подумаем. Учитывая, что PHP я не знаю и знать не хочу, остается один выбор – Perl. К тому же Perl, с моей точки зрения, концептуально более правильный язык и больше подходит на роль стандартного. Но не это важно, важны принципы и алгоритм, а реализовывать можно хоть на Ruby.

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

Что же нам потребуется? Один почтовый ящик, хостинг (хотя можно и локально) с поддержкой Perl и несколькими дополнительными модулями с CPAN. Ну и остальное «огнестрельное оружие», вроде putty, far, TheBat и т. д.

Переходим к практике

Рассмотрим очень простой пример. Первое, что нам потребуется – подключение нужных модулей:

use Net::POP3;use MIME::Parser;

use MIME::Entity;

use MIME::Head;

use MIME::Body;

use MIME::Words qw(:all);

use MIME::QuotedPrint;

use MIME::Base64;

Определим основные объекты и переменные:

my $parser = MIME::Parser->new;

$parser->output_to_core(1);

$parser->tmp_to_core(1);

$mail_server='127.0.0.1';

$username='login';

$password='password';

Теперь получим список писем:

$pop = Net::POP3->new($mail_server)

        or die "Can't open coonection to $mail_server :$!\n";

$pop->login($username, $password)

        or die "Can't Authenticate: $!\n";

$messages = $pop->list

        or die "Can't get listof undeleted messages: $!\n";

Начинаем обрабатывать каждое письмо:

foreach $msgid (keys %$messages)

    {

        $message = $pop->get($msgid);

        unless (defined $message)

            {

            warn "Couldn't fetch $msgid from server: $!\n";

            next;

            }

Следующий метод изначально был взят у Рэндола Шварца. Если вы поищете в Сети, то найдете нечто вроде Perl-Column, мне встречался даже перевод, правда, неполный.

Далее следует примерно такой алгоритм: если в письме есть часть типа text/plain, то берется именно эта часть, а все остальное игнорируется.

Таким образом, если мы встречаем письмо, где есть HTML-часть и текст, то в качестве входящих данных берется именно текст. Если текстовой части нет – письмо игнорируется.

        $pop->delete ( $msgid );

        @message = @$message;

        $ent = $parser->parse_data ( \@message );

        $bodyCoding = $ent->head->mime_attr( 'Content-type.charset' );

        $origType = $ent->head->get( 'Content-Transfer-Encoding',0 );

        if ( $ent->effective_type eq 'text/plain' )

            {

            # письмо - только текст

            $bodyCoding = $ent->head->mime_attr (

'Content-type.charset');

            $origType = $ent->head->get(

'Content-Transfer-Encoding',0 );

            $body = $ent->body_as_string;

            }

        elsif (

$ent->effective_type eq 'multipart/alternative'

                 and $ent->parts(0)->effective_type eq 'text/plain' )

                 {

      # письмо, где первая часть мультипар - текст

      $bodyCoding = $ent->parts(0)->head->mime_attr(

'Content-type.charset' );

      $origType = $ent->parts(0)->head->get(

'Content-Transfer-Encoding',0 );

      $body = $ent->parts(0)->body_as_string;

      }

  elsif (

$ent->effective_type eq 'multipart/alternative'

            and $ent->parts(1)->ffective_type eq 'text/plain' )

                 {

      # письмо, где вторая часть мультипарт - текст

      $bodyCoding = $ent->parts(1)->head->mime_attr(

'Content-type.charset');

      $origType = $ent->parts(1)->head->get(

'Content-Transfer-Encoding',0 );

      $body = $ent->parts(1)->body_as_string;

      }

  else {next}

  chomp $origType;

Чем универсален этот код, так это тем, что в нём происходят все стандартные MIME-декодировки – Base64 и Quoted-Printable – и перекодирование из ISO и KOI в Windows-1251.

        # Если закодировано, декодируем его, во имя счастья

        if (lc($origType) eq 'quoted-printable')

            { $body  =  MIME::QuotedPrint::decode($body); }

        if (lc($origType) eq 'base64')

            { $body  =  MIME::Base64::decode($body); }

        $bodyCoding = lc($bodyCoding);

        # Перекодировка кирилицы у тела, если надо.

        if ($bodyCoding ne '')

            {

      if ($bodyCoding eq 'koi8-r') {$bodyCoding = 'koi'}

            if ($bodyCoding eq 'koi8r') {$bodyCoding = 'koi'}

            if ($bodyCoding eq 'iso8859-5') {$bodyCoding = 'iso'}

            if ($bodyCoding eq 'koi8-u') {$bodyCoding = 'koi'}

      if ($bodyCoding eq 'koi' || $bodyCoding eq 'iso')

                { $body = encoder($body, $bodyCoding, 'win') }

        }

        $subj  =  join( "",

map {xcode( ${$_}[1], ${$_}[0])}

     decode_mimewords(

         $ent->head->get('Subject',0)

     )

      );

  $date = $ent->head->get('Date',0);

  }

Собственно, все. Переменная $subj содержит тему письма, $body – тело письма, а $date – дату. Остальные параметры письма вы сможете легко получить, используя уже подключенные в программе модули.

Теперь вы смело можете сохранить в базе данных полученные результаты. Я, например, сохраняю их таким образом:

        use collector;

        ($r) = Add2Revorum ( \$subj, \$body, \$date );

где модуль collector.pm – часть моего движка сайта, которая создает необходимую структуру и, используя ядро ret WebOS и модуль Storable, пишет её базу (обычные плоские файлы).

О проблеме альтернативной СУБД я напишу в другой статье. Те, кого это заинтересовало, могут обратиться за подробностями по интернет-адресу: http://jkeks.far.ru/ret.

Подпрограммы или процедуры, ответственные за перекодировку:

sub xcode {

  # определяем кодировку и вызываем перекодировщик, если нужно

  my ($charset, $src)  =  @_;

  my %charsets = (

    'windows-1251' =>'win',

    'iso8859-5' =>'iso',

    'koi8-r' =>'koi',

    'koi8r' =>'koi',

    'koi8-u' =>'koi',

  );

  return $src unless ($charsets{lc($charset)});

  return encoder($src, $charsets{lc($charset)}, 'win');

}

Огромная благодарность российскому разработчику библиотек pvd – Денису Познякову (Denis Poznyakov, pvdenis@usa.net) – за минимальный код перекодировки русских символов. Перекодировка основывается на данных полей письма, тут нет попытки создания какого-либо анализатора.

sub encoder {

  my $enstring = shift; my $cfrom = shift; my $cto = shift;

  my %codefunk = (

    win => "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF",

    koi => "\xE1\xE2\xF7\xE7\xE4\xE5\xF6\xFA\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF2\xF3\xF4\xF5\xE6\xE8\xE3\xFE\xFB\xFD\xFF\xF9\xF8\xFC\xE0\xF1\xC1\xC2\xD7\xC7\xC4\xC5\xD6\xDA\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD2\xD3\xD4\xD5\xC6\xC8\xC3\xDE\xDB\xDD\xDF\xD9\xD8\xDC\xC0\xD1",

    iso => "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF",

    dos => "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF",

    koi_lc => "tr/\xB3\xE0-\xFF/\xA3\xC0-\xDF/",

    koi_uc =>"tr/\xA3\xC0-\xDF/\xB3\xE0-\xFF/",

    win_lc => "tr/\xA8\xC0-\xDF/\xB8\xE0-\xFF/",

    win_uc =>"tr/\xB8\xE0-\xFF/\xA8\xC0-\xDF/",

    alt_lc => "tr/\xF0\x80-\x9F/\xF1\xA0-\xAF\xE0-\xEF/",

    alt_uc => alt_lc => "tr/\xF1\xA0-\xAF\xE0-\xEF/\xF0\x80-\x9F/",

    iso_lc => "tr/\xA1\xB0-\xCF/\xF1\xD0-\xEF/",

    iso_uc => "tr/\xF1\xD0-\xEF/\xA1\xB0-\xCF/",

    dos_lc => "tr/\x80-\x9F/\xA0-\xAF\xE0-\xEF/",

    dos_uc => "tr/\xA0-\xAF\xE0-\xEF/\x80-\x9F/",

    mac_lc => "tr/\xDD\x80-\xDF/\xDE\xE0-\xFE\xDF/",

    mac_uc => mac_lc => "tr/\xDE\xE0-\xFE\xDF/\xDD\x80-\xDF/"

  );

  if (!$enstring or !$cfrom or !$cto) {return 0}

  else {

    if ($cfrom ne "" and $cto ne "lc" and $cto ne "uc") {

      $_ = $enstring;$cfrom = $codefunk{$cfrom};$cto = $codefunk{$cto};

      eval "tr/$cfrom/$cto/"; return $_;

    }

    elsif (($cfrom ne "") and ($cto eq "lc" or $cto eq "uc")) {

      $_ = $enstring; $cfrom = $codefunk{"$cfrom\_$cto"};

      eval $cfrom; return $_;

    }

  }

  return $enstring;

}

Если вы не поняли, как это работает, поясню. Данный пример скачивает с почтового ящика все письма, обрабатывает их и передает системе управления базами данных либо куда-то еще. Этот код является основой описываемой технологии. Как я и обещал, соблюдена полная кросс-платформенность между Windows и UNUX-системами. Все используемые в скрипте библиотеки легко доступны.

От редактора: в процессе редактирования статьи было замечено, что тот же самый Outlook Express нечасто кодирует русские буквы в заголовках сообщений. Все это, конечно, зависит от настроек, но мало кто из пользователей Outlook занимается дотошной настройкой своего почтового клиента.

Поэтому процедура xcode при работе с такими заголовками не диагностировала необходимость перекодирования. Немного подумав, была придумана небольшая модификация. Это не панацея, а скромная попытка перекрыть некоторые проблемы – угадать кодировку KOI8-R в заголовке. Для этого внесем только одну коррективу в процедуру xcode – чуть усилим проверку:

    # закомментируем строку, возвращающую неизмененный

    # заголовок и продолжим проверку:

    # return $src unless ($charsets{lc($charset)});

    unless ($charsets{lc($charset)})

      {

    # если кодировка неопределенна, считаем вхождение

    # больших и маленьких русских букв

      $upper = "ЁЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ";

      $lower = "ёйцукенгшщзхъфывапролджэячсмитьбю";

      $ucount = eval("\$src =~ tr/$upper/$upper/;");

      $lcount = eval("\$src =~ tr/$lower/$lower/;");

      # если больших букв больше - скорее всего это KOI8

    # и мы перекодируем это в Windows

      return encoder($src, 'koi', 'win') if ($ucount > $lcount);

    # иначе, как и ранее, возвращаем неизмененный заголовок

      return $src;

      }

Собственно, идея основана на том факте, что слово «Новость» в кодировке KOI будет восприниматься как «оПЧПУФШ» в кодировке Windows. Прием довольно спорный, но имеет право на существование. Абсолютно не применим на больших объемах текста – поверьте на слово.

Тема безопасности, аутентификация, вклинивания

Любое письмо, попавшее на ящик, может стать атакой или просто спамом. Как с этим бороться?

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

Описанный выше сценарий также подходит к делу принципиально. Принимаются только те сообщения, которые пришли в виде текста. Кроме того, вырезаются баннеры, расположенные обычно после символов «\n— \n» (это – стандарт TheBat). Также скрипт соблюдает логику: «можно только то, что разрешено», а не «можно то, что не запрещено».

Если проблемно организовать рассылку, скорее всего вам необходимо будет добавить проверку ключа (например, в теме письма должен быть соответствующий идентификатор). Идентификатор отбрасывает почти все проблемы с безопасностью, однако это не накладывает ограничения на входящий трафик.

Но самый безопасный вариант – принимать только текст, зашифрованный или подписанный при помощи программ семейства PGP. Это также исключит возможность прочитывания писем при случайном доступе к ящику.

Немного рекламы

Ранее мы коснулись темы хранения данных. Важно понимать, что кроме простых функций вроде публикации рассылки, со временем функциональность может обрасти связями с различными разделами, а приходящие данные смогут иметь сложную структуру. Плюс ко всему – не каждый может себе позволить профессиональный хостинг.

Ради этого всего появилось на свет ядро ret WebOS, которое (как одно из направлений) предлагает альтернативу серверу SQL. Код системы минималистичен и для своей работы требует лишь наличия модуля Storable (который входит в стандартную поставку с Perl 5.8).

В свою очередь модуль blogs.pm предоставляет возможность хранить структуры данных любой сложности и осуществлять к ним доступ как к разделам сайта. Данные хранятся в плоских файлах. Интернет-адрес проекта: http://jkeks.far.ru/ret. Добро пожаловать!


Комментарии отсутствуют

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

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

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-41
Fax: (499) 277-12-45
E-mail: sa@samag.ru