В рамках корпоративной ERP-системы (упоминал в своей прошлой записи) разрабатывается web-mail-клиент (о как). Долго думал, использовать Pop3 или же imap. Все-таки выбрал imap, посмотрел в интернетах на наличие готовых решений. Нашел, но немного не того, пришлось пилить. Процесс, конечно еще продолжается, но костяк более-менее сделал (Скажу сразу, что дополнял класс. Он работает, но ряд вещей стоит все же переписать:
/*
* Класс предназначен для считывания данных(писем) почты посредством работы (IMAP подключени к серверу)
*/
class ImapCheck
{
private $mbox;
private $htmlmsg;
private $plainmsg;
private $charset;
private $attachments = array();
private $unread;
private $hcharset;
private $filescount =0;
/* public function __get($name)
{
if ($name=='mail') return $this->unread;
else return null;
}*/
public function getmail()
{
return $this->unread;
}
/**
* Конструктор
* @param string $host хост
* @param string $login аккаунт ящика
* @param string $pwd пароль
* @param array $options
* [letterID] = null|int - если известен ид письма
* [search] =
* ALL - return all messages matching the rest of the criteria
ANSWERED - match messages with the \\ANSWERED flag set
BCC "string" - match messages with "string" in the Bcc: field
BEFORE "date" - match messages with Date: before "date"
BODY "string" - match messages with "string" in the body of the message
CC "string" - match messages with "string" in the Cc: field
DELETED - match deleted messages
FLAGGED - match messages with the \\FLAGGED (sometimes referred to as Important or Urgent) flag set
FROM "string" - match messages with "string" in the From: field
KEYWORD "string" - match messages with "string" as a keyword
NEW - match new messages
OLD - match old messages
ON "date" - match messages with Date: matching "date"
RECENT - match messages with the \\RECENT flag set
SEEN - match messages that have been read (the \\SEEN flag is set)
SINCE "date" - match messages with Date: after "date"
SUBJECT "string" - match messages with "string" in the Subject:
TEXT "string" - match messages with text "string"
TO "string" - match messages with "string" in the To:
UNANSWERED - match messages that have not been answered
UNDELETED - match messages that are not deleted
UNFLAGGED - match messages that are not flagged
UNKEYWORD "string" - match messages that do not have the keyword "string"
UNSEEN - match messages which have not been read yet
* флаги для поиска
*/
public function ImapCheck($host, $login, $pwd, $options = array('search'=>'ALL'))
{
$messages=array();
$folder="INBOX";
//$folder="[Gmail]/&BCEEPwQwBDw-"; // если вам захочется почитать спам на гугломыле.
$this->mbox = imap_open ("{$host}$folder", $login,$pwd) or die(imap_last_error());//OP_HALFOPEN
if(isset($options["search"]))
{
if(!isset($options["letterID"]) || $options["letterID"] == NULL)
{
$arr = imap_search ($this->mbox, $options["search"]);
if ($arr !== false)
{
foreach ($arr as $i)
$messages[]=$this->getLEtter($i);
$this->unread=$messages;
unset($messages);
}
else {$this->unread=false;}
}
else
$this->unread[$options["letterID"]]=$this->getLEtter($options["letterID"]);
}
else
die("parametr options->search are empty!");
}
/**
* заголовок от письма
* @param $num номер письма в ящике
* @return array
*/
public function getHeaderInfo($num)
{
$headerArr = imap_headerinfo ( $this->mbox, $num);
$elements = imap_mime_header_decode($headerArr->subject);
$subj = "";
for ($p = 0; $p < count($elements); $p++)
{
if($elements[$p]->charset !="default" && strtolower($elements[$p]->charset) !="utf-8")
{
$subj .= iconv($elements[$p]->charset, 'UTF-8', $elements[$p]->text);
$this->charset = $elements[$p]->charset;
$this->hcharset = $elements[$p]->charset;
}
else if($elements[$p]->charset =="default")
{
$subj.= iconv('KOI8-R','UTF-8', $elements[$p]->text);
$this->charset = 'KOI8-R';
$this->hcharset = 'KOI8-R';
}
else
{
$subj.=$elements[$p]->text;
$this->charset = 'UTF-8';
$this->hcharset = 'UTF-8';
}
}
if(!isset($headerArr->sender[0]->personal))
$headerArr->sender[0]->personal = "unknown";
return array(
'from'=> $headerArr->sender[0]->mailbox . "@" . $headerArr->sender[0]->host,
'to'=> $headerArr->to[0]->mailbox . "@" . $headerArr->to[0]->host,
'name'=> $this->decode($headerArr->sender[0]->personal) ,
'subject'=>$subj,
'Date'=>strtotime($headerArr->Date)
);
}
/**
* чтение письма по номеру
* @param $num номер
* @return array
*/
public function getLetter($num)
{
$return = $this->getHeaderInfo($num);
$this->getmsg($num); //читаем тело письма (сообщение)
//imap_setflag_full($this->mbox, $i, "\\Seen"); //прочли письмо, поставили флаг, что прочли
$return["charset"] = $this->charset;
$return["plain"] = $this->plainmsg;
$return["html"] = $this->htmlmsg;
$return["attach"] = $this->attachments;
$return["letterID"] = $num;
return $return;
}
private function decode($enc)
{
$parts = imap_mime_header_decode($enc);
$str='';
for ($p=0; $pcharset;
$part = $parts[$p]->text;
if ($ch!=='default')
$str.=mb_convert_encoding($part,'UTF-8',$ch);
elseif ($ch=='default')
$str.=mb_convert_encoding($part,'UTF-8','KOI8-R');
else $str.=$part;
}
return $str;
}
private function getmsg($mid)
{
$this->htmlmsg = $this->plainmsg = $this->charset = '';
$this->attachments = array();
$s = imap_fetchstructure($this->mbox,$mid);
if (!isset($s->parts))
$this->getpart($mid,$s,0);
else
{
foreach ($s->parts as $partno0=>$p)
$this->getpart($mid,$p,$partno0+1);
}
}
private function getpart($mid,$p,$partno)
{
$data = ($partno) ? imap_fetchbody($this->mbox,$mid,$partno): imap_body($this->mbox,$mid);
if ($p->encoding==4)
$data = quoted_printable_decode($data);
elseif ($p->encoding==3)
$data = base64_decode($data);
$params = array();
if (isset($p->parameters))
foreach ($p->parameters as $x)
$params[ strtolower( $x->attribute ) ] = $x->value;
if (isset($p->dparameters))
foreach ($p->dparameters as $x)
$params[ strtolower( $x->attribute ) ] = $x->value;
if (isset($params['filename']) || isset($params['name']))
{
$filename = (isset($params['filename']))? $params['filename'] : $params['name'];
if(isset($this->attachments[$filename])) //если уже есть в атачменте такой файл, делаем "версионность"
{
$this->filescount ++;
$filename = $this->filescount."_".$filename;
}
$this->attachments[$filename] = $data;
}
elseif ($p->type==0 && isset($data))
{
if (strtolower($p->subtype)=='plain')
{
$this->plainmsg .= trim($this->ConvBody($data)) ."\n\n";
}
else
$this->htmlmsg .= $this->ConvBody($data) ."
";
if(isset($params['charset']))
$this->charset = $params['charset'];
}
elseif ($p->type==2 && isset($data))
{
$this->plainmsg .= trim($this->ConvBody($data)) ."\n\n";
}
if (isset($p->parts)) {
foreach ($p->parts as $partno0=>$p2)
$this->getpart($mid,$p2,$partno.'.'.($partno0+1));
}
}
private function ConvBody($text)
{
if(!empty($this->hcharset) && $this->hcharset !='UTF-8')
{
$text = iconv($this->hcharset, 'UTF-8', $text);
}
return $text;
}
/**
* Закрыть имап подключение
*/
public function close()
{
imap_close($this->mbox);
}
}
//TODO: отловить момент, когда делают рассылку и данный пользователь так же учавствует в ней, выдает адрес, перввый из списка [to]
подключение и юзание:
require "inc/imap.php";
$options = array('search'=>'SINCE "'.date("j F Y",strtotime("-1 DAY")).'"');//тип поиска сообщений на почте - собираем сообщения со вчера по седня :)
$rm = new ImapCheck("{server.ru/imap}","mail@server.ru","password",$options);
$mail_list = $rm->getmail(); //получили письма
$rm->close();
выплюнет массив с письмами примерно так:
[from] =>откуда
[to] => кому
[name] => имя приславшего
[subject] => название
[Date] => дата, письма
[charset] => кодировка
[plain] => если обычный текст
[html] => если хтмл-код
[letterID] => id письма на сервере (не постоянно! по факту это просто количественный номер)
[attach] => Array
(
[название_изображения] => бинарное содержание(то есть можно обычным fput воткнуть куда надо)
)
да, кстати,есть небольшая бага: в некоторых случаях название атачей будет типа =?UTF_8?B?..... лечится просто :
iconv_mime_decode("название файла",0, "кодировка")
надеюсь, кому-то помог.