| 
 | 
 | 
 <?php
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 require_once "../vendor/autoload.php";
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 /**
 | 
| 
 | 
 | 
  * 自动回复
 | 
| 
 | 
 | 
  * @author:dc
 | 
| 
 | 
 | 
  * @time 2025/7/2 9:58
 | 
| 
 | 
 | 
  * Class fob_ai_mail_auto_reply
 | 
| 
 | 
 | 
  */
 | 
| 
 | 
 | 
 class fob_ai_mail_auto_reply {
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     public $isStop = false;
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     /**
 | 
| 
 | 
 | 
      * @var \Lib\Db
 | 
| 
 | 
 | 
      */
 | 
| 
 | 
 | 
     public $fob_db;
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     /**
 | 
| 
 | 
 | 
      * @var \Lib\Db
 | 
| 
 | 
 | 
      */
 | 
| 
 | 
 | 
     public $db;
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     public $startTime = 0;
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     /**
 | 
| 
 | 
 | 
      * SyncToEsCmd constructor.
 | 
| 
 | 
 | 
      */
 | 
| 
 | 
 | 
     public function __construct()
 | 
| 
 | 
 | 
     {
 | 
| 
 | 
 | 
         $this->db = db();
 | 
| 
 | 
 | 
         $this->fob_db = fob_mysql();
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         $handler = function ($signal){
 | 
| 
 | 
 | 
             _echo('收到进程信号 '. $signal);
 | 
| 
 | 
 | 
             // 可以处理其他程序
 | 
| 
 | 
 | 
             $this->isStop = true;
 | 
| 
 | 
 | 
         };
 | 
| 
 | 
 | 
         pcntl_signal(SIGTERM, $handler); // 这个是kill
 | 
| 
 | 
 | 
         pcntl_signal(SIGINT, $handler); // 这个是 ctrl+c
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         $this->startTime = time();
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     /**
 | 
| 
 | 
 | 
      * @return bool
 | 
| 
 | 
 | 
      */
 | 
| 
 | 
 | 
     public function isStop(): bool
 | 
| 
 | 
 | 
     {
 | 
| 
 | 
 | 
         // 检查是否接收到信号
 | 
| 
 | 
 | 
         pcntl_signal_dispatch();
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         // 是否超过来最大执行时间
 | 
| 
 | 
 | 
         if(time()-43200 > $this->startTime){
 | 
| 
 | 
 | 
             return true;
 | 
| 
 | 
 | 
         }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         return $this->isStop;
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     public function handler(){
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         while (!$this->isStop()){
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
             $id = redis()->lPop('new_mail_ids');
 | 
| 
 | 
 | 
             if($id){
 | 
| 
 | 
 | 
                 // 检查是否到时间了
 | 
| 
 | 
 | 
                 list($did,$time)  = explode('.',$id);
 | 
| 
 | 
 | 
                 if($time > time()){
 | 
| 
 | 
 | 
                     redis()->rPush('new_mail_ids',$id);
 | 
| 
 | 
 | 
                     usleep(10000);
 | 
| 
 | 
 | 
                     continue;
 | 
| 
 | 
 | 
                 }
 | 
| 
 | 
 | 
                 // 查询数据
 | 
| 
 | 
 | 
                 $data = $this->db->throw()->first(\Model\listsSql::first('`id` = '.$did,'`id`,`folder_id`,`email_id`,`subject`,`is_hots`,`from`,`udate`'));
 | 
| 
 | 
 | 
                 if($data && !$data['is_hots']){
 | 
| 
 | 
 | 
                     // 不是屏蔽的
 | 
| 
 | 
 | 
                     $body = getBodyHtml(getMailBody($data['id']));
 | 
| 
 | 
 | 
                     if(isAiAutoMail($data['from'],$data['subject'],$body)===0){
 | 
| 
 | 
 | 
                         // 在检查下是否是 收件箱
 | 
| 
 | 
 | 
                         if($this->db->value(\Model\folderSql::has(['id'=>$data['folder_id'],'origin_folder'=>'INBOX']))){
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
                             // 检查 是否开启了自动回复
 | 
| 
 | 
 | 
                             list($postid,$source) = $this->getPostid($data['email_id']);
 | 
| 
 | 
 | 
                             if($source == 2){
 | 
| 
 | 
 | 
                                 $email = $this->db->throw()->first(\Model\emailSql::first($data['email_id']));
 | 
| 
 | 
 | 
                                 // 配置
 | 
| 
 | 
 | 
                                 $replySetting = $this->getAutoReplySetting($postid,$email['email']);
 | 
| 
 | 
 | 
                                 if($replySetting){
 | 
| 
 | 
 | 
                                     // 有配置才回复
 | 
| 
 | 
 | 
                                     $this->log([$data,$replySetting]); // 立即写入日志
 | 
| 
 | 
 | 
                                     \Lib\Mail\MailFun::sendEmail([
 | 
| 
 | 
 | 
                                         'subject'   =>  'Re:'.$data['subject'],
 | 
| 
 | 
 | 
                                         'tos'   =>  [['email'=>$data['from'],'name'=>explode('@',$data['from'])[0]]],
 | 
| 
 | 
 | 
                                         'body'  => $this->trimBody($replySetting['content'],$body)
 | 
| 
 | 
 | 
                                     ],$email);
 | 
| 
 | 
 | 
                                 }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
                             }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
                         }
 | 
| 
 | 
 | 
                     }
 | 
| 
 | 
 | 
                 }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
             }else{
 | 
| 
 | 
 | 
                 sleep(1);
 | 
| 
 | 
 | 
             }
 | 
| 
 | 
 | 
         }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     public function trimBody($reply,$inbox){
 | 
| 
 | 
 | 
         $reply = explode('</body>',$reply,2);
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         return $reply[0]."<pre>{$inbox}</pre>".($reply[1]??'');
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     public function log($msg){
 | 
| 
 | 
 | 
         logs($msg,LOG_PATH.'fob_ai_mail_auto_reply.log')->write(); // 立即写入日志
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     /**
 | 
| 
 | 
 | 
      * 读取自动回复的配置
 | 
| 
 | 
 | 
      * @param $postid
 | 
| 
 | 
 | 
      * @param $email
 | 
| 
 | 
 | 
      * @return false|mixed
 | 
| 
 | 
 | 
      * @author:dc
 | 
| 
 | 
 | 
      * @time 2025/7/2 11:22
 | 
| 
 | 
 | 
      */
 | 
| 
 | 
 | 
     public function getAutoReplySetting($postid,$email){
 | 
| 
 | 
 | 
         $sets = $this->fob_db->throw()->all("select * from `ai_mail_auto_reply_setting` where ".dbWhere([
 | 
| 
 | 
 | 
                 'postid'    =>  $postid
 | 
| 
 | 
 | 
             ]));
 | 
| 
 | 
 | 
         if(!$sets){
 | 
| 
 | 
 | 
             return false;
 | 
| 
 | 
 | 
         }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         foreach ($sets as $set){
 | 
| 
 | 
 | 
             $set['emails'] = @json_decode($set['emails'],true);
 | 
| 
 | 
 | 
             // 是否开启了
 | 
| 
 | 
 | 
             if($set['emails']&&(in_array($email,$set['emails'])||in_array('所有邮箱',$set['emails']))){
 | 
| 
 | 
 | 
                 // 必须设置了内容
 | 
| 
 | 
 | 
                 if($set['content']){
 | 
| 
 | 
 | 
                     $set['week'] = @json_decode($set['week'],true);
 | 
| 
 | 
 | 
                     // 是否满足周
 | 
| 
 | 
 | 
                     if(!$set['week'] || in_array(date('w'),$set['week'])){
 | 
| 
 | 
 | 
                         $hi = date('H:i');
 | 
| 
 | 
 | 
                         // 是否跨天
 | 
| 
 | 
 | 
                         if ($set['day2day']){
 | 
| 
 | 
 | 
                             // 跨天设置
 | 
| 
 | 
 | 
                             if($hi > $set['s_hour'] || $hi < $set['e_hour']){
 | 
| 
 | 
 | 
                                 return $set;
 | 
| 
 | 
 | 
                             }
 | 
| 
 | 
 | 
                         }else{
 | 
| 
 | 
 | 
                             // 非夸天
 | 
| 
 | 
 | 
                             if($hi > $set['s_hour'] && $hi < $set['e_hour']){
 | 
| 
 | 
 | 
                                 return $set;
 | 
| 
 | 
 | 
                             }
 | 
| 
 | 
 | 
                         }
 | 
| 
 | 
 | 
                     }
 | 
| 
 | 
 | 
                 }
 | 
| 
 | 
 | 
             }
 | 
| 
 | 
 | 
         }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         return false;
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     /**
 | 
| 
 | 
 | 
      * 项目id
 | 
| 
 | 
 | 
      * @author:dc
 | 
| 
 | 
 | 
      * @time 2025/5/20 15:44
 | 
| 
 | 
 | 
      */
 | 
| 
 | 
 | 
     public function getPostid($email_id){
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         // 没有找到历史,就找绑定表
 | 
| 
 | 
 | 
         $data = redis()->getSet('fob_bind_mail:'.$email_id,300,function ($email_id){
 | 
| 
 | 
 | 
             return $this->fob_db->throw()->first("select `post_id`,`source` from `e_mail_binds` where `email_id` = '{$email_id}' and `deleted_at` is null order by `id` desc limit 1");
 | 
| 
 | 
 | 
         },$email_id);
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         return [
 | 
| 
 | 
 | 
             $data['post_id']??0,
 | 
| 
 | 
 | 
             $data['source']??0,
 | 
| 
 | 
 | 
         ];
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 (new fob_ai_mail_auto_reply())->handler();
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 return 1; | 
 | 
 | 
\ No newline at end of file | 
...
 | 
...
 | 
 |