PHP-4 Эффективная работа


Отправка электронной почты
Прием электронной почты

Электронная почта является, пожалуй, самым древним из использующихся сегодня сегментов Интернета. По некоторым оценкам, трафик электронной почты составляет от 15 до 25% всего объема пересылаемых данных. Сегодня для работы с почтой написано немало красивых оболочек, позволяющих принимать и отправлять сообщения с помощью web-интерфейса. Примером может служить, скажем, http://www.mail.ru/.

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

12.1.Отправка электронной почты

Вначале давайте познакомимся с двумя функциями, которых достаточно для решения трех четвертей всех задач, возлагаемых на PHP-сценарии в части отправки почты. Это функции mai1() и ezmlm_hash.

12.1.1. Отправка почты: mail

boot mail (string to, string subject, string message
          [, string additional_headers
          [, string additional_parameters]])

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

В случае успешного завершения функция возвращает true, а при возникновении ошибки или неверной настройке конфигурационного файла php.ini возвращает false.

Вот простейший пример использования этой функции:
maiI("vovka.morkovka@voldemarus.ru", "Тестовое письмо",
       "Здравствуй Вова, милый мой,\nДруг мой ненаглядный! 2\n".
       "Во первых строках письма \nШлю тебе привет.\n");

примечание
       Несчастные мученики Windows! Вам необходимо использовать для разделения заголовков пару символов —\r\n .A кроме того, при работе с Windows вы должны иметь в виду, что заголовки ее : и bЬсс : почему-то становятся регистрочувствительными и должны записываться как Сс : и Вcс :, соответственно.

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

Если, наконец, вы используете пятый аргумент, PHP-машина просто добавит его содержимое к вызову почтового агента. Как правило, этот трюк используется для модификации значения заголовка Return-Path при работе с программой sendmail.

Вот как это можно применить на практике:
maiI("nikomu@nikuda.com", "Ни о чем", $message,
       "From: webmaster@$SERVER_NAME\n".
       "Reply-To: webmaster@$SERVER_NAME\nX-Mailer: PHP/" .
       phpversion());

Используя этот аргумент, вы можете также передать почтовому агенту дополнительные параметры командной строки.

Вот пример отправки письма с установкой дополнительных заголовков и дополнительного параметра командной строки:

mail($user, "$i-oe последнее предупреждение", $message,
       "From: webmaster@$SERVER_NAME", "-fwebmaster@$SERVERNAME");

Конечно, никто вам не запрещает собирать строки, передаваемые как текст или заголовки письма, с помощью оператора конкатенации:

/*
          получатели - в реальной программе список выбирается из
          базы данных
       */
$recipient .= "Вовка <vovka@vvv.infо.mil.ru>" . ", " ;
$recipient .= "Шеф <boss@vvv.info.mil.ru>" . ", ";
$recipient .= "Париса <root@larisa.info.mi1.ru>";

/* Тема сообщения */
$subject = "В августе нас ожидают следующие \"Дни варенья\"";
/* message */
$message .= "Это простая форматированная таблица КОИ8-Р\n";
$message .= "День \t\tМесяц \t\tгод\n";
$message .= "3 \t\tAвг \t\t1970\n";
$message .= "17\t\tAвг \t\tl973\n";

/* И сигнатура отправителя в конце */
$message .= "--\r\n"; //Индикатор начала сигнатуры
$message .= "Генератор сообщений о днях варенья";

$headers .= "From: Ваш подхалим <birthday@vvv.info.mil.ru>\n";
$headers .= "X-Sender: <birthday@vvv.info.mil.ru>\n";
$headers .= "X-Mailer: PHP\n"; // псевдопочтальон
$headers .= "X-Priority: l\n"; // Максимальный приоритет!
$headers .= "Return-Path: <root@info.mil.ru>\n"; // Анализ ошибок

/* Поскольку клиенты разные, отправляем в HTML */
$headers .= "Content-Type: text/html; charset=koi8-r\n"; // Mime
// кроме того, отправляем копию письма в архивную папку
$headers .= "Сс: birthdayarchive@video. info.mil.ru\n";

/* Все заголовки собраны, отправляем письма */
maiI($recipient, $subject, $message, $headers);

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

12.1.2. Вычисление ключа для списка рассылки:ezmlm hash

int ezmlm_hash (string addr)

Одно из относительно популярных средств работы с электронной почтой, использующее интерфейс РНР, — это программа управления почтовыми списками рассылки EZMLM. Как правило, архив клиентов системы хранится в базе данных, построенной на основе СУБД MySQL. В качестве ключевого идентификатора используется хэш-функция, вычисляемая на основании имени пользователя.

Вот как эта функция используется на практике:
$user = "kris@koehntopp.de";        // адрес почты пользователя
$hash = ezmlm_hash ($user) ;        // вычисляем хэш-функцию
$query = sprintf ("INSERT INTO sample VALUES (%s, '%s')",
                         $hash, $user);        // регистрируем клиента
$db->query($query) ;                                       // используем интерфейс db

12.2.Прием электронной почты

В этом параграфе мы рассмотрим функции, предназначенные для приема и обработки электронной почты. Входящие в состав РНР функции обеспечивают достаточно прозрачную поддержку всех трех основных протоколов «почтовых отделений»: ШАР, POP и NNTP. Все эти три протокола предназначены для работы с сообщениями, представленными в соответствии с форматом RFC-822.

Чтобы ваша PHP-машина оказалась в состоянии использовать эти функции, вы должны скомпилировать РНР с ключом --with-imap. Однако для этого вам придется предварительно установить библиотеку c-client. Найти ее последнюю версию вы можете по адресу: ftp://ftp.cac.washington.edu/imap/.

После ее сборки скопируйте сгенерированный файл c-dient/c-client.a в /usr/local/ lib/libc-client.a, а также поместите заголовочные файлы c-client/rfc822.h, mail.h и linkage.h в каталог/usr/local/include.

Функции этой библиотеки позволяют работать с любыми сообщениями в формате RFC822, поэтому функции i map_* оказываются в состоянии работать не только с родным IMAP-сервером, но также и с POP, и с NNTP, а также с локальным по- чтовым ящиком UNIX-системы.

Интересующимся построением системы обмена электронной почты настоятельно рекомендуется книга [8], а также несколько RFC, часть из которых можно найти на русском языке в Рунете:

RFC2821 Simple Mail Transfer Protocol (SMTP)
RFC822 Стандарт текстовых сообщений ARPA
RFC2060 Internet Message Access Protocol (IMAP) Version 4rev1
RFC1939 Post Office Protocol Version 3 (POPЗ)
RFC977 Network News Transfer Protocol (NNTP)
RFC2076 Common Internet Message Headers

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

12.2.1. Обслуживание почтового ящика

12.2.1.1. Проверка почтового ящика: imap_check

object imap_check (int imap_stream)

Функция предназначена для получения информации о текущем содержимом почтового ящика. В случае неудачи функция возвращает false. В случае успешного завершения результатом работы функции является объект, обладающий следующими свойствами:

Date      Дата последнего изменения содержимого ящика
Driver      Протокол, используемый для доступа к данному почтовому ящику (POPЗ, IMAP, NNTP)
Mailbox      Имя почтового ящика
Nmsgs      Количество сообщений в почтовом ящике
Recent     Количество новых (непрочитанных) сообщений в почтовом ящике

12.2.1.2. Создание почтового ящика: imap_createmailbox

int imap_createmaiIbox (int imap_stream, string mbox)

Функция предназначена для создания нового почтового ящика, имя которого определяется строкой mbox. Имена, содержащие буквы кириллицы, должны быть закодированы с помощью функции imap_utf 7_encode() (см. раздел 12.2.3.7). Функция возвращает true в случае успешного создания ящика и false, если создать ящик не удалось.

Ниже приведен пример использования функции imap_createmai lbox().
$mbox = imap_open("{your.imap.host}","username",
                   "password",OP_HALFOPEN)
          or diе("не могу подключиться: ". imap_\ast_error ());

$namel = "phpnewbox";
$name2 = imap_utf7_еnсоdе("\ss\/щичек") ;
$newname = $namel;

echo "Создается ящик с именем ' $namel'<br>\n";
# теперь мы создадим в папке inbox новый субъящик "phptestbox",
# проверим его состояние и тихонечко его удалим, возвратив тем
# самым inbox в его первоначальное состояние...
if(@imap_createmailbox($mbox,
          imap_utf7_encode("{your.imap.host}INBOX.$newname")
)) {
       $status = @imap_status($mbox,"{your.imap.host}INBOX.$newname",SA_ALL);
       if($status) {
          рrint("Новый ящик '$namel' имеет характеристики:<br>\n");
          print("Сообщений: ". $status->messages )."<br>\n";
          print("Новых: ". $status->recent
)."<br>\n";
          print("Непрочитанных: ". $status->unseen )."<br>\n";
          print("UIDnext: ". $status->uidnext )."<br>\n";
          print("UIDvaIidity : ". $status->uidvalidity )."<br>\n";

if(imap_renamemailbox($mbox,<br>
                    "{your.imap.host}INBOX.$newname",
                    "{your.imap.host}INBOX.$name2")) {
       echo "Ящик переименован из '$namel' в '$name2'<br>\n";
       $newname=$name2;
     } else {
       print "Ошибка при переименовании ящика: ".
               imap_last_error ()."<br>\n";
          }
       } else {
       print "Ошибка при считывании состояния ящика: ".
imap_last_error()."<br>\n";
       }
      if(@imap_deletemailbox($mbox,
                   "{your.imap.host}INBOX.$newname")) {
       print "Ящик удален. Состояние восстановлено.<br>\n";
       } else {
       print "Ошибка при удалении ящика: ".
               implode("<br>\n",imap_errors())."<br>\n";
       }
} else {
       print "He могу создать ящик: ".
implode("<br>\n",imap_errors())."<br>\n";
}
          imap_close($mbox);

См. также описания функций imap_renamemai lbox () (раздел 12.2.1.11), imap_deletemailbox() (раздел 12.2.1.3) и imap_open() (раздел 12.2.5.5).

12.2.1.3. Удаление ящика: imap_deletemailbox

int imap_deletemailbox (int imap_stream, string mbox)

Функция imap_deletemailbox() удаляет указанный почтовый ящик и возвращает true при успешном завершении операции или false — при возникновении ошибки.

12.2.1.4. Очистка ящика: imap_expunge

int imap_expunge (int imap_stream)

Функция imap_expunge() удаляет из почтового ящика все сообщения, помеченные для удаления с помощью функций imap_delete() (см. раздел 12.2.2.4), imap_mail_move() (см. раздел 12.2.2.13) или imap_setf lag_full () (см. раздел 12.2.2.16).

Функция возвращает true.

12.2.1.5. Анализ квот и статистики: imap_get_quota

array imap_get_quota (int imap_stream, string quota_root)

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

совет
       Функция доступна только пользователям библиотеки c-client2000.

Аргумент imap_stream должен представлять собой значение, полученное в результате вызова imap_status() (см. раздел 12.2.1.14). Чтобы функции определения квоты были доступны для использования, поток должен открываться администратором почтового сервера. Как правило, для этого в поле user . name используется имя quota_root. При этом часть name заменяется на имя почтового ящика, информацию об использовании которого вы хотите получить.

Вот как используется эта функция:
$mbox = imap_open("{your.imap.host}","mailadmin",
                         "password",OP_HALFOPEN)
          or die("нe могу подключиться: ". imap_last_error ()) ;

$quota_value = imap_get_quota($mbox, "user.flintstone");
if(is_array($quota_value)) {
       print "Степень заполненности : " . $quota_value['usage'];
       print "Предельный объем : " . $quota value['limit'];
}
imap_close($mbox);
См. также imap_open() (раздел 12.2.5.5) и imap_set_quota() (раздел 12.2.1.12). 

12.2.1.6. Список почтовых ящиков (детальный):imap_getmailboxes

array imap_getmaiIboxes (int imap_stream, string ref, string pattern)

Возвращает список объектов, каждый из которых содержит информацию о почтовом ящике IMАР-сервера. Каждый объект имеет следующие свойства:

name      Полное имя почтового ящика
delimiter      Разделитель сегментов имени, отражающий иерархию вложенности ящиков
attributes      Битовая маска

Свойство attritute (битовая маска) может принимать значения:
LATT_NOINFERIORS      Почтовый ящик не имеет «потомков» (то есть вложенных почтовых ящиков)
LATT_NOSELECT      Это просто контейнер, а не почтовый ящик, поэтому открыть его нельзя
LATT_MARKED      Почтовый ящик помечен (эта информация используется только сервером UW-IMAPD)
LATT_UNMARKED      Почтовый ящик не помечен (эта информация используется только сервером UW-IMAPD)

Если имя почтового ящика содержит буквы кириллицы, то все символы старшей половины кодовой таблицы ASCII должны декодироваться с помощью функции imap_utf7_decode().

Аргумент ref обычно представляет собой спецификацию IMAP-сервера в соответствии с описанием функции imap_open() (см. раздел 12.2.5.5), a pattern определяет точку начала осмотра иерархического дерева сервера. Так, если вы хотите получить информацию по всем почтовым ящикам, используйите значение «*».

совет
       Существуют два специальных символа, которые могут использоваться в составе аргумента pattern: «*» и «%». Первый из них, «*», означает, что вы хотите получить информацию обо всех ящиках. Второй, «%», означает, что вам необходима информация только по ящикам текущего уровня иерархии. Так, используя в качестве шаблона поиска одиночный символ «%», вы получите информацию только о ящиках верхнего уровня иерархии.

12.2.1.7. Список почтовых ящиков: imapjistmailbox

array imap_listmailbox (int imap_stream, string ref, string pattern) Функция возвращает массив, содержащий имена почтовых ящиков, определенных на сервере.

12.2.1.8. Считывание информации о ящике:imap_mailboxmsginfo

object imap_mailboxmsginfo (int imap_stream)

Возвращает информацию о текущем почтовом ящике. В случае неудачи возвращает false. В целом, эта функция подобна imap_status () (см. раздел 12.2.1.14), но дополнительно подсчитывает сумму объемов всех сообщений в ящике, что требует некоторого дополнительного времени. Результатом работы является объект со следующими свойствами:

DateДата последних изменений
DriverДрайвер
MailboxИмя почтового ящика
Nmsgs Количество сообщений
RecentКоличество новых сообщений
UnreadКоличество непрочитанных сообщений
DeletedКоличество удаленных сообщений
SizeОбщий размер ящика
А вот пример использования этой функции:
<?php
$mbox = imap_open("{your.imap.host}INBOX", "username", "password")
          or die('He могу подключиться: ". imap_last_error ());
$check = imap_mailboxmsginfo($mbox);

if           {
($check)
       print    "Date: " . $check->Date ,"<br>\n"
       print    "Driver: " . $check->Driver ."<br>\n" ;
       print    "Mailbox: . $check->Mailbox ."<br>\n" ;
       print    "Messages:. $check->Nmsgs ."<br>\n" ;
       print    "Recent: . $check->Recent ."<br>\n" ;
       print    "Unread: . $check->Unread ."<br>\n" ;
       print    "Deleted: . $check->Deleted ."<br>\n" ;
       print    "Size: " . $check->Size ."<br>\n"
} else {
       print    "Ошибка imap_check(): " . imap_last_error () . "<br>\n
}
          imap_close($mbox);
?>

12.2.1.9. Количество сообщений в ящике: imap_num_msg

int imap_num_msg (int imap_stream)

Возвращает количество сообщений в текущем почтовом ящике. См. также описания функций imap_num_recent() (раздел 12.2.1.10) и imap_status() (раздел 12.2.1.14).

12.2.1.10. Количество новых сообщений:imap_num_recent

int imap_num_recent (int imap_stream)

Возвращает количество новых сообщений в текущем почтовом ящике. См. также imap_num_msg() (раздел 12.2.1.9) и imap_status() (раздел 12.2.1.14).

назад
далее

Сайт управляется системой uCoz