-
Notifications
You must be signed in to change notification settings - Fork 591
/
Plugin.php
455 lines (410 loc) · 17.1 KB
/
Plugin.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
<?php
namespace TypechoPlugin\CommentNotifier;
use Typecho\Plugin\PluginInterface;
use Typecho\Widget\Helper\Form;
use Typecho\Widget\Helper\Form\Element\Text;
use Typecho\Widget\Helper\Form\Element\Checkbox;
use Typecho\Widget\Helper\Form\Element\Radio;
use Typecho\Widget\Helper\Layout;
use Widget\Options;
use Widget\Base\Comments;
use Typecho\Db;
use Typecho\Date;
use Utils\Helper;
/**
* typecho 评论通过时发送邮件提醒,要求typecho1.2.0及以上,项目地址<a href="https://github.com/jrotty/CommentNotifier" target="_blank">https://github.com/jrotty/CommentNotifier</a>
* @package CommentNotifier
* @author 泽泽社长
* @version 1.2.9
* @link http://blog.zezeshe.com
*/
require dirname(__FILE__) . '/PHPMailer/PHPMailer.php';
require dirname(__FILE__) . '/PHPMailer/SMTP.php';
require dirname(__FILE__) . '/PHPMailer/Exception.php';
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
class Plugin implements PluginInterface
{
/** @var string 控制菜单链接 */
public static $panel = 'CommentNotifier/console.php';
/**
* 激活插件方法,如果激活失败,直接抛出异常
*
* @access public
* @return string
*/
public static function activate()
{
\Typecho\Plugin::factory('Widget_Feedback')->finishComment = __CLASS__ . '::resendMail'; // 前台提交评论完成接口
\Typecho\Plugin::factory('Widget_Comments_Edit')->finishComment = __CLASS__ . '::resendMail'; // 后台操作评论完成接口
\Typecho\Plugin::factory('Widget_Comments_Edit')->mark = __CLASS__ . '::mark'; // 后台标记评论状态完成接口
\Typecho\Plugin::factory('Widget_Service')->refinishComment = __CLASS__ . '::refinishComment';//异步接口
Helper::addPanel(1, self::$panel, '评论邮件提醒', '评论邮件提醒控制台', 'administrator');
return _t('请配置邮箱SMTP选项!');
}
/**
* 禁用插件方法,如果禁用失败,直接抛出异常
*
* @static
* @access public
* @return void
*/
public static function deactivate()
{
Helper::removePanel(1, self::$panel);
}
/**
* 获取插件配置面板
*
* @access public
* @param Form $form 配置面板
* @return void
*/
public static function config(Form $form)
{
// 记录log
$log = new Checkbox('log', ['log' => _t('记录日志')], 'log', _t('记录日志'), _t('启用后将当前目录生成一个log.txt 注:目录需有写入权限'));
$form->addInput($log);
$yibu = new Radio('yibu', array('0' => _t('不启用'), '1' => _t('启用'),), '0', _t('异步提交'), _t('注意:如你博客使用ajax提交评论请不要开启此项否则可能导致邮件无法发送!'));
$form->addInput($yibu);
$layout = new Layout();
$layout->html(_t('<h3>邮件服务配置:</h3>'));
$form->addItem($layout);
// SMTP服务地址
$STMPHost = new Text('STMPHost', NULL, 'smtp.qq.com', _t('SMTP服务器地址'), _t('如:smtp.163.com,smtp.gmail.com,smtp.exmail.qq.com,smtp.sohu.com,smtp.sina.com'));
$form->addInput($STMPHost->addRule('required', _t('SMTP服务器地址必填!')));
// SMTP用户名
$SMTPUserName = new Text('SMTPUserName', NULL, NULL, _t('SMTP登录用户'), _t('SMTP登录用户名,一般为邮箱地址'));
$form->addInput($SMTPUserName->addRule('required', _t('SMTP登录用户必填!')));
// 发件邮箱
$from = new Text('from', NULL, NULL, _t('SMTP邮箱地址'), _t('请填写用于发送邮件的邮箱,一般与SMTP登录用户名一致'));
$form->addInput($from->addRule('required', _t('发件邮箱必填!')));
// SMTP密码
$description = _t('一般为邮箱登录密码, 有特殊如: QQ邮箱有独立的SMTP密码. 可参考: ');
$description .= '<a href="https://service.mail.qq.com/cgi-bin/help?subtype=1&&no=1001256&&id=28" target="_blank">QQ邮箱</a> ';
$description .= '<a href="https://mailhelp.aliyun.com/freemail/detail.vm?knoId=6521875" target="_blank">阿里邮箱</a> ';
$description .= '<a href="https://support.office.com/zh-cn/article/outlook-com-%E7%9A%84-pop%E3%80%81imap-%E5%92%8C-smtp-%E8%AE%BE%E7%BD%AE-d088b986-291d-42b8-9564-9c414e2aa040?ui=zh-CN&rs=zh-CN&ad=CN" target="_blank">Outlook邮箱</a> ';
$description .= '<a href="http://help.sina.com.cn/comquestiondetail/view/160/" target="_blank">新浪邮箱</a> ';
$SMTPPassword = new Text('SMTPPassword', NULL, NULL, _t('SMTP登录密码'), $description);
$form->addInput($SMTPPassword->addRule('required', _t('SMTP登录密码必填!')));
// 服务器安全模式
$SMTPSecure = new Radio('SMTPSecure', array('' => _t('无安全加密'), 'ssl' => _t('SSL加密'), 'tls' => _t('TLS加密')), '', _t('SMTP加密模式'));
$form->addInput($SMTPSecure);
// SMTP server port
$SMTPPort = new Text('SMTPPort', NULL, '25', _t('SMTP服务端口'), _t('默认25 SSL为465 TLS为587'));
$form->addInput($SMTPPort);
$layout = new Layout();
$layout->html(_t('<h3>邮件信息配置:</h3>'));
$form->addItem($layout);
// 发件人姓名
$fromName = new Text('fromName', NULL, NULL, _t('发件人姓名'), _t('发件人姓名'));
$form->addInput($fromName->addRule('required', _t('发件人姓名必填!')));
// 收件邮箱
$adminfrom = new Text('adminfrom', NULL, NULL, _t('站长收件邮箱'), _t('遇到待审核评论或文章作者邮箱为空时,评论提醒会发送到此邮箱地址!'));
$form->addInput($adminfrom->addRule('required', _t('收件邮箱必填!')));
// 模板
$template = new Text('template', NULL, 'default', _t('邮件模板选择'), _t('该项请不要在插件设置里填写,请到邮件模板列表页面选择模板启动!'));
$template->setAttribute('class', 'hidden');
$form->addInput($template);
}
/**
* 个人用户的配置面板
*
* @access public
* @param Form $form
* @return void
*/
public static function personalConfig(Form $form)
{
}
/**
* 插件实现方法
*
* @access public
* @return void
*/
public static function render()
{
}
/**
* @param $comment
* @return array
* @throws Typecho_Db_Exception
* 获取上级评论人
*/
public static function getParent($comment): array
{
$recipients = [];
$parent = Helper::widgetById('comments', $comment->parent);
$recipients = [
'name' => $parent->author,
'mail' => $parent->mail,
];
return $recipients;
}
/**
* @param $comment
* @return array
* @throws Typecho_Db_Exception
* 获取文章作者邮箱
*/
public static function getAuthor($comment): array
{
$CommentNotifier = Options::alloc()->plugin('CommentNotifier');
$recipients = [];
$db = Db::get();
$ae = $db->fetchRow($db->select()->from('table.users')->where('table.users.uid=?', $comment->ownerId));
if (empty($ae['mail'])) {
$ae['screenName'] = $CommentNotifier->fromName;
$ae['mail'] = $CommentNotifier->adminfrom;
}
$recipients = [
'name' => $ae['screenName'],
'mail' => $ae['mail'],
];
// 查询
return $recipients;
}
/**
* @param $comment
* @param Widget_Comments_Edit $edit
* @param $status
* @throws Typecho_Db_Exception
* @throws Typecho_Plugin_Exception
* 在后台标记评论状态时的回调
*/
public static function mark($comment, $edit, $status)
{
$recipients = [];
$CommentNotifier = Options::alloc()->plugin('CommentNotifier');
$from = $CommentNotifier->adminfrom; // 站长邮箱
// 在后台标记评论状态为[approved 审核通过]时, 发信给上级评论人或作者
if ($status == 'approved') {
$type = 0;
// 如果有上级
if ($edit->parent > 0) {
$recipients[] = self::getParent($edit);//获取上级评论信息
$type = 1;
} else {
$recipients[] = self::getAuthor($edit);//获取作者信息
}
// 如果自己回复自己的评论, 不做任何操作
if ($recipients[0]['mail'] == $edit->mail) {
return;
}
// 如果上级是博主, 不做任何操作
if ($recipients[0]['mail'] == $from) {
return;
}
//邮箱为空时就不发邮件
if (empty($recipients[0]['mail'])) {
return;
}
self::sendMail($edit, $recipients, $type);
}
}
/**
* @param Widget_Comments_Edit|Widget_Feedback $comment
* @throws Typecho_Db_Exception
* @throws Typecho_Plugin_Exception
* 评论/回复时的回调
*/
public static function refinishComment($comment)
{
$CommentNotifier = Options::alloc()->plugin('CommentNotifier');
$from = $CommentNotifier->adminfrom; // 站长邮箱
$fromName = $CommentNotifier->fromName; // 发件人
$recipients = [];
// 审核通过
if ($comment->status == 'approved') {
$type = 0;//0为无父级评论
// 不需要发信给博主
if ($comment->authorId != $comment->ownerId && $comment->mail != $from) {
$recipients[] = self::getAuthor($comment);//收到新评论后发送给文章作者
}
// 如果有上级
if ($comment->parent) {
$type = 1;//1为有父级评论
// 查询上级评论人
$parent = self::getParent($comment);//获取上级评论者邮箱
// 如果上级是博主和自己回复自己, 不需要发信
if ($parent['mail'] != $from && $parent['mail'] != $comment->mail) {
$recipients[] = $parent;
}
}
self::sendMail($comment, $recipients, $type);
} else {
// 如果所有评论必须经过审核, 通知博主审核评论
$recipients[] = ['name' => $fromName, 'mail' => $from];
self::sendMail($comment, $recipients, 2);//2为待审核评论
}
}
/**
* @param Widget_Comments_Edit|Widget_Feedback $comment
* @param array $recipients
* @param $type
*/
private static function sendMail($comment, array $recipients, $type)
{
if (empty($recipients)) return; // 没有收信人
try {
// 获取系统配置选项
$options = Options::alloc();
// 获取插件配置
$CommentNotifier = $options->plugin('CommentNotifier');
$from = $CommentNotifier->from; // 发件邮箱
$fromName = $CommentNotifier->fromName; // 发件人
// Server settings
$mail = new PHPMailer(false);
$mail->CharSet = PHPMailer::CHARSET_UTF8;
$mail->Encoding = PHPMailer::ENCODING_BASE64;
$mail->isSMTP();
$mail->Host = $CommentNotifier->STMPHost; // SMTP 服务地址
$mail->SMTPAuth = true; // 开启认证
$mail->Username = $CommentNotifier->SMTPUserName; // SMTP 用户名
$mail->Password = $CommentNotifier->SMTPPassword; // SMTP 密码
$mail->SMTPSecure = $CommentNotifier->SMTPSecure; // SMTP 加密类型 'ssl' or 'tls'.
$mail->Port = $CommentNotifier->SMTPPort; // SMTP 端口
$mail->setFrom($from, $fromName);
foreach ($recipients as $recipient) {
$mail->addAddress($recipient['mail'], $recipient['name']); // 发件人
}
if ($type == 1) {
$mail->Subject = '你在[' . $comment->title . ']的评论有了新的回复';
} elseif ($type == 2) {
$mail->Subject = '文章《' . $comment->title . '》有条待审评论';
} else {
$mail->Subject = '你的《' . $comment->title . '》文章有了新的评论';
}
$mail->isHTML(); // 邮件为HTML格式
// 邮件内容
$content = self::mailBody($comment, $options, $type);
$mail->Body = $content;
$mail->send();
// 记录日志
if ($CommentNotifier->log) {
$at = date('Y-m-d H:i:s');
if ($mail->isError()) {
$data = $at . ' ' . $mail->ErrorInfo; // 记录发信失败的日志
} else { // 记录发信成功的日志
$recipientNames = $recipientMails = '';
foreach ($recipients as $recipient) {
$recipientNames .= $recipient['name'] . ', ';
$recipientMails .= $recipient['mail'] . ', ';
}
$data = PHP_EOL . $at . ' 发送成功! ';
$data .= ' 发件人:' . $fromName;
$data .= ' 发件邮箱:' . $from;
$data .= ' 接收人:' . $recipientNames;
$data .= ' 接收邮箱:' . $recipientMails . PHP_EOL;
}
$fileName = dirname(__FILE__) . '/log.txt';
file_put_contents($fileName, $data, FILE_APPEND);
}
} catch (Exception $e) {
$fileName = dirname(__FILE__) . '/log.txt';
$str = "\nerror time: " . date('Y-m-d H:i:s') . "\n";
file_put_contents($fileName, $str, FILE_APPEND);
file_put_contents($fileName, $e, FILE_APPEND);
}
}
/**
* @param $comment
* @param $options
* @param $type
* @return string
* 很朴素的邮件风格
*/
private static function mailBody($comment, $options, $type): string
{
$commentAt = new Date($comment->created);
$commentAt = $commentAt->format('Y-m-d H:i:s');
$commentText = htmlspecialchars($comment->text);
$html = 'owner';
if ($type == 1) {
$html = 'guest';
} elseif ($type == 2) {
$html = 'notice';
}
$Pmail = '';
$Pname = '';
$Ptext = '';
if ($comment->parent) {
$parent = Helper::widgetById('comments', $comment->parent);
$Pmail = $parent->mail;
$Pname = $parent->author;
$Ptext = $parent->text;
}
$content = self::getTemplate($html);
$template = Options::alloc()->plugin('CommentNotifier')->template;
$search = array(
'{title}',//文章标题
'{time}',//评论发出时间
'{commentText}',//评论内容
'{author}',//评论人昵称
'{mail}',//评论者邮箱
'{permalink}',//评论楼层链接
'{siteUrl}',//网站地址
'{siteTitle}',//网站标题
'{Pname}',//父级评论昵称
'{Ptext}',//父级评论内容
'{Pmail}',//父级评论邮箱
'{url}',//当前模板文件夹路径
);
$replace = array(
$comment->title,
$commentAt,
$commentText,
$comment->author,
$comment->mail,
$comment->permalink,
$options->siteUrl,
$options->title,
$Pname,
$Ptext,
$Pmail,
Options::alloc()->pluginUrl . '/CommentNotifier/template/' . $template,
);
return str_replace($search, $replace, $content);
}
/**
* 获取评论模板
*
* @param template owner 为博主 guest 为访客
* @return false|string
*/
private static function getTemplate($template = 'owner')
{
$template .= '.html';
$templateDir = self::configStr('template', 'default');
$filePath = dirname(__FILE__) . '/template/' . $templateDir . '/' . $template;
if (!file_exists($filePath)) {//如果模板文件缺失就调用根目录下的default文件夹中用于垫底的模板
$filePath = dirname(__FILE__) . 'template/default/' . $template;
}
return file_get_contents($filePath);
}
public static function resendMail($comment)
{
if(Options::alloc()->plugin('CommentNotifier')->yibu==1){
Helper::requestService('refinishComment', $comment);
}else{
self::refinishComment($comment);
}
}
/**
* 从 Widget_Options 对象获取 Typecho 选项值(文本型)
* @param string $key 选项 Key
* @param mixed $default 默认值
* @param string $method 测空值方法
* @return string
*/
public static function configStr(string $key, $default = '', string $method = 'empty'): string
{
$value = Helper::options()->plugin('CommentNotifier')->$key;
if ($method === 'empty') {
return empty($value) ? $default : $value;
} else {
return call_user_func($method, $value) ? $default : $value;
}
}
}