Почтовые функции imap в РНР
Одним из возможных применений 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;
a
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):
<?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, перепроверка почтового ящика
отправителя и т.д. Это уже функциональные излишества, которые
каждый может добавить по мере необходимости.