IMAP w stylu PHP

Transkrypt

IMAP w stylu PHP
Artykuł pobrano ze strony eioba.pl
IMAP w stylu PHP
Wszyscy korzystamy z poczty elektronicznej. Ci z nas, którzy bardziej zaangażowani są w działalność w sieci
posiadają zazwyczaj wiele kont, z których pocztę pobierają poprzez protokół POP za pomocą programów, często z
rozbudowanymi funkcjami filtrującymi i porządkującymi pocztę. Wiadomości kopiowane są z serwera na nasz
komputer, tym samym ich odczyt odbywa się całkowicie lokalnie. Co zrobić jednak, kiedy dostęp do tej samej
poczty chcemy mieć w wielu miejscach? Być może na komputerze w domu, w pracy i na laptopie? Nie kasować
listów na serwerze i ściągnąć na każdym z nich osobno?
Istnieje inne rozwiązanie – korzystanie z poczty bezpośrednio na serwerze dzięki możliwościom jakie daje nam
protokół IMAP. Rozwinięcie tego skrótu - Internet Message Access Protocol – daje też dobry obraz jego faktycznych
możliwości. Nie jest on jedynie protokołem umożliwiającym ściąganie poczty. Kluczowe w tym przypadku słowo
'Access' oznacza możliwość korzystania z poczty znajdującej się na zdalnym serwerze tak jakby była ona
przechowywana lokalnie.
W tym artykule pokażę jak napisać w PHP pewne podstawowe moduły interfejsu do zarządzania pocztą poprzez
protokół IMAP. Zanim zaczniemy warto jednak sprawdzić, czy dostęp do twojego konta jest w ogóle możliwy za
pomocą IMAP – w Polsce nie jest to często oferowana funkcja. Głównym czynnikiem ograniczającym dostęp do IMAP
jest wymóg posiadania dobrego połączenia z Internetem, naturalnie za pomocą stałego łącza, co jeszcze do
niedawna nie było u nas łatwe do osiągnięcia. Na szczęście teraz DIAL-UP przechodzi do historii.
PHP w akcji
PHP posiada bardzo szeroką gamę funkcji służących korzystaniu z protokołu IMAP. Ich przydatność nie jest jednak
ograniczona wyłącznie do samego IMAP. Obsługują one równocześnie protokoły POP3 oraz NNTP a także dają
możliwość korzystania z lokalnych skrzynek pocztowych.
Wszystkie funkcje IMAP są powiązane z odpowiednim rozszerzeniem PHP, które nie jest domyślnie instalowane. W
systemie Windows konieczne będzie znalezienie w pliku php.ini linijki:
;extension=php_imap.dll
Należy usunąć na jej początku średnik oraz uruchomić ponownie oprogramowanie serwera, pod którym PHP u nas
pracuje.
Linux z kolei będzie wymagał od nas rekompilacji PHP z opcją:
--with-imap=/sciezka/do/imap
Połączenie
Aby w jakikolwiek sposób korzystać z zasobów konta IMAP musimy rozpocząć od połączenia z serwerem, które
otwiera nam funkcja imap_open(). Jej składnia wygląda następująco:
$mbox = imap_open("{mail.example.com:143}INBOX", "user", "haslo");
Gdzie mail.example.org jest przykładowym adresem serwera pocztowego, port 143 jest domyślny dla protokołu
IMAP, INBOX domyślną nazwą skrzynki pocztowej a user i haslo danymi użytkownika konta, koniecznymi do
zalogowania.
Ze względu na dużą wagę bezpieczeństwa komunikacji w ostatnich czasach możemy chcieć kontaktować się z
serwerem za pomocą szyfrowanego połączenia. W tym przypadku otwarcie połączenia będzie wyglądało
następująco:
$mbox = imap_open("{mail.example.com:993/ssl}INBOX", "user", "haslo");
Zmienił się port pod jakim będziemy się łączyć z serwerem, ale również zaznaczyliśmy potrzebę wywołania funkcji
SSL poprzez dodanie po nazwie serwera opcji /ssl. Takich możliwych do wykorzystania opcji jest więcej, pełną ich
listę można znaleźć w dokumentacji php. Na nasze potrzeby w obecnej chwili nie musimy znać ich reszty.
Wyświetlenie listy wiadomości
Zanim przystąpimy do pobierania i wyświetlania listy wiadomości na koncie musimy sprawdzić czy skrzynka w
ogóle jakieś wiadomości zawiera.
if (imap_num_msg($mbox) == 0)
{
echo 'Brak wiadomosci';
}
else
{
echo 'Ilość wiadomości: ' . imap_num_msq($mbox);
}
Jak łatwo się domyślić funkcja imap_num_msg() zwraca nam ilość wiadomości znajdujących się w otwartej
skrzynce. Zakładając, że jakieś wiadomości są na naszym koncie możemy je teraz wyświetlić:
echo '<table>
<tr>
<th>Lp</th>
<th>Data nadania</th>
<th>Nadawca</th>
<th>Temat</th>
</tr>';
for ($i = 1; $i <= imap_num_msg($mbox); $i++)
{
$naglowek = imap_headerinfo($mbox, $i, 80, 80);
echo '<tr>
<td>' . $i . '</td>
<td>' . gmdate('Y-m-d H:i:s', $naglowek->udate) . '</td>
<td><a href="mailto:' . $naglowek->from[0]->mailbox . '@' . $naglowek->from[0]->host . '">' .
$naglowek->from[0]->mailbox . '@' . $naglowek->from[0]->host . '</a></td>
<td>' . $naglowek->fetchsubject . '</a></td>
</tr>';
}
echo '</table>';
Kod stał się trochę niewyraźny poprzez dodanie znaczników HTML, ale taki jest naturalny sposób wyświetlania listy
wiadomości – w formie tabeli. Tworzymy pętlę o ilości powtórzeń równej liczbie wiadomości zwróconych funkcją
imap_num_msg().
Dla każdej wiadomości wywołujemy funkcję imap_headerinfo(), która zwraca obiekt zawierający informacje z
nagłówka wiadomości. Pierwszy jej parametrem jest zmienna przechowująca otwarte połączenie z serwerem,
drugim numer wiadomości, której nagłówki chcemy pobrać. Dwa kolejne parametry są opcjonalne – ustalają one
ograniczenia długości pól "od" oraz "temat".
Cały obiekt jest dosyć bogatą strukturą, której pełną zawartość wyjaśnia dokumentacja PHP. Dla naszych potrzeb
wykorzystaliśmy jedynie kilka wartości:
udate
zwraca datę i czas otrzymania wiadomości w formacie Unix, stąd potrzeba wykorzystania funkcji
gmdate(), aby dane te przedstawić w czytelniejszej formie
ta wartość przechowuje tablicę informacji o nadawcy wiadomości, osobno przechowując nazwę
skrzynki (mailbox), a więc to co znajduje się przed znakiem @, oraz osobno adres serwera, a więc
część adresu po @.
zwraca temat wiadomości, opcjonalnie skrócony do ilości znaków podanej jako parametr funkcji
fetchsubject
imap_headerinfo()
from[]
Istnieje również druga, bardzo słabo opisana w dokumentacji PHP, jednak mimo wszystko łatwiejsza w użyciu
funkcja do pobierania nagłówków wiadomości. Jest to mianowicie imap_headers(), która jako parametr przyjmuje
jedynie identyfikator połączenia, zwraca natomiast tablicę z danymi z nagłówków wszystkich wiadomości w
skrzynce.
O każdej wiadomości w tablicy znajdują się następujące informacje:
FlagiNumer)DataNadawcaTemat(Rozmiar)
Dla pewnej przykładowej wiadomości może to wyglądać tak:
A
A oznacza "Answered", czyli na tą wiadomość wysłano już odpowiedź.
123)
numer wiadomości w skrzynce to 123
14-Oct-2004
odebrana została 14 października 2004 roku
[email protected] nadawcy wiadomości
Example subject
temat wiadomości
(8415 chars)
długość wiadomości to 8415 znaków
Inne flagi jakie mogą posiadać wiadomości to:
N – New - nowa
R – Recent - niedawna
U – Unread - nieprzeczytana
F – Flagged - oflagowana
D – Deleted - usunięta
X – Draft – kopia robocza
Jak najłatwiej wyświetlić tak sformatowaną listę wiadomości? Może tak:
$naglowki = imap_headers($mbox);
if (!$naglowki)
{
print "Blad podczas pobierania naglowkow";
}
else
{
foreach($naglowki as $naglowek)
{
print "$naglowek";
}
}
Ponieważ funkcja imap_headers() pobiera całą listę wiadomości jej wykonanie może potrwać długo i znacznie
większa staje się szansa niepowodzenia. W przypadku błędu zwraca ona wartość false, stąd nasz warunek
sprawdzający czy pobieranie się udało.
Po wyświetleniu listy wiadomości pozostaje tylko zakończyć połączenie:
imap_close($mbox);
Funkcja zamykająca połączenie oprócz identyfikatora połączenia przyjmuje jeszcze jeden opcjonalny parametr –
flagę CL_EXPUNGE. Jeśli ten parametr zostanie ustawiony wszystkie wiadomości oflagowane do usunięcia zostaną
usunięte. Wiadomości oflagować można funkcją imap_delete() (nie usuwa ona fizycznie wiadomości a jedynie
oznacza jako usunięte). Już po zastosowaniu tej funkcji, a jeszcze przed fizycznym usunięciem wiadomości możemy
je przywrócić dzięki funkcji imap_undelete().
Fizycznie usunąć wiadomości do tego przeznaczone można również w każdej chwili wywołując funkcję
imap_expunge(). Flaga CL_EXPUNGE jest także opcjonalnym parametrem funkcji imap_open(), którego ustawienie
spowoduje skasowanie 'usuniętych' wiadomości w momencie zamykania połączenia.
Wyświetlenie konkretnej wiadomości
Tworząc stronę wyświetlającą cały list zaczniemy pewnie od wypisania nagłówków, takich jak nadawca, adresat czy
tytuł, co w praktyce opisane zostało przed chwilą przy okazji wyświetlania listy wszystkich wiadomości. Przejdźmy
więc do treści listu. Przyjmijmy, że identyfikator wiadomości którą chcemy wyświetlić mamy zapisany w zmiennej
$msg_id.
nl2br(imap_fetchbody($mbox, $msg_id, "1"));
Funkcja imap_fetchbody() zwraca żądaną część wiadomości. W naszym przypadku będzie to część pierwsza, a więc
czysty tekst, który dla poprawnego wyświetlenia musimy jeszcze poddać działaniu funkcji nl2br() zamieniającej
nowe linie w tekście na znaczniki <br />.
Można by się to tego sposobu wyświetlania ograniczyć, jednakże nie uwzględnia on wszystkich możliwych
wiadomości e-mail, które być może będziemy musieli wyświetlić. Tutaj niestety zaczynają się schody. Jak wszyscy
wiemy list elektroniczny może zostać napisany czystym tekstem, co jednak w obecnych czasach coraz częściej
ustępuje wersjom tzw. "wzbogaconym" czyli po prostu HTML. Zwłaszcza, że duża część programów domyślnie
ustawiona jest na wysyłanie listów w tym formacie, co zresztą typowym użytkownikom zdaje się podobać. Do tego
dochodzą wszelkie załączniki.
Wracając jednak do naszego wyświetlania wiadomości, jeżeli chcielibyśmy w systemie obsługi poczty uwzględnić
również przypadki innych maili niż czysto tekstowe, będziemy musieli głębiej zainteresować się nie tylko
możliwościami funkcji imap_fetchbody() ale również towarzyszącej jej imap_fetchstructure().
Ta nowa funkcja, jak wskazuje jej nazwa, służy analizie struktury wiadomości email. Zwraca bardzo bogato
wyposażony obiekt z informacjami, z których najistotniejsze dotyczą rodzaju danych, które zawiera wiadomość oraz
kodowania załączników.
Obsługa złożonych wiadomości to temat na zupełnie nowy artykuł, ograniczmy się tutaj więc do podstawowego
przykładu.
Wysyłanie poczty
Wysyłaniem poczty zajmuje się funkcja imap_mail(), której parametry przypominają znaną już zapewne mail():
imap_mail('[email protected]', 'temat', 'tresc wiadomosci');
Trzy powyższe parametry są wymagane, możemy jednak wykorzystać również kolejne opcjonalne, a są to:
dodatkowe nagłówki, podawane jako String
adresy cc – "carbon copy", co w polskiej wersji znaczy "do wiadomości"
adresy bcc – "blind karbon copy", po polsku "ukryte do wiadomości"
ścieżka zwrotna, czyli adres pod jaki domyślnie ma być wysyłana odpowiedź na list
Możemy więc już wysłać czysto tekstowego maila. Rozszerzenie IMAP daje nam jednak znacznie bardziej
zaawansowane możliwości. Korzystając z funkcji imap_mail_compose() możemy dodać do naszego maila zarówno
załączniki jak i stworzyć list w formacie HTML.
W tym miejscu, aby niepotrzebnie nie wydłużać tekstu zakładam, że masz pewne pojęcie o sposobie, w jaki
załączniki przesyłane są razem z listami.
Funkcja imap_mail_compose() wygeneruje nam pełną treść listu razem z nagłówkami i załącznikami na podstawie
dwóch parametrów:
dosłownie "koperta", spełnia podobną funkcję jak swój papierowy odpowiednik. Jest tablicą zawierającą
envelope
pola adresowe.
body
"ciało" czyli treść wiadomości razem z zakodowanymi załącznikami.
Przykładowy kod może wyglądać następująco:
// koperta zawiera adres nadawcy listu
$envelope["from"]= "[email protected]";
// pierwsza część mówi o tym że wiadomość zawiera różnego typu dane
$part1["type"] = TYPEMULTIPART;
$part1["subtype"] = "mixed";
// druga część to nasz załącznik
$part2["type"] = TYPEAPPLICATION;
$part2["encoding"] = ENCBINARY;
$part2["subtype"] = "octet-stream";
$part2["description"] = $plik;
$part2["contents.data"] = file_get_contents('test.txt');
// trzecia część to obrazek tła
$part3["type"] = TYPEIMAGE;
$part3["subtype"] = "jpeg";
$part3["encoding"] = ENCBINARY;
$part3["id"] = "abc";
$part3["description"] = "tlo";
$part3["contents.data"] = file_get_contents('tlo.jpg');
// czwarta część zawiera tekst jako HTML
$part4["type"] = TYPETEXT;
$part4["subtype"] = "html";
$part4["description"] = "czesc 3";
$part4["contents.data"] = "<html><body background=CID:abc>test1</body></html>\n\n\n\t";
// składamy treść w jedną tablicę
$body[1] = $part1;
$body[2] = $part2;
$body[3] = $part3;
$body[4] = $part4;
// generujemy wiadomość
$msg = imap_mail_compose($envelope, $body);
// oddzielamy nagłówki od ciała
$msg_head = substr($a, 0, strpos($msg, "\r\n\r\n"));
$msg_body = substr($a, strpos($msg, "\r\n\r\n"));
// wysyłamy wiadomość
imap_mail('[email protected]', 'Temat', $msg_body, $msg_head);
Jest to prosty przykład, który można udoskonalić. Rzecz, na którą warto zwrócić uwagę to, w jaki sposób zostało
zapisane w kodzie HTML odwołanie do obrazka, który ma być tłem. Każda część może mieć swój identyfikator
(Content-ID). Obrazek (część 3) ma ustawiony identyfikator jako abc i aby się odwołać do tego obrazka w HTMLu
użyłem zapisu CID:abc. Aby zobaczyć jak stworzyć bardziej złożoną wiadomość najlepiej utworzyć ją jakimś
klientem poczty i podejrzeć źródło.
Po odebraniu wiadomości z powyższego przykładu MS Outlook interpretował obrazek jako załącznik. Ukrycie
załącznika wymagałoby znacznie więcej starań i komplikacji, które na dobrą sprawę nie przynoszą żadnego efektu.
Dla funkcji imap_mail_compose() w dokumentacji PHP nie istnieje praktycznie żaden opis, warto jednak
przyglądnąć się licznym komentarzom napisanym przez czytelników.
NNTP, POP3
Jak wspomnieliśmy wcześniej, funkcje rozszerzenia IMAP obsługują poza tytułowym protokołem również POP3 oraz
NNTP.
POP3 jest powszechnie stosowanym protokołem do odbierania poczty, działającym na porcie 110. Korzystając z
niego możemy jedynie odebrać wiadomość i ją skasować. Nie działają żadne flagi, nie można nic wysyłać oraz nie
ma on wbudowanej obsługi katalogów.
Połączenie z POP3 nawiązujemy w identyczny sposób jak w przypadku IMAP, zmieniając jednak port i dodając do
imap_open() stosowną opcję:
$mbox = imap_open('{mail.example.com:110/pop3}INBOX', 'user', 'pass')
Protokół NNTP z kolei służy do obsługi list dyskusyjnych. Połączenie wywołuje się w jego przypadku nieco inaczej.
$nntp = imap_open('{news.example.com:119/nntp}pl.comp.lang.php', "", "")
Jak widać zamiast wywołania domyślnej skrzynki INBOX podajemy nazwę grupy dyskusyjnej, nazwą użytkownika i
hasło pozostawiamy puste. Teraz pobieramy nagłówki wiadomości:
$overview = imap_fetch_overview($nntp, "1:20", 0);
W tym momencie pobierzemy 20 wiadomości, zaczynając od wiadomości 1. Jeśli łączymy się nie z lokalnym
serwerem NNTP to nie polecam pobierania wszystkich nagłówków na raz, ponieważ spowoduje to
najprawdopodobniej przekroczenie limitu wykonywania skryptu.
Funkcja imap_fetch_overview() zwraca obiekt, który zawiera wszystkie interesujące nas informacje (m.in. temat –
"subject", datę – "date", nadawcę – "from", identyfikator wiadomości – "message_id").
Wyświetlamy teraz listę, którą pobraliśmy przed chwilą:
echo '<table>';
while (list($key, $val) = each($overview))
{
$temat = (empty($val->subject)) ? 'brak tematu' : $val->subject;
echo '<tr><td>' . $val->msgno . '</td>
<td>' . $temat . '</a>' . '</td>
<td>' . $val->from . '</td>
<td>' . $val->date . '</td></tr>';
}
echo '</table>';
Wyświetlanie zawartości danej wiadomości odbywa się w ten sam sposób jak podczas połączenia z IMAP.
echo nl2br(imap_fetchbody($nntp, $msgid, '1'));
Osoby korzystające z bardziej zaawansowanych programów do obsługi grup dyskusyjnych przywiązane będą
zapewne do widoku listy wiadomości w formie drzewa wątków, tzn. kiedy kolejne wiadomości będące
odpowiedziami na inne są pod nie wizualnie "podczepiane". Możemy również taki efekt osiągnąć stosując funkcję
imap_thread(). Szczegóły jej wykorzystania najlepiej również poznać studiując dokumentację PHP.
Podsumowanie
Artykuł ten miał za zadanie wprowadzić jedynie w bardzo bogaty świat możliwości związanych z rozszerzeniami
IMAP. Pełna lista dostępnych funkcji zawiera kilkadziesiąt pozycji, z których spora część przydatna jest głównie przy
próbach wyświetlania wiadomości o bardziej skomplikowanej zawartości.
Aby w pełni wykorzystać zarówno możliwości protokołu IMAP jak i jego obsługi w PHP warto zacząć od zapoznania
się z odpowiednim dokumentem RFC opisującym omawiany protokół. Być może to właśnie on jest przyszłością
poczty elektronicznej.
Autor: Piotr Lewandowski, Michał Paluchowski
Przedruk ze strony: http://nethut.pl/artykul/124/1
Artykuł pobrano ze strony eioba.pl

Podobne dokumenty