Одним из возможных применений imap функций является создание
почтового демона, который будет управлять подпиской и отпиской пользователей от
вашей почтовой рассылки. Для реализации этой задачи, обычно в рассылках
используются два метода. Первый предполагает, что пользователь должен зайти на
некую страницу и подтвердить свои действия, второй требует отправки письма.
Второй так же требует, чтобы скрипт-обработчик регулярно запускался cron
daemon?om. Из-за этого он не настолько популярен как первый способ.
Но, как можно заметить, наиболее серьезные рассылки используют второй способ.
Поэтому, если у вас есть возможность использования crond, воспользуйтесь им.
Собственно, разобраться в функциях не так сложно. Человек, который раньше
работал на РНР, без труда поймет, как с ними работать. Некоторые затруднения
могут возникнуть с разбором заголовков писем, которые будет обрабатывать
скрипт.
Алгоритм работы самого скрипта придумать несложно. Демон устанавливает
соединение с почтовым сервером, и проверяет наличие на нем писем. В случае если
писем нет, работа скрипта прекращается. Если письма есть, то происходит
разбор заголовков первого письма. Просматривается поля from и subject. Если поле
subject содержит один из двух допустимых вариантов заголовка (подписка или
отписка), то запись, которой соответствует значение поля from либо становится
активной (подтвержденной), либо удаляется из таблицы. В обоих случаях на адрес,
указанный в поле from посылается соответствующее извещение о действиях скрипта.
После этого письмо помечается для удаления. В случае если subject не содержит
допустимых тем, посылается уведомление об ошибке, и письмо так же помечается для
удаления. Затем скрипт переходит к следующему письму. Закончив разбор всех
писем, он очищает ящик.
Не буду утомлять читателя блок-схемами, так что сразу перейдем к делу. Для
открытия ящика используется функция imap_open. Поскольку РНР поддерживает работу
с несколькими протоколами, то необходимо явно указать, какой протокол
используется для работы с ящиком. В нашем случае это POP3 на 110 порту
(стандарт). Присваиваем результат выполнения скрипта переменной $my_box.
$my_box = imap_open("{you.pop.host/pop3:110}", "login",
"password");
В дальнейшем вы увидите, что эта переменная будет использоваться
пратически во всех imap функциях. Далее проверяем ящик на наличие писем.
Проверку выполняет функция imap_num_msg.
$n = imap_num_msg($my_box);
В результате переменная $n будет содержать количество писем в ящике.
Число это может быть или больше нуля, или равно ему (если ящик пуст). Если
письма есть, то в цикле while выполняем разбор писем, последовательно увеличивая
номер письма на единицу. Обратите внимание, что первое письмо в ящике будет
иметь номер 0, как, и первый элемент массива. Для увеличения номера письма,
присваиваем переменной $m значение 0, а потом в условиях выполнения цикла
увеличиваем ее на единицу $m++.
Для разбора интересующих нас заголовков достаточно двух функций: imap_header
и imap_fetch_overview. Для выполнения каждой из их, помимо ящика, нужно
указывать номер письма. В нашем случае, внутри цикла он будет равен переменной
$m.
Imap_header возвращает в результате выполнения объект, содержащий
исчерпывающую информацию о заголовке письма. Среди всего прочего, этот объект
содержит массив from, в котором содержаться четыре значения. Это personal, adl,
mailbox и host. Нас из них интересуют только mailbox и host. Подставляя их, мы
получим адрес, с которого было отправлено письмо.
$h = imap_header($my_box, $m); $h =
$h->from; … foreach ($h as $k => $v) { $mailbox =
$v->mailbox; $host = $v->host; $personal =
$v->personal; $email = $mailbox . «@» . $host;
imap_fetch_overview — позволит нам узнать тему письма. Для этих же целей
можно было бы использовать и imap_header но по ряду причин это, иногда может не
сработать. Из массива, который возвращает эта функция, нам нужно только поле
subject
$s = imap_fetch_overview($my_box, $m); foreach ($s as
$k => $v) { $subj = $v->subject; }
Дальнейшие наши действия сводятся к тому, чтобы вытащить email из базы, и
в случае наличия его там, пометить всю строку с этой записью как «проверенную»,
либо удалить. Предположим, что после заполнения формы рассылки на сайте,
подписчику присваивается статус 0, а после подтверждения подписки он меняется на
1.
if ($subj == "SUBSCRIBE") { mysql_query("UPDATE
subscribe SET stat=1 WHERE email=$my_email"); $del = imap_delete($my_box,
$m); mail($email, $add_sbj, $add_text, $headers); } elseif ($subj ==
"UNSUBSCRIBE") { mysql_query("DELETE FROM subscribe WHERE email =
$my_email"); $del = imap_delete($my_box, $m); mail($email, $del_sbj,
$del_text, $headers); } else { $del = imap_delete($my_box,
$m); mail($email, $err_sbj, $err_text, $headers); }
как уже говорилось выше, после выполнения всех действий скрипт очищает
ящик.
$clear = imap_expunge($my_box);
Данная простейшая программа, лишь демонстрация того, что на РНР можно
писать не только динамически изменяющиеся сайты, но и сервисы, которые
пользователю вообще не видны. Конечно, по части написания скриптов для shell,
рнр неприменим, в отличие от своего конкурента Perl, но тем не менее…
Листинг всей программы за исключением параметров соединения с базой
(db.php):
<? include "db.php"; $my_box =
imap_open("{you.pop.host/pop3:110}", "login", "password"); $n =
imap_num_msg($my_box); $m = 0; $add_text = "
Спасибо за подтверждение вашей подписки "; $add_sbj =
"You added!"; $del_text = "
Вы были удалены из списка рассылки. "; $del_sbj =
"Delete from list"; $err_text = "
Извините но этот почтовый ящик используется только для
администрирования рассылки"; $err_sbj = "Error"; $headers = "From:
Subscribe Robot <You@mail.box>
X-mailer: PHP4
Content-type: text/plain;
charset=windows-1251 "; if($n != 0) { while($m++ < $n) { $h =
imap_header($my_box, $m); $s = imap_fetch_overview($my_box, $m); $h =
$h->from; foreach ($h as $k =>$v) { $mailbox =
$v->mailbox; $host = $v->host; $personal =
$v->personal; $email = $mailbox . "@" . $host; $my_email =
mysql_escape_string($email); } foreach ($s as $k =>$v) { $subj =
$v->subject; } if ($subj == "SUBSCRIBE") { mysql_query("UPDATE table
SET stat=1 WHERE email=$my_email"); //print mysql_error(); $del =
imap_delete($my_box, $m); mail($email, $add_sbj, $add_text,
$headers); } elseif ($subj == "UNSUBSCRIBE") { mysql_query("DELETE FROM
table WHERE email = $my_email"); $del = imap_delete($my_box,
$m); mail($email, $del_sbj, $del_text, $headers); } else { $del =
imap_delete($open_box, $m); mail($email, $err_sbj, $err_text,
$headers); } } $clear = imap_expunge($my_box); } ?>
В листинг отсутствуют некоторые детали, например возможное
конвертирование из win в koi, перепроверка почтового ящика отправителя и т.д.
Это уже функциональные излишества, которые каждый может добавить по мере
необходимости.
Автор: Сергей Лисин |