Messager.php 5.7 KB
<?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 implements \IteratorAggregate {

    /**
     * 原始数据
     * @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();
    }

    /**
     * 实现 使用 foreach功能
     * @return \ArrayIterator
     * @author:dc
     * @time 2024/9/18 10:43
     */
    public function getIterator() {
        return new \ArrayIterator($this->item);
    }

    /**
     * 解析
     * @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_map(function ($v){
                        return strtolower(str_replace(['\\','(',')'],'',$v));
                    },$flags);
                    break;
                }
                case 'INTERNALDATE':{
                    // 内部时间
                    $date = '';
                    while (1){
                        $date .= array_shift($tokens);
                        if(substr($date,-1)=='"') break;
                        $date.= ' ';
                    }
                    $this->item[$msgno]->date = trim($date,'"');
                    break;
                }
                case 'RFC822.SIZE':{
                    $this->item[$msgno]->size = array_shift($tokens);
                    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;
    }




}