作者 邓超

1

1 <?php 1 <?php
2 2
3 -var_dump(str_starts_with('a_sdf','_'));  
4 3
5 4
6 //use Model\listsSql; 5 //use Model\listsSql;
7 6
8 //include_once __DIR__."/../vendor/autoload.php"; 7 //include_once __DIR__."/../vendor/autoload.php";
9 - 8 +//
  9 +//print_r(redis()->incr('asdfasdfasdfasdf',600));
10 10
11 //$ids = db()->all('select `id` from `'.\Model\emailSql::$table.'` limit 1000 offset 0'); 11 //$ids = db()->all('select `id` from `'.\Model\emailSql::$table.'` limit 1000 offset 0');
12 //print_r($ids); 12 //print_r($ids);
@@ -52,6 +52,8 @@ function start(){ @@ -52,6 +52,8 @@ function start(){
52 if(!$id){ 52 if(!$id){
53 co::sleep(1); 53 co::sleep(1);
54 }else{ 54 }else{
  55 + // 占用当前的id,占用2小时
  56 + redis()->add('just_sync_'.$id,time(),7200);
55 // 启动一个协程 57 // 启动一个协程
56 go(function () use (&$start_num,$worker_id,$id){ 58 go(function () use (&$start_num,$worker_id,$id){
57 $start_num++; 59 $start_num++;
@@ -71,10 +73,19 @@ function start(){ @@ -71,10 +73,19 @@ function start(){
71 } 73 }
72 74
73 // 协程完成后执行的函数 75 // 协程完成后执行的函数
74 - co::defer(function () use (&$start_num,$worker_id){ 76 + co::defer(function () use (&$start_num,$worker_id,$id){
75 // _echo('正常关闭进程('.$worker_id.')下的协程('.co::getCid().')'); 77 // _echo('正常关闭进程('.$worker_id.')下的协程('.co::getCid().')');
76 $start_num--; 78 $start_num--;
  79 + // 消除占用
  80 + redis()->delete('just_sync_'.$id);
  81 + // 写入日志
77 \Lib\Log::getInstance()->write(); 82 \Lib\Log::getInstance()->write();
  83 +
  84 + // 关闭数据库链接
  85 + db()->close();
  86 + // 关闭redis链接
  87 + redis()->close();
  88 +
78 }); 89 });
79 90
80 }); 91 });
@@ -2,6 +2,8 @@ @@ -2,6 +2,8 @@
2 2
3 error_reporting(E_ERROR | E_NOTICE | E_WARNING); 3 error_reporting(E_ERROR | E_NOTICE | E_WARNING);
4 4
  5 +ini_set('display_errors',0);
  6 +
5 // 开启4个进程 7 // 开启4个进程
6 define('WORKER_NUM',10); 8 define('WORKER_NUM',10);
7 // 开启最大1000个协程 9 // 开启最大1000个协程
@@ -55,6 +55,9 @@ abstract class Base { @@ -55,6 +55,9 @@ abstract class Base {
55 if(empty($data)){ 55 if(empty($data)){
56 app()->e('email_request_required'); 56 app()->e('email_request_required');
57 } 57 }
  58 + if($data['pwd_error']){
  59 + app()->e('imap_password_error',403);
  60 + }
58 } 61 }
59 62
60 if($filed == '*'){ 63 if($filed == '*'){
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 namespace Controller; 3 namespace Controller;
4 4
5 5
  6 +use Lib\Err;
6 use Lib\Mail\Mail; 7 use Lib\Mail\Mail;
7 use Lib\Mail\MailFun; 8 use Lib\Mail\MailFun;
8 use Model\folderSql; 9 use Model\folderSql;
@@ -23,16 +24,38 @@ class Folder extends Base { @@ -23,16 +24,38 @@ class Folder extends Base {
23 * @time 2023/2/18 10:58 24 * @time 2023/2/18 10:58
24 */ 25 */
25 public function lists(){ 26 public function lists(){
  27 +
  28 + try {
  29 + $emails = $this->getEmails();
  30 + }catch (Err $e){
  31 + $emails = [$this->getEmail()];
  32 + }
  33 +
  34 + $emails = array_column($emails,'email','id');
  35 +
26 // 查询 36 // 查询
27 $folders = db()->all( 37 $folders = db()->all(
28 \Model\folderSql::all( 38 \Model\folderSql::all(
29 - $this->getEmail('id'),  
30 - '`id`,`folder`,`pid`,`exsts`,`unseen`' 39 + array_keys($emails),
  40 + '`id`,`folder`,`pid`,`exsts`,`unseen`,`email_id`'
31 ) 41 )
32 ); 42 );
33 43
34 - // 转tree  
35 - $folders = list_to_tree($folders); 44 + $data = [];
  45 + foreach ($folders as $k=>$folder){
  46 + if (empty($data[$emails[$folder['email_id']]])){
  47 + $data[$emails[$folder['email_id']]] = [];
  48 + }
  49 + $data[$emails[$folder['email_id']]][$k] = $folder;
  50 + unset($data[$emails[$folder['email_id']]][$k]['email_id']);
  51 + }
  52 + $folders = $data;$data = null;
  53 +
  54 + foreach ($folders as $f=>$folder){
  55 + // 转tree
  56 + $folders[$f] = list_to_tree($folder);
  57 + }
  58 +
36 59
37 return $folders; 60 return $folders;
38 } 61 }
@@ -28,30 +28,42 @@ class Home extends Base { @@ -28,30 +28,42 @@ class Home extends Base {
28 $page = app()->request('page',1,'intval'); 28 $page = app()->request('page',1,'intval');
29 $page = $page ? $page : 1; 29 $page = $page ? $page : 1;
30 30
31 - $size = app()->request('size',20,'intval');  
32 - $size = $size ? $size : 1; 31 + $limit = app()->request('limit',20,'intval');
  32 + $limit = $limit ? $limit : 1;
  33 +
  34 + // 指定id
  35 + $ids = app()->request('mail_id');
  36 + $ids = is_array($ids) ? $ids : [$ids];
  37 + foreach ($ids as $i=>$d){
  38 + if(!is_numeric($d)){
  39 + unset($ids[$i]);
  40 + }
  41 + }
33 42
34 // 邮件文件夹的id 43 // 邮件文件夹的id
35 - $folder_id = app()->request('folder_id'); 44 + $folder_id = (int) app()->request('folder_id');
  45 + // 附件
  46 + $attachment = app()->request('attachment');
  47 +
  48 + $where = ['email_id'=>$this->getEmails('id')];
  49 + if($folder_id) $where['folder_id'] = $folder_id;
  50 + if($ids) $where['id'] = $ids;
  51 + if($attachment) $where['is_file'] = 1; //附件
36 52
37 $lists = db()->all( 53 $lists = db()->all(
38 listsSql::lists( 54 listsSql::lists(
39 - $this->getEmails('id'), 55 + dbWhere($where),
40 $page, 56 $page,
41 - $size,  
42 - (int) $folder_id 57 + $limit
43 ) 58 )
44 ); 59 );
45 60
46 // 总数 61 // 总数
47 $total = db()->count( 62 $total = db()->count(
48 - listsSql::listCount(  
49 - $this->getEmails('id'),  
50 - (int) $folder_id  
51 - ) 63 + listsSql::listCount(dbWhere($where))
52 ); 64 );
53 65
54 - app()->_json(listsPage($lists,$total,$page,$size)); 66 + app()->_json(listsPage($lists,$total,$page,$limit));
55 67
56 } 68 }
57 69
@@ -112,18 +124,18 @@ class Home extends Base { @@ -112,18 +124,18 @@ class Home extends Base {
112 */ 124 */
113 public function sync(){ 125 public function sync(){
114 126
115 - $where['email'] = web_request_emails(); 127 + $emails = web_request_emails();
116 128
117 - if(empty($where)){ 129 + if(empty($emails)){
118 app()->e('sync_request_param_error'); 130 app()->e('sync_request_param_error');
119 }else{ 131 }else{
120 // 查询id 132 // 查询id
121 - $datas = db()->all(emailSql::getValues($where,'`id`,`email`,`pwd_error`'));  
122 - foreach ($datas as &$v){ 133 + $datas = db()->all(emailSql::getValues(['email'=>$emails],'`id`,`email`,`pwd_error`'));
  134 + foreach ($datas as $k=>$v){
123 if(!$v['pwd_error']){ 135 if(!$v['pwd_error']){
124 redis()->rPush('sync_email_lists', $v['id']); 136 redis()->rPush('sync_email_lists', $v['id']);
125 } 137 }
126 - unset($v['id']); 138 + $datas[$k]['have_new'] = redis()->getDel('have_new_mail_'.$v['id']);
127 } 139 }
128 // 返回成功的参数值 140 // 返回成功的参数值
129 app()->_json($datas); 141 app()->_json($datas);
@@ -68,6 +68,7 @@ class Login { @@ -68,6 +68,7 @@ class Login {
68 $ret = db()->update(emailSql::$table,$data,dbWhere(['id'=>$id])); 68 $ret = db()->update(emailSql::$table,$data,dbWhere(['id'=>$id]));
69 }else{ 69 }else{
70 // 新增 70 // 新增
  71 + $data['email'] = $formData['email'];
71 $ret = db()->insert(emailSql::$table,$data); 72 $ret = db()->insert(emailSql::$table,$data);
72 73
73 if($ret){ 74 if($ret){
@@ -81,9 +82,7 @@ class Login { @@ -81,9 +82,7 @@ class Login {
81 82
82 83
83 if($ret){ 84 if($ret){
84 - app()->_json([  
85 - 'token' => $data['token']  
86 - ]); 85 + app()->_json(db()->first(emailSql::first($formData['email'],'`id`,`email`,`last_sync_time`')));
87 } 86 }
88 87
89 app()->e('login_error'); 88 app()->e('login_error');
@@ -181,7 +181,7 @@ function web_request_emails():array { @@ -181,7 +181,7 @@ function web_request_emails():array {
181 $emails = app()->request('emails'); 181 $emails = app()->request('emails');
182 $emails = is_array($emails) ? $emails : [$emails]; 182 $emails = is_array($emails) ? $emails : [$emails];
183 foreach ($emails as $k=>$email){ 183 foreach ($emails as $k=>$email){
184 - if(!\Lib\Verify::sEmail($email)){ 184 + if(!$email || !\Lib\Verify::sEmail($email)){
185 unset($emails[$k]); 185 unset($emails[$k]);
186 } 186 }
187 } 187 }
@@ -203,7 +203,7 @@ function web_request_emails():array { @@ -203,7 +203,7 @@ function web_request_emails():array {
203 function web_request_email():string { 203 function web_request_email():string {
204 $email = app()->request('email'); 204 $email = app()->request('email');
205 205
206 - if(!\Lib\Verify::sEmail($email)){ 206 + if(!$email || !\Lib\Verify::sEmail($email)){
207 app()->e('email_request_required'); 207 app()->e('email_request_required');
208 } 208 }
209 209
@@ -17,9 +17,10 @@ return [ @@ -17,9 +17,10 @@ return [
17 'server_error' => '服务器异常', 17 'server_error' => '服务器异常',
18 18
19 'login_error' => '登录失败', 19 'login_error' => '登录失败',
20 - 'login_error_imap' => '登录失败,请检查密码/是否开启imap服务', 20 + 'login_error_imap' => '登录失败,请检查密码是否正确或者是否开启imap/smtp服务',
21 'token_verify_error' => '令牌验证失败', 21 'token_verify_error' => '令牌验证失败',
22 'token_verify_notfound' => '令牌验证失败.', 22 'token_verify_notfound' => '令牌验证失败.',
  23 + 'imap_password_error' => '密码错误请重新登录.',
23 24
24 'param_request_error' => '参数异常', 25 'param_request_error' => '参数异常',
25 'folder_create_name_error' => '文件夹名称只能输入中文英文数字', 26 'folder_create_name_error' => '文件夹名称只能输入中文英文数字',
@@ -276,10 +276,14 @@ class DbPool { @@ -276,10 +276,14 @@ class DbPool {
276 * 结束 276 * 结束
277 */ 277 */
278 public function __destruct(){ 278 public function __destruct(){
279 - $this->client = null; 279 + $this->close();
280 } 280 }
281 281
282 282
  283 + public function close(){
  284 + $this->client = null;
  285 + }
  286 +
283 287
284 288
285 } 289 }
@@ -178,6 +178,9 @@ class Mail { @@ -178,6 +178,9 @@ class Mail {
178 // 循环 178 // 循环
179 $results = $this->client->fetchHeader($msgno); 179 $results = $this->client->fetchHeader($msgno);
180 if($results){ 180 if($results){
  181 + // 表示已存在新邮件
  182 + redis()->incr('have_new_mail_'.$email_id,120);
  183 +
181 // 批量插入 184 // 批量插入
182 foreach ($results as $key=>$result){ 185 foreach ($results as $key=>$result){
183 $header = $result['HEADER.FIELDS']; 186 $header = $result['HEADER.FIELDS'];
@@ -138,22 +138,38 @@ class RedisPool { @@ -138,22 +138,38 @@ class RedisPool {
138 /** 138 /**
139 * 自增 139 * 自增
140 * @param $key 140 * @param $key
  141 + * @param null $ttl
141 * @return int 142 * @return int
142 * @author:dc 143 * @author:dc
143 * @time 2023/2/17 15:29 144 * @time 2023/2/17 15:29
144 */ 145 */
145 - public function incr($key){ 146 + public function incr($key, $ttl = null){
  147 + if($ttl){
  148 + return $this->client->eval(
  149 + "local x = redis.call('incr',KEYS[1]);redis.call('expire',KEYS[1],ARGV[1]);return x",
  150 + [$key, $ttl],
  151 + 1
  152 + );
  153 + }
146 return $this->client->incr($key); 154 return $this->client->incr($key);
147 } 155 }
148 156
149 /** 157 /**
150 * 自减 158 * 自减
151 * @param $key 159 * @param $key
  160 + * @param null $ttl
152 * @return int 161 * @return int
153 * @author:dc 162 * @author:dc
154 - * @time 2023/2/17 15:29 163 + * @time 2023/3/16 11:19
155 */ 164 */
156 - public function decr($key){ 165 + public function decr($key,$ttl = null){
  166 + if($ttl){
  167 + return $this->client->eval(
  168 + "local x = redis.call('decr',KEYS[1]);redis.call('expire',KEYS[1],ARGV[1]);return x",
  169 + [$key, $ttl],
  170 + 1
  171 + );
  172 + }
157 return $this->client->decr($key); 173 return $this->client->decr($key);
158 } 174 }
159 175
@@ -169,6 +185,20 @@ class RedisPool { @@ -169,6 +185,20 @@ class RedisPool {
169 return $this->client->del($key); 185 return $this->client->del($key);
170 } 186 }
171 187
  188 + /**
  189 + * 获取值并删除
  190 + * @param $key
  191 + * @return mixed
  192 + * @author:dc
  193 + * @time 2023/3/16 11:36
  194 + */
  195 + public function getDel($key){
  196 + return $this->client->eval(
  197 + "local x = redis.call('get',KEYS[1]);if x then redis.call('del',KEYS[1]) end return x",
  198 + [$key],
  199 + 1
  200 + );
  201 + }
172 202
173 203
174 /** 204 /**
@@ -196,14 +226,7 @@ class RedisPool { @@ -196,14 +226,7 @@ class RedisPool {
196 226
197 public function __destruct() 227 public function __destruct()
198 { 228 {
199 - // TODO: Implement __destruct() method.  
200 - try {  
201 - if($this->client->ping()){  
202 - $this->client->close();  
203 - }  
204 - }catch (\RedisException $e){}  
205 -  
206 - $this->client = null; 229 + $this->close();
207 } 230 }
208 231
209 232
@@ -228,7 +251,21 @@ class RedisPool { @@ -228,7 +251,21 @@ class RedisPool {
228 } 251 }
229 252
230 253
  254 + /**
  255 + * 关闭
  256 + * @author:dc
  257 + * @time 2023/3/16 13:42
  258 + */
  259 + public function close(){
  260 + // TODO: Implement __destruct() method.
  261 + try {
  262 + if($this->client->ping()){
  263 + $this->client->close();
  264 + }
  265 + }catch (\RedisException $e){}
231 266
  267 + $this->client = null;
  268 + }
232 269
233 270
234 271
@@ -35,7 +35,7 @@ class Verify { @@ -35,7 +35,7 @@ class Verify {
35 * @author:dc 35 * @author:dc
36 * @time 2023/3/10 16:04 36 * @time 2023/3/10 16:04
37 */ 37 */
38 - public static function sEmail($email){ 38 + public static function sEmail(string $email){
39 return preg_match('/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/',$email); 39 return preg_match('/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/',$email);
40 } 40 }
41 41
@@ -57,7 +57,7 @@ class Verify { @@ -57,7 +57,7 @@ class Verify {
57 * @author:dc 57 * @author:dc
58 * @time 2023/3/13 10:59 58 * @time 2023/3/13 10:59
59 */ 59 */
60 - public static function sDomain($domain){ 60 + public static function sDomain(string $domain){
61 return preg_match('/[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?/',$domain); 61 return preg_match('/[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?/',$domain);
62 } 62 }
63 63
@@ -68,7 +68,7 @@ class Verify { @@ -68,7 +68,7 @@ class Verify {
68 * @author:dc 68 * @author:dc
69 * @time 2023/3/13 11:00 69 * @time 2023/3/13 11:00
70 */ 70 */
71 - public static function sUrl($url){ 71 + public static function sUrl(string $url){
72 return preg_match('/[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$/',$url); 72 return preg_match('/[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$/',$url);
73 } 73 }
74 74
@@ -15,13 +15,13 @@ class folderSql { @@ -15,13 +15,13 @@ class folderSql {
15 15
16 /** 16 /**
17 * 所有文件夹 17 * 所有文件夹
18 - * @param int $email_id 18 + * @param int|array $email_id
19 * @return string 19 * @return string
20 * @author:dc 20 * @author:dc
21 * @time 2023/2/18 9:22 21 * @time 2023/2/18 9:22
22 */ 22 */
23 - public static function all(int $email_id, $field = '`id`,`folder`,`pid`,`origin_folder`,`last_sync_time`'):string {  
24 - return "select {$field} from `".static::$table."` where `email_id` = {$email_id} order by `id` asc"; 23 + public static function all(int|array $email_id, $field = '`id`,`folder`,`pid`,`origin_folder`,`last_sync_time`'):string {
  24 + return "select {$field} from `".static::$table."` where ".dbWhere(['email_id'=>$email_id])." order by `id` asc";
25 } 25 }
26 26
27 27
@@ -20,37 +20,31 @@ class listsSql { @@ -20,37 +20,31 @@ class listsSql {
20 20
21 /** 21 /**
22 * 查询列表 22 * 查询列表
23 - * @param int|array $email_id 23 + * @param string $where
24 * @param int $p 24 * @param int $p
25 * @param int $size 25 * @param int $size
26 - * @param int $folder_id  
27 * @return string 26 * @return string
28 * @author:dc 27 * @author:dc
29 - * @time 2023/3/10 15:24 28 + * @time 2023/3/16 18:11
30 */ 29 */
31 - public static function lists(int|array $email_id, int $p, int $size, int $folder_id = 0){ 30 + public static function lists(string $where, int $p, int $size){
32 31
33 - $where = ['email_id'=>$email_id];  
34 - if($folder_id) $where['folder_id'] = $folder_id; 32 + $filed = '`id`,`uid`,`msgno`,`subject`,`from`,`from_name`,`to`,`date`,`size`,`recent`,`flagged`,`answered`,`deleted`,`seen`,`draft`,`udate`,`folder_id`,`is_file`,`cc`,`bcc`,`description`';
35 33
36 - $filed = '`id`,`uid`,`msgno`,`subject`,`from`,`to`,`date`,`size`,`recent`,`flagged`,`answered`,`deleted`,`seen`,`draft`,`udate`,`folder_id`,`is_file`,`cc`,`bcc`';  
37 -  
38 - return "select {$filed} from `".static::$table."` where ".dbWhere($where)." order by `udate` desc limit {$size} offset ".(($p-1)*30); 34 + return "select {$filed} from `".static::$table."` where ".$where." order by `udate` desc limit {$size} offset ".(($p-1)*30);
39 35
40 } 36 }
41 37
42 /** 38 /**
43 * 统计列表 39 * 统计列表
44 - * @param int|array $email_id  
45 - * @param int $folder_id 40 + * @param string $where
46 * @return string 41 * @return string
47 * @author:dc 42 * @author:dc
48 - * @time 2023/3/10 15:26 43 + * @time 2023/3/16 18:10
49 */ 44 */
50 - public static function listCount(int|array $email_id, int $folder_id = 0){  
51 - $where = ['email_id'=>$email_id];  
52 - if($folder_id) $where['folder_id'] = $folder_id;  
53 - return "select count(*) from `".static::$table."` where ".dbWhere($where); 45 + public static function listCount(string $where){
  46 +
  47 + return "select count(*) from `".static::$table."` where ".$where;
54 } 48 }
55 49
56 /** 50 /**