<?php namespace Lib\Imap\Parse; use Lib\Imap\Request\Msg; /** * 邮件列表 * @author:dc * @time 2024/9/14 15:33 * Class Messager * @package Lib\Imap\Parse */ class Messager { /** * 原始数据 * @var array */ protected array $result = []; /** * 解析后的数据 * @var array */ protected array $item = []; /** * 读取消息的 * @var Msg */ protected Msg $msg; public function __construct(array $result, Msg $msg) { $this->msg = $msg; $k = 0; foreach ($result as $item){ // 匹配出id和数据 if(preg_match("/\* (\d+) FETCH \(/",$item)){ $k++; $this->result[$k] = $item; }else{ if(isset($this->result[$k])){ $this->result[$k] .= $item; } } } $this->parse(); } /** * 解析 * @author:dc * @time 2024/9/14 17:35 */ protected function parse(){ foreach ($this->result as $item){ $item = trim($item); // 匹配出id和数据 if(preg_match("/\* (\d+) FETCH \(([\w\s\d\r\n\W]{1,})\)$/i",$item,$line)){ $this->parseFetch($line[1],$line[2]); } $line = null; } } /** * 解析头部信息,只能解析固定字段的属性 * @param int $msgno * @param string $line * UID 1568602720 INTERNALDATE "16-Sep-2019 10:58:40 +0800" FLAGS (\Seen) RFC822.HEADER {816} Received: from localhost (unknown [10.110.4.165]) by mfast8 (Coremail) with SMTP id t8CowAA3Za5g+n5d1b4tCA--.53220S2; Mon, 16 Sep 2019 10:58:40 +0800 (CST) Date: Mon, 16 Sep 2019 10:58:40 +0800 (GMT+08:00) From: =?utf-8?B?572R5piT6YKu566x5aSn5biI5Zui6Zif?= <developer.MailMaster@service.netease.com> To: zhlong0616@163.com Message-ID: <1803973093.340445.1568602720140.JavaMail.developer.MailMaster@service.netease.com> Subject: =?utf-8?B?5qyi6L+O5L2/55So572R5piT6YKu566x5aSn5biI?= MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_340444_1698792253.1568602720140" X-CM-TRANSID:t8CowAA3Za5g+n5d1b4tCA--.53220S2 X-Coremail-Antispam: 1Uf129KBjDUn29KB7ZKAUJUUBvt529EdanIXcx71UUUUU7v73 VFW2AGmfu7bjvjm3AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvj4RJUUUUUUUU X-Originating-IP: [10.110.4.165] RFC822.SIZE 5111 * @author:dc * @time 2024/9/18 11:46 */ protected function parseFetch(int $msgno, string $line) { $this->item[$msgno] = new MessageItem($msgno, $this->msg); $tokens = explode(' ',$line); while ($tokens){ $key = trim(array_shift($tokens)); switch ($key){ case 'UID':{ $this->item[$msgno]->uid = array_shift($tokens); break; } case 'FLAGS':{ $flags = []; while (1){ $flags[] = array_shift($tokens); if(substr(end($flags),-1)==')') break; } $this->item[$msgno]->flags = array_filter(array_map(function ($v){ return strtolower(str_replace(['\\','(',')'],'',$v)); },$flags),function ($v){ // 过滤空 return !empty($v); }); break; } case 'INTERNALDATE':{ // 内部时间 $date = ''; while (1){ $date .= array_shift($tokens); if($date!='"' && substr($date,-1)=='"') break; $date.= ' '; } $this->item[$msgno]->date = trim($date,'"'); break; } case 'RFC822.SIZE':{ $this->item[$msgno]->size = array_shift($tokens); break; } //* 1 FETCH (UID 1568602720 INTERNALDATE "16-Sep-2019 10:58:40 +0800" FLAGS (\Seen) BODYSTRUCTURE (("text" "html" ("charset" "utf-8") NIL NIL "quoted-printable" 4115 97 NIL NI //L NIL) "mixed" ("boundary" "----=_Part_340444_1698792253.1568602720140") NIL NIL) RFC822.HEADER {816} case 'BODYSTRUCTURE':{ $BODYSTRUCTURE = ''; $leftNum = $RightNum = 0; foreach ($tokens as $key=>$str){ // 还有括号不对等的情况,无语了 if($str == 'RFC822.HEADER'){ break; } // 找出现的次数 $leftNum += substr_count($str,'('); $RightNum += substr_count($str,')'); // 拼接起来 $BODYSTRUCTURE .= ' '.$str; unset($tokens[$key]); // 说明找到结束了 if($leftNum===$RightNum){ break; } } $tokens = array_values($tokens); $this->item[$msgno]->bodystructure = $BODYSTRUCTURE; break; } case 'RFC822.HEADER':{ $str = trim(implode(' ',$tokens)); // 是否带有字符数数量 if(preg_match("/^\{(\d+)\}/",$str,$num)){ $len = $num[1]+strlen($num[0]); $header = substr($str,0,$len); // 剩下的字符串 $tokens = explode(' ',substr($str,$len,9999)); // 踢出长度的头 $header = substr($header,strlen($num[0]),strlen($header)); }else{ // 以2个\r\n为结束 $str = explode("\r\n\r\n",trim($str)); $header = array_shift($str); // 剩余的字符串 $tokens = explode(' ',implode("\r\n\r\n",$str)); } $this->item[$msgno]->header = new Header($header); break; } default:{break;} } } } /** * 循环结果 * @param \Closure $closure * @author:dc * @time 2024/9/18 11:41 */ public function each(\Closure $closure):void { array_map($closure,$this->item); } /** * 获取一条消息 * @return bool|MessageItem * @author:dc * @time 2024/9/20 16:48 */ public function first():bool|MessageItem { if($this->item){ return $this->item[array_key_first($this->item)]; } return false; } /** * @return MessageItem[] * @author:dc * @time 2024/9/23 14:11 */ public function all():array { return $this->item; } }