Рецепты программирования на PHP

  Главная   Учебник   Статьи   FAQ   Книги   Ссылки  

PHP: Почтовый робот и CRON. Как выполнять регулярные действия в PHP.

© Дмитрий Бородин

www.php.spb.ru

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

Сразу хочется предупредить, что здесь будет рассказано о множестве способов сделать одну вещь разными способами, поэтому вам придется немного думать... Это к тому, что к статьтье по отправке писем с аттачем постоянно имеют притензии разные люди, которые не умееют заполнить ни "почтовый хост провайдера", ни даже "обратный адрес". Пока вы будете читать эту статью, вы узнаете о большом количестве ньюансов и поймете, что спрашивать или объяснять в 2х словах "как сделать почтового робота?" невозможно.

CRON - средство выполнять регулярные действия на серверах типа Unix. В Windows крон называют шедулером. Суть одна: делаем правила срабатывания крона, например раз в 2 минуты или в 23:59 по четвергам, и что делать, например запустить php-программу (чтобы та делала нужную работу). В форуме часто возникает вопрос "как делать что либо регулярно?". Именно крон решает эту проблему.

Больше ничего придумать нельзя. Разве что совсем не реагировать на почту.

Почтовый робот за 10 минут ("COMMAND")

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

Приступим. Разумеется, ваш сервер должен быть типа Unix, а не Windows. Еще вы должны иметь PHP в виде CGI программы. Попробуйте запустить из телнета комагду echo 123 | php (либо с путями: echo 123 | /usr/bin/php). Если вы увидите в ответ что-то, то ПХП на сервере есть. Напишут "файл не найден" - значит еще нет. Попробуйте поискать в других каталогах или спросить админа. Если действительно нет - нужно скомпилировать ПХП как CGI программу. Это сделать очень просто:

1) Ваш домашний каталог. Он не должен быть доступен из веба, т.е. не совпадать ни с одним веб-каталогом на сервере. Например, ваши веб-страницы живут в каталоге /www, а ваш домашний каталог - /home/dima. Вот там то мы и будем писать робота. Если вы положите такой скрипт в веб-каталог, получиться натуральный троян, типа телнет-доступа для всех желающих на сервер. В скрипте ничего страшного нет, просто чтение входного потока.

2) Создайте файл робота. Он будет в нашем домашнем каталоге /home/dima/mail.php (расширение никакого значения не имеет) следующего содержания:

#!/usr/bin/php

3) Как это работает. Мы еще не закончили, но уже видно, как это будет работать. Во-первых, данный скрипт будет запущен только при приходу письма. Во-вторых, вам подадут письмо в готовом виде - надо только открыть входной поток (файл со спец. именем php://stdin) и прочитать от туда текст. Представьте, что это обычный файл. После того, как вы прочитали письмо, функции почтового робота заканчиваются. Вы можете поместить письмо в переменную или сразу построчно обработать, но главное - это уже совсем другая история, каким образом реагировать на текст-письма (там есть заголовок, тело, поля в заголовке...). В примере мы записываем текст письма в файл /tmp/php-robot.txt (доступ к каталогу /tmp имеют все пользователи на сервере). Число 10`000 очень завышено. Максимальная длина письма, толи 1 Кбайт, толи 2 Кбайта (в этом пределе). Писем с большими по длине строками не бывает, это вам может гарантировать ваш почтовый сервер.

3) Настроим права на скрипт. Файл (mail.php) должен иметь атрибуты rwxr-xr-x, владелец и группа не имеют значения. Если вы умете юзать ФАР, то подведите курсор к файлу mail.php на FTP панели, нажмите Ctrl+A и проставьте все 9 галочек, кроме 5й и 8й слева.

4) Глюк с переводом каретки. Если вы создаете файл (mail.php) в Windows/DOS и потом копируете по FTP на сервер, глюк будет. Если создать файл прямо из консоли сервера каким-нибудь редактором (vi, joe, mc), то глюка не будет. Глюк заключается в разных переводых каретки. Причем надо конвертировать перевод каретки не во всем файле, а только в первой строке: #!/usr/bin/php. Глюк не имеет отношения к ПХП, а к Юниксам в целом. К сожалению, разработчики линуксов и прочего вместо того, чтобы профикситить сей давний глюк, особо проявившийся с появлением веба, занимаются не понятно чем. Чтобы исправить глюк, сравните на пререводы каретки у любого файла с сервера (не из веб-каталога) и файла с Windows. Итак решение по шагам:

5) Вам нужен админ сервера. Если вы живете на платном хостинге, админ может и не согласиться, но если ваш хостинг по месту работы - местный админ сделать обязан. Админов, которые что-то заявляют о дырявости ПХП или ненадежности таких технологий надо гнать с позором. В функции администратора сервера входит защита веб-сервера и веб-программ от взлома через сам сервер, а не методом ошибок в веб-программах. (Веб-программер, разумеется, должен писать программы без ошибок.) В том числе админ должен думать, что будет, если кто-то начнет целенаправлено спамить ваш хост письмами (есть элементарная защита - настройки в sendmail). Итак, к делу - надо в файл /etc/aliases поместить строку

testmail:     |/home/dima/mail.php

Допустим, ваш основной домен - php.spb.ru. Тогда адрес почтового робота будет testmail@php.spb.ru. Если домен не совпадает с основным, то можно воспользоваться виртульными доменами sendmail'а, обычно это файл с названием virtual (если админ не умеет - на мыло).

6) Не забудем пересоздать базу из файла aliases. На некоторых линухах установлен не sendmail, а что-то другое. Там не нужно пересоздавать базу. Но если в каталоге /etc вы найдете файл aliases.db, то вам это надо (запускать с правами рута):

makemap hash /etc/aliases.db < /etc/aliases ; newaliases

Возможно, досточно выполнить только одну из этих команд... Но так будет работь.

7) Альтернатива 5+6 пунктам (выполнить либо пункты 5+6, либо 7). Пункт 5 работает надежно - рекомендуется. А этот - может и не работать. Зато, если вы имете телнет-доступ на сервер, можно попробовать обойтись и без админа. Проверим, будет ли работать. Создайте файл /home/dima/.forward (не потеряйте точку). В файле строку:

|/home/dima/mail.php

Данный файл (.forward) дает возможноть любому пользователю, у когорого есть домашний каталог и шелл (только FTP - недостаточно), перенаправлять свою почту на нужные адреса (их может быть много) или запускать команды по приходу письма. E-mail пишут как есть, а команды начинают с вертикальной черты. Много записей разделяют либо запятой, либо переводом строки. Сделайте так и пошлите письмо работу. Обратите внимание, теперь у робота будет адрес пользователя данного каталога /home/dima. Т.е. никаких "testmail" в таком случае сделать нельзя. Для этого существуют алиасы, что и было описано в пунктах 5+6. Адрес будет совпадать с ваши логином на сервере, домен будет основной, т.е. e-mail получиться таким: dima@php.spb.ru. Если после письма файл логов не измениться - значит этот способ на данном сервере не работет (в принципе он должен работать).

8) Готово! Теперь шлем письмо на адрес робота и смотрим что получилось.

9) О правах и пользователях. Вниманию админу. Файл mail.php в описанной выше конфигурации (5 пункт) будет запущен от пользователя/группы daemon:daemon (это не рут). Если это опасно, то с помощью команды "su" измените пользователя на нужного. Пример: su юзер -c команда. Либо воспользуйтесь sudo или спец битом у файла mail.php.

Теория

Итак, мы пишем робота. Как мы определились выше, это будет программа на PHP, которая должна анализировать письма. Разумеется, не все сразу, а по очереди. Нам могут дать почту в двух видах: либо один файл с кучей писем (от 0 писем и более), либо файл с одним письмом (не более 1 письма). Второе разумеется удобнее, но не всегда доступно.

Давайте посмотрим из чего состоит одно письмо. Пример:

From dima@php.spb.ru  Fri Jun 15 03:01:23 2001
Received: from host (host [195.220.4.134])
        by php.spb.ru with ESMTP id f5EN1NJ04208
        for &lt;testmail@php.spb.ru&gt;; Fri, 15 Jun 2001 03:01:23 +0400
Date: Fri, 15 Jun 2001 02:49:28 +0400
From: Dmitry Borodin &lt;dima@php.spb.ru&gt;
X-Mailer: The Bat! (v1.51) Educational
X-Priority: 3 (Normal)
Message-ID: &lt;5995698897.20010615024928@php.spb.ru&gt;
To: testmail@php.spb.ru
MIME-Version: 1.0
Content-Type: text/plain; charset=koi8-r
Content-Transfer-Encoding: 8bit
Текст письма.
Текст письма.
Текст письма.

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

В письме есть заголовок и тело. Заголовок идет с первой строки. Тело отделено от заголовка пустой строкой. Если вам дают файл с множеством писем, то письма разделяются довольно просто. Если строка начинается со слова "From " (5 символов, включая пробел) - то это начало нового заголовка. Да, хоть это и невероятно, но именно так письма можно разделить между собой. Возникает вопрос - а не может ли слово "From" встретиться в тексте письма? Нет. Может встетиться "From:" или еще что, но "From" с пробелом не встретиться. Возникает следующий вопрос - а нельзя ли в тексте письма вставить кучу слов "From" (с пробелом) и нарушить работу вражеского почтового сервера? Тоже нельзя :-) Умный сервер заменит "From" на ">From".

Подготовим ПХП для запуска робота

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

Если вы ниже выберите вариант 1 или 2, вам Апач как CGI не нужен. И наоборот - если у вас нет Апача как CGI, то вы можете использовать только способы 1 или 2, чтобы организовать почтового робота или просто крон. В остальных случаях - Апач как CGI вам нужен. Если вы самостоятельно этого проверить не можете, обратитесь к администратору сервера с вопросом "Как запускать PHP в CGI-режиме?". Если скажет - нет такого, требуйте, чтобы появился :-) В конце концов вам от него нужно только адрес вида /usr/bin/php получить. Т.е. php - это название программы, а /usr/bin - каталог.

Вариант 1: без CRON, без Command, метод POP3 почты.

Это значит, что вы не имете доступа ни к крону, ни к описанному способу 'command'. Не расстраивайтесь :-) Наша почта находится либо на том же сервере, где и робот, либо на другом. Наша задача научиться забирать почту с POP3 ящика и выполнять данную функцию регулярно.

Как забрать почту с POP3 ящика. Надо изучить сокеты и POP3. Поверьте, это просто. Чтобы понять сокеты, предствьте, что это простые файлы, в которые можно писать и читать. Для забора почты нужно открыть сокет с сервером почты на 110 порту (порт POP3 сервера). Далее, как в файл, надо написать USER ваш_логин (пример: fputs($sock,"USER dima");), затем PASS ваш_пароль. После этого командой LIST получить список писем, еще командой RETR номер взять текст письма и стереть его с сервера. Всего надо изучить 6-7 команд протокала POP3. Это выходит за рамки данный статьи.

Теперь попробуем запускать нашу программу каждые 5 минут. К сожалению, методами ПХП напрямую это не возможно. Но мы попробуем. Допустим, на ваш сайт ходят люди :-) Если на ваш сайт никто не ходит, данный способ не заработает. Нужно сделать функцию (в каком-то общем файле), которую будут запускать из всех ваших скриптов. Функция должно проверять время модификации файла-флага, например, flag.txt. Если время модикации больше, чем 5 минут назад, то пора выполнять функицию проверки почты. После проверки почты, надо файл-флаг открыть на запись и закрыть, чтобы время модификации было изменено. Если же время модификации не превысело 5 минут, то функция ничего не делает. Как видите, ничего хитрого.

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

Вариант 2: без CRON, без Command, метод почты из файла.

Это значит, что вы по прежнему не имете доступа ни к крону, ни к способу 'command' и не понимаете сокетов с POP3. Тогда можно попытаться получать почту методом чтения ее из файла. Так читать можно только свою почту. Своя - это та, от чьего пользователя работает ПХП. Файл с почтой лежит в /var/spool/mail/имя_пользователя (или /var/mail). Настраиваем регулярный запуск проверки (описан в варианте 1) и для снятия почты открываем файл, читаем письма, делим их (там писем можнет быть от 0 и более) по слову "From" с пробелом. Попутно думаем, а кто еще будет иметь доступ к этому файлу почты.

Вариант 3: используем CRON

Крон - это средство вызвать ваш скрипт в нужное время. В вариантах 1 и 2 мы описали функцию для проверки почты. Здесь настроим ее регулярный запуск. Если у вас есть телнет на сервере, поищите каталог с кроном: /etc/cron, /var/spool/cron, /var/spool/cron/crontabs/, /usr/local/etc/cron и т.д... Попробуйте создать там файл с именем своего логина. К примеру для рута - файл "root". Такой файл там уже точно будет. Если получиться, то вы можете обойтись без админа. Создайте файл mail.php по образцу, описанному в первой главе. Там должна быть строка #!/usr/bin/php, но весь внутренний текст придется выкинуть. Там надо разметить функцию для проверки почты методом POP3 или из файла. Теперь вернемся к крону. Для автозапуска каждые 5 минут вашей программы mail.php нужно написать вот так: */5 * * * * /путь/к/файлу/mail.php Админу сервера, если вы самостоятельно не можете настроить крон, достаточно назвать время запуска и путь к файлу. После прописывния строки в файле крона его нужно перезапутить. Либо это сделает админ, либо вы (нажав Ctrl+Alt+Del на сервере), либо опять вы, но удаленно - завесив сервер кривой прогой на ПХП :-)

Вариант 4: используем COMMAND - запуск по приходу письма

Этот способ описан в первой главе. В файле mail.php выкидывайте содержимое и читайте пришедшее письмо, как простой файл. И делайте все, что нужно.

Подведем итог

Эти способы можно комбинировать. Главное - не впадать в панику, понять теорию и сесть писать программу. О конкретных непонятных вещах всегда можно спросить.

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

Мы узнали, что КРОН - это не страшный зверь, а файл всего с одной строкой вида */5 * * * * команда. Это средство есть на всех Юникс-серверах. Время можно настраивать очень гибко, но нам этого не надо (только лишь "раз в N минут").

Мы узнали, что нам скорее всего понадобиться ПХП как CGI-прогармма. Все привыкли использовать ПХП, вызываемый через веб (тут нам тип ПХП не важен - модуль Апача или CGI). А для выполнения скрипта требуется CGI. Может кто и не подозревал, но ПХП это отличное средство для написания разных скриптов даже у себя на рабочем компьюетере. В Windows можно легко регулярно копировать и упаковывать важные файлы, например (а то достал уже глючить). Вызывается проще простого: php.exe имя_файла. Еще, раз уж об Апаче разговор... Чтобы передать параметры в пхп-файл, вызыванный таким образом, надо сделать так: php.exe имя_файла &a=1&b=bbbb. Чтобы подавить строку X-Powered-By при таким запуске: ключ -q.

Hosted by uCoz