WWW.DISSERS.RU

БЕСПЛАТНАЯ ЭЛЕКТРОННАЯ БИБЛИОТЕКА

   Добро пожаловать!

Pages:     | 1 |   ...   | 5 | 6 || 8 | 9 |   ...   | 16 |

«Professional PHP4 LArgerich, W.Choi, J.Coggeshall, K.Egervari, M.Geisler, Z.Greant, A. Hill, C.Hubbard, J.Moore, D.O'DellJ.Parise, H.Rawat, T.Sani, CScollo, D.Thomas, C.Ullman ...»

-- [ Страница 7 ] --

Ресурсы Ресурсы Аннотированное пользователями справочное руководство РНР по функции m a i l ( ) можно найти здесь:

• http://www.php.net/manual/function.mail.php Дополнительная информация по электронной почте и телеконференциям есть в следующих RFC:

• http://www.rfc.net/ - RFC 821 (Simple Mail Transfer Protocol) • http://www.rfc.net/ - RFC 822 (Internet Mail Message Format) • http://www.rfc.net/ - RFC 1049 (поле заголовка Content-type) • http://www.rfc.net/ - RFC 2045-2049 (Multipurpose Internet Mail Extensi ons) • ' http://www.rfc.net/ - RFC 977 (Network News Transfer Protocol) • http://www.rfc.net/ - RFC 1036 (стандарты обмена сообщениями в USE NET) Дополнительная информация по наборам символов:

• http://www.rfc.net/ - RFC 2278 (IANA Charset Registration Procedures) • ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets/ - список заре гистрированных наборов символов Резюме В этой главе мы набрали обороты в освоении систем электронной почты и те леконференций. Мы познакомились с основами Usenet и системы электрон ной почты Интернета, а также со стандартными языками, или протоколами, которые используются серверами и клиентами для общения друг с другом:

SMTP и NNTP.

Мы также научились посылать с помощью РНР обычную электронную почту и более сложную, MIME. Основу возможностей РНР по работе с электронной почтой составляет встроенная функция mail(). Мы также показали, что в от сутствие локальной почтовой системы, на которую опирается функция mail (), можно отправлять электронную почту через удаленный сервер SMTP.

Кроме того, мы узнали, как отправлять статьи в выбранные телеконферен ции с помощью удаленного сервера NNTP.

Мы спроектировали и создали ряд классов, которые демонстрируют знания, полученные в этой главе:

• My_Mail: базовый класс для отправки обычных почтовых сообщений • My_Mime_Mail: более сложный класс, расширяющий My_Mail функциями MIME • My_Smtp_Mail: базовый почтовый класс для работы с удаленным сервером SMTP 414 Глава 11. Электронная почта и телеконференции • My_Smtp_Mime_Mail: почтовый класс SMTP с функциями MIME • My_Nntp: базовый класс NNTP, дающий возможность отправлять статьи в телеконференции Наконец, для применения в веб-интерфейсе мы построили класс почтового отправителя, который может посылать статьи в телеконференции или сооб щения электронной почты. Классы, созданные в данной главе, лягут в осно ву более сложного приложения для работы с электронной почтой и телекон ференциями, которое мы построим в главе 12, рассматривающей функции РНР для IMAP.

Получение электронной почты и статей телеконференций В предыдущей главе мы рассмотрели основы почтовой системы Интернета и Usenet. Мы также показали, как посылать электронную почту и публико вать статьи в телеконференциях с помощью РНР. Сейчас читатель должен достаточно разбираться в общей концепции электронной почты. Однако, как говорилось в предшествующей главе, получение сообщений электрон ной почты и статей из телеконференций в РНР связано с гораздо большими трудностями, чем их отправка. В этой главе мы познакомимся с новыми почтовыми протоколами и более сложными понятиями, относящимися к электронной почте и телеконференциям. Мы также изучим возможности, предоставляемые РНР для получения сообщений электронной почты и теле конференций с помощью функций IMAP. Предварительно необходимо про честь главу 11, подробно освещающую основы системы электронной почты и Usenet.

Вот главные темы, которые будут раскрыты в этой главе:

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

Мы завершим обсуждение электронной почты и телеконференций создани ем основанной на веб-службе почтовой системы типа Hotmail.

Начнем с рассмотрения протоколов, с помощью которых происходит полу чение электронной почты.

416 Глава 12. Получение электронной почты и статей телеконференций Протоколы для получения электронной почты Для получения сообщений почтовый клиент пользуется протоколом POP или IMAP. Подобно рассмотренному в предыдущей главе SMTP, протоколы POP и ШАР также являются строчно-ориентированными. POP - это прос той протокол с минимальным набором команд, тогда как IMAP относитель но сложен. Начнем с простого.

POP Главное различие между протоколами POP и IMAP заключается в том, где хранятся сообщения и где происходит доступ к ним. В POP сообщения за гружаются с почтового сервера на локальный жесткий диск, в IMAP же они остаются на сервере. Для того чтобы просмотреть определенное сообщение, его требуется загрузить. Может возникнуть вопрос, зачем вообще нужен IMAP. Рассмотрим такую ситуацию. В POP сообщения удаляются с сервера после их извлечения, если не настроить почтовый клиент так, чтобы они со хранялись. Для того чтобы снова прочесть сообщение, его придется взять с локального жесткого диска. IMAP же позволяет просматривать сообщения на сервере в любое время в желаемом месте.

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

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

Демон сервера IMAP или POP (imapd/popSd) запускается демоном inetd в от вет на каждое новое подключение клиента. Порты TCP, используемые POP и IMAP, указаны в файле /etc/services;

обычно это 110 и 143 соответственно.

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

tftelnet localhost imap Благодаря этому мы избавляемся от необходимости помнить действитель ные номера портов.

Пример сеанса POP Как обычно, полужирным шрифтом выделены команды POP, вводимые клиентом:

Протоколы для получения электронной почты Я telnet whoelse.com Trying 192.168.0.3...

Connected to whoelse.com.

Escape character is/."]!..

+OK POPS whoelse.com v2000.70 server ready HELO -ERfi Unknown AUTHORIZATION state command ;

' USER yonsuk +OK User name accepted,.password please PASS +OK Mailbox open, 5 messages LIST +OK Mailbox scan listing follows 1 2 3 4 5 RETR +OK 525 octets Return-Path: Received: from whatever.com (IDENT:wankyu@whatever.com[192.168.0.2]) by mail.somewhere.com (8.9.3/8.9.3) with SMTP id WAA for yonsuk;

Sun, 28 Jan 2001 23:18:09.+0900.

Date: Sun, 28 Jan 2001 23:18:09 + From: Wankyu Choi , To: yonsuk@whoelse.com Message-Id: :< F890755DE93ED411® whatever.com> Subject: Just a Note Don't forget to bring your notebook tomorrow.

Sleep tight.

DELE +OK Message deleted QUIT +OK Sayonara Connection closed by foreign host.

Я Версия З - это самая свежая реализация POP. Когда мы будем говорить о POP, будет иметься в виду РОРЗ, если не оговорено иное.

Сеанс POP начинается с подключения к серверу. В отличие от SMTP, ответы сервера POP начинаются с +ОК, что указывает на успешное выполнение дан ной команды, либо с -ERR, что указывает на ошибку. При написании про граммы-клиента POP можно воспользоваться регулярными выражениями, чтобы проверять, с чего начинается ответ сервера - с +ОК или - E R R. Обратите внимание на отсутствие в POP команды НЕЮ. Этим вызвано сообщение серве ра -ERR Unknown AUTHORIZATION state command.

!43ак. 418 Глава 12. Получение электронной почты и статей телеконференций Сеанс POP включает в себя три состояния: авторизации, транзакции и об новления. При каждом подключении к серверу клиент POP входит в состоя ние авторизации. Пользователь идентифицируется с помощью команд USER и PASS. Успешная аутентификация переводит пользователя в состояние тран закции, в котором он может получать и удалять сообщения.

В приведенном выше сеансе сервер сообщает о наличии в почтовом ящике сообщений. Команда LIST выводит список сообщений с указанием их разме ра в октетах (групп из 8 бит). Для того чтобы просмотреть конкретное сооб щение, следует подать команду RETR, указав в качестве аргумента номер со общения, в данном случае RETR 5. После этого можно увидеть содержимое со общения, которое wankyu§whatever. com послал для yonsuk@whoelse. com.

Команда DELE удаляет сообщение, номер которого указан в аргументе. Обра тите внимание, что команда DELE не уничтожает сообщение физически, а лишь помечает его как предназначенное для удаления. Фактическое удале ние происходит при завершении работы по команде QUIT. В данном примере это не показано, но можно восстановить сообщение, т. е. снять с него отмет ку об удалении с помощью команды RSET. Команда QUIT завершает состояние транзакции и инициирует состояние обновления. В состоянии обновления сервер POP затирает сообщения, помеченные для удаления, не выводя ника ких сообщений. Закончив эту работу, сервер закрывает сеанс. Если помечен ных для удаления сообщений нет, сервер завершает сеанс, не переходя в со стояние обновления.

Электронную почту может просмотреть любой клиент из любого места, под ключившись через telnet к серверу POP и воспользовавшись этими просты ми командами.

IMAP IMAP - более сложный протокол, чем POP. В POP можно обойтись горсткой команд, a IMAP - это совсем другая история. РНР предоставляет массу гото вых функций, относящихся к IMAP, с помощью которых можно общаться с серверами POP, IMAP и NNTP. Одно лишь количество их устрашает. Функ ции IMAP представляют собой фактически оболочки команд IMAP, и их названия и внешний вид соответствуют реальным командам IMAP. Один из лучших способов освоиться с функциями РНР для IMAP - посмотреть при меры сеансов, в которых действуют основные команды IMAP, и сопоставить их с соответствующими функциями РНР для IMAP. Мы познакомим вас с их именами, аргументами и возвращаемыми значениями.

Приведем пример сеанса ШАР и сравним его с сеансом POP.

Теги Основное отличие ШАР от других строчно-ориентированных протоколов в том, что каждой команде, подаваемой клиентом, должна предшествовать строка буквенно-цифровых символов, называемая тегом. Теги позволяют клиенту IMAP определить, к какой команде относится ответ сервера. Кли Протоколы для получения электронной почты ент IMAP должен генерировать во время сеанса уникальные теги. Сервер, в свою очередь, помечает свой ответ тегом, посланным клиентом. Сервер мо жет возвращать и не помеченные тегами ответы. Обычно непомеченные от веты без тегов представляют собой результирующие данные, порожденные командой клиента. Ответам без тегов предшествует звездочка (*).

Форматы почтовых ящиков Одно из самых крупных достоинств IMAP состоит в том, что он допускает наличие нескольких почтовых ящиков. Почтовый ящик действует подобно файловой системе. Полученное сообщение электронной почты помещается в ваш почтовый ящик. В простейшем случае почтовый ящик представляет со бой один обычный файл, в который помещаются все сообщения электронной почты. В UNIX главный почтовый ящик пользователя обычно расположен в каталоге /var/spool/mail/ и называется так же, как его учетная запись. На пример, текстовый файл /var/spool/mail/wankyu служит почтовым ящиком пользователя wankyu, в котором хранится его входящая почта.

В формате mbox используется почтовый ящик в виде одного текстового файла, к которому последовательно дописываются сообщения. Роль разде лителя сообщений играет строка, начинающаяся словом From. За этим сло вом следует пробел и почтовый адрес отправителя, а также дата и время за писи сообщения в почтовый ящик. Эта строка-разделитель обычно называ ется From_line, и ее не следует путать со строкой заголовка From:

From yonsuk@whoelse.com Sat Feb 17 17:31:28 2001 // A From_ line From: Yonsuk Song // A From header После каждого сообщения вставляется пустая строка:

From changsoo@>neoqst.com Sat Feb 17 17:31:28 A verbatim copy of the first e-mail message From yongpil@neoqst.com Sat Feb 17 17:50:35 A verbatim copy of the second e-mail message From sungho@neoqst.com Sat Feb 17 18:19:30 A verbatim copy of the third e-mail message Существует разновидность формата mbox, называемая MMDF, в которой каждое сообщение ограничено строками, содержащими четыре символа ctrl-A ( Л А Л А Л А Л А), без пустой строки между сообщениями.

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

420 Глава 12. Получение электронной почты и статей телеконференций Большинство серверов NNTP использует для работы с новыми статьями формат, аналогичный МН.

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

Каждый почтовый ящик при этом соответствует каталогу или файлу. INBOX (ящик для входящих сообщений) всегда является каталогом.

Обратите внимание, что сервер UW-IMAP в конечном счете дописывает сооб щения в один почтовый ящик формата mbox, а сервер Cyrus хранит каждое сообщение в виде отдельного файла в каталоге почтового ящика. Сервер Courier-IMAP уникален в том смысле, что поддерживает формат почтового ящика Maildir программы Qmail. Сервер UW-IMAP не позволяет двум кли ентам одновременно обратиться к одному и тому же почтовому ящику: это значит, что один из них может потерять блокировку своего почтового ящи ка, если к нему в то же самое время попытается обратиться другой клиент.

В серверах Cyrus и Courier-IMAP этой проблемы блокировки файлов нет.

Пример сеанса IMAP Сеанс IMAP состоит из четырех отдельных состояний. Поскольку поддержи вается несколько почтовых ящиков, один из них надо выбрать, прежде чем обращаться к находящимся в нем сообщениям:

• Состояние до аутентификации: клиент соединен с сервером • Аутентифицированное состояние: клиент успешно прошел аутентифика цию • Состояние выбранного ящика: выбор прошел успешно • Состояние конца сеанса: клиент послал команду LOGOUT или сервер за крыл соединение Подключимся по telnet к нашему localhost, на котором работает сервер IMAP:

# telnet localhost imap /:

Trying 127.0.0.1...

Connected to localhost.

Escape character is•'"]'.

'.'•* OK [CAPABILITY IMAP4 IMAP4REV1 LOGIN-REFERRALS AUTH=LOGIN] localhost IMAP4rev 2000.287 at Tue, 30 Jan 2001 16:15:07 +0900 (KST) Сервер приветствует пользователя непомеченным ответом (обратите внима ние на звездочку в начале ответа).

Для того чтобы сделать на сервере что-то полезное, необходимо зарегистри роваться. Команда LOGIN имеет два аргумента: имя учетной записи, которое также считается именем вашего почтового ящика, и пароль. Помните, что каждой команде должен предшествовать тег:

WCK001 LOGIN wankyu * CAPABILITY IMAP4 IMAP4REV1 NAMESPACE IDLE MAILBOX-REFERRALS SCAN SORT THREAD=R Протоколы для получения электронной почты EFERENCES THREADORDEREDSUBJECT MULTIAPPEND WCK0010K LOGIN completed Обратите внимание, что на команду LOGIN сервер вернул помеченный ответ "WCK001 OK LOGIN completed". Пока мы еще не готовы получать списки или чи тать сообщения. Сначала надо выбрать рабочий почтовый ящик. Особый почтовый ящик с именем INBOX предназначен для получения и хранения всех входящих сообщений. Для пользователя wankyu почтовый ящик INBOX обычно является каталогом в его личном каталоге, например /home/wankyu/ Mail/. В IMAP можно создавать, удалять и переименовывать любые почто вые ящики, кроме INBOX.

Выберем почтовый ящик INBOX с помощью команды SELECT и посмотрим на ответ сервера:

WCK002 SELECT INBOX ;

* 10 EXISTS * 6 RECENT * OK [UIOVALIDITY 980691555] UID validity status * OK [UIDNEXT 11] Predicted next UID * FLAGS (\Answered \Flagged \Deleted \Draft \Seen) * OK [PERMANENTFLAGS (\* \Answered \Flagged \Deleted \Draft \Seen)] Permanent flags WCK002 OK [READ-WRITE] SELECT completed Сервер сообщает, что у wankyu в ящике INBOX находится 10 сообщений, 6 из которых свежие и непрочитанные.

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

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

Свежие (recent) сообщения - это те, которые были доставлены в почтовый ящик после предыдущего сеанса, а «непросмотренные» сообщения - это те, которые не были прочтены с момента появления их в почтовом ящике. В от вете сервера есть строка FLAGS, указывающая, какие флаги для пометки со стояния сообщения поддерживаются сервером. Флаг подобен атрибуту фай ла и содержит информацию о состоянии рассматриваемого сообщения. Зна чения флагов описываются в следующей таблице (табл. 12.1):

Глава 12. Получение электронной почты и статей телеконференций Таблица 12.1. Флаги состояния почтового сообщения Описание Флаг Сообщение прочтено, и на него послан ответ \Answered Сообщение с какой-то целью помечено: важное, срочное или просто \Flagged имеет отметку о необходимости каких-то действий с ним Сообщение помечено для удаления. Фактическое удаление происхо \Deleted дит, когда клиент завершает сеанс или подает команду EXPUNGE Сообщение не закончено и представляет собой черновик. Оно должно \Draft быть отправлено после завершения \Seen Сообщение прочитано Для того чтобы прочесть сообщение, надо выполнить команду FETCH. Проч тем с ее помощью пятое сообщение в INBOX. Команда имеет несколько аргу ментов, первый из которых - номер сообщения. Остальные аргументы зави сят от того, что должна сделать эта команда:

WCK003 FETCH 5 BODY[1] * 5 FETCH (BODY[1] {61} Don't forget to bring your notebook tomorrow.

Sleep tight.

) WCK003 OK FETCH completed С помощью аргумента BODY можно указать, какую часть сообщения жела тельно получить, например BODY[0] для заголовков или BODY[1 ] для тела сооб щения. Посмотрим, как выглядят заголовки этого сообщения:

WCK003 FETCH 5 BODY[0] * 5 FETCH (BODY[0] {452} Return-Path;

Received: from vyhatever.com (IDENT:wankyu@whatever.com[192.168.0.2]) by mail.somewhere.com (8.9.3/8.9.3) with SMTP id WAA for yonsuk;

Sun, 28 Jan 2001 23:18:09 + Date: Sun, 28 Jan 2001 23:18:09 + From: Wankyu Choi To: yonsuk@whoelse.com Message-Id: < F890755DE93ED411@ whatever.com> Subject: Just a Note ) WCK004 OK FETCH completed Можно даже получить сводку о структуре сообщения с помощью аргумента BODYSTRUCTURE:

WCK005 FETCH 5 BODYSTRUCTURE * 5 FETCH (BODYSTRUCTURE ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" v 2 NIL NIL NIL)) WCK005 OK FETCH completed Протоколы для получения электронной почты Флаги можно получить аналогичным образом:

WCK006 FETCH 5 FLAGS :

* 5 FETCH (FLAGS (\Seen)) WCK006 OK FETCH completed Теперь мы знаем, что пятое сообщение прочтено (\Seen). Все эти действия можно объединить в одной команде, заключив аргументы в круглые скобки:

WCK007 FETCH 5 (BODYSTRUCTURE FLAGS) * 5 FETCH (BODYSTRUCTURE ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 2 NIL NIL NIL) FLAGS (\Seen)) WCK007 OK FETCH completed Рассмотрим процедуру создания почтового ящика. На сервере UW-IMAP почтовый ящик пользователя wankyu располагается в его исходном каталоге в качестве подкаталога с именем Mail:

/home/wankyu/Mail/ Если пользователь создает другой почтовый ящик с именем work, то в исход ном каталоге появляется файл с тем же именем:

/home/wankyu/work/ Обращаем внимание, что для создания контейнера почтовых ящиков, т. е.

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

На некоторых почтовых серверах, включая UW-IMAP, это прямой слэш (/), на других (Cyrus и Courier-IMAP) - отдельная точка (.). Например, на серве ре UW-IMAP создать почтовый ящик-контейнер можно командой:

WKC008 CREATE work/ WKC008 OK CREATE completed Приведенная команда IMAP создает почтовый ящик-контейнер с именем work, который представляет собой подкаталог исходного каталога пользова теля. Напротив, следующая команда создает почтовый ящик в виде тексто вого файла с именем work:

WKC008 CREATE work WKC008 OK CREATE completed Если новый почтовый ящик создается в ящике-контейнере w o r k, то в подка талоге work появляется одноименный файл почтового ящика:

/home/wankyu/work/Jan При перемещении по маршруту, начинающемуся из исходного каталога пользователя, получаем почтовый ящик с именем work/Jan.

Глава 12. Получение электронной почты и статей телеконференций Теперь мы закроем сеанс с помощью команды LOGOUT:

WCK009 LOGOUT * BYE whatever.com IMAP4rev1 server terminating connection WCK008 OK LOGOUT completed Connection closed by foreign host.

# ;

v. -.

Сравнение POP и IMAP В приведенном сеансе участвует лишь часть команд, предоставляемых ШАР.

Одна только команда FETCH может иметь множество видов с различными на борами аргументов. Однако благодаря богатому набору функций IMAP при обретает все большую поддержку. Вот некоторые другие его возможности:

• IMAP хранит все почтовые сообщения на сервере, благодаря чему доступ к ним можно получить с любого компьютера, находящегося в сети.

• IMAP хранит почтовые сообщения в нескольких расположенных на сер вере ящиках, и перемещать или извлекать сообщения в них можно с по мощью любого клиента IMAP. Можно создать такую иерархию почтовых ящиков, в которой сообщения будут объединяться по общим темам: per sonal, work, orders, orders/2001/08, orders/2000/09, orders/2001/10, orders/ 2001/01/11 и т.д.

• IMAP позволяет загрузить определенную интересующую вас часть почто вого сообщения вместо целого сообщения. Например, можно выбрасы вать спам с большими вложениями. В POP придется сначала загрузить сообщение, чтобы определить характер его содержания.

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

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

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

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

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

Получение электронной почты с помощью РНР Получение электронной почты с помощью РНР В РНР содержится большая группа функций, относящихся к ШАР. Как от мечалось выше, они представляют собой оболочки команд ШАР, и их имена и внешний вид можно сопоставить с действительными командами ШАР. Мы будем строить класс Webmail, который может работать как с электронной поч той, так и с телеконференциями, и одновременно будем поочередно знако миться с функциями РНР для ШАР. С помощью этих функций можно взаи модействовать с серверами POP или NNTP, так же как с сервером IMAP.

Этот класс предоставляет следующие важные возможности:

• Получение сообщений электронной почты с помощью POP или ШАР • Получение списка почтовых сообщений в выбранном почтовом ящике • Действия с почтовыми сообщениями на сервере IMAP • Управление почтовыми ящиками на сервере IMAP • Получение списка имеющихся телеконференций • Перемещение по иерархии телеконференций • Получение списка статей в выбранной телеконференции Мы постараемся сделать класс по возможности компактнее, в то же время обеспечив выполнение всех важных функций, чтобы продемонстрировать мощь функций РНР для IMAP и простоту их применения. Сначала посмот рим, как поздороваться с сервером.

Убедитесь, что РНР скомпилирован с параметром настройки —with-imap. В противном случае представленные здесь примеры работать не будут. Под Windows необходим модуль IMAP с именем php_imap.dll, но его имя может быть другим в зависимости от версии.

Соединение с сервером Функции IMAP позволяют работать со всеми тремя типами серверов, с кото рыми мы ознакомились к данному времени: POP, IMAP и NNTP. Работать с каким-либо из этих серверов так же просто, как с файлами или каталогами:

• Откройте соединение с сервером, создав поток, через который будет про исходить обмен данными с сервером • Выполните необходимые действия, общаясь с сервером через этот поток • Закончив работу с сервером, закройте поток и освободите связанные с ним ресурсы Создание и закрытие соединения с сервером осуществляют функции imap_open()и imap_close().

imap_open() int imap_open(string mailbox, string username, string password [, int flags]) 426 Глава 12. Получение электронной почты и статей телеконференций С помощью этой функции мы получаем поток, соединяющий с почтовым ящиком на сервере. В случае ошибки эта функция возвращает false. Поток это канал, через который клиент и сервер могут общаться друг с другом. Его действие похоже на действие дескриптора файла.

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

• OP_READONLY Открыть почтовый ящик в режиме только для чтения • OP_ANONYMOUS Не использовать и не обновлять файл. newsrc при работе по NNTP • OP_HALFOPEN При работе по IMAP или NNTP открыть соединение, не выбирая почто вый ящик (или телеконференцию) • CL.EXPUNGE Автоматически уничтожить почтовый ящик после закрытия соединения В четвертый аргумент можно ввести один или более этих флагов в следую щем виде:

OP_ANONYMOUS | OP_HALFOPEN // поразрядное ИЛИ флагов Обратите внимание, что эти флаги представляют собой константы и потому не должны заключаться в кавычки.

Как можно догадаться, imap_open() служит оболочкой для команд IMAP LO GIN и SELECT. С ее помощью можно также открывать потоки к серверам POP и NNTP.

imap_last_error() and imap_errors() string imap_last_error() Функция imap_last_error() возвращает последнюю возникшую ошибку IMAP в виде строки и не принимает аргументов.

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

array imap_errors() Обратите внимание, что после вызова этой функции стек ошибок очищается.

imap_close() int imap_close(int stream [, int flags]) Это оболочка для команды ШАР LOGOUT. Эта функция закрывает данный по ток IMAP и возвращает false в случае ошибки.

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

Пример установления соединения Для того чтобы соединиться с сервером ШАР, работающим, например, на пор ту 143 хоста whatever, com, можно применить эти функции следующим образом:

var $supported_protocois = arrayCimap', 'рорЗ', 'nntp');

var $port = 143;

var Suserid = ' ';

var $userpassword = ' ';

Свойство Sstream указывает на поток IMAP, a $mailbox - на текущий почто вый ящик:

var {stream = 0;

: var $maiibox = ':';

Если установить свойство $auto_expunge в true, то функция imap_close( ) унич тожит все сообщения, помеченные для удаления:

var $auto_expunge = true;

Нам потребуется новая группа специальных сообщений об ошибке. Обрати те внимание на использование свойства $ERR_ARGS_DELIMITER в качестве разде лителя сообщения об ошибке и последующего аргумента:

var $ERR_ARGS_DEUMITER = " ";

var $ERROR_MS6 = ";

.

var $ERR_STR_CONNECTION_FAILED = 'Connection failed!';

.

Получение электронной почты с помощью РНР var $ERR_STR_PROTOCOL_NOT_SUPPORTED = 'Protocol not supported!';

var $ERR_STR_CLOSE_ FAILED = 'Error closing the stream! ';

, var $ERR_STR_MAILBOX_NOT_AVAILABLE = 'Mailbox not available! ';

var $ERR_STR_OVERRIDE_START = "Override start () method!";

Метод init( ) инициализирует класс, присваивая внутренним свойствам зна чения переданных ему аргументов:

function init($host, $protocol='imap', $port=143, $userid=' ', $userpassword=' ') { $this->host = $host;

$this->protocol = Sprotocbl;

$this->port = $port;

$this->userid = $userid;

$this->userpassword = $userpassword;

Значение свойства $mailbox извлекается из глобального пространства имен:

$this->mailbox = $GLOBALS[ "mailbox"];

Если заданный протокол не входит как элемент в массив $j3upported_proto cols, то он считается недопустимым:

if (!in_array($this->protocol, $this->supported_protocols)) { $this->buildErrorMsg($this->ERR_STR_PROTOCOL_NOT_SUPPORTED, $this->protocol);

return false;

Если предстоит работать с протоколом NNTP, а свойство mailbox пустое, то поток IMAP должен быть открыт без выбора почтового ящика, для чего чет вертый аргумент функции imap_open( ) устанавливается в OP_HALFOPEN. Если у свойства $mailbox непустое значение, то оно используется в качестве назва ния телеконференции:

-if ($this->protocol>== 'nntp' && empty($this->mailbox)) { $mode ;

'= OPJALFOPEN;

'...} else Smode = false;

$this->stream = @imap_open("\{ $this->host/$this->protocol:$this->port}$this->mailbox", $this->userid, $this->userpassword, Smode);

;

: if (!$this->stream),{ $this->buildErrorMsg($this->ERR_STR_CONNECTION_FAILED, imap_last_error());

,, return false;

} return true;

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

startQ и end() Для того чтобы активировать экземпляр нашего класса, мы вызываем метод start (), а при завершении работы с экземпляром - метод end ( ) :

function start() I Метод start( ) должен заменяться дочерним классом, поскольку класс Webmail не предназначен для самостоятельной работы. Это метод интерфейса, кото рый должны реализовывать все производные классы:

$this->buildErrorMsg($this->ERR_STR_OVERRIDE_START);

return false;

Метод end () закрывает открытый поток:

function end() { if ($this->auto_expunge) $ret = @imap_close($this->stream, CL_EXPUNGE);

:

-else $ret = @imap_close($this->stream);

:

if (!$ret) { $this->buildErrorMsg($this->ERR_STR_CLOSE_ FAILED, imap_last_error());

return false;

} return true;

} PHP старается гарантировать закрытие всех открытых соединений при за вершении сценария. Однако хорошей практикой следует считать предостав ление в базовом классе какого-либо метода для сборки мусора.

buildErrorMsg() и errorMsgQ Метод buildErrorMsg( ) всего лишь устанавливает для свойства $ERROR_MS6 зна чение, состоящее из переданных ему аргументов, разделенных $ERR_ARGS_DE LIMITER:

function buildErrorMsg($err msg, $err_arg='') { $this->ERROR_MSG = $err msg. $this->ERR_ARGS_DELIMITER. $err_arg;

> Кроме того мы как обычно определим метод для вывода сообщений об ошиб ках:

Получение электронной почты с помощью РНР function errorMsgO { return $this->ERROR_MSG;

Тестирование класса Webmail Опробуем этот класс с различными протоколами и хостами:

'jv •:•:• ' Обратите внимание, как мы переопределили метод start ( ) в данном примере сценария, расширяющем класс Webmail. Этот сценарий лишь соединяется с указанным сервером. Чтобы получить нечто осмысленное, надо добавить в класс Webmail новые функции. Первое, что хотелось бы сделать после соеди нения с сервером IMAP, - это получить список сообщений в выбранном поч товом ящике.

Получение списка почтовых сообщений или статей Для получения списка сообщений в почтовом ящике или статей, опублико ванных в телеконференции, можно вызвать функции imapjieader() и imap_fetchstructure().

Глава 12. Получение электронной почты и статей телеконференций imap_header() object imap_header(int stream, int msg_no [, int fromlength, int subjectlength, string defaulthost]) Функция imap_header() возвращает заголовки сообщения или статьи, а функ ция imap_fetchstructure() подробно сообщает об их структуре. Можно обра щаться к функции imap_header() под другим ее именем, imap_headerinfo().

Эта функция возвращает объект, содержащий информацию о блоке заголов ков данного сообщения, со следующими свойствами (табл. 12.2):

Таблица 12.2, Информация о заголовках сообщения Заголовок Описание Date Дата создания сообщения, или заголовок Date Subject Заголовок Subject Заголовок Message-ID message_id References Заголовок References Точные копии заголовков То, From и Reply-To toaddress fromaddress reply_toaddress to, from, reply_to Массив объектов, содержащих адреса электронной почты из за головка. У каждого элемента есть следующие свойства со значе ниями, приведенными для адреса Wankyu Choi :

personal - полное имя - «Wankyu Choi» mailbox - имя почтового ящика - «wankyu» host - имя хоста - «whatever.com» Объекты обладают еще одним свойством с именем adl. Отправи тель сообщения может указать маршрут, по которому это сооб щение должно дальше следовать, который называется «source routing». Однако это свойство используется редко и обычно ни чего не содержит R для свежих и прочитанных Recent N для свежих и не прочитанных <пробел> для не являющихся свежими Unseen U для не просмотренных и не свежих <пробел> для просмотренных или не просмотренных и свежих Считается, что сообщение Recent имеет также статус Unseen. Не обходимо проверить оба флага, Recent и Unseen, чтобы опреде лить, должно ли сообщение быть прочитано А, если ответ отправлен Answered <пробел>, если ответ не отправлен Deleted D, если помечено для удаления <пробел>, если не помечено для удаления Получение электронной почты с помощью РНР Заголовок Описание X, если это черновик Draft <пробел>, если это не черновик F, если помечено флагами Flagged <пробел>, если не помечено флагами Порядковый номер сообщения Msgno Размер сообщения в байтах Size fetchfгот Значение заголовка From, отформатированное в соответствии с аргументом fromlength, задающим размер. Если аргумент от сутствует, это свойство ничего не возвращает. Учтите, что заго ловок From с символами не из набора ASCII следует декодировать с помощью функции IMAP, которая будет рассмотрена ниже. Ес ли обрезать закодированный заголовок, его значение будет раз рушено Значение заголовка Subject, отформатированное в соответствии с fetchsubject аргументом subjectlength, задающим размер. Если аргумент от сутствует, это свойство ничего не возвращает. С кодированным значением заголовка Subject возникает та же проблема, что и в свойстве fetchf rom С помощью этой функции можно получать метаданные сообщения:

$msg = ;

imap_header($stream, : 10, 30, 40);

if ($msg^>Unseen == 'U' | |. $msg->Recent == ' R ' ) { $flag = "(Unseen)";

} else $flag = "(Seen)";

Форматируем заголовок Date для получения краткого его варианта:

$msg_date = gmstrftime("%b %d %Y", strtQtlme($msg->date)').;

', ', Делаем возможным щелчок по адресу From:

$from_addr = $nisg->from[0]->mailbox. "@". $msg->from[0]->host;

: :

if ($msg->from[0]->personal ' ! = ") { $from_adclr = "From: ".

$msg->from[0]->personal. "";

} else { $from_addr = "From: $from_addr ";

Делаем возможным щелчок по адресу (адресам) Сс:

for.,($1=0;

$1 < count($msg->cc);

$i++):{ $msg->cc[$i]->host;

$cc_addr = $msg->cc[$i]-xnai.ib'ox. " if ($msg->cc[$i]->personal != " {) ) $msg->cc[$i]-> $ccs[] = "" 434 Глава 12. Получение электронной почты и статей телеконференций personal. "";

} else {.

. $ccs[] = "<а href=\"mailto: $cc_addr\">$cc_addr";

У нас есть хоть один адрес Сс?

if (count($ccs) > 0) { $cc_adr = "Сс: ", implodeC',", $ccs);

Выведем их:

echo("Date: $msg_date eclio("From: $from_addr
");

:

if (count($ccs) >0) { echo("Cc: $cc_adr
";

!

••>'-:V'...... • V:

echo("Size: $msg->Size bytes
");

;

•' e"cho( "Subject: $msg->subject
");

Функция imap_header() не возвращает UID сообщения. Для получения уни кального ID сообщения надо вызвать функцию imap_uid( ).

imap_uid() and imap_msgno() int imap_uid(int stream, int msg_no) int iraap_rasgno(int stream, int uid) Функция imap_uid( ) возвращает UID сообщения с заданным порядковым но мером, тогда как imap_msgno( ) возвращает порядковый номер сообщения с за данным UID.

Описываемая ниже функция imap_fetchstructure() предоставляет гораздо больше информации, чем imap_header( ).

\ imap_fetchstructure() object imap_fetchstructure(int stream, int msg_no [, int flags]) Эта функция возвращает метаданные указанного сообщения.

Если третий аргумент задан константой FT_UO, то функция воспринимает ар гумент msg_no как UID сообщения.

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

• type - заголовок Content-Type, присутствующий в блоке заголовка как це лое число Получение электронной почты с помощью РНР Свойство type может принимать следующие значения:

Значение Свойство Свойство Значение Text Audio 0 Multipart Image 1 Message Video 2 Application Other • encoding- заголовок Content-Transfer-Encoding, присутствующий в блоке заголовка как целое число Свойство encoding может принимать следующие значения:

Значение Значение Свойство Свойство base 7bit 0 quoted-printable 8bit 1 Binary Other • if subtype - true, если есть строка подтипа • subtype - подтип MIME • if id -true, если есть заголовок Message-ID • id - заголовок Message-ID • lines - количество строк в теле сообщения • bytes - размер сообщения в байтах • if parameters -true, если существует массив parameters • parameters - массив объектов, описывающих каждый параметр MIME parameters представляет собой массив объектов, каждый из которых облада ет двумя свойствами, носящими имена a t t r i b u t e и value. В нем содержатся дополнительные пары имя параметра/значение, используемые во всех по лях заголовка Content-Type данного сообщения. Например:

Sstruct = imap_fetchstructure($stream, 10);

Sparam = $struct->parameters[0];

echo($parara->attribute);

// BOUNDARY echo($param->value);

// • parts - массив объектов, описывающих каждую часть сообщения parts - массив объектов с такой же структурой, как объект верхнего уровня.

Первый элемент массива parts содержит текстовое тело данного сообщения.

Если в сообщении есть вложения, то во втором элементе массива содержится информация о структуре первой кодированной части тела:

Sstruct = imap_fetchstructure($stream, 10);

.

$num_parts = count($struct->parts) - 1;

436 Глава 12. Получение электронной почты и статей телеконференций if ($num_parts > 0) { ;

echo( "Message 10 has attachment(s)! "');

;

} else { echo("Message 10 has no attachment!");

} В некоторых полях заголовков могут присутствовать данные, являющиеся результатом кодировки текста, содержащего символы, не входящего в набор ASCII. Кодированный текст представляет собой последовательность отобра жаемых символов ASCII, начинающуюся с =? и оканчивающуюся ?=. Внутри нее есть еще два знака вопроса: первый в конце названия набора символов и второй — в начале закодированного в виде символов ASCII исходного текста.

Между этими двумя знаками вопроса могут находиться символы В/b или Q/q.

Символ В обозначает кодировку base64, а символ Q - кодировку quoted-prin table:

• From: =?ISO-8859-1?Q?Petr=E9?= Приведенный выше заголовок From содержит текст в кодировке quoted-prin table из набора символов ISO -8859-1:

• From: =?ks_c_5601-1987?B?w9a/z7HU?= • Subject :, =?ks_c_5601-1987?B?wcu828fVtM+02S4g?= Приведенные выше заголовки From и Subject содержат текст в кодировке Ьа se64 из набора символов ks_c_5601_1987 корейского языка.

Для того чтобы раскодировать эти поля заголовков, надо вызвать функцию imapjnime_header_decode().

imap_mime_header_decode() array imapjnime_header_decode(string var) Эта функция возвращает массив объектов, у каждого из которых есть два свойства: charset и text.

Вызовем эту функцию, передав ей первый приведенный выше заголовок From:

Sheader = "=?ks_c_560l-1987?B? w9a/z7HU?= ";

$dec_array = ima:pjnime_header_decode($header);

echo( "Charset: ". $dec_array[0]->charset. "
");

echo( "Decoded text: ". $dec_array[0]->text);

Л У М СЛедующий результат ° Charset: ks_c_5601- Decoded text " Если элемент возвращенного массива не закодирован и записан в чистом Рис. 12.1. Результат работы US-ASCII, то свойство charset этого функции imap_mime_header_decode() элемента имеет значение default.

Получение электронной почты с помощью РНР Можно, например, отсортировать список сообщений электронной почты или статей по дате создания или теме. Это удобно делать с помощью функции imap_sort().

imap_sort() array imap_sort(int stream, int criteria, int reverse, int flags) Данная функция возвращает отсортированный массив сообщений или ста тей. Массив можно отсортировать в обратном порядке, задав для аргумента reverse значение true.

Аргумент criteria определяет порядок сортировки (табл. 12.3):

Таблица 12.3. Значения аргумента criteria Аргумент Описание Сортировать по полю заголовка Date SORTDATE Сортировать по дате поступления SORTARRIVAL Сортировать по полю заголовка From SORTFROM Сортировать по полю заголовка Subject SORTSUBJECT Сортировать по полю заголовка То. Участвует только первый адрес в SORTTO заголовке Сортировать по полю заголовка Сс. Участвует только первый адрес в SORTCC заголовке Сортировать по размеру сообщения в октетах SORTSIZE Четвертый аргумент flags, необязательный, может принимать одно из сле дующих значений (табл. 12.4):

Таблица 12.4. Значения аргумента flags Аргумент Описание Возвращать UID сообщений. В его отсутствие возвращаются поряд SEJJID ковые номера сообщений Не загружать обрабатываемые сообщения. Возвращаются только SE NOPREFETCH порядковые номера или UID сообщений, и последующие вызовы функций для получения дополнительных данных должны снова со единяться с сервером. По умолчанию загружаются все заголовки вместе с номерами или UID сообщений. Установка этого флага сни жает производительность. Отключение этого режима может повы сить эффективность функции Следующий фрагмент кода выводит список сообщений, отсортированный по теме в порядке убывания:

$msgs = imap_sort($stream, SORTSUBJECT, 1, О, SE_NOPREFETCH);

if (!is_array($msgs)) { 438 Глава 12. Получение электронной почты и статей телеконференций return "No message or error occurred while fetching messages!";

> else { $str = ";

} foreach ($msgs as $msg_no) { $msg = imap_header($this->stream, $msg_no);

$str.= "$msg->subject
";

> return $str;

Теперь смастерим метод, который возвращает список сообщений электрон ной почты или статей телеконференций.

Вывод списка сообщений в классе Webmail Для того чтобы добавить в класс Webmail метод для вывода списка сообще ний, надо определить ряд новых свойств.

Новые свойства Список можно сортировать в выбранном порядке. По умолчанию сортиров ка осуществляется в порядке создания сообщений или статей. Для сортиров ки в порядке возрастания свойству $ reverse присваивается значение false.

Будем разрабатывать класс Webmail дальше:

.// webmail_class_ver2.php class Webmail.:..{• var Ssort = 'SORTDATE';

var Sreverse = ;

0| Дополнительные строки специальных сообщений:

var $ERR_STR_MAILBOX_STATUS_ERROR = 'Cannot get stat for the mailbox!';

var $STR_NO_SUBJECT = 'NO SUBJECT';

.

var $STR_NO_FROM = 'UNKNOWN';

initQ Метод init() делает новые переменные глобальными с помощью массива SGLOBALS. Свойство $sort устанавливает порядок сортировки списка.

function init($host, $protocol='imap', $port=143, $userid,$userpassword) ' В том случае, если глобальные переменные пусты, надо оставить без измене ния значения по умолчанию:

if (isset($GLOBALS["sort"])) $this->sort = $GLOBALS["sort"];

if (lsset($GLOBALsi"reverse"])) Получение электронной почты с помощью РНР $tfiis-> reverse = $GLOBALS[" reverse"];

} getMsgListQ Новый метод getMsgList( ) возвращает двумерный массив, элементы которого хранят информацию заголовков сообщений в виде другого массива.

Свойство $so rt устанавливает поле, по которому сортируются сообщения, и по умолчанию принимает значение SORTDATE:

function getMsgList($read action, $mail_action) { $msgs = @imap_sort($this->stream, $this~>sort, $this->reverse, SE_NOPREFETCH);

Если возвращенное значение $msgs оказывается не массивом, это означает, что сообщений в данном почтовом ящике или телеконференции нет:

if (!is_array($msgs)) return false;

Получить объект метаданных для каждого сообщения:

for ($1=0;

$1 < count($msgs);

$!«•) { Получим как порядковый номер, так и UID сообщения:

•"••••:...$msg = @imap_header($this->stream, $msg_no);

$arr[$i]["no"] = $msg_no = $msgs[$i];

$arr[$i]["uid"3 > $msg_uid = imap_uid($this->stream, $msg_no);

Было ли сообщение прочтено?

if ($msg->Unseen == 'U' | | $msg->Recent == 'R') { $arr[$i]["unseen"] = true;

} else { $arr[$i]["unseen"] = false;

Значение заголовка Date слишком длинное, чтобы уместиться в ячейке таб лицы. Укоротим его. Функция strtotime( ) возвращает временную отметку в формате UNIX по заданной строке с датой:

$arr[$i]["date"] = gmstrftime("%b %d %Y", strtotime($msg->date));

Получим метаданные текущего сообщения:

Sstruct = @imap_fetchstructure($this->stream, $msg_no);

Первым элементом в свойстве parts возвращаемого объекта является тексто вое тело сообщения. Если в свойстве более одного элемента, это означает, что в сообщении есть вложения, и тогда перед его темой помещается знак @:

440 Глава 12. Получение электронной почты и статей телеконференций $num_parts = count ($struct»parts) - 1;

if ($num_parts > 0) $msg_prefix = "@";

": else $msgj>refix = ";

При необходимости декодируются заголовки MIME. Метод decodeHeader() возвращает декодированное значение заголовка, если в нем содержатся сим волы, отличные от ASCII:

if (empty($ii)sg->subject)) { $arr[$i]["subject"] = $this ->buildllrl("$read_action&msg_uid=$msg_uid&mailbox= $this->mailbox", $this->STR_NO_SUBJECT);

:

: } else { $msg_subject = $this->decodeHeader($msg->subject);

$arr[$i]["subject"] = $this >buildU rl ( "$read_action&msg_uid=$msg_uid&mailbox=".

"$this->mailbox", "$msg_prefix$msg^subject");

!;

: :

Метод makeAdd ress( ) принимает массив объектов, содержащих свойства адре са сообщения, и преобразует каждый почтовый адрес в ссылку, используя для справки второй аргумент:

if (empty($msg->from)) { $arr[$i]["from" ] = $this->STR_NO_FROM;

} else { $arr[$i]["from"] = $this->makeAddress($msg->from, "$mail_action&msg_uid=$msg_uid&mailbox=$this->mailbox");

return $arr;

> С помощью метода getMsg( ) выполняется чтение сообщения или статьи. Мы построим его в следующем разделе.

makeAddressQ Функция makeAddress( ) возвращает строку, содержащую адреса электронной почты, разделенные запятыми. Если задан аргумент $action, то каждый ад рес преобразуется в ссылку на основании этого аргумента:

function makeAddress($emails, Saction) ".'.:'. ( if (!is_array($emails)) return;

foreach ($emails as $email) { В заголовке From может содержаться закодированный текст:

Spersonal = $this->decodeHeader($email->personal);

$address = $email->mailbox. "@". $email->host;

if (iempty($personal)) { Получение электронной почты с помощью РНР "$arr[] = $this->buildllrl("$action&email=$address", Spersonal);

:;

} else { $arr[] = $this->buildUri("$action&einail=$address", Saddress);

.., return implodeC,', $arr);

;

] }. ;

;

;

..;

';

' -..''. "J' & - ', lШ decodeHeaderQ Метод decodeHeader( ) возвращает декодированное значение заголовка:

function decodeHeader($arg) { $dec_array = imap_minie_header_decode($arg);

Используется только свойство text возвращаемого объекта:

foreach ($dec_array as $obj) $arr[]= $obj->text;

if (count($arr) >0) return implodeC', $arr);

else return $arg;

buildUrl() Метод buildUrl( ) служит средством получения URL, вызывающего текущий сценарий. Например, аргумент $oncllck используется, чтобы обеспечить функциональность JavaScript:

function buildUrl($options, Slink, $onclick='') { global $PHP_SELF;

if ( empty (Sonclick)) $onclick = " OnClick=\"$onclick\"";

!

: return "$link" ;

Тестирование класса Webmail Теперь можно создать экземпляр класса Webmail, соединиться с почтовым сервером или сервером телеконференций и получить список сообщений или статей. Следующий сценарий соединяется с news.php.net и выводит список статей, опубликованных в конференции php.test. Для получения данных с сервера потребуется некоторое время:

:

if (strtolower($struct->parts[0]->subtype).== 'html') $html = 1;

} else if ($struct->parts[0]->encodlng == 4) {.$arr["body"] = imap_qprint(imap_fetchbody($this->stream, $this~>rnsg_uid, 1, FT_UID));

if (strtolower($struct->parts[0]->subtype) == 'html') $html = 1;

'••"'•••: } else { if ($struct->encoding == 3) { $arr["body"] = imap_base64(imap_fetchbody($this->stream, $this->msg_uid, 1, FTJJID));

if (strtolower($struct->subtype) == 'html') $html = 1;

} else if ($struct->encoding = = 4 ) { $arr["body"3 = irnap_qprint(imap_fetchbody($this->stream, $this->msg_uid, 1, FT_UID));

if (strtolower($struct->subtype) == 'html') $html = 1;

} else { $arr["body"] = imap_fetchbody($this->stream, • $this->insg_uid, 1, FTJJID);

if (strtolower($struct->subtype) == "html') $html = 1;

} >'-' ' :: ^ • ' : •. ' Преобразуем ссылки, если они есть в теле сообщения. Если ссылки уже до пускают возможность щелчка (сообщение имеет формат HTML), пропускаем блок кода:

if (!$html) { $arr["body"] = str_replace("\r\n", "
", $arr["body"]);

$arr["body"] = eregi_replace( "http://([-a-zO-9\_\./"@?=%(&

)|]+)", "http://\\K/a>", $arr["body"]);

$arr["body"] = eregi_replace( "ftp://([-a-zO-9\_\./'@?=%&arap;

]+)", "ftp://\\K/a>", $arr["body"]);

$arr["body"] = eregi_replace( "([-a-zO-9\_\.]+)@([-a-zO-9\_\.]+)", "\\1@\\2", $arr["body"]);

:

' - :.','• '"":: ". '. > •.••.''•'.V' ' "...': ' • fe : i Добавим ссылки на вложенные файлы, если таковые имеются:

for ($1=0;

$i< count($struct->parts);

$i++) { В массиве parameters содержится свойство NAME, значение которого дает имя вложенного файла:

foreach ($struct->parts[$i]->parameters as $attr) if (strtolower($attr->attribute) == 'name') { Sfilename = $this->decodeHeader($attr->value);

break;

448 Глава 12. Получение электронной почты и статей телеконференций $arr["parts"][$i] = $this->buildllrl("$download_action&".

"mailbox=$this->mailbox&".

"msg_uid=$this->msg_uid&".

"part_no=$i&filename=$filename", $filename);

} return $arr;

downloadAttachment() Этот метод передает содержимое указанной части тела в стандартный вывод, веб-броузер:

function downloadAttachmentO, { Istruct = @imap_fetchstructure($this->stream, $this->msg_uid, FT_UID);

if (!$struct) { $this->buildErrorMsg($this->ERR_STR_MSG_UIO_INVALID.

;

$this->msg_UID, imap_last_error());

return false;

Выясним основной тип части тела:

switch ($struct->parts[$this->part_no]->type) { case 0: $type = 'text';

break;

case 1: :$type = 'multipart';

break;

case 2: $type = 'message 1 ;

break;

case 3: $type = 'application';

break;

case : 4: $type = 'audio';

: break;

case 5: $type = 'image';

break;

case 6: $type = 'video';

break;

default: $type = 'other';

break;

Если в части тела содержится gif-изображение, то свойство type получает значение image, a subtype устанавливается в gif :

Ssubtype = $struct->parts[$tliis->part_no]r>subtype;

Получение электронной почты с помощью РНР Вызываем функцию header( ), чтобы вывести заголовки HTML:

header( "Content-Type : $type/$subtype" ) ;

Заголовок Content-Disposition заставляет броузер использовать имя файла, заданное в качестве атрибута filename:

header ("Content-Disposition: ;

filename=$this->filename");

Правильным форматом этого заголовка является "Content-Disposition: at tachment;

filename=$this->filename". Некоторые броузеры, в том числе IE, реагируют на этот заголовок странным образом, когда в нем указано значе ние "attachment". В качестве значения заголовка рекомендуется задавать пустую строку или "inline".

Снова проверяем тип кодировки:

if ($struct->parts[$this->part_no]->encoding == 3) { echo(@imap_base64(imap_fetchbody($this->stream, $this->msg_uid, $this->part_no+1, FTJJID)));

} else if ($struct->parts[$this->part_no]->encoding == 4) { //QUOTED J^INTABLE echo(@imap_qprint(imap_fetchbody($this->stream, $this->msg_uid, $this->part_no-H, FTJJID)));

} else { echo(@imap_fetchbody($this->stream, $this->msg_uid, $this->part_no+1, FTJJID));

} return true;

Тестирование класса Webmail Теперь мы можем читать сообщения с помощью класса Webmail. В следую щем сценарии показано, как расширить этот класс и воспользоваться вновь добавленными возможностями:

\n");

echo($this->htinlFooter( ) ) ;

return true;

Pile Edit View Search Go iookmarks Tasks Ц UnwookKwon Feb1S? г as !lbiiilsijLmUltenjl Chanqsoo(Ciro рёмэаЙЙ" Г ЗА Is thallrue?

ChanoBoo Kim I Г 33 \№&ЯШ& Г зг Comc.,j!;

i.so0icl Feb рёь19шГ р„_ ^_.

"febWmi" DELETE r COPYr MOVE^ T Document! Done (ОД61 »a) Рис. 12.4. Основной интерфейс приложения Получение электронной почты с помощью РНР menuQ Метод menu ( ) выводит ссылку для отправки сообщений электронной почты или статей телеконференций. Можно расширять функциональность, созда вая новые методы и добавляя ссылки на них в этот метод:

function menu() • • :: • { if ($this->protocol == 'nntp') { $menu_str = $this-> buildUrl("action=mailForm&mode=article&mailbox=$this->mailbox", '[Post]');

.

$menu_str = $this->buildUrl('action=mailForm&inode=new'i ;

: '[Send]');

:

'> return $menu_str;

" ma\\Form() Этот метод мы уже видели в предыдущей главе, однако он значительно усо вершенствован, чтобы показывать различные формы в зависимости от ре жима $mode, выбранного пользователем:

!

function mailFormO iv ;

;

:

:':':;

.. :. -.. • ' ( ::v. ' '.. : -:':::>, ""', global $PHP_SELF, $mode, Semail;

' ;

$is_news = false;

Если пользователь отвечает на сообщение электронной почты, то надо уда лить исходное сообщение и надлежащим образом установить значения заго ловков:

if ($mode == 'reply') { $msg •:

- $this->getMsg( ", " ) ;

if (!$msg) $mail_to = Ismail;

Л :Л else {. •, '-,'. •'•V-.;

/-': 6-й.

$mail_date - $msg["date"];

$mail_to = $msg["raw_from"];

$mail_cc = $msg["raw_cc"];

$mail_subject = "Re: ". $msg["subject"];

$mail_body ^ " — Original Message($mail_date) — \r\n".

eregi_replace("
", "\r\n", $msg["body"]);

% ;

fc ' > ' -' Пользователю требуется переслать текущее сообщение электронной почты.

Сохраняем заголовок From и добавляем строку "Fwd : " перед заголовком Subject:

} else if ($mode == 'forward') { $msg = $this->getMsg( ", " ;

) 468 Глава 12. Получение электронной почты и статей телеконференций if (!$msg) return false;

$mail_from = $msg["raw_froiri"];

$mail_date = $msg["date"];

$mail_subject = "Fwd: ". $msg["subject"];

$mail_reply_to = $mail_from;

$mail_body =."--- Original Message($mail_date) —\r\h".

eregi_replace("
", "\r\n", $msg["body"]);

Если пользователь хочет опубликовать статью в телеконференции, то надо установить флаг $is_news:

} else if ($mode == 'article') { $mail_to = $this->mailbox;

$is_news = true;

Для того чтобы ответить на статью в телеконференции, надо также задать заголовок References. Получаем исходное значение заголовка References и до бавляем к нему заголовок Message-ID текущей статьи:

} else if ($mode == 'followup') { $mail_to = $this->mailbox;

$msg = $this->getMsg(", " ;

) $mail_references = $msg["references"]. ". $msg["message_id"];

$mail_subject = "Re: ". $msg["subject"];

$is_news = true;

} $ret_str ="\n";

return $ret_str;

' sendWebmailQ Метод sendWebnailO может обойтись без информации NNTP, поскольку она передается при инициализации класса Webmail. Удалим глобальные перемен ные, содержащие информацию NNTP. Остальной код будет почти таким же, как в предыдущей версии, за исключением дополнительной функции, копи рующей все исходящие сообщения в почтовый ящик «Sent»:

s function sendWebmail() W,. i : : '• :

;

" •'.'•..••: ( ' ' ;

• • ' "...

global $is_news, $use_smtp, $smtp_host, $smtp_port;

:

/ if (!$my_mail->send()) { $this->buildErrorMsg($my_mail->errorMsg());

return false;

;

-. >•,..;

'• '. •;

";

;

"•:'.. • ' " :....' $mail_str = $myjnail->view_msg();

if (!$mail_str) return false;

Вспомним, что метод appendMailO копирует данное сообщение в указанный почтовый ящик:

if (!empty($this->sent_mailbox)) { if (!$this->appendMail($mail_str, $this->sent_mailbox)) { return false;

return true;

':.

} ;

... :'"::• copyMsg() Этот метод копирует сообщения с UID из заданного набора в указанный поч товый ящик. Он представляет собой оболочку метода copyMailMsg( ):

function copyMsgO { : global $MSG_UIDS;

if (!is_array($MSG_UIDS)) { $tnis->buildErrorMsg($this->ERR_STR_NO_UIOS);

:

return false;

' 472. Глава 12. Получение электронной почты и статей телеконференций if (!$this->copyMailMsg(implode(",", $MSG_UIDS))) return false;

return true;

moveMsg() Этот метод перемещает сообщения с UID из заданного набора в указанный почтовый ящик. Он представляет собой оболочку метода moveMailMsg( ):

function moveMsgO { global SMSGJJIDS;

if (!is_array($MSG_UIDS)) { $this->buildErrorMsg($this->ERR_STR_NO_UIDS);

return false;

} if (!$this->moveMailMsg(iinplode(",", SMSGJJIDS») return 0;

return true;

} deleteMsg() Этот метод удаляет сообщения с UID из заданного набора текущего почтово го ящика. Он представляет собой оболочку метода deleteMailMsg( ). Обратите внимание, что этот метод действительно уничтожает указанные сообщения.

Можно усовершенствовать его так, чтобы перед уничтожением сообщения перемещались в почтовый ящик «Deleted». Такую функцию не составит тру да реализовать с помощью метода appendMail( ):

function deleteMsgO { global SMSGJJIDS;

if (!is_array($MSG_UIDS)) { $this->buildErrorMsg($this->ERR_STR_NOJJIDS);

return true;

} if (!$this->deleteMailMsg(implode(V, SMSGJJIDS))) return 0;

return true;

createMailboxFormQ Этот метод возвращает форму, с помощью которой пользователь может со здать новый почтовый ящик. Форма показывается прямо под списком поч товых ящиков в левой части веб-страницы, приведенной на первом снимке экрана:

function createMailboxForm() Получение электронной почты с помощью РНР global $PHP_SELF;

if ($this->protocol != 'imap') return;

$ret_str = "\n";

return $ret_str;

} msgTableHeader(), msgTableRow() и msgTableFooterQ Простые вспомогательные методы для показа таблицы со списком сообщений:

function msgTableHeader() return "

\n";

•'Ч "" } function msgTableRow($width, $cell_data, $is_th=0, $bg_color='»FFFFFFp, $align='CENTER', $valign='TOP') Свежие или непросмотренные сообщения отображаются полужирным шрифтом, для чего аргумент $is_th должен иметь значение true:

if (!$is_th) $row_tag = 'td';

else $row_tag = 'th';

return "<$row_tag width=\"$width%\" align=\"$align\" valign=\"$valign\" bgcolor=\"$bg_color\" nowrap>$cell_data\n";

} function msgTableFooterO { return "

\n";

} listMsg() Этот метод возвращает таблицу со списком сообщений:

function listMsgO { global $PHP_SELF, $cur_page;

$order = $this->reverse;

474 Глава 12. Получение электронной почты и статей телеконференций Свежие сообщения должны появиться в начале списка. Обращаем порядок при сортировке по SORTDATE:

: : if ($this->sort == 'SORTDATE') $this->reverse.= (integer)! $this->reverse;

Может показаться, что в приведенном операторе if приведение типа излиш не, однако оно необходимо, чтобы глобальная переменная $ reverse не полу чила значения null.

IMAP позволяет осуществлять групповые операции над сообщениями:

if ($this->protocol =='imap') { $ret_str.= "\n";

$ret_str.= "
\n"r $ret_str.="

\n";

Покажем меню навигации, создав гиперссылки для всех страниц:

for ($i = 1;

$i •<= $num_page;

$i++) { if ($cur_page == $i) $ret_str.= "[$i]";

else $ret_str. = $this->buildUrl("action=listMsg".

"&mailbox=$this->mailbox&".

"sort=$this->sort&reverse=$order&".

"cur_page=$i", " [ '• : 1. ' ">•.

$ret_str.="

\n";

return $ret_str;

' MstMailboxO Возвращает список почтовых ящиков в виде ряда строк HTML:

function listMailbox($mailbox=' ' )..;

^":" '••'( $str = "";

;

Получим список почтовых ящиков в виде массива:

$mailboxes = $this->getMailboxList($mailbox);

if (!$mailboxes) return false;

;

Добавим к каждому ящику количество непрочитанных сообщений:

foreach ($mailboxes as $mbox=>$unseen) { if ($this->protocol !='nntp' && $this->protocol-!='pop31 && $mbox != 'INBOX') { Если мы работаем не с сервером новостей, обеспечим ссылку, с помощью ко торой пользователь может удалить почтовый ящик. Обратите внимание на метод JavaScript confirm(), который предотвращает случайное удаление пользователем почтового ящика:

$del_prefix = $this->buildllrl("action=deleteMailbox".

"&del_mailbox=$mbox", "[X]", Получение электронной почты с помощью РНР "if (!confirm( 'Are you sure?')) return false;

");

} else $del_pref ix = ' ' ;

if ($this->protocol == 'nntp') { $str.= $this->buildUrl("action=listMsg&mailbox=$mbox", "$mbox($unseen)"). "
\n";

} else { $str.= $del_prefix. $this->buildUrl("action=listMailbox".

"&mailbox=$mbox", "$mbox($unseen)"). "
\n";

return $str;

readMsg() Форматирует и возвращает выбранное сообщение в удобном для пользователя формате HTML, как демонстрирует следующий снимок экрана (рис. 12.5):

iN http: /lotalhost ProPHP4/Chapterl2,'webmail,php-Netscape. J gfe ' E* iiew Search fio aookmarks lasks tiolp 'I'tocalhostfProPHPIfChapterlZfviebmail.php Date: Feb19 2001 04: From: Yongpil Park Subject: Thanks a lot!

[Forward this message) Thanks for your reply.

I attached the document you requested.

Talk to you later.

Best Regards, Yongpil Park, NeoQuest Communications, inc.

DocUMrtl Dent (Onu Рис. 12.5. Вывод сообщения для пользователя function readMsgO ' Читаем содержимое сообщения и записываем его в массив $msg. Метод get Msg( ) принимает два аргумента, задающие действия, выполняемые для пре образования вложений и адресов электронной почты в гиперссылки. Напри мер, при щелчке по вложению снова вызывается приложение, при этом пе ременная Saction оказывается установленной в downloadAttachment:

478 Глава 12. Получение электронной почты и статей телеконференций $rasg = $this->getMsg('action=downloadAttachment', '-actions mailForm&mode=reply' );

if (!$msg) return false;

$ret_str = "Date: ". $msg["date"].:."
\n";

$ret_str.= "From: ". $msg["from"], "
\n";

if (!empty($msg["cc"])) $ret_str.= "Cc: ".

.,.., $msg["cc"]. "
\n";

if (!empty($msg["references"])) $ret_str. = :"fteferences:

::

". $msg[" references"]. "
\ri";

$ret_str.= "Subject: " • $msg[ "subject"], "
\n";

s;

;

Если пользователь работает с сервером NNTP, то он может послать ответ на текущую статью. Если нет, он может ответить на сообщение электронной почты или переслать его кому-либо другому:

if: ($this->protocol == 'nntp') < $ret_str.3 $this->buildUrl("action=mailForm&mailbox=".

''$this->mailbox&mode=followup&rosg_uid=$triis->msg_uid", "[Reply. to this article]");

} else { : $ret_str.= $this->buildUrl("action=mailForm&mailbox=".

"$this->mailbox&mode=forward&msg_uid=$this->msg_uid", "[Forward this message]");

} $ret_str.= "

\n";

$ret_str.= "

". $msg["body"]. "\n";

Проверим, есть ли в сообщении вложения:

if ($msg["num_parts"] > 0) { $ret_str.= "\n";

for ($i = 0;

$i < count($msg["parts"]);

$1+*) $ret_str.= $msg["parts"][$i]. "
\n";

} return $ret_str;

htmlHeader() и htmlFooter() Наконец, имеются методы htmlHeader() и htmlFooterO, которые просто выво дят ряд тегов HTML, требуемых в начале и в конце веб-страницы. Можно скопировать их из приложения, которое мы построили в предыдущей главе:

function htmlHeader($title=' ', $charset='') {} function htmlFooterO <} Следующий раздел кода, создающий экземпляр определенного нами класса, должен показаться знакомым:

Получение электронной почты с помощью РНР $host = "localhost";

Sprotocol = "imap";

$port = 143;

Suserid = "wankyu";

Suserpassword = "12345";

$wmail = new MyJJebmailO;

if (! $wmail->init($host, $protocol, Sport', JiiSe rid, Suserpassword)) echo($wmail->errorMsg());

if (!$wmail->start($action)) echo($wmail->errorMsg());

$wmail->end();

С помощью этого приложения возможно подключение к серверу телеконфе ренций. Измените настройки и попробуйте соединиться с news. p h p. net. Сле дующий снимок экрана (рис. 12.6) демонстрирует, что получится, если со единиться с этим сервером и выбрать телеконференцию p h p. test:

,. Fte E* »ew Search go Bookmarks tasks Help :

p.announced 1) NO SliUJtcr JHOM •™ • ^ • is;

'fo :Вапод.двд evoj;

en.te«! ЕшжСёЗас !FebH2l<)l ;

75"ltest Mickolas Hevde 74 'Re-" J2i- ilFeblf'gnl '/3 \S1± iiiiobu! -с.сот Feb 07 21Ю :72 i i ti [7t |70 IJlSli.;

tUi:ilJj f v eb ЖМ IffiOh i69vRa[{e [Sascha'Srh^imann Эп'зб 2СЮ1"' C'hD,pgar(Ji6g) fee ijakp ;

jin].,VyintSad iJan262001 ) :! Dho.teinplate(29) [б?! pan262CB phixcvs( S Php.oa(1896) I QhD,notes(lOSD8) pHoJanqnOl) DhD^MI?) Рис. 12.6. Соединение с сервером телеконференций news.php.net Большинство серверов NNTP возвращает десятки тысяч имеющихся теле конференций. Если вы решите подключиться с помощью этого приложения к одному из таких серверов, получение списка конференций займет неимоверно много времени, либо наступит тайм-аут приложения в ожидании ответа сер вера. Данное приложение предназначено для работы с небольшими серверами телеконференций типа news.php.net.

480 Глава 12. Получение электронной почты и статей телеконференций Ресурсы Дополнительную информацию по POP и IMAP можно получить в следую щих RFC:

• http://www.rfc.net/ - RFC 1939 (Post Office Protocol Version 3) • http://www.rfc.net/ - RFC 2060 (Internet Message Access Protocol Version 4 Revision 1) • http://www.imap.org/ - соединение по IMAP Дополнительные сведения о серверах IMAP можно получить на их домаш них страницах:

• http://www.washington.edu/imap (UW-IMAP Server) • http://asg.web.cmu.edu/cyrus/imapd (Cyrus IMAP Server) • http://www.inter7.com/courierimap (Courier IMAP Server) Резюме В этой главе мы рассмотрели дополнительные протоколы, необходимые для получения почты с сервера: POP и IMAP. Мы узнали, что IMAP обладает ря дом преимуществ перед POP:

• Доступ к сообщениям IMAP можно получить в любое время из любого места • Для размещения сообщений IMAP можно использовать произвольное ко личество почтовых ящиков, группируя сообщения по темам • Сообщения IMAP можно загружать по частям или целиком • Управление сообщениями IMAP можно облегчить, помечая их флагами Мы изучили достаточное количество связанных с IMAP функций РНР, что бы разбираться и писать сложные приложения электронной почты и теле конференций, основанные на POP/IMAP или NNTP. Было продемонстриро вано, как просто работать с серверами POP/IMAP или NNTP, выполняя сле дующие простые шаги:

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

Сетевое взаимодействие и TCP/IP С распространением сетей, основанных на TCP/IP, и служб, доступных че рез эти сети, возник значительный интерес к способам и средствам доступа к этим службам. Сценарии РНР не составляют исключения в этой тенденции.

В данной главе мы рассмотрим функции, предоставляемые РНР для такого рода доступа, построив демонстрационные приложения, в которых эти функции применяются.

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

В данной главе мы не станем рассматривать такое взаимодействие, а обра тим свое внимание на функциональность, доступную сценариям РНР для со единения с другими службами, придерживающимися протоколов TCP/IP, и взаимодействия с ними. В частности, мы рассмотрим следующие аспекты программирования TCP/IP:

• Краткое введение в семейство протоколов TCP/IP • Разрешение имен и сетевые службы каталогов, такие как Domain Name System (DNS - система доменных имен) и Yellow Pages/Network Informa tion Services (YP/NIS- «желтые страницы»/сетевая информационная служба) • API сокетов, предоставляемый РНР • Клиентские функции Simple Network Management Protocol (SNMP) простого протокола сетевого управления 163ак. 482 Глава 13. Сетевое взаимодействие и TCP/IP • Приложения, непосредственно работающие с некоторыми протоколами, и функциональные интерфейсы к другим протоколам Протокол Интернета Протокол Интернета - Internet Protocol (IP) обеспечивает средства доставки данных между отправителем и получателем. Для обозначения объектов, об менивающихся данными, в нем используются понятия IP-адресов отправи теля и получателя. Протокол IP, по существу, является протоколом без уста новления соединения;

это означает, что уровень протокола IP не хранит со стояние или информацию о пакетах (известных также как дейтаграммы IP), которые он получает.

IP просто направляет все входящие пакеты данных уровню, находящемуся непосредственно над ним, т. е. уровням TCP и UDP (описываемым ниже).

Эти пакеты данных могут нести в себе ответ сервера. В обратном направле нии могут посылаться пакеты, направляемые более высокими уровнями протоколов драйверу устройства, например запроса HTTP, посылаемого веб броузером.

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

Часто надежности можно добиться, применяя различные системы под тверждения и ретрансляции, которые мы рассмотрим в следующем разделе.

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

• Размер пакета и фрагментирование Данные посылаются и принимаются в виде блоков, лучше всего подходя щих для данного приложения. Например, telnet может единовременно посылать в линию лишь несколько байт данных, тогда как FTP, скажем, посылает одновременно несколько килобайт. Размер пакета конечен и за висит от размера пакетов данных, поддерживаемых сетевой аппарату рой, например Ethernet. Положение еще более осложняется тем, что в се тях, через которые проходят данные между двумя машинами, могут ис пользоваться блоки данных разного размера как на аппаратном уровне, так и на уровне протоколов.

• Маршрутизация Сеть организации может содержать в себе подсеть, которая может быть соединена с внешней сетью, также представляющей собою подсеть. Что Протоколы транспортного уровня бы попасть к получателю, пакету IP часто приходится пройти через не сколько подсетей. Маршрутизатор - это хост TCP/IP, который соединен по меньшей мере с двумя подсетями и позволяет направлять трафик из одной подсети в другую. В пакете IP, выходящем с машины, есть IP-адре са только отправителя и получателя. За направление пакета IP к получа телю отвечает логика маршрутизации, имеющаяся на машине отправите ля и на промежуточных маршрутизаторах по пути к получателю.

• Время существования (Time-to-Live) Нельзя, чтобы пакеты циркулировали по сети до бесконечности;

они должны быть доставлены получателю или уничтожены по прошествии некоторого времени. Уровень IP гарантирует это с помощью атрибута времени существования (TTL - time-to-live) для каждого пакета данных.

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

Протоколы транспортного уровня Мы видели, что протокол IP не гарантирует надежную доставку пакетов данных и что он делегирует эту функцию протоколам более высокого уров ня. Над уровнем IP находится транспортный уровень, обычно представляе мый TCP или UDP. Часто выбор между TCP или UDP определяется требова ниями приложений к производительности или надежности.

Pages:     | 1 |   ...   | 5 | 6 || 8 | 9 |   ...   | 16 |



© 2011 www.dissers.ru - «Бесплатная электронная библиотека»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.