用户
 找回密码
 入住 CI 中国社区
搜索
查看: 1984|回复: 0
收起左侧

[插件 Plugin] 不规矩的异步邮件队列处理插件

[复制链接]
发表于 2017-7-3 15:56:42 | 显示全部楼层 |阅读模式
本帖最后由 hyperlau 于 2017-7-3 16:02 编辑

不管是用CI的email类还是其他类,只要在php里调用smtp发邮件都会碰到需要等待发送完成才能返回的情况,用户体验非常不好,不爽,不利索。。。。
还好会perl,改了改N年前写的发邮件脚本,在php里写一条text到一个邮件队列的文本文件,然后crontab调用perl脚本来处理邮件队列,发送完成直接删掉这行,然后写日志到一个日志文本文件,没有等待,没有延迟,多开心~~
代码如下:
PHP部分:
PHP复制代码
 
<?php
class Msg {
        protected $CI;
        public function __construct()
        {
                $this->CI =& get_instance();
        }
 
        public function send_mail_q($to,$sub,$msg) {
                $this->CI->load->helper('file');
                $line='to:'.$to.'<end>sub:'.$sub.'<end>msg:'.$msg.'<end>'."\n";
                write_file('/tmp/mail_q', $line,"a");
        }
 
}
?>
 
 
复制代码

Perl部分:
PHP复制代码
 
#!/usr/bin/perl -w
use strict;
use warnings;
use Tie::File;
use File::Path qw( mkpath );
use Time::Local;
use Net::SMTP;
use Authen::SASL;
 
 
$|=1;
 
my $mail_q='/tmp/mail_q';
my $log='/tmp/mail_log';
our $MailDebug = 0;
our $MailTimeout = 30;
our $MailUser = 'abc@abc.com';
our $MailPass = 'passwod';
our $MailHost = 'smtp.exmail.qq.com';
our $MailFrom = 'abc@abc.com';
our @MailList = ();
 
$SIG{'INT'}=sub {print "Script is running!!\n"};
 
unless (-e $mail_q) {
        dielogger($log,"can't found $_!");
}
 
my $result;
tie (my @lines,'Tie::File',$mail_q) || dielogger($log,"can't tie file to \@lines !SYSTEM_MSG: $!");
for (my $i=0;$i< @lines;$i++) {
        if ($lines[$i]=~/to:(.*)\<end\>sub:(.*)\<end\>msg:(.*)\<end\>$/) {
                $result=mail_send($2,$3,$1);
                if ($result==0) {
                        $lines[$i].=" SEND OK\n";
                        logger($log,$lines[$i]);
                        delete $lines[$i];
                }
        }
}
 
sub mail_send {
        my ($MailSubject, $MailContent,$MailTo) = @_;
        my $smtp = Net::SMTP->new($MailHost, Timeout=>$MailTimeout, Debug=>$MailDebug);
        if(!$smtp) {
                dielogger($log,"Can not connect to the mail server!");
                return 1;
        } else {
                my $auth_stat = $smtp->auth($MailUser, $MailPass);
                if (!$auth_stat) {
                        dielogger($log,"Mail account authentification failed!");
                        return 2;
                } else {
                        $smtp->mail($MailFrom);
                        $smtp->to($MailTo);
                        $smtp->data();
                        $smtp->datasend("Content-Type: text/html; charset=UTF-8\n");
                        $smtp->datasend("From:" . $MailFrom . "\n");
                        $smtp->datasend("To:" . $MailTo . "\n");
                        $smtp->datasend("Subject:" . $MailSubject . "\n");
                        $smtp->datasend("\n");
                        $smtp->datasend($MailContent);
                        $smtp->dataend();
                }
                $smtp->quit();
        }
        return 0;
}
 
sub logger
{
        my ($f,$m)=@_;
        open(LOGF,">>",$f)|| die "Failed to open $f.  [\033[31mFAILED\033[0m]\n";
        my $msg=get_time() . " $m\n";
        print $msg;
        print LOGF $msg;
        close LOGF;
}
 
sub dielogger
{
        my ($f,$m)=@_;
        logger($f,$m . " ##############  QUIT  ##############\n");
        exit 1
}
 
sub get_time {
        my @time_format = (localtime())[5,4,3,2,1,0];
        $time_format[0] += 1900;
        $time_format[1] += 1;
        foreach $_(@time_format) {
                $_ = sprintf("%02d", $_);
        }
        my $cur_time = "$time_format[0]-$time_format[1]-$time_format[2] $time_format[3]:$time_format[4]:$time_format[5]";
        return($cur_time);
}
 
 
复制代码

Perl代码可以保存在/usr/local/nginx/html/app/third_party/q_mail.pl , 要注意权限,因为大部分web服务器都运行在一个牢笼用户下,要保证脚本可读可执行运行前需要安装所需的库,在shell下执行:
PHP复制代码
 
cpan Tie::File
cpan Net::SMTP
cpan Authen::SASL
 
复制代码

crontab: ( 一分钟执行一次)
PHP复制代码
 
* * * * * /usr/local/nginx/html/app/third_party/q_mail.pl &
 
复制代码

整合到自己的代码里,可以这样调用:
PHP复制代码
 
$this->load->library('msg');
$this->msg->send_mail_q('def@def.com','标题','内容');
 
复制代码


完成!

本版积分规则