Почтовые функции в РНР

Автор статьи: Сергей Лисин ©
Сайт Автора: cvacubo.com
E-mail Автора: нет
Дата публикации: 24.04.2006

Одним из возможных применений 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 <[email protected]>X-mailer: PHP4Content-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,
  перепроверка почтового ящика отправителя и т.д.
  Это уже функциональные излишества, которые каждый может добавить по мере необходимости.