Home >Backend Development >PHP Tutorial >PHP proxy implementation for unified mailbox login (swoole), _PHP tutorial
在工作的过程中,经常会有很多应用有发邮件的需求,这个时候需要在每个应用中配置smtp服务器。一旦公司调整了smtp服务器的配置,比如修改了密码等,这个时候对于维护的人员来说要逐一修改应用中smtp的配置。这样的情况虽然不多见,但遇上了还是很头痛的一件事情。
知道了问题,解决起来就有了方向。于是就有了自己开发一个简单的smtp代理的想法,这个代理主要的功能(参照问题)主要是:
1.接受指定IP应用的smtp请求;
2.应用不需要知道smtp的用户和密码;
3.转发应用的smtp请求。
开发的环境:Linux,php(swoole);
代码如下:
<?<span>php </span><span>/*</span><span>* * * SMTP Proxy Server * @author Terry Zhang, 2015-11-13 * * @version 1.0 * * 注意:本程序只能运行在cli模式,且需要扩展Swoole 1.7.20+的支持。 * * Swoole的源代码及安装请参考 https://github.com/swoole/swoole-src/ * * 本程序的使用场景: * * 在多个分散的系统中使用同一的邮件地址进行系统邮件发送时,一旦邮箱密码修改,则要修改每个系统的邮件配置参数。 * 同时,在每个系统中配置邮箱参数,使得邮箱的密码容易外泄。 * * 通过本代理进行邮件发送的客户端,可以随便指定用户名和密码。 * * </span><span>*/</span> <span>//</span><span>error_reporting(0);</span> <span>defined</span>('DEBUG_ON') or <span>define</span>('DEBUG_ON', <span>false</span><span>); </span><span>//</span><span>主目录</span> <span>defined</span>('BASE_PATH') or <span>define</span>('BASE_PATH',<span> __DIR__); </span><span>class</span><span> CSmtpProxy{ </span><span>//</span><span>软件版本</span> <span>const</span> VERSION = '1.0'<span>; </span><span>const</span> EOF = "\r\n"<span>; </span><span>public</span> <span>static</span> <span>$software</span> = "SMTP-Proxy-Server"<span>; </span><span>private</span> <span>static</span> <span>$server_mode</span> =<span> SWOOLE_PROCESS; </span><span>private</span> <span>static</span> <span>$pid_file</span><span>; </span><span>private</span> <span>static</span> <span>$log_file</span><span>; </span><span>private</span> <span>$smtp_host</span> = 'localhost'<span>; </span><span>private</span> <span>$smtp_port</span> = 25<span>; </span><span>private</span> <span>$smtp_user</span> = ''<span>; </span><span>private</span> <span>$smtp_pass</span> = ''<span>; </span><span>private</span> <span>$smtp_from</span> = ''<span>; </span><span>//</span><span>待写入文件的日志队列(缓冲区)</span> <span>private</span> <span>$queue</span> = <span>array</span><span>(); </span><span>public</span> <span>$host</span> = '0.0.0.0'<span>; </span><span>public</span> <span>$port</span> = 25<span>; </span><span>public</span> <span>$setting</span> = <span>array</span><span>(); </span><span>//</span><span>最大连接数</span> <span>public</span> <span>$max_connection</span> = 50<span>; </span><span>/*</span><span>* * @var swoole_server </span><span>*/</span> <span>protected</span> <span>$server</span><span>; </span><span>protected</span> <span>$connection</span> = <span>array</span><span>(); </span><span>public</span> <span>static</span> <span>function</span> setPidFile(<span>$pid_file</span><span>){ self</span>::<span>$pid_file</span> = <span>$pid_file</span><span>; } </span><span>public</span> <span>static</span> <span>function</span> start(<span>$startFunc</span><span>){ </span><span>if</span>(!<span>extension_loaded</span>('swoole'<span>)){ </span><span>exit</span>("Require extension `swoole`.\n"<span>); } </span><span>$pid_file</span> = self::<span>$pid_file</span><span>; </span><span>$server_pid</span> = 0<span>; </span><span>if</span>(<span>is_file</span>(<span>$pid_file</span><span>)){ </span><span>$server_pid</span> = <span>file_get_contents</span>(<span>$pid_file</span><span>); } </span><span>global</span> <span>$argv</span><span>; </span><span>if</span>(<span>empty</span>(<span>$argv</span>[1<span>])){ goto usage; }</span><span>elseif</span>(<span>$argv</span>[1] == 'reload'<span>){ </span><span>if</span> (<span>empty</span>(<span>$server_pid</span><span>)){ </span><span>exit</span>("SMTP Proxy Server is not running\n"<span>); } posix_kill(</span><span>$server_pid</span>,<span> SIGUSR1); </span><span>exit</span><span>; }</span><span>elseif</span> (<span>$argv</span>[1] == 'stop'<span>){ </span><span>if</span> (<span>empty</span>(<span>$server_pid</span><span>)){ </span><span>exit</span>("SMTP Proxy is not running\n"<span>); } posix_kill(</span><span>$server_pid</span>,<span> SIGTERM); </span><span>exit</span><span>; }</span><span>elseif</span> (<span>$argv</span>[1] == 'start'<span>){ </span><span>//</span><span>已存在ServerPID,并且进程存在</span> <span>if</span> (!<span>empty</span>(<span>$server_pid</span>) and posix_kill(<span>$server_pid</span>,(int) 0<span>)){ </span><span>exit</span>("SMTP Proxy is already running.\n"<span>); } </span><span>//</span><span>启动服务器</span> <span>$startFunc</span><span>(); }</span><span>else</span><span>{ usage</span>: <span>exit</span>("Usage: php {<span>$argv</span>[0]} start|stop|reload\n"<span>); } } </span><span>public</span> <span>function</span> __construct(<span>$host</span>,<span>$port</span><span>){ </span><span>$flag</span> =<span> SWOOLE_SOCK_TCP; </span><span>$this</span>->server = <span>new</span> swoole_server(<span>$host</span>,<span>$port</span>,self::<span>$server_mode</span>,<span>$flag</span><span>); </span><span>$this</span>->host = <span>$host</span><span>; </span><span>$this</span>->port = <span>$port</span><span>; </span><span>$this</span>->setting = <span>array</span><span>( </span>'backlog' => 128, 'dispatch_mode' => 2,<span> ); } </span><span>public</span> <span>function</span><span> daemonize(){ </span><span>$this</span>->setting['daemonize'] = 1<span>; } </span><span>public</span> <span>function</span> getConnectionInfo(<span>$fd</span><span>){ </span><span>return</span> <span>$this</span>->server->connection_info(<span>$fd</span><span>); } </span><span>/*</span><span>* * 启动服务进程 * @param array $setting * @throws Exception </span><span>*/</span> <span>public</span> <span>function</span> run(<span>$setting</span> = <span>array</span><span>()){ </span><span>$this</span>->setting = <span>array_merge</span>(<span>$this</span>->setting,<span>$setting</span><span>); </span><span>//</span><span>不使用swoole的默认日志</span> <span>if</span>(<span>isset</span>(<span>$this</span>->setting['log_file'<span>])){ self</span>::<span>$log_file</span> = <span>$this</span>->setting['log_file'<span>]; </span><span>unset</span>(<span>$this</span>->setting['log_file'<span>]); } </span><span>if</span>(<span>isset</span>(<span>$this</span>->setting['max_connection'<span>])){ </span><span>$this</span>->max_connection = <span>$this</span>->setting['max_connection'<span>]; </span><span>unset</span>(<span>$this</span>->setting['max_connection'<span>]); } </span><span>if</span>(<span>isset</span>(<span>$this</span>->setting['smtp_host'<span>])){ </span><span>$this</span>->smtp_host = <span>$this</span>->setting['smtp_host'<span>]; </span><span>unset</span>(<span>$this</span>->setting['smtp_host'<span>]); } </span><span>if</span>(<span>isset</span>(<span>$this</span>->setting['smtp_port'<span>])){ </span><span>$this</span>->smtp_port = <span>$this</span>->setting['smtp_port'<span>]; </span><span>unset</span>(<span>$this</span>->setting['smtp_port'<span>]); } </span><span>if</span>(<span>isset</span>(<span>$this</span>->setting['smtp_user'<span>])){ </span><span>$this</span>->smtp_user = <span>$this</span>->setting['smtp_user'<span>]; </span><span>unset</span>(<span>$this</span>->setting['smtp_user'<span>]); } </span><span>if</span>(<span>isset</span>(<span>$this</span>->setting['smtp_pass'<span>])){ </span><span>$this</span>->smtp_pass = <span>$this</span>->setting['smtp_pass'<span>]; </span><span>unset</span>(<span>$this</span>->setting['smtp_pass'<span>]); } </span><span>if</span>(<span>isset</span>(<span>$this</span>->setting['smtp_from'<span>])){ </span><span>$this</span>->smtp_from = <span>$this</span>->setting['smtp_from'<span>]; </span><span>unset</span>(<span>$this</span>->setting['smtp_from'<span>]); } </span><span>$this</span>->server->set(<span>$this</span>-><span>setting); </span><span>$version</span> = <span>explode</span>('.',<span> SWOOLE_VERSION); </span><span>if</span>(<span>$version</span>[0] == 1 && <span>$version</span>[1] < 7 && <span>$version</span>[2] <20<span>){ </span><span>throw</span> <span>new</span> <span>Exception</span>('Swoole version require 1.7.20 +.'<span>); } </span><span>//</span><span>事件绑定</span> <span>$this</span>->server->on('start',<span>array</span>(<span>$this</span>,'onMasterStart'<span>)); </span><span>$this</span>->server->on('shutdown',<span>array</span>(<span>$this</span>,'onMasterStop'<span>)); </span><span>$this</span>->server->on('ManagerStart',<span>array</span>(<span>$this</span>,'onManagerStart'<span>)); </span><span>$this</span>->server->on('ManagerStop',<span>array</span>(<span>$this</span>,'onManagerStop'<span>)); </span><span>$this</span>->server->on('WorkerStart',<span>array</span>(<span>$this</span>,'onWorkerStart'<span>)); </span><span>$this</span>->server->on('WorkerStop',<span>array</span>(<span>$this</span>,'onWorkerStop'<span>)); </span><span>$this</span>->server->on('WorkerError',<span>array</span>(<span>$this</span>,'onWorkerError'<span>)); </span><span>$this</span>->server->on('Connect',<span>array</span>(<span>$this</span>,'onConnect'<span>)); </span><span>$this</span>->server->on('Receive',<span>array</span>(<span>$this</span>,'onReceive'<span>)); </span><span>$this</span>->server->on('Close',<span>array</span>(<span>$this</span>,'onClose'<span>)); </span><span>$this</span>->server-><span>start(); } </span><span>public</span> <span>function</span> <span>log</span>(<span>$msg</span>,<span>$level</span> = 'debug',<span>$flush</span> = <span>false</span><span>){ </span><span>if</span><span>(DEBUG_ON){ </span><span>$log</span> = <span>date</span>('Y-m-d H:i:s').' ['.<span>$level</span>."]\t" .<span>$msg</span>."\n"<span>; </span><span>if</span>(!<span>empty</span>(self::<span>$log_file</span><span>)){ </span><span>$debug_file</span> = <span>dirname</span>(self::<span>$log_file</span>).'/debug.log'<span>; </span><span>file_put_contents</span>(<span>$debug_file</span>, <span>$log</span>,<span>FILE_APPEND); </span><span>if</span>(<span>filesize</span>(<span>$debug_file</span>) > 10485760){<span>//</span><span>10M</span> <span>unlink</span>(<span>$debug_file</span><span>); } } </span><span>echo</span> <span>$log</span><span>; } </span><span>if</span>(<span>$level</span> != 'debug'<span>){ </span><span>//</span><span>日志记录</span> <span>$this</span>->queue[] = <span>date</span>('Y-m-d H:i:s')."\t[".<span>$level</span>."]\t".<span>$msg</span><span>; } </span><span>if</span>(<span>count</span>(<span>$this</span>->queue)>10 && !<span>empty</span>(self::<span>$log_file</span>) || <span>$flush</span><span>){ </span><span>if</span> (<span>filesize</span>(self::<span>$log_file</span>) > 209715200){ <span>//</span><span>200M</span> <span>rename</span>(self::<span>$log_file</span>,self::<span>$log_file</span>.'.'.<span>date</span>('His'<span>)); } </span><span>$logs</span> = ''<span>; </span><span>foreach</span> (<span>$this</span>->queue <span>as</span> <span>$q</span><span>){ </span><span>$logs</span> .= <span>$q</span>."\n"<span>; } </span><span>file_put_contents</span>(self::<span>$log_file</span>, <span>$logs</span>,<span>FILE_APPEND); </span><span>$this</span>->queue = <span>array</span><span>(); } } </span><span>public</span> <span>function</span><span> shutdown(){ </span><span>return</span> <span>$this</span>->server-><span>shutdown(); } </span><span>public</span> <span>function</span> close(<span>$fd</span><span>){ </span><span>return</span> <span>$this</span>->server->close(<span>$fd</span><span>); } </span><span>public</span> <span>function</span> send(<span>$fd</span>,<span>$data</span><span>){ </span><span>$data</span> = <span>strtr</span>(<span>$data</span>,<span>array</span>("\n" => "", "\0" => "", "\r" => ""<span>)); </span><span>$this</span>-><span>log</span>("[P --> C]\t" . <span>$data</span><span>); </span><span>return</span> <span>$this</span>->server->send(<span>$fd</span>,<span>$data</span>.self::<span>EOF); } </span><span>/*</span><span>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 事件回调 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++</span><span>*/</span> <span>public</span> <span>function</span> onMasterStart(<span>$serv</span><span>){ </span><span>global</span> <span>$argv</span><span>; swoole_set_process_name(</span>'php '.<span>$argv</span>[0].': master -host='.<span>$this</span>->host.' -port='.<span>$this</span>-><span>port); </span><span>if</span>(!<span>empty</span>(<span>$this</span>->setting['pid_file'<span>])){ </span><span>file_put_contents</span>(self::<span>$pid_file</span>, <span>$serv</span>-><span>master_pid); } </span><span>$this</span>-><span>log</span>('Master started.'<span>); } </span><span>public</span> <span>function</span> onMasterStop(<span>$serv</span><span>){ </span><span>if</span> (!<span>empty</span>(<span>$this</span>->setting['pid_file'<span>])){ </span><span>unlink</span>(self::<span>$pid_file</span><span>); } </span><span>$this</span>->shm-><span>delete(); </span><span>$this</span>-><span>log</span>('Master stop.'<span>); } </span><span>public</span> <span>function</span> onManagerStart(<span>$serv</span><span>){ </span><span>global</span> <span>$argv</span><span>; swoole_set_process_name(</span>'php '.<span>$argv</span>[0].': manager'<span>); </span><span>$this</span>-><span>log</span>('Manager started.'<span>); } </span><span>public</span> <span>function</span> onManagerStop(<span>$serv</span><span>){ </span><span>$this</span>-><span>log</span>('Manager stop.'<span>); } </span><span>public</span> <span>function</span> onWorkerStart(<span>$serv</span>,<span>$worker_id</span><span>){ </span><span>global</span> <span>$argv</span><span>; </span><span>if</span>(<span>$worker_id</span> >= <span>$serv</span>->setting['worker_num'<span>]) { swoole_set_process_name(</span>"php {<span>$argv</span>[0]}: worker [task]"<span>); } </span><span>else</span><span> { swoole_set_process_name(</span>"php {<span>$argv</span>[0]}: worker [{<span>$worker_id</span>}]"<span>); } </span><span>$this</span>-><span>log</span>("Worker {<span>$worker_id</span>} started."<span>); } </span><span>public</span> <span>function</span> onWorkerStop(<span>$serv</span>,<span>$worker_id</span><span>){ </span><span>$this</span>-><span>log</span>("Worker {<span>$worker_id</span>} stop."<span>); } </span><span>public</span> <span>function</span> onWorkerError(<span>$serv</span>,<span>$worker_id</span>,<span>$worker_pid</span>,<span>$exit_code</span><span>){ </span><span>$this</span>-><span>log</span>("Worker {<span>$worker_id</span>} error:{<span>$exit_code</span>}."<span>); } </span><span>public</span> <span>function</span> onConnect(<span>$serv</span>,<span>$fd</span>,<span>$from_id</span><span>){ </span><span>if</span>(<span>count</span>(<span>$this</span>->server->connections) <= <span>$this</span>-><span>max_connection){ </span><span>$info</span> = <span>$this</span>->getConnectionInfo(<span>$fd</span><span>); </span><span>if</span>(<span>$this</span>->isIpAllow(<span>$info</span>['remote_ip'<span>])){ </span><span>//</span><span>建立服务器连接</span> <span>$cli</span> = <span>new</span> Client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC); <span>//</span><span>异步非阻塞</span> <span>$cli</span>->on('connect',<span>array</span>(<span>$this</span>,'onServerConnect'<span>)); </span><span>$cli</span>->on('receive',<span>array</span>(<span>$this</span>,'onServerReceive'<span>)); </span><span>$cli</span>->on('error',<span>array</span>(<span>$this</span>,'onServerError'<span>)); </span><span>$cli</span>->on('close',<span>array</span>(<span>$this</span>,'onServerClose'<span>)); </span><span>$cli</span>->fd = <span>$fd</span><span>; </span><span>$ip</span> = <span>gethostbyname</span>(<span>$this</span>-><span>smtp_host); </span><span>if</span>(<span>$cli</span>->connect(<span>$ip</span>,<span>$this</span>->smtp_port) !== <span>false</span><span>){ </span><span>$this</span>->connection[<span>$fd</span>] = <span>$cli</span><span>; }</span><span>else</span><span>{ </span><span>$this</span>->close(<span>$fd</span><span>); </span><span>$this</span>-><span>log</span>('Cannot connect to SMTP server. Connection #'.<span>$fd</span>.' close.'<span>); } }</span><span>else</span><span>{ </span><span>$this</span>-><span>log</span>('Blocked clinet connection, IP deny : '.<span>$info</span>['remote_ip'],'warn'<span>); </span><span>$this</span>->server->close(<span>$fd</span><span>); </span><span>$this</span>-><span>log</span>('Connection #'.<span>$fd</span>.' close.'<span>); } }</span><span>else</span><span>{ </span><span>$this</span>-><span>log</span>('Blocked clinet connection, too many connections.','warn'<span>); </span><span>$this</span>->server->close(<span>$fd</span><span>); } } </span><span>public</span> <span>function</span> onReceive(<span>$serv</span>,<span>$fd</span>,<span>$from_id</span>,<span>$recv_data</span><span>){ </span><span>$info</span> = <span>$this</span>->getConnectionInfo(<span>$fd</span><span>); </span><span>$this</span>-><span>log</span>("[P <-- C]\t".<span>trim</span>(<span>$recv_data</span><span>)); </span><span>//</span><span>禁止使用STARTTLS</span> <span>if</span>(<span>strtoupper</span>(<span>trim</span>(<span>$recv_data</span>)) == 'STARTTLS'<span>){ </span><span>$this</span>->server->send(<span>$fd</span>,"502 Not implemented".self::<span>EOF); </span><span>$this</span>-><span>log</span>("[P --> C]\t502 Not implemented"<span>); }</span><span>else</span><span>{ </span><span>//</span><span>重置登陆验证 </span> <span>if</span>(<span>preg_match</span>('/^AUTH\s+LOGIN(.*)/', <span>$recv_data</span>,<span>$m</span><span>)){ </span><span>$m</span>[1] = <span>trim</span>(<span>$m</span>[1<span>]); </span><span>if</span>(<span>empty</span>(<span>$m</span>[1<span>])){ </span><span>//</span><span>只发送AUTH LOGIN 接下来将发送用户名</span> <span>$this</span>->connection[<span>$fd</span>]->user = <span>$this</span>-><span>smtp_user; }</span><span>else</span><span>{ </span><span>$recv_data</span> = 'AUTH LOGIN '.<span>base64_encode</span>(<span>$this</span>->smtp_user).self::<span>EOF; </span><span>$this</span>->connection[<span>$fd</span>]->pass = <span>$this</span>-><span>smtp_pass; } }</span><span>else</span><span>{ </span><span>if</span>(<span>preg_match</span>('/^HELO.*|^EHLO.*/', <span>$recv_data</span><span>)){ </span><span>$recv_data</span> = 'HELO '.<span>$this</span>->smtp_host.self::<span>EOF; } </span><span>//</span><span>重置密码</span> <span>if</span>(!<span>empty</span>(<span>$this</span>->connection[<span>$fd</span>]-><span>pass)){ </span><span>$recv_data</span> = <span>base64_encode</span>(<span>$this</span>->connection[<span>$fd</span>]->pass).self::<span>EOF; </span><span>$this</span>->connection[<span>$fd</span>]->pass = ''<span>; } </span><span>//</span><span>重置用户名</span> <span>if</span>(!<span>empty</span>(<span>$this</span>->connection[<span>$fd</span>]-><span>user)){ </span><span>$recv_data</span> = <span>base64_encode</span>(<span>$this</span>->connection[<span>$fd</span>]->user).self::<span>EOF; </span><span>$this</span>->connection[<span>$fd</span>]->user = ''<span>; </span><span>$this</span>->connection[<span>$fd</span>]->pass = <span>$this</span>-><span>smtp_pass; } </span><span>//</span><span>重置mail from</span> <span>if</span>(<span>preg_match</span>('/^MAIL\s+FROM:.*/', <span>$recv_data</span><span>)){ </span><span>$recv_data</span> = 'MAIL FROM:<'.<span>$this</span>->smtp_from.'>'.self::<span>EOF; } } </span><span>if</span>(<span>$this</span>->connection[<span>$fd</span>]-><span>isConnected()){ </span><span>$this</span>->connection[<span>$fd</span>]->send(<span>$recv_data</span><span>); </span><span>$this</span>-><span>log</span>("[P --> S]\t".<span>trim</span>(<span>$recv_data</span><span>)); } } } </span><span>public</span> <span>function</span> onClose(<span>$serv</span>,<span>$fd</span>,<span>$from_id</span><span>){ </span><span>if</span>(<span>isset</span>(<span>$this</span>->connection[<span>$fd</span><span>])){ </span><span>if</span>(<span>$this</span>->connection[<span>$fd</span>]-><span>isConnected()){ </span><span>$this</span>->connection[<span>$fd</span>]-><span>close(); </span><span>$this</span>-><span>log</span>('Connection on SMTP server close.'<span>); } } </span><span>$this</span>-><span>log</span>('Connection #'.<span>$fd</span>.' close. Flush the logs.','debug',<span>true</span><span>); } </span><span>/*</span><span>--------------------------------------------- * * 服务器连接事件回调 * ----------------------------------------------</span><span>*/</span> <span>public</span> <span>function</span> onServerConnect(<span>$cli</span><span>){ </span><span>$this</span>-><span>log</span>('Connected to SMTP server.'<span>); } </span><span>public</span> <span>function</span> onServerReceive(<span>$cli</span>,<span>$data</span><span>){ </span><span>$this</span>-><span>log</span>("[P <-- S]\t".<span>trim</span>(<span>$data</span><span>)); </span><span>if</span>(<span>$this</span>->server->send(<span>$cli</span>->fd,<span>$data</span><span>)){ </span><span>$this</span>-><span>log</span>("[P --> C]\t".<span>trim</span>(<span>$data</span><span>)); } } </span><span>public</span> <span>function</span> onServerError(<span>$cli</span><span>){ </span><span>$this</span>->server->close(<span>$cli</span>-><span>fd); </span><span>$this</span>-><span>log</span>('Connection on SMTP server error: '.<span>$cli</span>->errCode.' '.socket_strerror(<span>$cli</span>->errCode),'warn'<span>); } </span><span>public</span> <span>function</span> onServerClose(<span>$cli</span><span>){ </span><span>$this</span>-><span>log</span>('Connection on SMTP server close.'<span>); </span><span>$this</span>->server->close(<span>$cli</span>-><span>fd); } </span><span>/*</span><span>* * IP地址过滤 * @param unknown $ip * @return boolean </span><span>*/</span> <span>public</span> <span>function</span> isIpAllow(<span>$ip</span><span>){ </span><span>$pass</span> = <span>false</span><span>; </span><span>if</span>(<span>isset</span>(<span>$this</span>->setting['ip']['allow'<span>])){ </span><span>foreach</span> (<span>$this</span>->setting['ip']['allow'] <span>as</span> <span>$addr</span><span>){ </span><span>$pattern</span> = '/'.<span>str_replace</span>('*','\d+',<span>str_replace</span>('.', '\.', <span>$addr</span>)).'/'<span>; </span><span>if</span>(<span>preg_match</span>(<span>$pattern</span>, <span>$ip</span>) && !<span>empty</span>(<span>$addr</span><span>)){ </span><span>$pass</span> = <span>true</span><span>; </span><span>break</span><span>; } } } </span><span>if</span>(<span>$pass</span><span>){ </span><span>if</span>(<span>isset</span>(<span>$this</span>->setting['ip']['deny'<span>])){ </span><span>foreach</span> (<span>$this</span>->setting['ip']['deny'] <span>as</span> <span>$addr</span><span>){ </span><span>$pattern</span> = '/'.<span>str_replace</span>('*','\d+',<span>str_replace</span>('.', '\.', <span>$addr</span>)).'/'<span>; </span><span>if</span>(<span>preg_match</span>(<span>$pattern</span>, <span>$ip</span>) && !<span>empty</span>(<span>$addr</span><span>)){ </span><span>$pass</span> = <span>false</span><span>; </span><span>break</span><span>; } } } } </span><span>return</span> <span>$pass</span><span>; } } </span><span>class</span> Client <span>extends</span><span> swoole_client{ </span><span>/*</span><span>* * 记录当前连接 * @var unknown </span><span>*/</span> <span>public</span> <span>$fd</span><span> ; </span><span>public</span> <span>$user</span> = ''<span>; </span><span>/*</span><span>* * smtp登陆密码 * @var unknown </span><span>*/</span> <span>public</span> <span>$pass</span> = ''<span>; }</span>
配置文件例子:
<span>/*</span><span>* * 运行配置 </span><span>*/</span> <span>return</span> <span>array</span><span>( </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>array</span><span>( </span>'allow' => <span>array</span>('192.168.0.*'), 'deny' => <span>array</span>('192.168.10.*','192.168.100.*'),<span> ) );</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: xxxx@xxxx.com // 根据情况填写
——————————————————————————————————————————————————————
存在的问题:
1、不支持ssl模式;
2、应用的from还是要填写正确,否则发出的邮件发件人会显示错误。