Home >Backend Development >PHP Tutorial >PHP proxy implementation for unified mailbox login (swoole), _PHP tutorial

PHP proxy implementation for unified mailbox login (swoole), _PHP tutorial

WBOY
WBOYOriginal
2016-07-12 09:04:091073browse

PHP 进行统一邮箱登陆的代理实现(swoole),

  在工作的过程中,经常会有很多应用有发邮件的需求,这个时候需要在每个应用中配置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还是要填写正确,否则发出的邮件发件人会显示错误。

 

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/1073816.htmlTechArticlePHP 进行统一邮箱登陆的代理实现(swoole), 在工作的过程中,经常会有很多应用有发邮件的需求,这个时候需要在每个应用中配置smtp服务...
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn