内容已更新到: https://loveyu.org/3811.html
先挖个坑放在这里,回去的路上好好想想。
事情是这样的,现在评论的时候有个邮件发送过程,这个步骤太慢了,得想个什么办法解决。难道得弄个异步队列么?好好考虑下,明天实现下。
挖坑结束,采用类似RPC的形式来加快处理流程。通过一个插件来替换wp_mail()的函数,对最后的一步send()操作进行拦截,然后把将PHPmailer对象存储到数据库中,调用远程服务,程序返回,然后开始邮件发送操作。
替换wp_mail()函数
函数主要包含了几个功能,其一替换原函数,其二添加对象到数据库,其三修改状态,其四通知RPC服务(最重要为此步)
if(!function_exists('wp_mail')) :/**
* 该函数为对原始函数的覆盖函数
* @param string|array $to 收信人
* @param string $subject 邮件标题
* @param string $message 邮件正文
* @param string $headers 头信息
* @param array $attachments 附件列表
* @return bool
*/{
function wp_mail($to, $subject, $message, $headers = '', $attachments = array()){
$atts = apply_filters('wp_mail', compact('to', 'subject', 'message', 'headers', 'attachments'));
//..........................原始文件为wp-include/pluggable.php wp_mail
//$phpmailer->Send();//从这里开始替换
//将对象存入数据库
$status = quick_mail_save($insert_id, $phpmailer, $to, $subject);
if(!$status){
try{
if($phpmailer->send()){
quick_mail_set_flag($insert_id, 5);
return true;
} else{
return false;
}
} catch(Exception $ex){
return false;
}
}
return true;
}
}
endif;
/**
* 启用数据库前对表的创建操作
*/
function quick_mail_active(){
/**
* @var WPDB $wpdb
*/
global $wpdb;
$wpdb->query("DROP TABLE IF EXISTS `{$wpdb->prefix}quick_mail`");
$wpdb->query("CREATE TABLE `{$wpdb->prefix}quick_mail` (
`qm_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`qm_subject` varchar(255) NOT NULL COMMENT '邮件主题',
`qm_time` int(10) unsigned NOT NULL COMMENT '发送时间',
`qm_to` varchar(255) NOT NULL COMMENT '收信人',
`qm_obj` text NOT NULL COMMENT 'phpmailer 序列化对象',
`qm_status` tinyint(3) unsigned DEFAULT '0' COMMENT '状态,0为未执行状态,1为执行状态,2为完成状态, 3为发送失败, 4为发送异常,5直接发送成功',
PRIMARY KEY (`qm_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;");
}
/**
* 设置邮件的状态
* @param int $id 邮件ID
* @param int $status 邮件状态 0-5
* @return bool 是否设置成功
*/
function quick_mail_set_flag($id, $status){
$id = (int)$id;
if($id < 1){
return false;
}
/**
* @var WPDB $wpdb
*/
global $wpdb;
$rt = $wpdb->update("{$wpdb->prefix}quick_mail", ['qm_status' => $status], ['qm_id' => $id]);
return $rt > 0;
}
/**
* 将邮件信息保存到数据库中
* @param int $insert_id
* @param PHPMailer $obj
* @param string $to 邮件发送的对象
* @param string $title 邮件标题
* @return bool 是否成功发送,如果失败会返回原函数继续执行
*/
function quick_mail_save(&$insert_id, PHPMailer $obj, $to, $title){
if(is_array($to)){
$to = implode(",", $to);
}
$insert_id = NULL;
/**
* @var WPDB $wpdb
*/
global $wpdb;
$ret = $wpdb->insert("{$wpdb->prefix}quick_mail", [
'qm_subject' => $title,
'qm_to' => $to,
'qm_time' => time(),
'qm_obj' => base64_encode(serialize($obj))
]);
if(!$ret){
return false;
}
$insert_id = $wpdb->insert_id;
return $wpdb->insert_id > 0 && quick_mail_notify($wpdb->insert_id);
}
/**
* 通知邮件服务有新邮件需要发送
* @param string $id
* @return bool
*/
function quick_mail_notify($id){
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if(!$socket){
return false;
}
if(!socket_connect($socket, "127.0.0.1", "27889")){
return false;
}
if(!socket_write($socket, "{$id}")){
socket_close($socket);
return false;
}
$flag = false;
$buff = socket_read($socket, 1024); //服务返回的状态特别短,因此一次读取是足够的
$buff = strtolower(trim($buff));
if($buff == "ok"){
$flag = true;
}
socket_close($socket);
return $flag;
}
register_activation_hook(__FILE__, 'quick_mail_active');//插件激活操作
* 该函数为对原始函数的覆盖函数
* @param string|array $to 收信人
* @param string $subject 邮件标题
* @param string $message 邮件正文
* @param string $headers 头信息
* @param array $attachments 附件列表
* @return bool
*/{
function wp_mail($to, $subject, $message, $headers = '', $attachments = array()){
$atts = apply_filters('wp_mail', compact('to', 'subject', 'message', 'headers', 'attachments'));
//..........................原始文件为wp-include/pluggable.php wp_mail
//$phpmailer->Send();//从这里开始替换
//将对象存入数据库
$status = quick_mail_save($insert_id, $phpmailer, $to, $subject);
if(!$status){
try{
if($phpmailer->send()){
quick_mail_set_flag($insert_id, 5);
return true;
} else{
return false;
}
} catch(Exception $ex){
return false;
}
}
return true;
}
}
endif;
/**
* 启用数据库前对表的创建操作
*/
function quick_mail_active(){
/**
* @var WPDB $wpdb
*/
global $wpdb;
$wpdb->query("DROP TABLE IF EXISTS `{$wpdb->prefix}quick_mail`");
$wpdb->query("CREATE TABLE `{$wpdb->prefix}quick_mail` (
`qm_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`qm_subject` varchar(255) NOT NULL COMMENT '邮件主题',
`qm_time` int(10) unsigned NOT NULL COMMENT '发送时间',
`qm_to` varchar(255) NOT NULL COMMENT '收信人',
`qm_obj` text NOT NULL COMMENT 'phpmailer 序列化对象',
`qm_status` tinyint(3) unsigned DEFAULT '0' COMMENT '状态,0为未执行状态,1为执行状态,2为完成状态, 3为发送失败, 4为发送异常,5直接发送成功',
PRIMARY KEY (`qm_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;");
}
/**
* 设置邮件的状态
* @param int $id 邮件ID
* @param int $status 邮件状态 0-5
* @return bool 是否设置成功
*/
function quick_mail_set_flag($id, $status){
$id = (int)$id;
if($id < 1){
return false;
}
/**
* @var WPDB $wpdb
*/
global $wpdb;
$rt = $wpdb->update("{$wpdb->prefix}quick_mail", ['qm_status' => $status], ['qm_id' => $id]);
return $rt > 0;
}
/**
* 将邮件信息保存到数据库中
* @param int $insert_id
* @param PHPMailer $obj
* @param string $to 邮件发送的对象
* @param string $title 邮件标题
* @return bool 是否成功发送,如果失败会返回原函数继续执行
*/
function quick_mail_save(&$insert_id, PHPMailer $obj, $to, $title){
if(is_array($to)){
$to = implode(",", $to);
}
$insert_id = NULL;
/**
* @var WPDB $wpdb
*/
global $wpdb;
$ret = $wpdb->insert("{$wpdb->prefix}quick_mail", [
'qm_subject' => $title,
'qm_to' => $to,
'qm_time' => time(),
'qm_obj' => base64_encode(serialize($obj))
]);
if(!$ret){
return false;
}
$insert_id = $wpdb->insert_id;
return $wpdb->insert_id > 0 && quick_mail_notify($wpdb->insert_id);
}
/**
* 通知邮件服务有新邮件需要发送
* @param string $id
* @return bool
*/
function quick_mail_notify($id){
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if(!$socket){
return false;
}
if(!socket_connect($socket, "127.0.0.1", "27889")){
return false;
}
if(!socket_write($socket, "{$id}")){
socket_close($socket);
return false;
}
$flag = false;
$buff = socket_read($socket, 1024); //服务返回的状态特别短,因此一次读取是足够的
$buff = strtolower(trim($buff));
if($buff == "ok"){
$flag = true;
}
socket_close($socket);
return $flag;
}
register_activation_hook(__FILE__, 'quick_mail_active');//插件激活操作
Python 实现服务功能
py不怎么熟,就基本没怎么写注释,相对还是比较简单的。唯一的不足就是不知道啥情况日志文件死活不输出。当然这里并没有使用Python进行邮件发送,当然要发送也绝对是可以的,只是感觉没什么必要而已。利用现有的PHPmailer更方便。
import socket
import threading
import datetime
import os
BUF_SIZE = 1024
PHP_SCRIPT = "wordpress\\quick_mail.php" ###PHP执行程序
def write_log(msg):
time = datetime.datetime.now()
time = time.strftime('%Y-%m-%d %H:%M:%S')
print("[%s] %s" % (time, msg))
class RunPHP(threading.Thread):
def __init__(self, client, address):
threading.Thread.__init__(self)
self.client = client
self.address = address
def send_mail(self, qm_id):
write_log("%s:%s run script: %s" % (self.address[0], self.address[1], qm_id))
write_log(
"%s:%s output: %s" % (self.address[0], self.address[1], os.popen("php %s %s" % (PHP_SCRIPT, qm_id)).read()))
def run(self):
flag = False
data = self.client.recv(BUF_SIZE)
qm_id = 0
if data:
qm_id = int(bytes.decode(data, "utf-8"))
if qm_id > 0:
flag = True
if flag:
self.client.send('ok'.encode())
else:
self.client.send('error'.encode())
self.client.close()
if qm_id > 0:
self.send_mail(qm_id)
class QuickMail(threading.Thread):
def __init__(self, ip, port):
threading.Thread.__init__(self)
self.port = port
self.ip = ip
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind((ip, port))
self.socket.listen(10)
def run(self):
write_log("service startup on %s:%s" % (self.ip, self.port))
while True:
client, address = self.socket.accept()
RunPHP(client, address).start()
lst = QuickMail("127.0.0.1", 27889)
lst.start()
import threading
import datetime
import os
BUF_SIZE = 1024
PHP_SCRIPT = "wordpress\\quick_mail.php" ###PHP执行程序
def write_log(msg):
time = datetime.datetime.now()
time = time.strftime('%Y-%m-%d %H:%M:%S')
print("[%s] %s" % (time, msg))
class RunPHP(threading.Thread):
def __init__(self, client, address):
threading.Thread.__init__(self)
self.client = client
self.address = address
def send_mail(self, qm_id):
write_log("%s:%s run script: %s" % (self.address[0], self.address[1], qm_id))
write_log(
"%s:%s output: %s" % (self.address[0], self.address[1], os.popen("php %s %s" % (PHP_SCRIPT, qm_id)).read()))
def run(self):
flag = False
data = self.client.recv(BUF_SIZE)
qm_id = 0
if data:
qm_id = int(bytes.decode(data, "utf-8"))
if qm_id > 0:
flag = True
if flag:
self.client.send('ok'.encode())
else:
self.client.send('error'.encode())
self.client.close()
if qm_id > 0:
self.send_mail(qm_id)
class QuickMail(threading.Thread):
def __init__(self, ip, port):
threading.Thread.__init__(self)
self.port = port
self.ip = ip
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind((ip, port))
self.socket.listen(10)
def run(self):
write_log("service startup on %s:%s" % (self.ip, self.port))
while True:
client, address = self.socket.accept()
RunPHP(client, address).start()
lst = QuickMail("127.0.0.1", 27889)
lst.start()
对邮件队列查询并发送邮件
这个就相对容易看懂了,有时候我相对纠结,为啥不用WP的配置文件。那货加载了一大堆东西,感觉用不着,所以就不用管它了,每次直接PDO连接,方便快捷省事。
<?php
/**
* 快速邮件发送执行脚本
*/
$qm_id = isset($argv[1]) ? $argv[1] : NULL;
if($qm_id === NULL){
die("param error");
}
$qm_id = (int)$qm_id;
if($qm_id < 1){
die("mail id read error!");
}
try{
$pdo = new PDO("mysql:host=127.0.0.1;dbname=worpress", "root", "123456");
}catch (Exception $ex){
die($ex->getMessage());
}
$stmt = $pdo->prepare("select `qm_obj` from `wp_quick_mail` where `qm_id`={$qm_id} and `qm_status`=0");
if(!$stmt->execute()){
die("read database error");
}
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
set_flag($pdo, $qm_id, 1);
if(!isset($data[0]['qm_obj'])){
die("read mail error:" . $qm_id);
}
require_once __DIR__ . '/wp-includes/class-phpmailer.php';
require_once __DIR__ . '/wp-includes/class-smtp.php';
/**
* @var $mail PHPMailer
*/
$mail = unserialize(base64_decode($data[0]['qm_obj']));
try{
if($mail->send()){
set_flag($pdo, $qm_id, 2);
die("send ok:" . $qm_id);
} else{
set_flag($pdo, $qm_id, 3);
die("send fail:" . $qm_id);
}
} catch(Exception $ex){
set_flag($pdo, $qm_id, 4);
die($ex->getMessage());
}
function set_flag(PDO $pdo, $qm_id, $status){
$status = (int)$status;
$qm_id = (int)$qm_id;
$stmt = $pdo->prepare("update `wp_quick_mail` set `qm_status` = {$status} where `qm_id`={$qm_id}");
if(!$stmt->execute()){
die("mail set status error.ID:" . $qm_id . ",status:" . $status);
}
}
/**
* 快速邮件发送执行脚本
*/
$qm_id = isset($argv[1]) ? $argv[1] : NULL;
if($qm_id === NULL){
die("param error");
}
$qm_id = (int)$qm_id;
if($qm_id < 1){
die("mail id read error!");
}
try{
$pdo = new PDO("mysql:host=127.0.0.1;dbname=worpress", "root", "123456");
}catch (Exception $ex){
die($ex->getMessage());
}
$stmt = $pdo->prepare("select `qm_obj` from `wp_quick_mail` where `qm_id`={$qm_id} and `qm_status`=0");
if(!$stmt->execute()){
die("read database error");
}
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
set_flag($pdo, $qm_id, 1);
if(!isset($data[0]['qm_obj'])){
die("read mail error:" . $qm_id);
}
require_once __DIR__ . '/wp-includes/class-phpmailer.php';
require_once __DIR__ . '/wp-includes/class-smtp.php';
/**
* @var $mail PHPMailer
*/
$mail = unserialize(base64_decode($data[0]['qm_obj']));
try{
if($mail->send()){
set_flag($pdo, $qm_id, 2);
die("send ok:" . $qm_id);
} else{
set_flag($pdo, $qm_id, 3);
die("send fail:" . $qm_id);
}
} catch(Exception $ex){
set_flag($pdo, $qm_id, 4);
die($ex->getMessage());
}
function set_flag(PDO $pdo, $qm_id, $status){
$status = (int)$status;
$qm_id = (int)$qm_id;
$stmt = $pdo->prepare("update `wp_quick_mail` set `qm_status` = {$status} where `qm_id`={$qm_id}");
if(!$stmt->execute()){
die("mail set status error.ID:" . $qm_id . ",status:" . $status);
}
}
运行
最后,后台运行python程序,然后启用插件,一切就绪,不用担心失败。失败了会自动调用原有的程序,还是很靠谱的。
每次直接PDO连接所有的数据库缓存设置就全跪了。。
不过这玩意好像也不需要缓存啊= =
一个小站用不到PDO缓存之类的吧。这个是用异步的形式发送的邮件,也可以用队列的形式。缓存是减少数据库连接和缓解磁盘压力吧。
你居然在,看这是14年的文了,现在还能用么
话说我现在还在用这个东西,我博客程序14年之后就没怎么更新过了,唉
那就是可以?你WP版本号是?
最新 4.5.3
我真日了狗了,为什么你博客邮件发出来我这里IMAP客户端都是秒提示,其他所有邮件都没这么快的.
能和 WP-SMTP 一起用么?而且我看Github代码好像没有写SMTP服务器信息的位置?
我真日了狗了,为什么你博客邮件发出来我这里IMAP客户端都是秒提示,其他所有邮件都没这么快的
QQ企业邮箱,SMTP,或许你的腾讯的服务
奇怪。。我现在用的不是TX的
代码还是太多, 看的头疼啊。
代码发你邮箱了,适量修改就OK了
谢谢了。。
越来越厉害了。。 呵
还要用插件,我用的是代码,慢点没多少关系。
我要的是加快邮件发送速度,这里用插件才能实现部分功能
我的站现在不显示图片 也无法上传图片 愁啊~
怎么说呢,这是个比较神奇的问题。看看是不是网站配置问题
都改晕了 真不知该怎么改
贴出来看看
这样的 http://image16.poco.cn/mypoco/myphoto/20141104/10/17489809920141104100657032.png
http://image16.poco.cn/mypoco/myphoto/20141104/10/17489809920141104100712080.png?791x845_130
其实我想说的是服务器的配置,还有你看看图片地址,看能否单独访问
当然不可以 要是简单 我就不必这么纠结~
还有,你网站现在似乎不能访问,是不是和这点有关,再其次图片是不是用了cdn或其他缓存插件
缓存啥的早就删除了~ 客服正在重新安装
还有客服那就不用操心了
评论楼层你设置了多少
大概是10层吧,我手机上看已经混乱了
最少20层
每页15条顶级评论,回复不限,最大嵌套8层
可以设置再大点 我的站终于满血复活了
恭喜。不过在大点就得考虑下了,现在我还得兼容移动端的,有点不好弄。
今天该实现了吧~
还真没有,刚想到办法而已!
那整理整理思绪,然后在实现吧。
搞定!!!
我空间邮件功能禁止的
很多虚拟空间都这样吧
挖坑要埋了自己么?
好想法,不过坑太浅,闷不死