PHP 进行统一邮箱登陆的代理实现(swoole),
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还是要填写正确,否则发出的邮件发件人会显示错误。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











이 기사는 공식 웹 사이트에 액세스하는 것부터 등록 정보 작성, 등록 정보 작성, 확인, 사용자 계약 읽기 등의 모든 단계를 다루는 자세한 Gate.io 등록 자습서를 제공합니다.이 기사는 또한 2 차 검증을 설정하고 실제 인증을 설정하고 초보자의 디지털 자산 거래를 시작하는 등의 성공적인 등록을 성공적으로 등록한 후 보안 조치를 강조합니다.

JWT는 주로 신분증 인증 및 정보 교환을 위해 당사자간에 정보를 안전하게 전송하는 데 사용되는 JSON을 기반으로 한 개방형 표준입니다. 1. JWT는 헤더, 페이로드 및 서명의 세 부분으로 구성됩니다. 2. JWT의 작업 원칙에는 세 가지 단계가 포함됩니다. JWT 생성, JWT 확인 및 Parsing Payload. 3. PHP에서 인증에 JWT를 사용하면 JWT를 생성하고 확인할 수 있으며 사용자 역할 및 권한 정보가 고급 사용에 포함될 수 있습니다. 4. 일반적인 오류에는 서명 검증 실패, 토큰 만료 및 대형 페이로드가 포함됩니다. 디버깅 기술에는 디버깅 도구 및 로깅 사용이 포함됩니다. 5. 성능 최적화 및 모범 사례에는 적절한 시그니처 알고리즘 사용, 타당성 기간 설정 합리적,

정적 바인딩 (정적 : :)는 PHP에서 늦은 정적 바인딩 (LSB)을 구현하여 클래스를 정의하는 대신 정적 컨텍스트에서 호출 클래스를 참조 할 수 있습니다. 1) 구문 분석 프로세스는 런타임에 수행됩니다. 2) 상속 관계에서 통화 클래스를 찾아보십시오. 3) 성능 오버 헤드를 가져올 수 있습니다.

이 기사는 초보자에게 자세한 GATE.IO 등록 자습서를 제공하여 공식 웹 사이트 액세스, 정보 작성, 신원 확인 등을 포함하여 등록 프로세스를 점차적으로 완료하도록 안내하고 등록 후 보안 설정을 강조합니다. 또한이 기사는 Binance, Ouyi 및 참깨 오픈 도어와 같은 다른 교환을 언급했습니다. 초보자는 자신의 요구에 따라 올바른 플랫폼을 선택하고 독자들에게 디지털 자산 투자가 위험하고 합리적으로 투자해야한다는 것을 상기시키는 것이 좋습니다.

Docker 환경을 사용할 때 Docker 환경에 Extensions를 설치하기 위해 PECL을 사용하여 오류의 원인 및 솔루션. 종종 일부 두통이 발생합니다 ...

Laravel의 이메일을 처리하지 않는 방법은 LaRavel을 사용하는 것입니다.

Laravel 이메일 전송이 실패 할 때 반환 코드를 얻는 방법. Laravel을 사용하여 응용 프로그램을 개발할 때 종종 확인 코드를 보내야하는 상황이 발생합니다. 그리고 실제로 ...

PHP의 마법 방법은 무엇입니까? PHP의 마법 방법은 다음과 같습니다. 1. \ _ \ _ Construct, 객체를 초기화하는 데 사용됩니다. 2. \ _ \ _ 파괴, 자원을 정리하는 데 사용됩니다. 3. \ _ \ _ 호출, 존재하지 않는 메소드 호출을 처리하십시오. 4. \ _ \ _ get, 동적 속성 액세스를 구현하십시오. 5. \ _ \ _ Set, 동적 속성 설정을 구현하십시오. 이러한 방법은 특정 상황에서 자동으로 호출되어 코드 유연성과 효율성을 향상시킵니다.
