PHP 进行统一邮箱登陆的代理实现(swoole)
在工作的过程中,经常会有很多应用有发邮件的需求,这个时候需要在每个应用中配置smtp服务器。一旦公司调整了smtp服务器的配置,比如修改了密码等,这个时候对于维护的人员来说要逐一修改应用中smtp的配置。这样的情况虽然不多见,但遇上了还是很头痛的一件事情。
知道了问题,解决起来就有了方向。于是就有了自己开发一个简单的smtp代理的想法,这个代理主要的功能(参照问题)主要是:
1.接受指定IP应用的smtp请求;
2.应用不需要知道smtp的用户和密码;
3.转发应用的smtp请求。
开发的环境:Linux,php(swoole);
代码如下:
16f086cec199e61e2d963c5ca764f997server = <span style="color: #0000ff;">new</span> swoole_server(<span style="color: #800080;">$host</span>,<span style="color: #800080;">$port</span>,self::<span style="color: #800080;">$server_mode</span>,<span style="color: #800080;">$flag</span><span style="color: #000000;">); </span><span style="color: #800080;">$this</span>->host = <span style="color: #800080;">$host</span><span style="color: #000000;">; </span><span style="color: #800080;">$this</span>->port = <span style="color: #800080;">$port</span><span style="color: #000000;">; </span><span style="color: #800080;">$this</span>->setting = <span style="color: #0000ff;">array</span><span style="color: #000000;">( </span>'backlog' => 128, 'dispatch_mode' => 2,<span style="color: #000000;"> ); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> daemonize(){ </span><span style="color: #800080;">$this</span>->setting['daemonize'] = 1<span style="color: #000000;">; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> getConnectionInfo(<span style="color: #800080;">$fd</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span>->server->connection_info(<span style="color: #800080;">$fd</span><span style="color: #000000;">); } </span><span style="color: #008000;">/*</span><span style="color: #008000;">* * 启动服务进程 * @param array $setting * @throws Exception </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> run(<span style="color: #800080;">$setting</span> = <span style="color: #0000ff;">array</span><span style="color: #000000;">()){ </span><span style="color: #800080;">$this</span>->setting = <span style="color: #008080;">array_merge</span>(<span style="color: #800080;">$this</span>->setting,<span style="color: #800080;">$setting</span><span style="color: #000000;">); </span><span style="color: #008000;">//</span><span style="color: #008000;">不使用swoole的默认日志</span> <span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$this</span>->setting['log_file'<span style="color: #000000;">])){ self</span>::<span style="color: #800080;">$log_file</span> = <span style="color: #800080;">$this</span>->setting['log_file'<span style="color: #000000;">]; </span><span style="color: #0000ff;">unset</span>(<span style="color: #800080;">$this</span>->setting['log_file'<span style="color: #000000;">]); } </span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$this</span>->setting['max_connection'<span style="color: #000000;">])){ </span><span style="color: #800080;">$this</span>->max_connection = <span style="color: #800080;">$this</span>->setting['max_connection'<span style="color: #000000;">]; </span><span style="color: #0000ff;">unset</span>(<span style="color: #800080;">$this</span>->setting['max_connection'<span style="color: #000000;">]); } </span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$this</span>->setting['smtp_host'<span style="color: #000000;">])){ </span><span style="color: #800080;">$this</span>->smtp_host = <span style="color: #800080;">$this</span>->setting['smtp_host'<span style="color: #000000;">]; </span><span style="color: #0000ff;">unset</span>(<span style="color: #800080;">$this</span>->setting['smtp_host'<span style="color: #000000;">]); } </span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$this</span>->setting['smtp_port'<span style="color: #000000;">])){ </span><span style="color: #800080;">$this</span>->smtp_port = <span style="color: #800080;">$this</span>->setting['smtp_port'<span style="color: #000000;">]; </span><span style="color: #0000ff;">unset</span>(<span style="color: #800080;">$this</span>->setting['smtp_port'<span style="color: #000000;">]); } </span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$this</span>->setting['smtp_user'<span style="color: #000000;">])){ </span><span style="color: #800080;">$this</span>->smtp_user = <span style="color: #800080;">$this</span>->setting['smtp_user'<span style="color: #000000;">]; </span><span style="color: #0000ff;">unset</span>(<span style="color: #800080;">$this</span>->setting['smtp_user'<span style="color: #000000;">]); } </span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$this</span>->setting['smtp_pass'<span style="color: #000000;">])){ </span><span style="color: #800080;">$this</span>->smtp_pass = <span style="color: #800080;">$this</span>->setting['smtp_pass'<span style="color: #000000;">]; </span><span style="color: #0000ff;">unset</span>(<span style="color: #800080;">$this</span>->setting['smtp_pass'<span style="color: #000000;">]); } </span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$this</span>->setting['smtp_from'<span style="color: #000000;">])){ </span><span style="color: #800080;">$this</span>->smtp_from = <span style="color: #800080;">$this</span>->setting['smtp_from'<span style="color: #000000;">]; </span><span style="color: #0000ff;">unset</span>(<span style="color: #800080;">$this</span>->setting['smtp_from'<span style="color: #000000;">]); } </span><span style="color: #800080;">$this</span>->server->set(<span style="color: #800080;">$this</span>-><span style="color: #000000;">setting); </span><span style="color: #800080;">$version</span> = <span style="color: #008080;">explode</span>('.',<span style="color: #000000;"> SWOOLE_VERSION); </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$version</span>[0] == 1 && <span style="color: #800080;">$version</span>[1] 1e7c438afd183dbf6e975c8350587f3dserver->on('start',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onMasterStart'<span style="color: #000000;">)); </span><span style="color: #800080;">$this</span>->server->on('shutdown',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onMasterStop'<span style="color: #000000;">)); </span><span style="color: #800080;">$this</span>->server->on('ManagerStart',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onManagerStart'<span style="color: #000000;">)); </span><span style="color: #800080;">$this</span>->server->on('ManagerStop',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onManagerStop'<span style="color: #000000;">)); </span><span style="color: #800080;">$this</span>->server->on('WorkerStart',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onWorkerStart'<span style="color: #000000;">)); </span><span style="color: #800080;">$this</span>->server->on('WorkerStop',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onWorkerStop'<span style="color: #000000;">)); </span><span style="color: #800080;">$this</span>->server->on('WorkerError',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onWorkerError'<span style="color: #000000;">)); </span><span style="color: #800080;">$this</span>->server->on('Connect',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onConnect'<span style="color: #000000;">)); </span><span style="color: #800080;">$this</span>->server->on('Receive',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onReceive'<span style="color: #000000;">)); </span><span style="color: #800080;">$this</span>->server->on('Close',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onClose'<span style="color: #000000;">)); </span><span style="color: #800080;">$this</span>->server-><span style="color: #000000;">start(); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> <span style="color: #008080;">log</span>(<span style="color: #800080;">$msg</span>,<span style="color: #800080;">$level</span> = 'debug',<span style="color: #800080;">$flush</span> = <span style="color: #0000ff;">false</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">if</span><span style="color: #000000;">(DEBUG_ON){ </span><span style="color: #800080;">$log</span> = <span style="color: #008080;">date</span>('Y-m-d H:i:s').' ['.<span style="color: #800080;">$level</span>."]\t" .<span style="color: #800080;">$msg</span>."\n"<span style="color: #000000;">; </span><span style="color: #0000ff;">if</span>(!<span style="color: #0000ff;">empty</span>(self::<span style="color: #800080;">$log_file</span><span style="color: #000000;">)){ </span><span style="color: #800080;">$debug_file</span> = <span style="color: #008080;">dirname</span>(self::<span style="color: #800080;">$log_file</span>).'/debug.log'<span style="color: #000000;">; </span><span style="color: #008080;">file_put_contents</span>(<span style="color: #800080;">$debug_file</span>, <span style="color: #800080;">$log</span>,<span style="color: #000000;">FILE_APPEND); </span><span style="color: #0000ff;">if</span>(<span style="color: #008080;">filesize</span>(<span style="color: #800080;">$debug_file</span>) > 10485760){<span style="color: #008000;">//</span><span style="color: #008000;">10M</span> <span style="color: #008080;">unlink</span>(<span style="color: #800080;">$debug_file</span><span style="color: #000000;">); } } </span><span style="color: #0000ff;">echo</span> <span style="color: #800080;">$log</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$level</span> != 'debug'<span style="color: #000000;">){ </span><span style="color: #008000;">//</span><span style="color: #008000;">日志记录</span> <span style="color: #800080;">$this</span>->queue[] = <span style="color: #008080;">date</span>('Y-m-d H:i:s')."\t[".<span style="color: #800080;">$level</span>."]\t".<span style="color: #800080;">$msg</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">if</span>(<span style="color: #008080;">count</span>(<span style="color: #800080;">$this</span>->queue)>10 && !<span style="color: #0000ff;">empty</span>(self::<span style="color: #800080;">$log_file</span>) || <span style="color: #800080;">$flush</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">if</span> (<span style="color: #008080;">filesize</span>(self::<span style="color: #800080;">$log_file</span>) > 209715200){ <span style="color: #008000;">//</span><span style="color: #008000;">200M</span> <span style="color: #008080;">rename</span>(self::<span style="color: #800080;">$log_file</span>,self::<span style="color: #800080;">$log_file</span>.'.'.<span style="color: #008080;">date</span>('His'<span style="color: #000000;">)); } </span><span style="color: #800080;">$logs</span> = ''<span style="color: #000000;">; </span><span style="color: #0000ff;">foreach</span> (<span style="color: #800080;">$this</span>->queue <span style="color: #0000ff;">as</span> <span style="color: #800080;">$q</span><span style="color: #000000;">){ </span><span style="color: #800080;">$logs</span> .= <span style="color: #800080;">$q</span>."\n"<span style="color: #000000;">; } </span><span style="color: #008080;">file_put_contents</span>(self::<span style="color: #800080;">$log_file</span>, <span style="color: #800080;">$logs</span>,<span style="color: #000000;">FILE_APPEND); </span><span style="color: #800080;">$this</span>->queue = <span style="color: #0000ff;">array</span><span style="color: #000000;">(); } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> shutdown(){ </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span>->server-><span style="color: #000000;">shutdown(); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> close(<span style="color: #800080;">$fd</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span>->server->close(<span style="color: #800080;">$fd</span><span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> send(<span style="color: #800080;">$fd</span>,<span style="color: #800080;">$data</span><span style="color: #000000;">){ </span><span style="color: #800080;">$data</span> = <span style="color: #008080;">strtr</span>(<span style="color: #800080;">$data</span>,<span style="color: #0000ff;">array</span>("\n" => "", "\0" => "", "\r" => ""<span style="color: #000000;">)); </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>("[P --> C]\t" . <span style="color: #800080;">$data</span><span style="color: #000000;">); </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span>->server->send(<span style="color: #800080;">$fd</span>,<span style="color: #800080;">$data</span>.self::<span style="color: #000000;">EOF); } </span><span style="color: #008000;">/*</span><span style="color: #008000;">+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 事件回调 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++</span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onMasterStart(<span style="color: #800080;">$serv</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">global</span> <span style="color: #800080;">$argv</span><span style="color: #000000;">; swoole_set_process_name(</span>'php '.<span style="color: #800080;">$argv</span>[0].': master -host='.<span style="color: #800080;">$this</span>->host.' -port='.<span style="color: #800080;">$this</span>-><span style="color: #000000;">port); </span><span style="color: #0000ff;">if</span>(!<span style="color: #0000ff;">empty</span>(<span style="color: #800080;">$this</span>->setting['pid_file'<span style="color: #000000;">])){ </span><span style="color: #008080;">file_put_contents</span>(self::<span style="color: #800080;">$pid_file</span>, <span style="color: #800080;">$serv</span>-><span style="color: #000000;">master_pid); } </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Master started.'<span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onMasterStop(<span style="color: #800080;">$serv</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">if</span> (!<span style="color: #0000ff;">empty</span>(<span style="color: #800080;">$this</span>->setting['pid_file'<span style="color: #000000;">])){ </span><span style="color: #008080;">unlink</span>(self::<span style="color: #800080;">$pid_file</span><span style="color: #000000;">); } </span><span style="color: #800080;">$this</span>->shm-><span style="color: #000000;">delete(); </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Master stop.'<span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onManagerStart(<span style="color: #800080;">$serv</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">global</span> <span style="color: #800080;">$argv</span><span style="color: #000000;">; swoole_set_process_name(</span>'php '.<span style="color: #800080;">$argv</span>[0].': manager'<span style="color: #000000;">); </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Manager started.'<span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onManagerStop(<span style="color: #800080;">$serv</span><span style="color: #000000;">){ </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Manager stop.'<span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onWorkerStart(<span style="color: #800080;">$serv</span>,<span style="color: #800080;">$worker_id</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">global</span> <span style="color: #800080;">$argv</span><span style="color: #000000;">; </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$worker_id</span> >= <span style="color: #800080;">$serv</span>->setting['worker_num'<span style="color: #000000;">]) { swoole_set_process_name(</span>"php {<span style="color: #800080;">$argv</span>[0]}: worker [task]"<span style="color: #000000;">); } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> { swoole_set_process_name(</span>"php {<span style="color: #800080;">$argv</span>[0]}: worker [{<span style="color: #800080;">$worker_id</span>}]"<span style="color: #000000;">); } </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>("Worker {<span style="color: #800080;">$worker_id</span>} started."<span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onWorkerStop(<span style="color: #800080;">$serv</span>,<span style="color: #800080;">$worker_id</span><span style="color: #000000;">){ </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>("Worker {<span style="color: #800080;">$worker_id</span>} stop."<span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onWorkerError(<span style="color: #800080;">$serv</span>,<span style="color: #800080;">$worker_id</span>,<span style="color: #800080;">$worker_pid</span>,<span style="color: #800080;">$exit_code</span><span style="color: #000000;">){ </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>("Worker {<span style="color: #800080;">$worker_id</span>} error:{<span style="color: #800080;">$exit_code</span>}."<span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onConnect(<span style="color: #800080;">$serv</span>,<span style="color: #800080;">$fd</span>,<span style="color: #800080;">$from_id</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">if</span>(<span style="color: #008080;">count</span>(<span style="color: #800080;">$this</span>->server->connections) 47a89b7a2c122dfa8d80fd30a58109ec<span style="color: #000000;">max_connection){ </span><span style="color: #800080;">$info</span> = <span style="color: #800080;">$this</span>->getConnectionInfo(<span style="color: #800080;">$fd</span><span style="color: #000000;">); </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$this</span>->isIpAllow(<span style="color: #800080;">$info</span>['remote_ip'<span style="color: #000000;">])){ </span><span style="color: #008000;">//</span><span style="color: #008000;">建立服务器连接</span> <span style="color: #800080;">$cli</span> = <span style="color: #0000ff;">new</span> Client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC); <span style="color: #008000;">//</span><span style="color: #008000;">异步非阻塞</span> <span style="color: #800080;">$cli</span>->on('connect',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onServerConnect'<span style="color: #000000;">)); </span><span style="color: #800080;">$cli</span>->on('receive',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onServerReceive'<span style="color: #000000;">)); </span><span style="color: #800080;">$cli</span>->on('error',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onServerError'<span style="color: #000000;">)); </span><span style="color: #800080;">$cli</span>->on('close',<span style="color: #0000ff;">array</span>(<span style="color: #800080;">$this</span>,'onServerClose'<span style="color: #000000;">)); </span><span style="color: #800080;">$cli</span>->fd = <span style="color: #800080;">$fd</span><span style="color: #000000;">; </span><span style="color: #800080;">$ip</span> = <span style="color: #008080;">gethostbyname</span>(<span style="color: #800080;">$this</span>-><span style="color: #000000;">smtp_host); </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$cli</span>->connect(<span style="color: #800080;">$ip</span>,<span style="color: #800080;">$this</span>->smtp_port) !== <span style="color: #0000ff;">false</span><span style="color: #000000;">){ </span><span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>] = <span style="color: #800080;">$cli</span><span style="color: #000000;">; }</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{ </span><span style="color: #800080;">$this</span>->close(<span style="color: #800080;">$fd</span><span style="color: #000000;">); </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Cannot connect to SMTP server. Connection #'.<span style="color: #800080;">$fd</span>.' close.'<span style="color: #000000;">); } }</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{ </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Blocked clinet connection, IP deny : '.<span style="color: #800080;">$info</span>['remote_ip'],'warn'<span style="color: #000000;">); </span><span style="color: #800080;">$this</span>->server->close(<span style="color: #800080;">$fd</span><span style="color: #000000;">); </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Connection #'.<span style="color: #800080;">$fd</span>.' close.'<span style="color: #000000;">); } }</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{ </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Blocked clinet connection, too many connections.','warn'<span style="color: #000000;">); </span><span style="color: #800080;">$this</span>->server->close(<span style="color: #800080;">$fd</span><span style="color: #000000;">); } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onReceive(<span style="color: #800080;">$serv</span>,<span style="color: #800080;">$fd</span>,<span style="color: #800080;">$from_id</span>,<span style="color: #800080;">$recv_data</span><span style="color: #000000;">){ </span><span style="color: #800080;">$info</span> = <span style="color: #800080;">$this</span>->getConnectionInfo(<span style="color: #800080;">$fd</span><span style="color: #000000;">); </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>("[P 4bf69159e86f72b49e912e89ff24ef84server->send(<span style="color: #800080;">$fd</span>,"502 Not implemented".self::<span style="color: #000000;">EOF); </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>("[P --> C]\t502 Not implemented"<span style="color: #000000;">); }</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{ </span><span style="color: #008000;">//</span><span style="color: #008000;">重置登陆验证 </span> <span style="color: #0000ff;">if</span>(<span style="color: #008080;">preg_match</span>('/^AUTH\s+LOGIN(.*)/', <span style="color: #800080;">$recv_data</span>,<span style="color: #800080;">$m</span><span style="color: #000000;">)){ </span><span style="color: #800080;">$m</span>[1] = <span style="color: #008080;">trim</span>(<span style="color: #800080;">$m</span>[1<span style="color: #000000;">]); </span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">empty</span>(<span style="color: #800080;">$m</span>[1<span style="color: #000000;">])){ </span><span style="color: #008000;">//</span><span style="color: #008000;">只发送AUTH LOGIN 接下来将发送用户名</span> <span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]->user = <span style="color: #800080;">$this</span>-><span style="color: #000000;">smtp_user; }</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{ </span><span style="color: #800080;">$recv_data</span> = 'AUTH LOGIN '.<span style="color: #008080;">base64_encode</span>(<span style="color: #800080;">$this</span>->smtp_user).self::<span style="color: #000000;">EOF; </span><span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]->pass = <span style="color: #800080;">$this</span>-><span style="color: #000000;">smtp_pass; } }</span><span style="color: #0000ff;">else</span><span style="color: #000000;">{ </span><span style="color: #0000ff;">if</span>(<span style="color: #008080;">preg_match</span>('/^HELO.*|^EHLO.*/', <span style="color: #800080;">$recv_data</span><span style="color: #000000;">)){ </span><span style="color: #800080;">$recv_data</span> = 'HELO '.<span style="color: #800080;">$this</span>->smtp_host.self::<span style="color: #000000;">EOF; } </span><span style="color: #008000;">//</span><span style="color: #008000;">重置密码</span> <span style="color: #0000ff;">if</span>(!<span style="color: #0000ff;">empty</span>(<span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]-><span style="color: #000000;">pass)){ </span><span style="color: #800080;">$recv_data</span> = <span style="color: #008080;">base64_encode</span>(<span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]->pass).self::<span style="color: #000000;">EOF; </span><span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]->pass = ''<span style="color: #000000;">; } </span><span style="color: #008000;">//</span><span style="color: #008000;">重置用户名</span> <span style="color: #0000ff;">if</span>(!<span style="color: #0000ff;">empty</span>(<span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]-><span style="color: #000000;">user)){ </span><span style="color: #800080;">$recv_data</span> = <span style="color: #008080;">base64_encode</span>(<span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]->user).self::<span style="color: #000000;">EOF; </span><span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]->user = ''<span style="color: #000000;">; </span><span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]->pass = <span style="color: #800080;">$this</span>-><span style="color: #000000;">smtp_pass; } </span><span style="color: #008000;">//</span><span style="color: #008000;">重置mail from</span> <span style="color: #0000ff;">if</span>(<span style="color: #008080;">preg_match</span>('/^MAIL\s+FROM:.*/', <span style="color: #800080;">$recv_data</span><span style="color: #000000;">)){ </span><span style="color: #800080;">$recv_data</span> = 'MAIL FROM:7730fadb62ecf373a6f652e40d6cd8c0smtp_from.'>'.self::<span style="color: #000000;">EOF; } } </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]-><span style="color: #000000;">isConnected()){ </span><span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]->send(<span style="color: #800080;">$recv_data</span><span style="color: #000000;">); </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>("[P --> S]\t".<span style="color: #008080;">trim</span>(<span style="color: #800080;">$recv_data</span><span style="color: #000000;">)); } } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onClose(<span style="color: #800080;">$serv</span>,<span style="color: #800080;">$fd</span>,<span style="color: #800080;">$from_id</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span><span style="color: #000000;">])){ </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]-><span style="color: #000000;">isConnected()){ </span><span style="color: #800080;">$this</span>->connection[<span style="color: #800080;">$fd</span>]-><span style="color: #000000;">close(); </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Connection on SMTP server close.'<span style="color: #000000;">); } } </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Connection #'.<span style="color: #800080;">$fd</span>.' close. Flush the logs.','debug',<span style="color: #0000ff;">true</span><span style="color: #000000;">); } </span><span style="color: #008000;">/*</span><span style="color: #008000;">--------------------------------------------- * * 服务器连接事件回调 * ----------------------------------------------</span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onServerConnect(<span style="color: #800080;">$cli</span><span style="color: #000000;">){ </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Connected to SMTP server.'<span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onServerReceive(<span style="color: #800080;">$cli</span>,<span style="color: #800080;">$data</span><span style="color: #000000;">){ </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>("[P 289e824d28d0676efd417da19e58cbb4server->send(<span style="color: #800080;">$cli</span>->fd,<span style="color: #800080;">$data</span><span style="color: #000000;">)){ </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>("[P --> C]\t".<span style="color: #008080;">trim</span>(<span style="color: #800080;">$data</span><span style="color: #000000;">)); } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onServerError(<span style="color: #800080;">$cli</span><span style="color: #000000;">){ </span><span style="color: #800080;">$this</span>->server->close(<span style="color: #800080;">$cli</span>-><span style="color: #000000;">fd); </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Connection on SMTP server error: '.<span style="color: #800080;">$cli</span>->errCode.' '.socket_strerror(<span style="color: #800080;">$cli</span>->errCode),'warn'<span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> onServerClose(<span style="color: #800080;">$cli</span><span style="color: #000000;">){ </span><span style="color: #800080;">$this</span>-><span style="color: #008080;">log</span>('Connection on SMTP server close.'<span style="color: #000000;">); </span><span style="color: #800080;">$this</span>->server->close(<span style="color: #800080;">$cli</span>-><span style="color: #000000;">fd); } </span><span style="color: #008000;">/*</span><span style="color: #008000;">* * IP地址过滤 * @param unknown $ip * @return boolean </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> isIpAllow(<span style="color: #800080;">$ip</span><span style="color: #000000;">){ </span><span style="color: #800080;">$pass</span> = <span style="color: #0000ff;">false</span><span style="color: #000000;">; </span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$this</span>->setting['ip']['allow'<span style="color: #000000;">])){ </span><span style="color: #0000ff;">foreach</span> (<span style="color: #800080;">$this</span>->setting['ip']['allow'] <span style="color: #0000ff;">as</span> <span style="color: #800080;">$addr</span><span style="color: #000000;">){ </span><span style="color: #800080;">$pattern</span> = '/'.<span style="color: #008080;">str_replace</span>('*','\d+',<span style="color: #008080;">str_replace</span>('.', '\.', <span style="color: #800080;">$addr</span>)).'/'<span style="color: #000000;">; </span><span style="color: #0000ff;">if</span>(<span style="color: #008080;">preg_match</span>(<span style="color: #800080;">$pattern</span>, <span style="color: #800080;">$ip</span>) && !<span style="color: #0000ff;">empty</span>(<span style="color: #800080;">$addr</span><span style="color: #000000;">)){ </span><span style="color: #800080;">$pass</span> = <span style="color: #0000ff;">true</span><span style="color: #000000;">; </span><span style="color: #0000ff;">break</span><span style="color: #000000;">; } } } </span><span style="color: #0000ff;">if</span>(<span style="color: #800080;">$pass</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">if</span>(<span style="color: #0000ff;">isset</span>(<span style="color: #800080;">$this</span>->setting['ip']['deny'<span style="color: #000000;">])){ </span><span style="color: #0000ff;">foreach</span> (<span style="color: #800080;">$this</span>->setting['ip']['deny'] <span style="color: #0000ff;">as</span> <span style="color: #800080;">$addr</span><span style="color: #000000;">){ </span><span style="color: #800080;">$pattern</span> = '/'.<span style="color: #008080;">str_replace</span>('*','\d+',<span style="color: #008080;">str_replace</span>('.', '\.', <span style="color: #800080;">$addr</span>)).'/'<span style="color: #000000;">; </span><span style="color: #0000ff;">if</span>(<span style="color: #008080;">preg_match</span>(<span style="color: #800080;">$pattern</span>, <span style="color: #800080;">$ip</span>) && !<span style="color: #0000ff;">empty</span>(<span style="color: #800080;">$addr</span><span style="color: #000000;">)){ </span><span style="color: #800080;">$pass</span> = <span style="color: #0000ff;">false</span><span style="color: #000000;">; </span><span style="color: #0000ff;">break</span><span style="color: #000000;">; } } } } </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$pass</span><span style="color: #000000;">; } }</span><span style="color: #0000ff;">class</span> Client <span style="color: #0000ff;">extends</span><span style="color: #000000;"> swoole_client{ </span><span style="color: #008000;">/*</span><span style="color: #008000;">* * 记录当前连接 * @var unknown </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span> <span style="color: #800080;">$fd</span><span style="color: #000000;"> ; </span><span style="color: #0000ff;">public</span> <span style="color: #800080;">$user</span> = ''<span style="color: #000000;">; </span><span style="color: #008000;">/*</span><span style="color: #008000;">* * smtp登陆密码 * @var unknown </span><span style="color: #008000;">*/</span> <span style="color: #0000ff;">public</span> <span style="color: #800080;">$pass</span> = ''<span style="color: #000000;">;}</span>
配置文件例子:
<span style="color: #008000;">/*</span><span style="color: #008000;">* * 运行配置</span><span style="color: #008000;">*/</span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">array</span><span style="color: #000000;">( </span>'worker_num' => 12, 'log_file' => BASE_PATH.'/logs/proxyserver.log', 'pid_file' => BASE_PATH.'/logs/proxyserver.pid', 'heartbeat_idle_time' => 300, 'heartbeat_check_interval' => 60, 'max_connection' => 50, <br> //配置真实的smtp信息 'smtp_host' => '', 'smtp_port' => 25, 'smtp_user' => '', 'smtp_pass' => '', 'smtp_from' => '', 'ip' => <span style="color: #0000ff;">array</span><span style="color: #000000;">( </span>'allow' => <span style="color: #0000ff;">array</span>('192.168.0.*'), 'deny' => <span style="color: #0000ff;">array</span>('192.168.10.*','192.168.100.*'),<span style="color: #000000;"> ));</span>
运行例子:
defined('BASE_PATH') or define('BASE_PATH', __DIR__);defined('DEBUG_ON') or define('DEBUG_ON', true);//服务器配置require BASE_PATH.'/CSmtpProxy.php';$settings = require BASE_PATH.'/conf/config.php';CSmtpProxy::setPidFile($settings['pid_file']);CSmtpProxy::start(function(){ global $settings; $serv = new CSmtpProxy('0.0.0.0', 25); $serv->daemonize(); $serv->run($settings);});
应用配置:
smtp host: 192.168.0.* //指定smtpproxy 运行的服务器IP。
port: 25
user: xxxx //随意填写
pass: xxxx //随意填写
from: [email protected] // 根据情况填写
——————————————————————————————————————————————————————
存在的问题:
1、不支持ssl模式;
2、应用的from还是要填写正确,否则发出的邮件发件人会显示错误。