项目中加邮件报警的目的是,当在项目的某个地方报了错误,它会立即发送邮件,提示报错内容,这样我们就可以第一时间去定位问题并去修复它们。
在thinkphp框架内部中有个日志处理系统,每次运行中报错日志系统会在日志文件中记录一条报错日志。
在默认情况下,日志记录通道只有File一种,只要再加一个邮件通道就可以实现邮件报警。
首先,找到config\log.php文件,添加如下配置:
<?php
// +----------------------------------------------------------------------
// | 日志设置
// +----------------------------------------------------------------------
return [
// 默认日志记录通道
'default' => 'file',
// 日志记录级别
'level' => [],
// 日志类型记录的通道
'type_channel' => [
'error' => [
'email',
'file'
],
'alert' => [
'email',
'file'
]
],
// 关闭全局日志写入
'close' => false,
// 全局日志处理 支持闭包
'processor' => null,
// 日志通道列表
'channels' => [
'file' => [
// 日志记录方式
'type' => 'File',
// 日志保存目录
'path' => '',
// 单文件日志写入
'single' => false,
// 独立日志级别
'apart_level' => ['error', 'alert'],
// 最大日志文件数量
'max_files' => 0,
// 使用JSON格式记录
'json' => false,
// 日志处理
'processor' => null,
// 关闭通道日志写入
'close' => false,
// 日志输出格式化
'format' => '[%s][%s] %s',
// 是否实时写入
'realtime_write' => false,
],
// 邮箱通道
'email' => [
'type' => \app\admin\driver\EmailDriver::class,
'realtime_write' => false,
],
],
];
安装PHPMailer
composer require phpmailer/phpmailer
新建一个app\admin\driver\EmailDriver.php文件,内容如下
<?php
namespace app\admin\driver;
use Mailer;
use think\contract\LogHandlerInterface;
use think\facade\Log;
class EmailDriver implements LogHandlerInterface
{
public function save(array $log): bool
{
$mail = new Mailer();
$tpl = file_get_contents(public_path() . 'tpl/email_tpl.html');
$logText = "<code id='code'>";
foreach ($log as $key => $value) {
foreach($value as $k => $v){
$logText .= "<span class='code-date'>[ <em>" . date("c") .
"</em> ]</span><span class='code-type'>[" . $key . "]</span><span class='code-content'>" . $v . "</span>";
}
}
$logText .= "</code>";
$content = str_replace("{{ERRORCODE}}", $logText, $tpl);
$altBody = json_encode($log, JSON_UNESCAPED_UNICODE);
$emailArr = ['xxxx@163.com', 'xxx@qq.com'];
$title = 'xxxxxxxx';
$result = $mail->send($emailArr, $title , $content, $altBody);
Log::info('发送报警邮件结果:' . json_encode($result));
return true;
}
}
上面的发送邮件地址和标题自定义
邮件模板public\tpl\email_tpl.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EMAIL</title>
<style>
* {margin: 0;padding: 0;box-sizing: border-box;}#code {font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;}pre {font-size: .875rem;line-height: 1.25rem;}.code-box {background-color: #282b35;padding: 1rem 1.8rem;font-size: 1em;margin: 1rem;overflow-x: auto;}.code-date {color: #df0002;}.code-type {color: #df0002;margin-left: 0.5rem;}.code-content {margin-left: 0.8rem;color: #939599;}
</style>
</head>
<body>
<div class="code-box">
<pre
class="hljs accesslog">{{ERRORCODE}}</pre>
</div>
</body>
</html>
在写个extend\Mailer.php扩展
<?php
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\PHPMailer;
/**
* PHP电子邮件发送扩展
*/
class Mailer {
public $mail;
public function __construct()
{
$this->mail = new PHPMailer(true);
//服务器配置
$this->mail->CharSet ="UTF-8"; //设定邮件编码
$this->mail->SMTPDebug = 0; // 调试模式输出
$this->mail->isSMTP(); // 使用SMTP
$this->mail->Host = 'smtp.163.com'; // SMTP服务器
$this->mail->SMTPAuth = true; // 允许 SMTP 认证
$this->mail->Username = 'xxxxxxxxx'; // SMTP 用户名 即邮箱的用户名
$this->mail->Password = 'xxxxxxxxx'; // SMTP 密码 部分邮箱是授权码(例如163邮箱)
$this->mail->SMTPSecure = 'ssl'; // 允许 TLS 或者ssl协议
$this->mail->Port = 465; // 服务器端口 25 或者465 具体要看邮箱服务器支持
$this->mail->setFrom('xxxxxxxxx', 'xxxxxxxxx'); //发件人
}
/**
* 发送邮件
*
* @param mixed $sendAddress 发送地址,当传数组时可以发送多个人
* @param string $subject 标题
* @param string $body 内容
* @param string $altBody 不支持HTML时显示内容
* @return void
*/
public function send($sendAddress, $subject, $body, $altBody = ''){
try {
if(is_array($sendAddress)){
foreach($sendAddress as $address){
$this->mail->addAddress($address); //收件人
}
} else {
$this->mail->addAddress($sendAddress); //收件人
}
$this->mail->isHTML(true); // 是否以HTML文档格式发送
$this->mail->Subject = $subject;
$this->mail->Body = $body;
$this->mail->AltBody = $altBody;
$this->mail->send();
return true;
} catch (Exception $e) {
return $e->getMessage();
}
}
}
里面xxxx部分需要自己配置
最后随便写个bug测试一下报警结果
邮件效果