Header.php 6.4 KB
<?php

namespace Lib\Imap\Parse;


/**
 * 解析邮件
 * @author:dc
 * @time 2024/9/10 16:54
 * Class Header
 */
class Header{

    /**
     * @var array
     */
    private array $attributes = [];

    /**
     * 原始头信息
     * @var string
     */
    protected string $raw_header;

    /**
     * Header constructor.
     * @param string $raw_header
     */
    public function __construct(string $raw_header)
    {
        $this->raw_header = $raw_header;

        $this->rfc822_parse_headers();
    }


    /**
     * @param string $name
     * @param string $value
     * @param bool $append
     * @author:dc
     * @time 2024/9/11 16:24
     */
    public function setAttribute(string $name, string $value, bool $append = true){
        $name = strtolower($name);

        if(!$append){
            $this->attributes[$name] = $value;
        }else{
            if(isset($this->attributes[$name]))
                $this->attributes[$name] .= "\r\n".$value;
            else
                $this->attributes[$name] = $value;
        }
    }


    /**
     * 解析邮件头部
     * @author:dc
     * @time 2024/9/10 16:29
     */
    private function rfc822_parse_headers(){
        $header = explode("\r\n",$this->raw_header);
        $name = '';
        foreach ($header as $str){
            // 判断是否是上一行的
            if(str_starts_with($str,' ') || str_starts_with($str,"\t")){
                $this->setAttribute($name,$str);
            }elseif(str_contains($str,':')){
                list($name, $str) = explode(":",$str,2);
                $this->setAttribute($name,$str);
            }

        }

        foreach ($this->attributes as $name => $attribute){
            $attribute = trim($attribute);
            $this->attributes[$name] = $attribute;
        }
    }


    public function __get(string $name)
    {
        return $this->get($name);
    }

    /**
     * 读取字段
     * @param string $name
     * @return mixed
     * @author:dc
     * @time 2024/9/11 15:06
     */
    public function get(string $name):mixed {
        $name = strtolower($name);

        $m = 'get'.str_replace(' ','',ucwords(str_replace('-',' ',$name)));

        if(method_exists($this,$m)){
            return $this->{$m}();
        }

        return $this->attributes[$name]??'';
    }


    /**
     * 获取收件地址 可能是假地址
     * @param bool $is_obj 是否解析成对象 Address
     * @return Address[]
     * @author:dc
     * @time 2024/9/11 15:03
     */
    public function getTo(bool $isArray = false):array {
        // 如果有这个字段,就用这个字段  to字段的邮箱可能被伪造
        if(!empty($this->attributes['delivered-to'])){
            $to = $this->attributes['delivered-to'];
        }else{
            $to = $this->attributes['to']??'';
        }

        return $this->parseAddress($to,$isArray);
    }

    /**
     * 解析地址
     * @param string $address
     * @param false $isArray 是否返回数组
     * @return array
     * @author:dc
     * @time 2024/9/29 14:54
     */
    private function parseAddress(string $address, $isArray = false){
        $arr = [];
        if($address){
            foreach (explode(',',$address) as $k=>$str){
                $arr[$k] = Address::make($str);
                if($isArray) $arr[$k] =  $arr[$k]->toArray();
            }
        }

        return $arr;
    }

    /**
     * 抄送人
     * @return array
     * @author:dc
     * @time 2024/9/11 15:53
     */
    public function getCc(bool $isArray = false):array
    {
        return $this->parseAddress($this->attributes['cc']??'',$isArray);
    }

    /**
     * 密送人
     * @return array
     * @author:dc
     * @time 2024/9/11 15:54
     */
    public function getBcc(bool $isArray = false):array
    {
        return $this->parseAddress($this->attributes['bcc']??'',$isArray);
    }



    /**
     * 发件人 可能是欺炸 发件人
     * @return Address
     * @author:dc
     * @time 2024/9/11 15:19
     */
    public function getFrom():Address {
        return Address::make($this->attributes['from']??'');
    }

    /**
     * 获取解码后的主题
     * @return string
     * @author:dc
     * @time 2024/9/11 15:22
     */
    public function getSubject():string {
        return static::mime_decode($this->attributes['subject']??'');
    }


    /**
     * Boundary
     * @param string $str
     * @return string
     * @author:dc
     * @time 2024/9/11 16:05
     */
    public function getBoundary(string $str = ''): string
    {
        $pre = "/boundary=(.*?(?=;)|(.*))/i";
        // 在内容类型中读取 大多少情况都在这里面
        $contentType = $str ? $str: ($this->attributes['content-type']??'');
        if($contentType){
            preg_match($pre,$contentType,$b);
            if(!empty($b[1])){
                return trim(str_replace(['"',';'],'',$b[1]));
            }
        }
        if($this->raw_header && !$str){
            return $this->getBoundary($this->raw_header);
        }

        return '';
    }

    /**
     * 这个是是否加急 1加急 3普通 5不急
     * @return string
     */
    public function getPriority(): string
    {
        if(!empty($this->attributes['priority'])){
            return $this->attributes['priority'];
        }

        if(!empty($this->attributes['x-priority'])){
            return $this->attributes['x-priority'];
        }

        return '3';
    }



    /**
     * @return array
     */
    public function getAttributes(): array
    {
        return $this->attributes;
    }

    /**
     * @return array
     * @author:dc
     * @time 2024/9/11 16:15
     */
    public function toArray():array {
        $arr = [];
        foreach ($this->attributes as $key=>$attr){
            $arr[$key] = $this->get($key);
        }

        return $arr;
    }


    /**
     * @return string
     */
    public function getRaw(): string
    {
        return $this->raw_header;
    }

    /**
     * 解析加密字符
     * @param string $str
     * @return string
     * @author:dc
     * @time 2024/9/29 14:21
     */
    public static function mime_decode(string $str):string {
        $str = trim($str);
        if(preg_match("/^=\?([a-z0-9-]{3,})\?[bq]\?/i",$str,$code)){
            // 解码 这个函数好像已经转码了,
            $str = mb_decode_mimeheader($str);

            return $str;
            // 转字符编码
//            return mb_convert_encoding($str,'utf-8',$code[1]);
        }

        return $str;
    }


}