作者 邓超

优化 back

... ... @@ -24,7 +24,7 @@ foreach ($tables as $table){
file_put_contents($name,$c['Create Table']);
if(in_array($table,['lists_auto','lists','bodies','bodies_back','lists_hot'])){
if(in_array($table,['lists_auto','lists','lists_back','bodies','bodies_back','lists_hot'])){
continue;
}
... ...
<?php
include_once "../vendor/autoload.php";
/**
* 把lists表的is_hots字段为1的记录插入到list_hot表中 并删除list表中的这些记录
*/
// 进程管理器
$pm = new \Swoole\Process\Manager();
// 启动业务进程
$pm->addBatch(10,function (\Swoole\Process\Pool $pool, int $worker_id){
if($worker_id == 0){
// 一个月以前的数据
$one_month_ago = strtotime(date('Y-m-d', strtotime('-1 month')));
// 查询lists lists_hot
$id = redis()->rPop('lists_to_lists_hot');
if(!$id) {
$id = 389884523;
}else{
$id = redis()->rPush('lists_to_lists_hot', $id);
}
$limit = 100;
while (true){
// echo "正在查询 id {$id}\n";
$data = db()->all("select `id` from lists where id > {$id} and `is_hots` = 1 and `udate` < {$one_month_ago} limit {$limit};");
if($data){
foreach ($data as $item) {
$id = $item['id'];
redis()->rPush('lists_to_lists_hot', $item['id']);
}
}else{
sleep(5);
}
}
}else{
// 迁移数据
while (true){
$id = redis()->lPop('lists_to_lists_hot');
if($id){
$data = db()->first("select * from lists where `id` = {$id} limit 1;");
if($data){
try {
db()->throw()->insert('lists_back', $data);
} catch (\Exception $e) {
@file_put_contents('lists_to_lists_hot.data.error.log', json_encode($data)."\n", FILE_APPEND);
}
db()->delete('lists', ['id' => $id]);
echo $id . " ok \n";
}
}else{
sleep(1);
}
}
}
});
$pm->start();
... ... @@ -237,10 +237,7 @@ class SyncToEsCmd {
*/
public function getDataByEs($id,$is_check_body) {
try {
$data = $this->db->throw()->first(\Model\listsSql::first('`id` = '.$id));
if(!$data){
$data = $this->db->throw()->first(\Model\listsSql::firstHot('`id` = '.$id));
}
$data = \Model\listsSql::first($this->db,'`id` = '.$id,'*',true);
}catch (Throwable $e){
$this->log([$id]);
// redis()->rPush('sync_to_es',$origin_id);
... ...
... ... @@ -260,7 +260,7 @@ class Folder extends Base {
}
// 是否存在邮件
if(db()->count(listsSql::first(dbWhere(['folder_id'=>$folder['id'],'email_id'=>$email['id']])))){
if(listsSql::count(db(),dbWhere(['folder_id'=>$folder['id'],'email_id'=>$email['id']]))){
app()->e('folder_delete_exist_mail');
}
... ...
... ... @@ -23,319 +23,38 @@ use function Swoole\Coroutine\Http\request;
* Class Home
* @package Controller
*/
class Home extends Base {
class Home extends Base
{
/**
* 邮件列表
* @author:dc
* @time 2023/2/17 14:12
*/
public function lists(){
// 分页 页数
$page = app()->request('page',1,'intval');
$page = $page ? $page : 1;
$limit = app()->request('limit',20,'intval');
$limit = $limit ? $limit : 1;
// 指定id
$ids = app()->request('mail_id');
$ids = is_array($ids) ? $ids : [$ids];
foreach ($ids as $i=>$d){
if(!is_numeric($d)){
unset($ids[$i]);
}
}
// 附件
$attachment = app()->request('attachment',0,'bool_Val');
// 已读/未读
$seen = app()->request('seen',-1,'intval');
// 软删
$deleted = app()->request('deleted',0,'intval');
$where = ['email_id'=>$this->getEmails('id')];
$folder_id = ['-'];
if (app()->requestArr('folder_id')){
$folder_id = app()->requestArr('folder_id');
}else{
// 目录
$folder = app()->request('folder','收件箱','folderAlias');
if($folder !== true || $folder!=='true'){
$folderList = db()->all(folderSql::all($where['email_id']));
// 文件夹id
if($folderList){
foreach ($folderList as $item){
if(
// 数组文件夹
(is_array($folder) && in_array($item['folder'],$folder))
|| $item['folder'] == $folder
){
$folder_id[] = $item['id'];
}
}
}
}
}
if(!$folder_id){
app()->e('folder_not_fount');
}
$folder_id = array_filter($folder_id,'is_int');
//目录
if($folder_id) $where['folder_id'] = array_values($folder_id);
if($ids) $where['id'] = $ids;
if(paramHas('attachment')){
$where['is_file'] = $attachment ? 1 : 0; //附件
}
// 软删
$where['deleted'] = $deleted;
// 已读/未读
if(paramHas('seen')){
if(in_array($seen,[0,1])){
$where['seen'] = $seen;
}
}
$where['_'] = [];
// 搜索关键字
$keyword = app()->request('keyword','',['htmlspecialchars','addslashes']);
if($keyword){
$where['_'][] = '`subject` like "%'.$keyword.'%"';
}
// 那个发的
$address = app()->request('address');
if($address){
if(is_array($address)){
// 发贱人
if(Verify::sEmail($address['from']??'')){
$where['from'] = $address['from'];
}
// 收件人
if(Verify::sEmail($address['to']??'')){
$where['_'][] = '`to_name` like "%'.$address.'%"';
}
}else if(Verify::sEmail($address)){
// 收件人/发件人
$where['_'][] = '(`from` = "'.$address.'" or `to_name` like "%'.$address.'%")';
}
}
// from 搜索收件人
if(app()->requestHas('from')){
// 如果是发件箱
if($folder == '发件箱'){
$tos = app()->request('from');
if(!$tos){
// 不让查询数据
$where['id'] = 0;
}else {
$tos = array_map(function ($v){
return "find_in_set('".addcslashes($v,"'")."',`to`)";
},is_array($tos) ? $tos : [$tos]);
$where['_'][] = '('.implode(' or ',$tos).')';
}
}else{
$where['from'] = app()->request('from');
if(!$where['from']){
// 不让查询数据
$where['id'] = 0;
}
}
}
// 回复
if (paramHas('answered')){
$where['answered'] = app()->request('answered',0,'bool_Val')?1:0;
}
// 这个主要是来筛选 是否是自己发送的
$fromto = app()->request('formorto');
if($fromto=='from'){
$where['from'] = $this->getEmails('email');
}elseif ($fromto=='to'){
$where['from.notin'] = $this->getEmails('email');
}
/**
* 不查询哪些发件人的邮件
*/
$form_not_in = app()->request('from_not_in');
if($form_not_in){
$form_not_in = is_array($form_not_in) ? $form_not_in : [$form_not_in];
$form_not_in = array_filter($form_not_in,function ($v){
if(is_string($v) && Verify::sEmail($v)){
return true;
}
return false;
});
if($form_not_in){
if(isset($where['from.notin'])){
$where['from.notin'] = array_merge($where['from.notin'],$form_not_in);
}else{
$where['from.notin'] = $form_not_in;
}
}
}
if(!empty($where['from.notin'])){
$where['from.notin'] = array_unique($where['from.notin']);
}
$lists = db()->all(
listsSql::lists(
dbWhere($where),
$page,
$limit
)
);
$lists = $lists ? $lists : [];
// map
$lists = array_map(function ($v){
$v['uuid'] = get_email_uuid($v['subject'],$v['udate'],$v['from'],$v['to'],$v['size']);
if(!empty($v['description'])){
$v['description'] = @html_entity_decode($v['description'], ENT_COMPAT, 'UTF-8');
}
$v['to_name'] = @json_decode($v['to_name'],true);
$v['to_name'] = $v['to_name']?:[];
if($v['to_name']){
if(!empty($v['to_name'][0]['email'])){
$v['to'] = $v['to_name'][0]['email'];
}
$v['to_name'] = MailFun::mb_coding($v['to_name'][0]['name']??'');
}
if(is_array($v['to_name'])){
$v['to_name'] = '';
}
// 邮件箱
$v['folder_name'] = db()->cache(86400)->value(folderSql::first($v['folder_id'],'folder'));
return $v;
},$lists);
// 总数
$total = db()->count(
listsSql::listCount(dbWhere($where))
);
app()->_json(listsPage($lists,$total,$page,$limit));
}
/**
* 统计
* @throws \Lib\Err
* @author:dc
* @time 2024/10/14 16:20
*/
public function count()
{
$where = [];
$start_time = app()->request('start_time',0,'intval');
$end_time = app()->request('end_time',0,'intval');
// if($start_time || $end_time){
// $where['email_id'] = $this->getEmails('id');
// }
$where['_'] = [];
if($start_time){
$where['_'][] = '`udate` >= '.$start_time;
}
if($end_time){
$where['_'][] = '`udate` <= '.$end_time;
}
$where['_'] && $where['_'] = implode(' and ',$where['_']);
$where['folder_id'] = [];
// 目录
$folderList = db()->all(folderSql::all($this->getEmails('id')));
// 文件夹id
foreach ($folderList as $item) {
if ($item['folder'] == '收件箱') {
$where['folder_id'][] = $item['id'];
}
}
// 软删
$where['deleted'] = 0;
// 总数
$inbox = db()->cache(3600)->count(listsSql::listCount(dbWhere($where)));
if(app()->request('show')=='inbox'){
app()->_json(['inbox'=>$inbox]);
}
// 未读
$where['seen'] = 0;
$unseen = db()->cache(3600)->count(listsSql::listCount(dbWhere($where)));
$where['folder_id'] = [];
foreach ($folderList as $item) {
if ($item['folder'] == '发件箱') {
$where['folder_id'][] = $item['id'];
}
}
unset($where['seen']);
//发件箱
$send = db()->cache(3600)->count(listsSql::listCount(dbWhere($where)));
app()->_json(['inbox'=>$inbox,'unseen'=>$unseen,'send'=>$send]);
}
/**
* 检测邮箱状态
* @author:dc
* @time 2023/3/28 16:19
*/
public function check(){
public function check()
{
$lists = db()->all(emailSql::getValues(['email'=>web_request_emails()],'`id`,`pwd_error`,`email`,`password`,`imap`'));
if(count($lists)>1){
return array_column($lists,'pwd_error','email');
$lists = db()->all(emailSql::getValues(['email' => web_request_emails()], '`id`,`pwd_error`,`email`,`password`,`imap`'));
if (count($lists) > 1) {
return array_column($lists, 'pwd_error', 'email');
}
foreach ($lists as $k=>$list){
foreach ($lists as $k => $list) {
// if(!$list['pwd_error']){
$list['host'] = $list['imap'];
$list['password'] = base64_decode($list['password']);
$imap = ImapPool::get(new ImapConfig($list));
$n = $imap->login()->isOk();
if($n){
if($lists[$k]['pwd_error']){
db()->update(emailSql::$table,['pwd_error'=>0],'`id` = '.$list['id']);
if ($n) {
if ($lists[$k]['pwd_error']) {
db()->update(emailSql::$table, ['pwd_error' => 0], '`id` = ' . $list['id']);
}
$lists[$k]['pwd_error'] = 0;
}else{
if(!$lists[$k]['pwd_error']){
db()->update(emailSql::$table,['pwd_error'=>1],'`id` = '.$list['id']);
} else {
if (!$lists[$k]['pwd_error']) {
db()->update(emailSql::$table, ['pwd_error' => 1], '`id` = ' . $list['id']);
}
$lists[$k]['pwd_error'] = 1;
}
... ... @@ -343,7 +62,7 @@ class Home extends Base {
}
return array_column($lists,'pwd_error','email');
return array_column($lists, 'pwd_error', 'email');
}
... ... @@ -353,35 +72,36 @@ class Home extends Base {
* @author:dc
* @time 2023/2/18 17:32
*/
public function send_mail(){
public function send_mail()
{
$email = $this->getEmail();
$yzemail = function(&$value,$field){
if($value){
if(!is_array($value)){
if(@json_decode($value,true)){
$value = json_decode($value,true);
}else{
$value = [['email'=>$value,'name'=>'']];
$yzemail = function (&$value, $field) {
if ($value) {
if (!is_array($value)) {
if (@json_decode($value, true)) {
$value = json_decode($value, true);
} else {
$value = [['email' => $value, 'name' => '']];
}
}
foreach ($value as $item){
if(!Verify::sEmail($item['email'])){
app()->e([$field.'_verify_error',$item['email']]);
foreach ($value as $item) {
if (!Verify::sEmail($item['email'])) {
app()->e([$field . '_verify_error', $item['email']]);
}
}
}
};
$formData = Verify::checks([
'nickname|'.__('nickname') => ['max'=>50],
'subject|'.__('subject') => ['required','max'=>500],
'body|'.__('body_email') => ['required'],
'tos|'.__('to_email') => ['required',$yzemail],
'cc|'.__('to_cc') => [$yzemail],
'bcc|'.__('to_bcc') => [$yzemail],
'priority|'.__('priority_email') => ['in'=>[1,3,5]],
'nickname|' . __('nickname') => ['max' => 50],
'subject|' . __('subject') => ['required', 'max' => 500],
'body|' . __('body_email') => ['required'],
'tos|' . __('to_email') => ['required', $yzemail],
'cc|' . __('to_cc') => [$yzemail],
'bcc|' . __('to_bcc') => [$yzemail],
'priority|' . __('priority_email') => ['in' => [1, 3, 5]],
// 'attachment|'.__('files_email') => [
// 'file'=>[
// 'ext' => [],
... ... @@ -389,165 +109,163 @@ class Home extends Base {
// 'mine' => []
// ]
// ],
'receipt|'.__('receipt_email') => []
],[
'receipt|' . __('receipt_email') => []
], [
]);
$sendData = [];
$sendData['email'] = $email['email'];
$sendData['nickname'] = $formData['nickname']??'';
$sendData['nickname'] = $formData['nickname'] ?? '';
$sendData['tos'] = $formData['tos'];
if(count($sendData['tos'])>100){
app()->e(['tos_number_error',100]);
if (count($sendData['tos']) > 100) {
app()->e(['tos_number_error', 100]);
}
// 抄送
$sendData['cc'] = [];
if(($formData['isCc']??0) && !empty($formData['cc'])){
if (($formData['isCc'] ?? 0) && !empty($formData['cc'])) {
$sendData['cc'] = $formData['cc'];
}
if(count($sendData['cc'])>10){
app()->e(['cc_number_error',10]);
if (count($sendData['cc']) > 10) {
app()->e(['cc_number_error', 10]);
}
// 密送
$sendData['bcc'] = [];
if(($formData['isBcc']??0) && !empty($formData['bcc'])){
if (($formData['isBcc'] ?? 0) && !empty($formData['bcc'])) {
$sendData['bcc'] = $formData['bcc'];
}
// 添加自定义头信息 预热邮件
if(!empty($formData['aicc-hot'])){
if (!empty($formData['aicc-hot'])) {
$sendData['mail-header'] = [
'Aicc-Hot-Mail' => 'hot' // 预热邮件
];
}
if(count($sendData['bcc'])>10){
app()->e(['bcc_number_error',10]);
if (count($sendData['bcc']) > 10) {
app()->e(['bcc_number_error', 10]);
}
$sendData['reply_to'] = [];//回复到那个邮件
//Attachments 附件 上传的
$sendData['attachment'] = [];
// 这个是直接上传文件
$attachment = app()->file('attachment');
if($attachment){
foreach ($attachment as $file){
if($file->move()){
if ($attachment) {
foreach ($attachment as $file) {
if ($file->move()) {
$sendData['attachment'][] = [
'name' => $file->name,
'filename' => $file->name,
'signName' => $file->saveName,
'path' => $file->savePath.$file->saveName
'path' => $file->savePath . $file->saveName
];
}else{
app()->e(['attachment_upload_error',$file->name]);
} else {
app()->e(['attachment_upload_error', $file->name]);
}
}
}
// 这个是通过了上传接口上传的文件
$attachment = app()->request('attachmentapi');
if($attachment){
foreach ($attachment as $file){
$file = json_decode($file,true);
if(empty($file['data']['saveName'])|| !is_file(PUBLIC_PATH.$file['data']['saveName'])){
app()->e('附件('.$file['data']['name'].")异常");
if ($attachment) {
foreach ($attachment as $file) {
$file = json_decode($file, true);
if (empty($file['data']['saveName']) || !is_file(PUBLIC_PATH . $file['data']['saveName'])) {
app()->e('附件(' . $file['data']['name'] . ")异常");
}
$sendData['attachment'][] = [
'name' => $file['data']['name'],
'filename' => $file['data']['name'],
'signName' => $file['data']['saveName'],
'path' => PUBLIC_PATH.$file['data']['saveName']
'path' => PUBLIC_PATH . $file['data']['saveName']
];
}
}
// 远程路径,云文件
$attachmentUrl = app()->request('attachmentUrl');
if(is_array($attachmentUrl)){
foreach ($attachmentUrl as $file){
$file = is_array($file) ? $file : json_decode($file,true);
if(!empty($file['url']) && !empty($file['name'])){
$file = new UploadFile($file['name'],$file['url']);
if($file->move()){
if (is_array($attachmentUrl)) {
foreach ($attachmentUrl as $file) {
$file = is_array($file) ? $file : json_decode($file, true);
if (!empty($file['url']) && !empty($file['name'])) {
$file = new UploadFile($file['name'], $file['url']);
if ($file->move()) {
$sendData['attachment'][] = [
'name' => $file->name,
'filename' => $file->name,
'signName' => $file->saveName,
'path' => $file->savePath.$file->saveName
'path' => $file->savePath . $file->saveName
];
}else{
app()->e(['attachment_upload_error',$file->name]);
} else {
app()->e(['attachment_upload_error', $file->name]);
}
}
}
}
$sendData['receipt'] = empty($formData['receipt']) ? '' : 1;// 回执,阅读后收回执的邮箱
$sendData['priority'] = $formData['priority']??3;// 是否紧急邮件
$sendData['priority'] = $formData['priority'] ?? 3;// 是否紧急邮件
$sendData['subject'] = $formData['subject'];// //Content 主题,标题
// 删除script标记
$sendData['body'] = strip_tags_content($formData['body'],'<script>',true);
$sendData['body'] = strip_tags_content($formData['body'], '<script>', true);
// 下划线
$sendData['body'] = str_replace('class="sensitive-word"',' ',$sendData['body']);
$sendData['body'] = str_replace('style="text-decoration-line: underline; text-decoration-style: wavy; text-decoration-color: red;"',' ',$sendData['body']);
$sendData['body'] = str_replace('class="sensitive-word"', ' ', $sendData['body']);
$sendData['body'] = str_replace('style="text-decoration-line: underline; text-decoration-style: wavy; text-decoration-color: red;"', ' ', $sendData['body']);
// 不重要的信息
$sendData['jobName'] = $formData['jobName']??'';//任务标题
$sendData['massSuit'] = $formData['massSuit']??0;// 是否是群发单显
$sendData['jobName'] = $formData['jobName'] ?? '';//任务标题
$sendData['massSuit'] = $formData['massSuit'] ?? 0;// 是否是群发单显
// 定时发送时间
$timer = app()->request('timerValue',0);
if(is_numeric($timer) && $timer){
$timer = time()+$timer;
}else if (is_string($timer)){
$timer = app()->request('timerValue', 0);
if (is_numeric($timer) && $timer) {
$timer = time() + $timer;
} else if (is_string($timer)) {
$timer = strtotime($timer);
}else{
} else {
$timer = 0;
}
// 是否存草稿
if(app()->request('saveType')=='draft'){
if (app()->request('saveType') == 'draft') {
// 保存
$draftid = listsSql::saveDraft($sendData,$email,app()->request('draft_id',0,'intval'));
$draftid = listsSql::saveDraft($sendData, $email, app()->request('draft_id', 0, 'intval'));
// 保存失败
if($draftid){
app()->_json(['draft_id'=>$draftid]);
if ($draftid) {
app()->_json(['draft_id' => $draftid]);
}
app()->e('save_draft_error');
}
// 定时发送 或者是单条发送
else if((app()->request('timer') && $timer > time()) || $sendData['massSuit']){
} // 定时发送 或者是单条发送
else if ((app()->request('timer') && $timer > time()) || $sendData['massSuit']) {
if($sendData['massSuit']){
if ($sendData['massSuit']) {
// 每次发送间隔的时间
$sendData['masssuit_interval_send'] = app()->request('masssuit_interval_send');
$sendData['masssuit_interval_send']['start'] = intval($sendData['masssuit_interval_send']['start']??0);
$sendData['masssuit_interval_send']['end'] = intval($sendData['masssuit_interval_send']['end']??1);
$sendData['masssuit_interval_send']['start'] = intval($sendData['masssuit_interval_send']['start'] ?? 0);
$sendData['masssuit_interval_send']['end'] = intval($sendData['masssuit_interval_send']['end'] ?? 1);
}
// 插入任务
$job_id = db()->insert(sendJobsSql::$table,[
$job_id = db()->insert(sendJobsSql::$table, [
'email_id' => $email['id'],
'maildata' => $sendData,
'title' => $sendData['jobName'] ? : $sendData['subject'],
'title' => $sendData['jobName'] ?: $sendData['subject'],
'total' => count($sendData['tos']),
'send_time' => $timer?:time()
'send_time' => $timer ?: time()
]);
if($job_id){
if ($job_id) {
// 返回任务id
app()->_json(['job_id'=>$job_id]);
app()->_json(['job_id' => $job_id]);
}
app()->e('send_timer_job_error');
}
else{
} else {
// 立即发送
$email['hot_email'] = db()->cache(86400,false)->count("select count(*) from `hot_mail` where ".dbWhere(['email'=>$email['email']]));
$email['hot_email'] = db()->cache(86400, false)->count("select count(*) from `hot_mail` where " . dbWhere(['email' => $email['email']]));
$email['not_proxy'] = app()->request('not_proxy');//是否要代理
$result = MailFun::sendEmail($sendData,$email);
if($result[0]){
$result = MailFun::sendEmail($sendData, $email);
if ($result[0]) {
app()->_json(['messageId' => $result[1]]);
}
// 错误
... ... @@ -562,54 +280,55 @@ class Home extends Base {
* @author:dc
* @time 2023/3/10 10:38
*/
public function sync(){
public function sync()
{
$emails = web_request_emails();
$sync_type = app()->request('sync_type');
if(empty($emails)){
if (empty($emails)) {
app()->e('sync_request_param_error');
}else{
} else {
// 查询id
if(count($emails)===1){
if (count($emails) === 1) {
$emails = $emails[0];
}
$datas = db()->cache(3600)->all(emailSql::getValues(['email'=>$emails],'`id`,`email`,`pwd_error`'));
foreach ($datas as $k=>$v){
if(!$v['pwd_error']){
if(app()->requestHas('blacklist')){
$datas = db()->cache(3600)->all(emailSql::getValues(['email' => $emails], '`id`,`email`,`pwd_error`'));
foreach ($datas as $k => $v) {
if (!$v['pwd_error']) {
if (app()->requestHas('blacklist')) {
$blacklist = app()->request('blacklist');
if(is_array($blacklist)){
if (is_array($blacklist)) {
$blacklist = [
'emails' => $blacklist['emails']??[],
'domain' => $blacklist['domain']??[],
'emails' => $blacklist['emails'] ?? [],
'domain' => $blacklist['domain'] ?? [],
];
// 黑名单,7天过期时间
redis()->set('blacklist:'.$v['id'],$blacklist,86400*7);
redis()->set('blacklist:' . $v['id'], $blacklist, 86400 * 7);
}
// 删除
if(!$blacklist||(empty($blacklist['emails'])&&empty($blacklist['domain']))){
redis()->delete('blacklist:'.$v['id']);
if (!$blacklist || (empty($blacklist['emails']) && empty($blacklist['domain']))) {
redis()->delete('blacklist:' . $v['id']);
}
}
$source = app()->request('source');
// 是否立即同步
if($sync_type == 'immediately'){
try{
if(redis()->add('sync_immediately:'.$v['id'],1,10)){
if ($sync_type == 'immediately') {
try {
if (redis()->add('sync_immediately:' . $v['id'], 1, 10)) {
(new SyncMail($v['id']))->isUidAfter()->sync();
}
}catch (\Throwable $e){
} catch (\Throwable $e) {
logs($e->getTraceAsString());
}
}else{
redis()->rPush('sync_email_lists'.($source==1?'_my':''), $v['id']);
} else {
redis()->rPush('sync_email_lists' . ($source == 1 ? '_my' : ''), $v['id']);
}
}
$datas[$k]['have_new'] = redis()->getDel('have_new_mail_'.$v['id']);
$datas[$k]['have_new'] = redis()->getDel('have_new_mail_' . $v['id']);
// 计算
// $folders = db()->all(folderSql::all($v['id'],'`id`'));
... ... @@ -638,7 +357,8 @@ class Home extends Base {
* @author:dc
* @time 2023/3/17 16:15
*/
public function seen_2_unseen(){
public function seen_2_unseen()
{
$this->setFlags('seen');
}
... ... @@ -648,7 +368,8 @@ class Home extends Base {
* @author:dc
* @time 2023/4/10 16:30
*/
public function answered_2_unanswered(){
public function answered_2_unanswered()
{
$this->setFlags('answered');
}
... ... @@ -658,33 +379,32 @@ class Home extends Base {
* @author:dc
* @time 2024/6/21 16:35
*/
public function star_2_unstar(){
logs("操作星标邮件 ".print_r(app()->request(),1));
public function star_2_unstar()
{
logs("操作星标邮件 " . print_r(app()->request(), 1));
$this->setFlags('flagged');
}
/**
* 邮件移动
* @author:dc
* @time 2023/3/21 11:41
*/
public function move(){
$this->moveCopy(function (Mail $mailInstance,$uid,$origin_folder,$to_origin_folder){
public function move()
{
$this->moveCopy(function (Mail $mailInstance, $uid, $origin_folder, $to_origin_folder) {
// try {
// return $mailInstance->move($uid,$origin_folder,$to_origin_folder);
// }catch (\Throwable $e){
// if(app()->request('move_err_copy',1)){
// 复制成功
try {
if($mailInstance->copy($uid,$origin_folder,$to_origin_folder)){
return $mailInstance->deleted($uid,$origin_folder);
if ($mailInstance->copy($uid, $origin_folder, $to_origin_folder)) {
return $mailInstance->deleted($uid, $origin_folder);
}
}catch (\Throwable $e){
logs('移动失败:'.$e->getMessage());
} catch (\Throwable $e) {
logs('移动失败:' . $e->getMessage());
return false;
}
... ... @@ -696,53 +416,52 @@ class Home extends Base {
}
private function moveCopy(\Closure $call){
private function moveCopy(\Closure $call)
{
$emails = $this->getEmails();
$mail_ids = app()->requestArr('mail_ids');
if(!($mail_ids && is_array($mail_ids))){
if (!($mail_ids && is_array($mail_ids))) {
app()->e('param_request_error');
}
foreach ($mail_ids as $k=>$id){
if(!is_numeric($id)){
foreach ($mail_ids as $k => $id) {
if (!is_numeric($id)) {
unset($mail_ids[$k]);
}
}
// 移动到的文件夹
$to_folder = folderAlias(app()->request('folder'));
if(empty($to_folder)){
if (empty($to_folder)) {
app()->e('folder_move_error');
}
if($to_folder == '草稿箱'){
if ($to_folder == '草稿箱') {
app()->e('folder_move_to_draft_error');
}
if($to_folder == '发件箱'){
if ($to_folder == '发件箱') {
app()->e('folder_move_to_send_error');
}
$data = db()->all(listsSql::all(dbWhere(['id'=>$mail_ids,'email_id'=>array_column($emails,'id')]),'`id`,`uid`,`email_id`,`folder_id`'));
if($data){
$data = listsSql::all(db(), dbWhere(['id' => $mail_ids, 'email_id' => array_column($emails, 'id')]), '`id`,`uid`,`email_id`,`folder_id`');
if ($data) {
// 查询邮箱
$emails = array_column($emails,null,'id');
$emails = array_column($emails, null, 'id');
$uids = [];
foreach ($data as $datum){
foreach ($data as $datum) {
// 只有草稿箱才没有uid
// if($datum['uid']<0){
// }
// 删除
if ($to_folder == '回收站'){
if ($to_folder == '回收站') {
// 删除数据,真实删除
db()->update(listsSql::$table,[
listsSql::update(db(), [
'deleted' => 1
],dbWhere([
'id' => $datum['id']
]));
], $datum['id']);
continue;
}
if(empty($uids[$datum['email_id']][$datum['folder_id']])){
if (empty($uids[$datum['email_id']][$datum['folder_id']])) {
$uids[$datum['email_id']][$datum['folder_id']] = [];
}
$uids[$datum['email_id']][$datum['folder_id']][] = [
... ... @@ -751,34 +470,34 @@ class Home extends Base {
];
}
foreach ($uids as $eid=>$arr){
foreach ($uids as $eid => $arr) {
// 查询需要移动的文件夹
$to_origin_folder = db()->first(folderSql::first(['email_id'=>$eid,'folder'=>$to_folder]));
if($to_origin_folder){
foreach ($arr as $fid=>$uid){
$to_origin_folder = db()->first(folderSql::first(['email_id' => $eid, 'folder' => $to_folder]));
if ($to_origin_folder) {
foreach ($arr as $fid => $uid) {
// 查询目录
$folder = db()->first(folderSql::first($fid));
if($folder){
if ($folder) {
// 开始远程
$mailInstance = new Mail($emails[$eid]['email'],base64_decode($emails[$eid]['password']),$emails[$eid]['imap']);
$mailInstance = new Mail($emails[$eid]['email'], base64_decode($emails[$eid]['password']), $emails[$eid]['imap']);
if($mailInstance->login()==1){
$localUids = array_column($uid,'uid');
if ($mailInstance->login() == 1) {
$localUids = array_column($uid, 'uid');
// 检查 远程是否有邮件
$mailInstance->client->selectFolder($folder['origin_folder']);
$originUids = $mailInstance->client->fetch($localUids,'UID',true);
$originUids = $mailInstance->client->fetch($localUids, 'UID', true);
if($originUids){
if ($originUids) {
// 进行移动 远程有的邮件
$ret = $call($mailInstance,array_column($originUids,'UID'),$folder['origin_folder'],$to_origin_folder['origin_folder']);
}else{
$ret = $call($mailInstance, array_column($originUids, 'UID'), $folder['origin_folder'], $to_origin_folder['origin_folder']);
} else {
$ret = true;
}
// TODO:: 这个过程无法保证原子性。没办法
// 先复制
if($ret){
$uret = db()->update(listsSql::$table,['deleted'=>1],dbWhere(['id'=>array_column($uid,'id')]));
if ($ret) {
listsSql::update(db(), ['deleted' => 1], dbWhere(['id' => array_column($uid, 'id')]));
}
... ... @@ -808,10 +527,11 @@ class Home extends Base {
* @author:dc
* @time 2024/3/9 13:50
*/
public function copy(){
$this->moveCopy(function (Mail $mailInstance,$uid,$origin_folder,$to_origin_folder){
public function copy()
{
$this->moveCopy(function (Mail $mailInstance, $uid, $origin_folder, $to_origin_folder) {
return $mailInstance->copy($uid,$origin_folder,$to_origin_folder);
return $mailInstance->copy($uid, $origin_folder, $to_origin_folder);
});
}
... ... @@ -823,11 +543,12 @@ class Home extends Base {
* @author:dc
* @time 2024/3/14 14:18
*/
public function expunge(){
public function expunge()
{
$email = $this->getEmail();
$mailInstance = new Mail($email['email'],base64_decode($email['password']),$email['imap']);
$mailInstance = new Mail($email['email'], base64_decode($email['password']), $email['imap']);
if($mailInstance->login()==1 && $mailInstance->expunge()){
if ($mailInstance->login() == 1 && $mailInstance->expunge()) {
app()->_json([]);
}
... ... @@ -835,8 +556,6 @@ class Home extends Base {
}
/**
* 远程标签
* @param $d
... ... @@ -844,83 +563,75 @@ class Home extends Base {
* @author:dc
* @time 2023/3/21 14:28
*/
private function setFlags($d){
private function setFlags($d)
{
$emails = $this->getEmails();
$mail_ids = app()->request('mail_ids');
// 全部标记
if(!$mail_ids){
if (!$mail_ids) {
app()->e('标记失败');
$folder = app()->request('folder','收件箱','folderAlias');
$folder = app()->request('folder', '收件箱', 'folderAlias');
// 查询 当前的 文件夹 如果有选中文件夹 就 查询出 选中文件夹的id
$fids = db()->all(folderSql::all(array_column($emails,'id'),'`id`,`folder`'));
foreach ($fids as $fk=>$fid){
if($fid['folder'] != $folder){
$fids = db()->all(folderSql::all(array_column($emails, 'id'), '`id`,`folder`'));
foreach ($fids as $fk => $fid) {
if ($fid['folder'] != $folder) {
unset($fids[$fk]);
}
}
if($fids){
if ($fids) {
// 查询要标记的 邮件id
$sql = listsSql::all(dbWhere(['folder_id'=>array_column($fids,'id'),'seen'=>0]),'`id`');
$mail_ids = db()->all($sql);
// $mail_ids2 = db()->all(str_replace('from `lists` where','from `lists_hot` where',$sql));
// $mail_ids = array_merge($mail_ids,$mail_ids2);
$mail_ids = array_column($mail_ids,'id');
$mail_ids = listsSql::all(db(), dbWhere(['folder_id' => array_column($fids, 'id'), 'seen' => 0]), '`id`');
$mail_ids = array_column($mail_ids, 'id');
}
}
if($mail_ids){
$mail_ids = is_array($mail_ids) ? $mail_ids : explode(',',$mail_ids);
if ($mail_ids) {
$mail_ids = is_array($mail_ids) ? $mail_ids : explode(',', $mail_ids);
}
if(!($mail_ids && is_array($mail_ids))){
if (!($mail_ids && is_array($mail_ids))) {
app()->e('param_request_error');
}
foreach ($mail_ids as $k=>$id){
if(!is_numeric($id)){
foreach ($mail_ids as $k => $id) {
if (!is_numeric($id)) {
unset($mail_ids[$k]);
}
}
// 已读或未读
$fv = (int) app()->request($d);
$fv = (int)app()->request($d);
$fv = $fv ? 1 : 0;
// if(app()->request('source')==2){
$ids = es('email_lists_branch_'.app()->request('postid','','intval'))
$ids = es('email_lists_branch_' . app()->request('postid', '', 'intval'))
->search([
"_source" => ["uuid"],
'query'=>[
'bool'=>[
'must'=>[
['terms'=>['uuid'=>$mail_ids]]
'query' => [
'bool' => [
'must' => [
['terms' => ['uuid' => $mail_ids]]
]
]
]
],0,1000);
], 0, 1000);
$mail_ids = [];
foreach ($ids['hits']['hits']??[] as $item){
foreach ($ids['hits']['hits'] ?? [] as $item) {
$mail_ids[] = $item['_source']['uuid'];
}
$sql = listsSql::all(dbWhere(['id'=>$mail_ids]),'`id`,`uid`,`email_id`,`folder_id`');
// }
// else{
// $sql = listsSql::all(dbWhere(['id'=>$mail_ids,'email_id'=>array_column($emails,'id')]),'`id`,`uid`,`email_id`,`folder_id`');
$data = listsSql::all(db(), dbWhere(['id' => $mail_ids]), '`id`,`uid`,`email_id`,`folder_id`');
// }
$data = db()->all($sql);
// $data2 = db()->all(str_replace('from `lists` where','from `lists_hot` where',$sql));
// $data = array_merge($data,$data2);
if($data){
if ($data) {
// 查询邮箱
$emails = array_column(db()->all(emailSql::all(dbWhere(['id'=>array_column($data,'email_id')]))),null,'id');
$emails = array_column(db()->all(emailSql::all(dbWhere(['id' => array_column($data, 'email_id')]))), null, 'id');
$uids = [];
foreach ($data as $datum){
if(empty($uids[$datum['email_id']])){
foreach ($data as $datum) {
if (empty($uids[$datum['email_id']])) {
$uids[$datum['email_id']][$datum['folder_id']] = [];
}
$uids[$datum['email_id']][$datum['folder_id']][] = [
... ... @@ -929,33 +640,36 @@ class Home extends Base {
];
}
foreach ($uids as $eid=>$arr){
foreach ($arr as $fid=>$uid){
foreach ($uids as $eid => $arr) {
foreach ($arr as $fid => $uid) {
// 查询目录
$folder = db()->first(folderSql::first($fid));
if($folder){
if ($folder) {
// 开始远程
if(empty($emails[$eid])){
if (empty($emails[$eid])) {
$emails[$eid] = db()->first(emailSql::first($eid));
}
$mailInstance = new Mail($emails[$eid]['email'],base64_decode($emails[$eid]['password']),$emails[$eid]['imap']);
$mailInstance = new Mail($emails[$eid]['email'], base64_decode($emails[$eid]['password']), $emails[$eid]['imap']);
if($mailInstance->login()==1){
switch ($d){
if ($mailInstance->login() == 1) {
switch ($d) {
// 已读 未读
case 'seen':{
$mailInstance->seen(array_column($uid,'uid'),$folder['origin_folder'],$fv);
case 'seen':
{
$mailInstance->seen(array_column($uid, 'uid'), $folder['origin_folder'], $fv);
break;
}
// 未回复/已回复
case 'answered':{
$mailInstance->answered(array_column($uid,'uid'),$folder['origin_folder'],$fv);
case 'answered':
{
$mailInstance->answered(array_column($uid, 'uid'), $folder['origin_folder'], $fv);
break;
}
// 星标
case 'flagged':{
$mailInstance->flagged(array_column($uid,'uid'),$folder['origin_folder'],$fv);
case 'flagged':
{
$mailInstance->flagged(array_column($uid, 'uid'), $folder['origin_folder'], $fv);
break;
}
// 回收站,已删 未删,软删
... ... @@ -968,10 +682,8 @@ class Home extends Base {
$mailInstance = null;
}
// 更新数据
db()->update(listsSql::$table,[
$d => $fv
],dbWhere([
'id' => array_column($uid,'id')
listsSql::update(db(), [$d => $fv], dbWhere([
'id' => array_column($uid, 'id')
]));
}
... ... @@ -993,82 +705,78 @@ class Home extends Base {
* @author:dc
* @time 2023/4/1 9:24
*/
public function info(){
$reload = app()->request('reload',0,'intval');
public function info()
{
$reload = app()->request('reload', 0, 'intval');
$sync_num = 0;
HOME_INFO_BODY:
$id = app()->request('id',0,'intval');
$id = app()->request('id', 0, 'intval');
$udate = app()->request('udate',0,'intval');
$udate = app()->request('udate', 0, 'intval');
$subject = app()->request('subject');
if($udate&&$subject){
$data = db()->first(listsSql::first(dbWhere(['id'=>$id,'udate'=>$udate])));
// if($data && trim($data['subject']) != trim($subject)){
// $data = [];
// }
if($data){
if ($udate && $subject) {
$data = listsSql::first(db(), dbWhere(['id' => $id, 'udate' => $udate]));
if ($data) {
$email = db()->first(emailSql::first($data['email_id']));
}
}else{
} else {
// 没有,说明没有同步过来
$email = $this->getEmail('*',false);
$data = db()->first(listsSql::first(dbWhere(['id'=>$id])));
if(!$data){
$data = db()->first(listsSql::firstHot(dbWhere(['id'=>$id])));
}
if($data){
$email = $this->getEmail('*', false);
$data = listsSql::first(db(), dbWhere(['id' => $id]));
if ($data) {
$email = db()->first(emailSql::first($data['email_id']));
}
}
if($data){
$data['uuid'] = get_email_uuid($data['subject'],$data['udate'],$data['from'],$data['to'],$data['size']);
if ($data) {
$data['uuid'] = get_email_uuid($data['subject'], $data['udate'], $data['from'], $data['to'], $data['size']);
$data['description'] = @html_entity_decode($data['description']??'', ENT_COMPAT, 'UTF-8');
$data['description'] = @html_entity_decode($data['description'] ?? '', ENT_COMPAT, 'UTF-8');
$data['to_name'] = $data['to_name'] ? json_decode($data['to_name'],true) : [];
if(!$data['to_name']){
$data['to_name'] = [["email"=>$email['email'],'name'=>'']];
$data['to_name'] = $data['to_name'] ? json_decode($data['to_name'], true) : [];
if (!$data['to_name']) {
$data['to_name'] = [["email" => $email['email'], 'name' => '']];
}
$data['cc'] = $data['cc'] ? json_decode($data['cc'],true) : [];
$data['bcc'] = $data['bcc'] ? json_decode($data['bcc'],true) : [];
$data['cc'] = $data['cc'] ? json_decode($data['cc'], true) : [];
$data['bcc'] = $data['bcc'] ? json_decode($data['bcc'], true) : [];
$data['to_name'] = array_map(function ($t){
if(!empty($t['name'])){
$data['to_name'] = array_map(function ($t) {
if (!empty($t['name'])) {
$t['name'] = MailFun::mb_coding($t['name']);
}
return $t;
},$data['to_name']);
}, $data['to_name']);
$postid = app()->request('postid','','intval');
$esData = ($postid ? es('email_lists_branch_'.$postid) : es())->get(['id'=>$data['email_id'].'_'.$data['folder_id'].'_'.$data['uid']]);
$data['postid'] = $esData['_source']['postid']??0;
$postid = app()->request('postid', '', 'intval');
$esData = ($postid ? es('email_lists_branch_' . $postid) : es())->get(['id' => $data['email_id'] . '_' . $data['folder_id'] . '_' . $data['uid']]);
$data['postid'] = $esData['_source']['postid'] ?? 0;
// 是否再次 重新获取
$data['allowreply'] = db()->value(folderSql::first(['id'=>$data['folder_id']],'folder'))!='发件箱'?1:0;
$data['allowreply'] = db()->value(folderSql::first(['id' => $data['folder_id']], 'folder')) != '发件箱' ? 1 : 0;
$body = getMailBody($id);
if($body && !$reload){
$data['body'] = json_decode($body['text_html'],true);
if ($body && !$reload) {
$data['body'] = json_decode($body['text_html'], true);
$htmlbody = '';
foreach ($data['body'] as $bd){
foreach ($data['body'] as $bd) {
// if(!empty($bd['charset'])){
// $charset = $bd['charset'];
// }
if(($bd['type']??'') == 'text/html'){
if (($bd['type'] ?? '') == 'text/html') {
$htmlbody = base64_decode($bd['body']);
}
}
foreach ($data['body'] as $bdk=>$bd){
foreach ($data['body'] as $bdk => $bd) {
if(count($bd)==1){
if(isset($bd['body'])){
if (count($bd) == 1) {
if (isset($bd['body'])) {
$data['body'][$bdk]['type'] = 'text/html';
}
}
if(!empty($bd['path'])){
if (!empty($bd['path'])) {
$data['body'][$bdk]['name'] = MailFun::isBase64($bd['name']) ? @base64_decode($bd['name']) : $bd['name'];
$data['body'][$bdk]['filename'] = MailFun::isBase64($bd['filename']) ? @base64_decode($bd['filename']) : $bd['filename'];
... ... @@ -1080,15 +788,15 @@ class Home extends Base {
$data['body'][$bdk]['size'] = 0;
$data['body'][$bdk]['url'] = '';
if(is_file($bd['path'])){
if (is_file($bd['path'])) {
// 文件大小
$data['body'][$bdk]['size'] = filesize($bd['path']);
// 文件访问地址
$data['body'][$bdk]['url'] = APP_HOST.str_replace(PUBLIC_PATH,'',$bd['path']);
$data['body'][$bdk]['url'] = APP_HOST . str_replace(PUBLIC_PATH, '', $bd['path']);
}
// 验证编码是否有其他编码字符,这里编辑了未知编码
if(!@json_encode($data['body'][$bdk])){
if (!@json_encode($data['body'][$bdk])) {
// 抛弃原有的名字,显示已存储到服务器的名字
$data['body'][$bdk]['name'] = $data['body'][$bdk]['signName'];
$data['body'][$bdk]['filename'] = $data['body'][$bdk]['signName'];
... ... @@ -1097,13 +805,12 @@ class Home extends Base {
unset($data['body'][$bdk]['path']);
// 内容区是有有cid
if ($htmlbody && !empty($bd['content-id'])){
if(!strpos($htmlbody,"\"cid:{$bd['content-id']}\"")){
if ($htmlbody && !empty($bd['content-id'])) {
if (!strpos($htmlbody, "\"cid:{$bd['content-id']}\"")) {
unset($data['body'][$bdk]['content-id']);
}
}
// 没有html内容,content-id是不可能有的
else if(!$htmlbody){
} // 没有html内容,content-id是不可能有的
else if (!$htmlbody) {
unset($data['body'][$bdk]['content-id']);
}
}
... ... @@ -1112,7 +819,7 @@ class Home extends Base {
'data' => $data
];
}// 草稿
else if(!$data['uid'] && $data['draft']){
else if (!$data['uid'] && $data['draft']) {
$data['body'] = [];
return [
'data' => $data
... ... @@ -1120,12 +827,12 @@ class Home extends Base {
}
// 循环几次
if($data['uid'] >= 0 && $sync_num < 1){
$folder = db()->value(folderSql::first(['id'=>$data['folder_id']],'origin_folder'));
try{
(new SyncMail(db()->first(emailSql::first($data['email_id']))))->mail($folder,[$data['uid']],true);
}catch (\Throwable $e){
logs('read body:'.$e->getMessage().$e->getTraceAsString());
if ($data['uid'] >= 0 && $sync_num < 1) {
$folder = db()->value(folderSql::first(['id' => $data['folder_id']], 'origin_folder'));
try {
(new SyncMail(db()->first(emailSql::first($data['email_id']))))->mail($folder, [$data['uid']], true);
} catch (\Throwable $e) {
logs('read body:' . $e->getMessage() . $e->getTraceAsString());
app()->e('邮箱登录验证异常');
}
... ... @@ -1133,10 +840,10 @@ class Home extends Base {
$reload = 0;
goto HOME_INFO_BODY;
}
logs('超过读取body次数 '.$data['id']);
logs('超过读取body次数 ' . $data['id']);
}else{
logs('读取body 没有查询到数据 '.$id.'-'.($email['email']??''));
} else {
logs('读取body 没有查询到数据 ' . $id . '-' . ($email['email'] ?? ''));
}
app()->e('mail_body_error');
... ... @@ -1149,8 +856,9 @@ class Home extends Base {
* @author:dc
* @time 2024/8/7 14:12
*/
public function desubscribe(){
$key = app()->request('key','');
public function desubscribe()
{
$key = app()->request('key', '');
app()->_json(MailFun::deSubscribeUrl($key));
}
... ... @@ -1161,21 +869,23 @@ class Home extends Base {
* @author:dc
* @time 2025/7/17 9:50
*/
public function bodyinfo(){
public function bodyinfo()
{
$id = app()->request('list_id');
$body = getMailBody($id);
if(!$body){
$data = db()->first(listsSql::first(dbWhere(['id'=>$id]),'folder_id,email_id,uid'));
$folder = db()->value(folderSql::first(['id'=>$data['folder_id']],'origin_folder'));
try{
(new SyncMail($data['email_id']))->mail($folder,[$data['uid']],true);
}catch (\Throwable $e){}
if (!$body) {
$data = listsSql::first(db(), dbWhere(['id' => $id]), 'folder_id,email_id,uid');
$folder = db()->value(folderSql::first(['id' => $data['folder_id']], 'origin_folder'));
try {
(new SyncMail($data['email_id']))->mail($folder, [$data['uid']], true);
} catch (\Throwable $e) {
}
}
$body = getMailBody($id);
app()->_json(@json_decode($body['text_html']??"[]",true));
app()->_json(@json_decode($body['text_html'] ?? "[]", true));
}
... ... @@ -1185,22 +895,23 @@ class Home extends Base {
* @author:dc
* @time 2025/9/18 16:50
*/
public function resync_to_es(){
$postid = (int) app()->request('postid');
if(app()->request('postid')=='0a'){
redis()->rPush('resync_to_es_inbox_list','0a');
public function resync_to_es()
{
$postid = (int)app()->request('postid');
if (app()->request('postid') == '0a') {
redis()->rPush('resync_to_es_inbox_list', '0a');
return;
}
if(redis()->has('resync_to_es_inbox:'.$postid)){
if (redis()->has('resync_to_es_inbox:' . $postid)) {
app()->e('失败,请等待10分钟后在重试');
}
$h = (int) date('H');
if(!$postid && $h>=6&& $h<=18){
$h = (int)date('H');
if (!$postid && $h >= 6 && $h <= 18) {
app()->e('刷所有项目只能在早6点前或晚18点后');
}
redis()->rPush('resync_to_es_inbox_list',$postid);
redis()->rPush('resync_to_es_inbox_list', $postid);
app()->e('请求成功,请等待5-15分钟');
... ... @@ -1214,29 +925,21 @@ class Home extends Base {
* @author:dc
* @time 2025/11/27 14:16
*/
public function my_resync_to_es(){
public function my_resync_to_es()
{
$id = 0;
$total = 0;
$email_id = intval(app()->request('email_id'));
while (1){
// echo $id."\n";
$mailLists = db()->all("select `id` from `lists` where `email_id` = {$email_id} and `id` > {$id} order by `id` asc limit 1000");
if(empty($mailLists)){
break;
}
foreach ($mailLists as $mailList){
$mailLists = listsSql::all(db(), dbWhere(['email_id' => $email_id]), 'id');
foreach ($mailLists as $mailList) {
$total++;
$id = $mailList['id'];
redis()->rPush('sync_to_es',$id.'.1');
redis()->rPush('sync_to_es', $id . '.1');
}
}
return $total;
}
}
... ...
... ... @@ -284,13 +284,6 @@ class MailListV2Es extends Base {
// 邮件箱
$v['folder_name'] = db()->cache(86400)->value(folderSql::first($v['folder_id'],'folder'));
// 暂时这样吧
$info = db()->first(\Model\listsSql::first('id = '.$v['id'],'`flagged`,`seen`,`deleted`'));
if($info){
$v['flagged'] = $info['flagged'];
$v['seen'] = $info['seen'];
$v['deleted'] = $info['deleted'];
}
return $v;
... ...
... ... @@ -280,15 +280,6 @@ class MailListV2Es2 extends Base {
// 邮件箱
$v['folder_name'] = db()->cache(86400)->value(folderSql::first($v['folder_id'],'folder'));
// 暂时这样吧
$info = db()->first(\Model\listsSql::first('id = '.$v['id'],'`flagged`,`seen`,`deleted`'));
if($info){
$v['flagged'] = $info['flagged'];
$v['seen'] = $info['seen'];
$v['deleted'] = $info['deleted'];
}
// 手动触发同步es
// 手动触发同步es
if(empty($v['is_auto']) && $v['folder_name']=='收件箱' && isAiAutoMail($v['from'],$v['subject'])) redis()->rPush('sync_to_es',$v['id'].'.1');
... ...
... ... @@ -45,7 +45,7 @@ class SyncMailToEs {
public $es;
public function handler(){
if(in_array($this->table,['lists','lists_hot'])){//,'lists_auto'
if(in_array($this->table,['lists','lists_hot','lists_back'])){//,'lists_auto'
if($this->type=='create'){
$this->create();
... ... @@ -70,17 +70,12 @@ class SyncMailToEs {
}
else if($this->table == 'lists'){
redis()->rPush('sync_to_es',$this->data['id']);
// $id = $this->data['email_id'].'_'.$this->data['folder_id'].'_'.$this->data['uid'];
// if(empty($this->data['is_auto'])){
// $this->data['is_auto'] = 0;
// }
// $this->es->save($id,$this->getData($this->data));
}
else if($this->table == 'lists_back'){
redis()->rPush('sync_to_es',$this->data['id']);
}
else if($this->table == 'lists_auto'){
redis()->rPush('sync_to_es',$this->data['list_id']);
// $data = db()->first(listsSql::first('`id` = '.$this->data['list_id']));
// $id = $data['email_id'].'_'.$data['folder_id'].'_'.$data['uid'];
// $this->es->save($id,$this->getData($data));
}
}
... ... @@ -94,9 +89,9 @@ class SyncMailToEs {
// if($this->table == 'lists_hot'){
//
// }
if($this->table == 'lists'){
if(in_array($this->table,['lists','lists_back'])){
// 更新es
$lists = db()->all(listsSql::all($this->where,'`id`'));
$lists = listsSql::all(db(),$this->where,'`id`');
foreach ($lists as $list){
redis()->rPush('sync_to_es',$list['id'].'.1');
// $id = $list['email_id'].'_'.$list['folder_id'].'_'.$list['uid'];
... ...
... ... @@ -83,7 +83,7 @@ class fob_ai_mail_auto_reply {
continue;
}
// 查询数据
$data = $this->db->throw()->first(\Model\listsSql::first('`id` = '.$did,'`id`,`folder_id`,`email_id`,`subject`,`is_hots`,`from`,`udate`,`to`,`uid`'));
$data = \Model\listsSql::first($this->db,'`id` = '.$did,'`id`,`folder_id`,`email_id`,`subject`,`is_hots`,`from`,`udate`,`to`,`uid`',true);
if($data && !$data['is_hots']){
// 不是屏蔽的
... ...
... ... @@ -86,7 +86,7 @@ class fob_hot_ai_mail_auto_reply
// }
// 查询数据
$data = $this->db->first(\Model\listsSql::first('`id` = ' . $did, '`id`,`to`,`folder_id`,`email_id`,`subject`,`is_hots`,`from`,`udate`,`uid`'));
$data = \Model\listsSql::first($this->db,'`id` = ' . $did, '`id`,`to`,`folder_id`,`email_id`,`subject`,`is_hots`,`from`,`udate`,`uid`');
if ($data && $data['is_hots']) {
// 在检查下是否是 收件箱
if ($this->db->cache(3600)->value(\Model\folderSql::has(['id' => $data['folder_id'], 'origin_folder' => 'INBOX']))) {
... ...
... ... @@ -110,453 +110,6 @@ class Mail {
}
/**
* 同步文件夹
* @param int $email_id
* @param DbPool|null $db
* @return mixed
* @author:dc
* @time 2023/2/5 10:58
*/
public function syncFolder($email_id,$db=null){
$db = $db ? $db : db();
// 读取所有文件夹,未解密
$folders = $this->client->getFolder();
foreach ($folders as $k=>$item){
$pname = explode('/',$item['folder']);
if(count($pname)>1){
array_pop($pname);
$pname = implode('/',$pname);
}else{
$pname = '';
}
$folders[$k]['pname'] = $pname;
}
$p = 0;
$uuids = [];
while ($folders){
foreach ($folders as $fk=>$folder){
$uuid = md5($email_id.$folder['folder']);
$uuids[$uuid] = $uuid;
// 查找/出现的次数
if (substr_count($folder['folder'],'/') == $p){
// 查找pid
$pid = $db->value(folderSql::has(['uuid'=>md5($email_id.$folder['pname'])]));
$pid = $pid ? $pid : 0;
// try {
$folder_name = '';
// 已发送
if(in_array('Send',$folder['check'])){
$folder_name = folderAlias('Send');
}
// 草稿
elseif(in_array('Drafts',$folder['check'])){
$folder_name = folderAlias('Drafts');
}
// 垃圾
elseif(in_array('Junk',$folder['check'])){
$folder_name = folderAlias('Junk');
}
// 回收站
elseif(in_array('Trash',$folder['check'])){
$folder_name = folderAlias('Trash');
}
if(!$folder_name){
$fn = explode('/',$folder['parseFolder']);
$folder_name = folderAlias(end($fn));
}
if(!$db->count(folderSql::has(['uuid'=>$uuid]))){
$db->insert(folderSql::$table,[
'email_id' => $email_id,
'folder' => folderAlias($folder_name),
'origin_folder' => $folder['folder'],
'uuid' => $uuid,
'pid' => $pid
],false);
}else{
$db->update(folderSql::$table,[
'email_id' => $email_id,
'folder' => folderAlias($folder_name),
'origin_folder' => $folder['folder'],
'uuid' => $uuid,
'pid' => $pid
],dbWhere(['email_id' => $email_id,'uuid' => $uuid]),false);
}
// }catch (\Throwable $e){
// 这里就不处理失败了
// }
unset($folders[$fk]);
}
}
$p++;
}
if($uuids){
// 删除以前的
$db->delete(folderSql::$table,['uuid.notin'=>$uuids,'email_id'=>$email_id]);
}
}
/**
* 同步邮件
* @param $email_id
* @param $folder_id
* @param string $folder
* @param null|DbPool $db
* @return bool|array
* @throws \Exception
* @author:dc
* @time 2023/2/18 9:54
*/
public function syncMail($email_id,$folder_id,$folder='INBOX') {
if(empty($folder)){
return 0;
}
// _echo('正在同步文件夹:'.$folder);
$db = db();
// 选择文件夹
try {
$status = $this->client->selectFolder($folder);
}catch (\Throwable $e){
return 0;
}
// 是否有邮件
if (!is_array($status) || !isset($status['EXISTS']) || !$status['EXISTS']){
return true;
}
// 更新数量
$upFolderData = ['exsts'=>$status['EXISTS'],'last_sync_time' => time()];
// 谷歌 不返未读数量 谢特
if(isset($status['UNSEEN'])){
$upFolderData['unseen'] = $status['UNSEEN'];
}
$db->update(
folderSql::$table,
$upFolderData,
dbWhere(['id'=>$folder_id]),
false
);
// 读取黑名单
$blacklist = redis()->get('blacklist:'.$email_id);
$blackFolder = '';
if($blacklist){
$blackFolder = $db->cache(86400*30)->value(folderSql::originFolder($email_id,'垃圾箱'));
}
//
$nu = 100;
$msgno = 1;
$success_uid = [];
while (true){
// 结束操作了
if(redis()->get(SYNC_RUNNING_REDIS_KEY) == 'stop'){
break;
}
// 是否结束了
if($status['EXISTS'] < $msgno){
break;
}
// 是否超过了最大数量
$maxmsgno = ($msgno-1)+$nu;
if($maxmsgno > $status['EXISTS']){
$maxmsgno = $status['EXISTS'];
}
$uids = $this->client->fetch(range($msgno,$maxmsgno),'UID');
if(!$uids){
break;
}
$uids = array_column($uids,'UID');
foreach ($uids as $k=>$uid){
if($db->cache(86400*30,false)->value(listsSql::first(dbWhere(['email_id'=>$email_id,'folder_id'=>$folder_id,'uid'=>$uid]),'count(*) as c'))){
unset($uids[$k]);
}
}
$msgno += $nu;
// 开始同步
if($uids){
$this->syncUidEmail(
$uids,
$email_id,
$folder,
$folder_id,
$blacklist,
$blackFolder,
$db
);
$success_uid = array_merge($success_uid,$uids);
}
}
// 更新数量
if(!isset($status['UNSEEN'])){
// 统计未读数量
$unseen = $db->count(listsSql::listCount(dbWhere([
'seen' => 0,
'deleted' => 0,
// 'email_id' => $email_id,
'folder_id' => $folder_id,
])));
$db->update(
folderSql::$table,
['unseen' => $unseen],
dbWhere(['id'=>$folder_id]),
false
);
}
return $success_uid;
}
/**
* 同步邮件 只通过 uid获取
* @param array $uids
* @param $email_id
* @param $folder
* @param $folder_id
* @param $blacklist
* @param $blackFolder
* @param \Lib\DbPool $db
* @throws \Exception
* @author:dc
* @time 2023/8/2 15:35
*/
public function syncUidEmail(array $uids,$email_id,$folder,$folder_id,$blacklist,$blackFolder,$db){
$results = $this->client->fetchHeader($uids,true);
if($results && is_array($results)){
// 表示已存在新邮件
if($folder == 'INBOX') redis()->incr('have_new_mail_'.$email_id,120);
// 批量插入
foreach ($results as $key=>$result){
$header = $result['HEADER.FIELDS'];
foreach ($result['FLAGS'] as $k=>$FLAG){
$result['FLAGS'][$k] = strtolower(str_replace('\\','',$FLAG));
}
try {
foreach ($header as $k=>$item){
$header[strtolower($k)] = $item;
}
// 没有收件人
$header['to'] = MailFun::toOrFrom($header['to']??'');
$header['from'] = MailFun::toOrFrom($header['from']);
// 抄送 ,密送
$cc = [];
$bcc = [];
if($header['cc']??''){
$cc = MailFun::toOrFrom($header['cc']);
}
if($header['bcc']??''){
$bcc = MailFun::toOrFrom($header['bcc']);
}
$data = [
'uid' => $result['UID'],
'subject' => $header['subject']??($header['Subject']??($header['SUBJECT']??'')),
'cc' => $cc,
'bcc' => $bcc,
'from' => $header['from'][0]['email']??'',
'from_name' => $header['from'][0]['name']??'',
'to' => $header['to']?implode(',',array_column($header['to'],'email')):'',
'to_name' => json_encode($header['to']),
'date' => strtotime(is_array($header['date']??'') ? $header['date'][0] : $header['date']??''),
// 'message_id' => $header['message-id']??'',
'udate' => strtotime($result['INTERNALDATE']),
'size' => $result['RFC822.SIZE']??0,
'recent' => in_array('recent',$result['FLAGS']) ? 1 : 0,
'seen' => in_array('seen',$result['FLAGS']) ? 1 : 0,
'draft' => in_array('draft',$result['FLAGS']) ? 1 : 0,
'flagged' => in_array('flagged',$result['FLAGS']) ? 1 : 0,
'answered' => in_array('answered',$result['FLAGS']) ? 1 : 0,
'folder_id' => $folder_id,
'email_id' => $email_id,
'is_file' => MailFun::isFile($result['BODYSTRUCTURE']??'') ? 1: 0 //是否附件
];
$data['date'] = $data['date'] ? : 0;
// 验证是否存在黑名单中
if($blacklist && $blackFolder!=$folder){
// 邮箱是否在黑名单中
$isBlacklist = false;
if (!empty($blacklist['emails']) && is_array($blacklist['emails']) && in_array($data['from'],$blacklist['emails'])){
$isBlacklist = true;
}
// 域是否存在
if (!empty($blacklist['domain']) && is_array($blacklist['domain']) && in_array(explode('@',$data['from'])[1],$blacklist['domain'])){
$isBlacklist = true;
}
if($isBlacklist && $blackFolder){
// 移入垃圾箱
try {
$this->client->move([$result['UID']],$blackFolder);
}catch (\Throwable $e){
logs('移动邮件失败 '.$result['UID'].':'.$e->getMessage().$e->getTraceAsString());
}
continue;
}
}
}catch (\Throwable $e){
logs(
'邮件解析失败:'.PHP_EOL.$e->getMessage().PHP_EOL.print_r($result,true),
LOG_PATH.'/imap/mail/'.$email_id.'/'.$result['UID'].'.log'
);
unset($results[$key]);
continue;
}
// 插入数据库
// 主题太长了就截取掉
$data['subject'] = mb_substr($data['subject'],0,3500);
try {
$id = $db->throw()->insert(listsSql::$table,$data);
if($id){
Event::call(SyncMail::class,$id,$data);
}
}catch (\Throwable $e){
// 插入失败,尝试更新
$db->update(listsSql::$table,$data,dbWhere([
'email_id'=> $data['email_id'],
'folder_id' => $data['folder_id'],
'uid' => $data['uid']
]));
}
$results[$key] = [];
}
}
}
/**
* 同步 邮件 内容 body
* @param $folder_name
* @param $uid
* @param $id
* @param null $db
* @return bool
* @throws \Exception
* @author:dc
* @time 2023/4/23 17:40
*/
public function syncBody($folder_name, $uid , $id, $db=null):bool {
if(empty($folder_name)){
return 0;
}
$db = $db ? $db : db();
// 选择文件夹
$this->client->selectFolder($folder_name);
$body = $this->client->fetchBody([$uid],MAIL_ATTACHMENT_PATH,true);
$body = array_values($body);
$body = $body[0]['RFC822.TEXT']??'';
if(!empty($body)){
$description = '';
foreach ($body as $key=>$item){
if(!empty($item['body'])){
// 过滤二进制
$item['body'] = preg_replace('/<0x[a-f\d]+>/','',$item['body']);
$body[$key]['body'] = base64_encode($item['body']);
}
if(!$description && in_array($item['type']??'',['text/html','text/plain'])){
if(!empty($item['charset'])){
$value = mb_iconv($item['body']?:'','utf-8',$item['charset']?:null);
$value = $value ? $value : $item['body'];
}else{
$value = $item['body'];
}
$value = @html_entity_decode($value, ENT_COMPAT, 'UTF-8');
$value=preg_replace("/<(script.*?)>(.*?)<(\/script.*?)>/si","",$value); //过滤script标签
$value=preg_replace("/<(\/?script.*?)>/si","",$value); //过滤script标签
$value=preg_replace("/javascript/si","Javascript",$value); //过滤script标签
$value=preg_replace("/<(style.*?)>(.*?)<(\/style.*?)>/si","",$value); //过滤style标签
$value=preg_replace("/<(\/?style.*?)>/si","",$value); //过滤style标签
$value = strip_tags($value);
$value = str_replace(["\n","\\n","&nbsp;"],'',$value);
$description = mb_substr(trim($value),0,190);
}
if(!empty($body[$key]['filename'])){
$body[$key]['filename'] = base64_encode($body[$key]['filename']);
}
if(!empty($body[$key]['name'])){
$body[$key]['name'] = base64_encode($body[$key]['name']);
}
}
bodySql::insertOrUpdate([
'lists_id' => $id,
'text_html' => $body // todo::因为邮件会出现多编码问题,会导致数据库写不进去
]);
// 更新描述
try {
$db->update(listsSql::$table,[
'description' => @base64_encode($description) ? $description : '',
'is_file' => MailFun::isBodyFile($body)
],dbWhere([
'id' => $id
]));
}catch (\Throwable $e){
$db->update(listsSql::$table,[
'is_file' => MailFun::isBodyFile($body)
],dbWhere([
'id' => $id
]));
}
}
return true;
}
/**
* 设置为未读
... ...
... ... @@ -18,51 +18,21 @@ class listsSql {
public static $table = 'lists';
/**
* 查询列表
* @param string $where
* @param int $p
* @param int $size
* @return string
* @author:dc
* @time 2023/3/16 18:11
*/
public static function lists(string $where, int $p, int $size){
$filed = '`id`,`uid`,`subject`,`from`,`from_name`,`to`,`date`,`size`,`recent`,`flagged`,`answered`,`deleted`,`seen`,`draft`,`udate`,`folder_id`,`is_file`,`cc`,`bcc`,`description`,`email_id`,`to_name`';
return "select {$filed} from `".static::$table."` where ".$where." order by `udate` desc limit {$size} offset ".(($p-1)*$size);
public static function update(\Lib\Db $db,$data,$where) {
if(is_array($where)){
$where = dbWhere($where);
}elseif (is_numeric($where)) {
$where = dbWhere(['id' => $where]);
}
/**
* 统计列表
* @param string $where
* @return string
* @author:dc
* @time 2023/3/16 18:10
*/
public static function listCount(string $where){
return "select count(*) from `".static::$table."` where ".$where;
$num = 0;
foreach ([self::$table,"lists_back",/* "lists_hot" */] as $table) {
$num += $db->update($table,$data,$where);
}
/**
* 获取已有的uid
* @param int $email_id
* @param int $folder_id
* @param array $uids
* @return string
* @author:dc
* @time 2023/4/23 16:54
*/
public static function getUids(int $email_id, int $folder_id, array $uids){
return "select `uid` from `".static::$table."` where ".dbWhere(['email_id'=>$email_id,'folder_id'=>$folder_id,'uid'=>$uids]);
return $num;
}
/**
* 根据id查询
* @param string $where
... ... @@ -70,27 +40,61 @@ class listsSql {
* @author:dc
* @time 2023/3/17 16:24
*/
public static function first(string $where,$filed='*'):string {
public static function first($db,string $where,$filed='*', $throw=false) {
foreach ([self::$table,"lists_back","lists_hot"] as $table) {
$sql = "select {$filed} from `".$table."` where ".$where.' limit 1';
if($throw){
$data = $db->throw($throw)->first($sql);
}else{
$data = $db->first($sql);
}
if($data) {
return $data;
}
}
return "select {$filed} from `".self::$table."` where ".$where.' limit 1';
return [];
}
public static function firstHot(string $where,$filed='*'):string {
return "select {$filed} from `lists_hot` where ".$where.' limit 1';
public static function count($db,string $where){
$num = 0;
foreach ([self::$table,"lists_back",/*"lists_hot"*/] as $table) {
$sql = "select count(*) as `mc` from `".$table."` where ".$where;
$data = $db->value($sql);
if($data && is_numeric($data)) {
$num += $data;
}
}
return $num;
}
/**
* 查询所有
* @param $db
* @param $where
* @param string $filed
* @return string
* @return array
* @author:dc
* @time 2024/1/22 11:15
*/
public static function all($where,$filed='*'){
return "select {$filed} from `".self::$table."` where ".$where;
public static function all($db,$where,$filed='*'){
if(is_array($where)){
$where = dbWhere($where);
}
$data = [];
foreach ([self::$table,"lists_back"] as $table) {
$sql = "select {$filed} from `".$table."` where ".$where;
$all = $db->all($sql);
if($all) {
$data = array_merge($data, $all);
}
}
return $data;
}
/**
... ... @@ -133,12 +137,13 @@ class listsSql {
if($draftid){
// 修改
unset($draftData['uid']);
if(!db()->update(listsSql::$table,$draftData,dbWhere(
$t = listsSql::update(db(),$draftData,dbWhere(
[
'id' => $draftid,
'email_id' => $draftData['email_id']
]
))){
));
if(!$t){
return 0;
}
}else{
... ...
... ... @@ -407,7 +407,7 @@ class SyncMail {
foreach ($uids as $k=>$uid){
$num = redis()->get('h_'.$folder_id.'_'.$uid,function () use ($folder_id,$uid){
$num = $this->db->value(listsSql::first(dbWhere(['email_id'=>$this->emailId(),'folder_id'=>$folder_id,'uid'=>$uid]),'count(*) as c'));
$num = listsSql::count($this->db,dbWhere(['email_id'=>$this->emailId(),'folder_id'=>$folder_id,'uid'=>$uid]));
if($num){
redis()->set('h_'.$folder_id.'_'.$uid,1,86400);
}
... ... @@ -455,10 +455,15 @@ class SyncMail {
if($this->isStop) return $sync_number;
if($this->isUid){
$maxUid = $this->db->value(listsSql::first(dbWhere([
$maxUid = listsSql::first($this->db,dbWhere([
'email_id'=>$this->emailId(),
'folder_id'=>$folder_id,
]),'max(uid)'));
]),'max(`uid`) as `uid`');
if($maxUid && $maxUid['uid']){
$maxUid = $maxUid['uid'];
}else {
$maxUid = 0;
}
$maxUid = $maxUid?$maxUid:0;
if($this->isUid==1&&!$maxUid){
return 0;
... ... @@ -567,11 +572,14 @@ class SyncMail {
$data['subject'] = str_replace('_',' ',$data['subject']);
// 查询是否存在
$id = $this->db->value(listsSql::first(dbWhere([
$id = listsSql::first($this->db,dbWhere([
'email_id'=> $data['email_id'],
'folder_id' => $data['folder_id'],
'uid' => $data['uid']
]),'`id`'));
]),'`id`');
if($id){
$id = $id['id'];
}
if(!$id){
$this->eLog(
... ... @@ -643,7 +651,7 @@ class SyncMail {
$data['uid'],
$data['subject'],
));
$this->db->update(listsSql::$table,$data,dbWhere(['id'=> $id]));
listsSql::update($this->db,$data,dbWhere(['id'=> $id]));
}
if(php_sapi_name()=='cli' && $this->isBody === null){
... ... @@ -771,7 +779,7 @@ class SyncMail {
}
// 更新描述
$this->db->update(listsSql::$table,[
listsSql::update($this->db,[
'description'=>
Fun::mb_convert_encoding(mb_substr($mailBody,0,150),'utf-8')
],dbWhere(['id'=> $id]));
... ...