作者 邓超

proxy

  1 +<?php
  2 +
  3 +namespace Controller;
  4 +
  5 +use Lib\Mail\Mail;
  6 +use Lib\Mail\MailFun;
  7 +use Lib\UploadFile;
  8 +use Lib\Verify;
  9 +use Model\bodySql;
  10 +use Model\emailSql;
  11 +use Model\folderSql;
  12 +use Model\listsSql;
  13 +use Model\sendJobsSql;
  14 +use Service\MailProxy;
  15 +use Service\SyncMail;
  16 +
  17 +
  18 +/**
  19 + * 读取代理服务器配置
  20 + * @author:dc
  21 + * @time 2025/3/10 16:36
  22 + * Class ServerProxy
  23 + * @package Controller
  24 + */
  25 +class ServerProxy extends Base {
  26 +
  27 + /**
  28 + * shopk和mail-server都必须使用这个 进行分配
  29 + * @return array[]
  30 + * @author:dc
  31 + * @time 2025/3/10 16:39
  32 + */
  33 + public function index(){
  34 + $email = app()->request('email');
  35 + $smtp = app()->request('smtp');
  36 + $imap = app()->request('imap');
  37 + $proxy = new MailProxy($email,$imap,$smtp);
  38 + $proxy->proxySuccess();
  39 + app()->_json([
  40 + 'imap_proxy' => $proxy->getImapProxy(),
  41 + 'smtp_proxy' => $proxy->getSmtpProxy()
  42 + ]);
  43 + }
  44 +
  45 +
  46 +
  47 +}
  48 +
  49 +
  50 +
  51 +
  52 +
  53 +
  54 +
  55 +
  56 +
  57 +
  58 +
  59 +
  60 +
  61 +
  1 +server {
  2 + listen 10087; # 监听的端口
  3 + proxy_pass smtp.gmail.com:465;
  4 +}
  5 +server {
  6 + listen 10086; # 监听的端口
  7 + proxy_pass imap.gmail.com:993;
  8 +}
  9 +server {
  10 + listen 10088; # 监听的端口
  11 + proxy_pass imap-mail.outlook.com:993;
  12 +}
  13 +server {
  14 + listen 10089; # 监听的端口
  15 + proxy_pass smtp-mail.outlook.com:465;
  16 +}
  17 +server {
  18 + listen 10092; # 监听的端口
  19 + proxy_pass imap.mail.yahoo.com:993;
  20 +}
  21 +server {
  22 + listen 10093; # 监听的端口
  23 + proxy_pass smtp.mail.yahoo.com:465;
  24 +}
  25 +server {
  26 + listen 10080; # 监听的端口
  27 + proxy_pass imaphz.qiye.163.com:993;
  28 +}
  29 +server {
  30 + listen 10081; # 监听的端口
  31 + proxy_pass smtphz.qiye.163.com:465;
  32 +}
  33 +
  34 +server {
  35 + listen 10094; # 监听的端口
  36 + proxy_pass imap.qiye.aliyun.com:993;
  37 +}
  38 +server {
  39 + listen 10095; # 监听的端口
  40 + proxy_pass smtp.qiye.aliyun.com:465;
  41 +}
@@ -7,18 +7,19 @@ @@ -7,18 +7,19 @@
7 return [ 7 return [
8 8
9 '/' => [\Controller\Test::class, 'home'], 9 '/' => [\Controller\Test::class, 'home'],
  10 + 'axxx' => [\Controller\Test::class, 'a'],
10 11
11 // 登录操作 12 // 登录操作
12 'login' => [\Controller\Login::class, 'login'], 13 'login' => [\Controller\Login::class, 'login'],
13 // 邮件列表 14 // 邮件列表
14 - 'lists' => [\Controller\Home::class, 'lists'], 15 + 'lists' => [\Controller\HomeEs::class, 'lists'],
15 // 统计 16 // 统计
16 - 'count' => [\Controller\Home::class, 'count'], 17 + 'count' => [\Controller\HomeEs::class, 'count'],
17 // 这个是单独处理的 aicc那边的应用 18 // 这个是单独处理的 aicc那边的应用
18 'v2/lists' => [\Controller\v2\Home::class, 'lists'], 19 'v2/lists' => [\Controller\v2\Home::class, 'lists'],
19 // 黑格专用路由 20 // 黑格专用路由
20 - 'fob/lists' => [\Controller\fob_ai\MailListV2::class, 'lists'],  
21 - 'fob/count' => [\Controller\fob_ai\MailListV2::class, 'count'],// 统计数量 21 + 'fob/lists' => [\Controller\fob_ai\MailListV2Es::class, 'lists'],
  22 + 'fob/count' => [\Controller\fob_ai\MailListV2Es::class, 'count'],// 统计数量
22 23
23 'fob/v2/lists' => [\Controller\fob_ai\MailListV2::class, 'lists'], 24 'fob/v2/lists' => [\Controller\fob_ai\MailListV2::class, 'lists'],
24 'fob/v2/count' => [\Controller\fob_ai\MailListV2::class, 'count'],// 统计数量 25 'fob/v2/count' => [\Controller\fob_ai\MailListV2::class, 'count'],// 统计数量
@@ -27,6 +28,9 @@ return [ @@ -27,6 +28,9 @@ return [
27 'fob/es/count' => [\Controller\fob_ai\MailListV2Es::class, 'count'],// 统计数量 28 'fob/es/count' => [\Controller\fob_ai\MailListV2Es::class, 'count'],// 统计数量
28 29
29 30
  31 + // 代理 ip分配
  32 + 'proxy/server' => [\Controller\ServerProxy::class,'index'],
  33 +
30 34
31 35
32 // 邮件详情 36 // 邮件详情
  1 +<?php
  2 +
  3 +namespace Service;
  4 +
  5 +use Lib\Mail\MailFun;
  6 +
  7 +/**
  8 + * @author:dc
  9 + * @time 2025/3/11 9:20
  10 + * Class MailProxy
  11 + * @package Service
  12 + */
  13 +class MailProxy {
  14 +
  15 + /** 原域名
  16 + * @var
  17 + */
  18 + protected $originImapHost = '';
  19 +
  20 + protected $originSmtpHost = '';
  21 +
  22 +
  23 + /**
  24 + * 代理服务器
  25 + * @var string
  26 + */
  27 + private $proxyImapHost = '';
  28 +
  29 + private $proxySmtpHost = '';
  30 +
  31 + /**
  32 + * 代理配置
  33 + * @var array
  34 + */
  35 + protected $config = [
  36 +
  37 + 'smtp.gmail.com:465' => '10087',
  38 + 'imap.gmail.com:993' => '10086',
  39 +
  40 + 'imap-mail.outlook.com:993' => '10088',
  41 + 'smtp-mail.outlook.com:465' => '10089',
  42 +
  43 + 'imap.mail.yahoo.com:993' => '10092',
  44 + 'smtp.mail.yahoo.com:465' => '10093',
  45 +
  46 + 'imaphz.qiye.163.com:993' => '10080',
  47 + 'smtphz.qiye.163.com:465' => '10081',
  48 +
  49 + 'imap.qiye.aliyun.com:993' => '10094',
  50 + 'smtp.qiye.aliyun.com:465' => '10095',
  51 +
  52 + 'imap.qq.com:993' => '10096',
  53 + 'smtp.qq.com:465' => '10097',
  54 +
  55 + ];
  56 +
  57 + /**
  58 + * 代理服务器 地址
  59 + * @var string[]
  60 + */
  61 + protected $proxyService = [
  62 + '43.134.162.250', // 这个是新加坡服务器 代理
  63 + '43.154.117.107', // 这个是 shopk的那台服务器
  64 + ];
  65 +
  66 + /**
  67 + * 分配到的ip服务
  68 + * @var string
  69 + */
  70 + protected $assignIp = '';
  71 +
  72 + /**
  73 + * 邮箱
  74 + * @var string
  75 + */
  76 + protected $email = '';
  77 +
  78 + /**
  79 + * MailProxy constructor.
  80 + * @param string $email
  81 + * @param string $imap
  82 + * @param string $smtp
  83 + * @throws \Exception
  84 + */
  85 + public function __construct(string $email, string $imap, string $smtp)
  86 + {
  87 + $this->email = str_replace(['"',"'"],'',$email);
  88 + // 先分配
  89 + $this->assignEmail();
  90 +
  91 + $this->originImapHost = $imap;
  92 +
  93 + $this->originSmtpHost = $smtp;
  94 + // 解析
  95 + $this->proxyImapHost = $this->parse($imap,993);
  96 + // 解析
  97 + $this->proxySmtpHost = $this->parse($smtp,465);
  98 + }
  99 +
  100 + /**
  101 + * 代理地址
  102 + * @author:dc
  103 + * @time 2025/3/13 17:38
  104 + */
  105 + public function getImapProxy(){
  106 + return $this->proxyImapHost;
  107 + }
  108 +
  109 + /**
  110 + * 代理地址
  111 + * @return string
  112 + * @author:dc
  113 + * @time 2025/3/14 10:31
  114 + */
  115 + public function getSmtpProxy(){
  116 + return $this->proxySmtpHost;
  117 + }
  118 +
  119 + /**
  120 + * @return mixed
  121 + */
  122 + public function getOriginImapHost(): string
  123 + {
  124 + return $this->originImapHost;
  125 + }
  126 +
  127 + /**
  128 + * @return string
  129 + */
  130 + public function getOriginSmtpHost(): string
  131 + {
  132 + return $this->originSmtpHost;
  133 + }
  134 +
  135 + /**
  136 + * 解析地址
  137 + * @param string $host
  138 + * @param int $port
  139 + * @return string
  140 + * @author:dc
  141 + * @time 2025/3/13 17:18
  142 + */
  143 + public function parse(string $host, int $port){
  144 + $host = parse_url($host);
  145 + // 协议
  146 + $scheme = $host['scheme']??'ssl';
  147 + // 地址
  148 + $serve = strtolower(empty($host['host']) ? $host['path'] : $host['host']);
  149 +
  150 + // 传入的是代理地址 并且是数据库里面已分配的ip
  151 + if(in_array($serve,$this->proxyService)){
  152 + // 传入的服务器 和 分配的不一致 更新分配的
  153 + if($serve != $this->assignIp){
  154 + $this->assignIp = $serve;
  155 + // 更新 ip
  156 + db()->throw()->update('mail_proxy',[
  157 + 'ip' => $this->assignIp
  158 + ],dbWhere(['email'=>$this->email]),false);
  159 + }
  160 +
  161 + }else{
  162 + // 端口
  163 + $port = (empty($host['port'])?$port:$host['port']);
  164 +
  165 + // 端口不在,说明没有配置
  166 + if(empty($this->config[$serve.':'.$port])){
  167 + // 返回不代理
  168 + $this->assignIp = $serve;
  169 + }else{
  170 + if(in_array($this->assignIp,$this->proxyService)){
  171 + $port = $this->config[$serve.':'.$port]; // 代理服务器端口
  172 + }
  173 + }
  174 +
  175 + }
  176 +
  177 + // 组装
  178 + $proxyHost = $scheme.'://'.$this->assignIp.":".(empty($host['port'])?$port:$host['port']);
  179 +
  180 +
  181 + return implode(':',MailFun::getHostPort($proxyHost));
  182 + }
  183 +
  184 + /**
  185 + * 分配邮箱 到 服务器
  186 + * @author:dc
  187 + * @time 2025/3/11 18:01
  188 + */
  189 + private function assignEmail(){
  190 + $data = db()->throw()->first('select * from mail_proxy where email = "'.$this->email.'"');
  191 + // 存在记录 并且 还在服务器列表
  192 + if($data && in_array($data['ip'],$this->proxyService)){
  193 + $this->assignIp = $data['ip'];
  194 + return ;
  195 + }
  196 + // 一个月活跃用户
  197 + $t = date('Y-m-d H:i:s',strtotime("-30 day"));
  198 + foreach ($this->proxyService as $ip){
  199 + $num = db()->count("select count(*) from `mail_proxy` where `status` = 1 and `time` > '{$t}' and `ip` = '{$ip}'");
  200 + // 每个ip分配1000个
  201 + if($num<1000){
  202 + $this->assignIp = $ip;
  203 + // 如果某个服务器 停止了,进来了就要重新分配
  204 + if($data){
  205 + db()->throw()->update('mail_proxy',[
  206 + 'ip' => $this->assignIp
  207 + ],'id = '.$data['id']);
  208 + }else{
  209 + db()->throw()->insert('mail_proxy',[
  210 + 'email' => $this->email,
  211 + 'ip' => $this->assignIp,
  212 + 'time' => date('Y-m-d H:i:s'),
  213 + 'status' => 0
  214 + ],false);
  215 + }
  216 +
  217 + return ;
  218 + }
  219 + }
  220 +
  221 + throw new \Exception('没有资源可分配');
  222 + }
  223 +
  224 +
  225 + /**
  226 + * 标记为正常使用代理
  227 + * @author:dc
  228 + * @time 2025/3/14 14:39
  229 + */
  230 + public function proxySuccess(){
  231 + db()->update('mail_proxy',[
  232 + 'status' => 1
  233 + ],dbWhere(['email'=>$this->email]),false);
  234 + }
  235 +
  236 +
  237 +
  238 +}
  239 +
  240 +
  241 +
  242 +
  243 +
  244 +
  245 +
  246 +
  247 +
  248 +
  249 +
  250 +
  251 +
  252 +
  253 +
  254 +
  1 +<!DOCTYPE html>
  2 +<html lang="en">
  3 +<head>
  4 + <meta charset="UTF-8">
  5 + <title>Title</title>
  6 +</head>
  7 +<body>
  8 +
  9 +<style>
  10 + pre{
  11 + background-color: #f0f0f0;
  12 + }
  13 +</style>
  14 +<h3><div style="text-align:center">深圳国际贸易单一窗口业务对接创贸集团技术方案</div></h3>
  15 +<p>> 一. 签名</p>
  16 +<ol>
  17 + <li>签名采用rsa 2048</li>
  18 +</ol>
  19 +
  20 +<pre>
  21 + <code class="language-injectablephp">
  22 + /**
  23 + * rsa 签名
  24 + * @param array $data 请求的参数
  25 + * @return string 签名字符串
  26 + */
  27 + function rsaEnSign(array $data){
  28 + ksort($data);
  29 + $dataString = http_build_query($data);
  30 + if (openssl_sign($dataString, $signature, 'private_key', OPENSSL_ALGO_SHA1)) {
  31 + return base64_encode($signature);
  32 + } else {
  33 + return '';
  34 + }
  35 + }
  36 + </code>
  37 +</pre>
  38 +
  39 +<ol start="2">
  40 + <li>验证数据</li>
  41 +</ol>
  42 +
  43 +<pre>
  44 + <code class="language-injectablephp">
  45 + /**
  46 + * 验证数据来源
  47 + * @param array $data
  48 + * @param string $sign
  49 + */
  50 + function rsaVerify(array $data, string $sign){
  51 + ksort($data);
  52 + $dataString = http_build_query($data);
  53 + $verified = openssl_verify($dataString, base64_decode($sign), 'public_key', OPENSSL_ALGO_SHA1);
  54 + if ($verified === 1) {
  55 + // 验证成功
  56 + } elseif ($verified === 0) {
  57 + // 验证失败
  58 + } else {
  59 + // 签名错误
  60 + $errorMsg = openssl_error_string();
  61 + }
  62 + }
  63 + </code>
  64 +</pre>
  65 +<p>> 二. 接口</p>
  66 +<ol>
  67 + <li><p>用户授权</p>
  68 + <ul>
  69 + <li>请求地址 /api/southern/auth</li>
  70 +
  71 + <li>请求类型 POST</li>
  72 +
  73 + <li>签名规则 rsa</li>
  74 +
  75 + <li>请求示例</li>
  76 +
  77 + </ul>
  78 +
  79 + <pre>
  80 + <code class="language-injectablephp">
  81 + $postData = [
  82 + 'payload' => [
  83 + "serviceFlowId" => "本次业务操作流水id",
  84 + "uniCode" => "南方电子口岸给对接方分配的 唯一ID号",
  85 + "mobile" => "手机",
  86 + "userId" => "用户 ID",
  87 + "userName" => "用户名称",
  88 + "entName" => "企业名称",
  89 + "scCode" => "企业统一社会信用代码"
  90 + ],
  91 + 'sign' => '',
  92 + ];
  93 + $postData['sign'] = rsaEnSign($postData['payload']);
  94 + $result = Http::post('url', $postData);
  95 + if($result['code']===200){
  96 + // 成功
  97 + }else{
  98 + // 失败
  99 + }
  100 + </code>
  101 + </pre>
  102 +
  103 + <ul>
  104 + <li>返回结果 成功</li>
  105 + </ul>
  106 +
  107 + <pre>
  108 + <code class="language-json">
  109 + {
  110 + "code": 200,
  111 + "message": "SUCCESS",
  112 + "data": {
  113 + "url": [
  114 + {
  115 + "name": "ai搜索",
  116 + "url": "https://fob.ai.cc/ai_search?iframe_sign=xxxxx"
  117 + },
  118 + {
  119 + "name": "企业洞察",
  120 + "url": "https://fob.ai.cc/ai_company_search?iframe_sign=xxxxx"
  121 + },
  122 + ...
  123 + ],
  124 + "uniCode": "1",
  125 + "firstLogin": true //是否第一次登录
  126 + },
  127 + "success": true
  128 + }
  129 + </code></pre>
  130 +
  131 + <ul>
  132 + <li>失败信息</li>
  133 +
  134 + </ul>
  135 +
  136 + <pre>
  137 + <code class="language-json">
  138 + {
  139 + "code": 500,
  140 + "message": "签名验证失败",
  141 + "success": false
  142 + }
  143 + </code>
  144 + </pre>
  145 +
  146 + </li>
  147 +
  148 + <li><p>意向登记</p>
  149 + <ul>
  150 + <li>请求地址 /api/southern/intention</li>
  151 +
  152 + <li>请求类型 POST</li>
  153 +
  154 + <li>签名规则 rsa</li>
  155 +
  156 + <li>请求示例</li>
  157 +
  158 + </ul>
  159 +
  160 + <pre><code class="language-injectablephp">
  161 + $postData = [
  162 + "guid"=>"166970C4-AF54-470A-87E4-D598463783A2",
  163 + "busiCode"=> "CMJT04",
  164 + "senderId"=> "XXXXXX",
  165 + "version"=> "1.0",
  166 + 'payload' => [
  167 + "serviceFlowId"=> "F2310011420000001",
  168 + "orgName"=>"xxx",
  169 + "orgCode"=>"xxx",
  170 + "userId"=>"xxx",
  171 + "userName"=>"xxxxx 有限公司",
  172 + "contactAddress"=> "xxxxxxxxxxxxxxxxxx",
  173 + "contactMan"=> "xxx",
  174 + "contactTel"=> "xxx",
  175 + "email"=> "xxx",
  176 + "position"=> "xxx",
  177 + "notes"=> "xxx"
  178 + ],
  179 + 'sign' => '',
  180 + ];
  181 + $postData['sign'] = rsaEnSign($postData['payload']);
  182 + $result = Http::post('url', $postData);
  183 + if($result['code']===200){
  184 + // 成功
  185 + }else{
  186 + // 失败
  187 + }
  188 + </code></pre>
  189 +
  190 + <ul>
  191 + <li>返回结果 成功</li>
  192 +
  193 + </ul>
  194 +
  195 + <pre>
  196 + <code class="language-json">
  197 + {
  198 + "code": 200,
  199 + "message": "SUCCESS",
  200 + "data": {
  201 + "serviceFlowId": "F2310011420000001",
  202 + "status": "11",
  203 + "statusTime": "20230818081331",
  204 + "statusDetail": ""
  205 + },
  206 + "success": true
  207 + }
  208 + </code>
  209 + </pre>
  210 +
  211 + <ul>
  212 + <li>失败信息</li>
  213 + </ul>
  214 +
  215 + <pre><code class="language-json">
  216 + {
  217 + "code": 500,
  218 + "message": "签名验证失败",
  219 + "success": false
  220 + }</code></pre>
  221 +
  222 + </li>
  223 +
  224 +</ol>
  225 +
  226 +</body>
  227 +</html>