diff --git a/.env.example b/.env.example index 673af49..8b2e916 100644 --- a/.env.example +++ b/.env.example @@ -29,7 +29,8 @@ SIMPLE_JWT_PREFIX=jwt WEB_URL=http://im.gzydong.club IMG_URL=http://im-img0.gzydong.club UPLOAD_PATH=/www/data/lumenim -IP_ADDRESS=0.0.0.0 +## 管理员邮箱 +ADMIN_EMAIL= # ---- 邮件配置 ---- MAIL_DRIVER=smtp diff --git a/app/Controller/Api/V1/AuthController.php b/app/Controller/Api/V1/AuthController.php index 1765aed..d7e9920 100644 --- a/app/Controller/Api/V1/AuthController.php +++ b/app/Controller/Api/V1/AuthController.php @@ -204,4 +204,15 @@ class AuthController extends CController return $this->response->success($data, '验证码发送成功...'); } + + /** + * 发送验证码 + * @RequestMapping(path="test", methods="get") + */ + public function test() + { + //$user = User::first(); + //$name = $user->yuanodng; + var_dump($name); + } } diff --git a/app/Exception/Handler/AppExceptionHandler.php b/app/Exception/Handler/AppExceptionHandler.php index 9ca8855..ddca7dd 100644 --- a/app/Exception/Handler/AppExceptionHandler.php +++ b/app/Exception/Handler/AppExceptionHandler.php @@ -4,7 +4,9 @@ declare(strict_types=1); namespace App\Exception\Handler; +use App\Cache\Repository\LockRedis; use App\Constants\ResponseCode; +use App\Support\MailerTemplate; use Hyperf\Contract\StdoutLoggerInterface; use Hyperf\ExceptionHandler\ExceptionHandler; use Hyperf\HttpMessage\Stream\SwooleStream; @@ -30,9 +32,12 @@ class AppExceptionHandler extends ExceptionHandler $data = json_encode([ 'code' => ResponseCode::SERVER_ERROR, - 'message' => 'Internal Server Error.' + 'message' => 'Internal Server Error.', + 'errors' => config('app_env') == 'dev' ? $throwable->getTrace() : [], ], JSON_UNESCAPED_UNICODE); + $this->sendAdminEmail($throwable); + return $response->withHeader('Server', 'Lumen IM')->withStatus(500)->withBody(new SwooleStream($data)); } @@ -44,4 +49,31 @@ class AppExceptionHandler extends ExceptionHandler { return true; } + + /** + * 发送系统报错通知邮件 + * + * @param Throwable $throwable + */ + public function sendAdminEmail(Throwable $throwable) + { + $error = implode(':', [ + 'error', + time(), + md5($throwable->getFile() . $throwable->getCode() . $throwable->getLine()), + ]); + + $adminEmail = config('admin_email'); + if ($adminEmail && LockRedis::getInstance()->lock($error, 60 * 30)) { + try { + email()->send( + $adminEmail, + '系统报错通知', + container()->get(MailerTemplate::class)->errorNotice($throwable) + ); + } catch (\Exception $exception) { + + } + } + } } diff --git a/app/Exception/Handler/JwtAuthExceptionHandler.php b/app/Exception/Handler/JwtAuthExceptionHandler.php index 2bf471c..59275c8 100644 --- a/app/Exception/Handler/JwtAuthExceptionHandler.php +++ b/app/Exception/Handler/JwtAuthExceptionHandler.php @@ -17,22 +17,17 @@ class JwtAuthExceptionHandler extends ExceptionHandler { public function handle(Throwable $throwable, ResponseInterface $response) { - // 判断被捕获到的异常是希望被捕获的异常 - if ($throwable instanceof AuthException) { - // 格式化输出 - $data = json_encode([ - 'code' => $throwable->getCode(), - 'message' => $throwable->getMessage(), - 'data' => [] - ], JSON_UNESCAPED_UNICODE); + // 格式化输出 + $data = json_encode([ + 'code' => $throwable->getCode(), + 'message' => $throwable->getMessage(), + 'data' => [] + ], JSON_UNESCAPED_UNICODE); - // 阻止异常冒泡 - $this->stopPropagation(); + // 阻止异常冒泡 + $this->stopPropagation(); - return $response->withAddedHeader('content-type', 'application/json; charset=utf-8')->withStatus(401)->withBody(new SwooleStream($data)); - } - - return $response; + return $response->withAddedHeader('content-type', 'application/json; charset=utf-8')->withStatus(401)->withBody(new SwooleStream($data)); } /** @@ -43,6 +38,6 @@ class JwtAuthExceptionHandler extends ExceptionHandler */ public function isValid(Throwable $throwable): bool { - return true; + return $throwable instanceof AuthException; } } diff --git a/app/Exception/Handler/ValidateExceptionHandler.php b/app/Exception/Handler/ValidateExceptionHandler.php index 22b866f..cfed111 100644 --- a/app/Exception/Handler/ValidateExceptionHandler.php +++ b/app/Exception/Handler/ValidateExceptionHandler.php @@ -23,22 +23,17 @@ class ValidateExceptionHandler extends ExceptionHandler */ public function handle(Throwable $throwable, ResponseInterface $response) { - // 判断被捕获到的异常是希望被捕获的异常 - if ($throwable instanceof ValidateException) { - // 格式化输出 - $data = json_encode([ - 'code' => $throwable->getCode(), - 'message' => $throwable->getMessage(), - 'data' => [] - ], JSON_UNESCAPED_UNICODE); + // 格式化输出 + $data = json_encode([ + 'code' => $throwable->getCode(), + 'message' => $throwable->getMessage(), + 'data' => [] + ], JSON_UNESCAPED_UNICODE); - // 阻止异常冒泡 - $this->stopPropagation(); + // 阻止异常冒泡 + $this->stopPropagation(); - return $response->withAddedHeader('content-type', 'application/json; charset=utf-8')->withStatus(200)->withBody(new SwooleStream($data)); - } - - return $response; + return $response->withAddedHeader('content-type', 'application/json; charset=utf-8')->withStatus(200)->withBody(new SwooleStream($data)); } /** @@ -49,6 +44,6 @@ class ValidateExceptionHandler extends ExceptionHandler */ public function isValid(Throwable $throwable): bool { - return true; + return $throwable instanceof ValidateException; } } diff --git a/app/Support/Mail.php b/app/Support/Mail.php index a28850b..6a8f337 100644 --- a/app/Support/Mail.php +++ b/app/Support/Mail.php @@ -12,65 +12,34 @@ use PHPMailer\PHPMailer\Exception; */ class Mail { - /** - * 发送邮件验证码 - * - * @param string $email 邮箱地址 - * @param string $sms_code 验证码 - * @param string $title 邮件标题 - * @return bool - */ - public function sendEmailCode(string $email, string $sms_code, string $title) - { - $view = $this->view(config('view.engine'), 'emails.verify-code', [ - 'service_name' => "邮箱绑定", - 'sms_code' => $sms_code, - 'domain' => config('domain.web_url') - ]); - - try { - return $this->mail($email, $title, $view); - } catch (\Exception $e) { - return false; - } - } - /** * @param string $address * @param string $subject * @param string $view * @return bool - * @throws \PHPMailer\PHPMailer\Exception */ - private function mail(string $address, string $subject, string $view): bool + public function send(string $address, string $subject, string $view): bool { - $config = config('mail'); - $mail = new PHPMailer(); // PHPMailer对象 - $mail->CharSet = 'UTF-8'; // 设定邮件编码,默认ISO-8859-1,如果发中文此项必须设置,否则乱码 - $mail->IsSMTP(); // 设定使用SMTP服务 - $mail->SMTPDebug = 0; // 关闭SMTP调试功能 - $mail->SMTPAuth = true; // 启用 SMTP 验证功能 - $mail->SMTPSecure = 'ssl'; // 使用安全协议 - $mail->Host = $config['host']; // SMTP 服务器 - $mail->Port = $config['port']; // SMTP服务器的端口号 - $mail->Username = $config['username']; // SMTP服务器用户名 - $mail->Password = $config['password']; // SMTP服务器密码 - $mail->SetFrom($config['from'], $config['name']); // 邮箱,昵称 - $mail->Subject = $subject; - $mail->MsgHTML($view); - $mail->AddAddress($address); // 收件人 - return $mail->Send(); - } - - /** - * @param string $engine - * @param string $template - * @param array $params - * @return string - */ - private function view(string $engine, string $template, array $params = []): string - { - $config = config('view.config', []); - return container()->get($engine)->render($template, $params, $config); + try { + $config = config('mail'); + $mail = new PHPMailer(); // PHPMailer对象 + $mail->CharSet = 'UTF-8'; // 设定邮件编码,默认ISO-8859-1,如果发中文此项必须设置,否则乱码 + $mail->IsSMTP(); // 设定使用SMTP服务 + $mail->SMTPDebug = 0; // 关闭SMTP调试功能 + $mail->SMTPAuth = true; // 启用 SMTP 验证功能 + $mail->SMTPSecure = 'ssl'; // 使用安全协议 + $mail->Host = $config['host']; // SMTP 服务器 + $mail->Port = $config['port']; // SMTP服务器的端口号 + $mail->Username = $config['username']; // SMTP服务器用户名 + $mail->Password = $config['password']; // SMTP服务器密码 + $mail->SetFrom($config['from'], $config['name']); // 邮箱,昵称 + $mail->Subject = $subject; + $mail->MsgHTML($view); + $mail->AddAddress($address); // 收件人 + return $mail->Send(); + } catch (\Exception $e) { + logger()->error($e->getTraceAsString()); + return false; + } } } diff --git a/app/Support/MailerTemplate.php b/app/Support/MailerTemplate.php index cd34875..3f5990c 100644 --- a/app/Support/MailerTemplate.php +++ b/app/Support/MailerTemplate.php @@ -2,6 +2,8 @@ namespace App\Support; +use Throwable; + /** * 邮件视图模板 * @@ -17,13 +19,13 @@ class MailerTemplate * @param array $params 模板参数 * @return string */ - public function view(string $engine, string $template, $params = []): string + private function view(string $engine, string $template, $params = []): string { return container()->get($engine)->render($template, $params, config('view.config', [])); } /** - * 邮件验证码模板 + * 验证码通知 - 邮件模板 * * @param string $sms_code 验证码 * @param array $params 模板参数 @@ -39,10 +41,15 @@ class MailerTemplate } /** - * 注册成功通知 + * 系统错误通知 - 邮件模板 + * + * @param Throwable $throwable + * @return string */ - public function register() + public function errorNotice(Throwable $throwable) { - + return $this->view(config('view.engine'), 'emails.error-notice', [ + 'throwable' => $throwable->getTraceAsString() + ]); } } diff --git a/app/Support/SendEmailCode.php b/app/Support/SendEmailCode.php index 3b02469..ee57530 100644 --- a/app/Support/SendEmailCode.php +++ b/app/Support/SendEmailCode.php @@ -57,7 +57,10 @@ class SendEmailCode $this->setCode($key, $sms_code);; // ...执行发送(后期使用队列) - container()->get(Mail::class)->sendEmailCode($email, $sms_code, 'Lumen IM(绑定邮箱验证码)'); + email()->send( + $email, 'Lumen IM(绑定邮箱验证码)', + container()->get(MailerTemplate::class)->emailCode($sms_code) + ); return true; } diff --git a/app/helper.php b/app/helper.php index cef6fce..03c8523 100644 --- a/app/helper.php +++ b/app/helper.php @@ -119,13 +119,20 @@ function response() return container()->get(ResponseInterface::class); } + +function email() +{ + return container()->get(\App\Support\Mail::class); +} + + /** * 从HTML文本中提取所有图片 * * @param string $content HTML文本 * @return array */ -function get_html_images($content) +function get_html_images(string $content) { $pattern = "//"; preg_match_all($pattern, htmlspecialchars_decode($content), $match); @@ -147,7 +154,7 @@ function get_html_images($content) * @param string $day2 日期2 * @return float|int */ -function diff_date($day1, $day2) +function diff_date(string $day1, string $day2) { $second1 = strtotime($day1); $second2 = strtotime($day2); @@ -180,7 +187,7 @@ function get_media_url(string $path) */ function create_image_name(string $ext, int $width, int $height) { - return uniqid() . Str::random(16) . uniqid() . '_' . $width . 'x' . $height . '.' . $ext; + return uniqid() . Str::random() . '_' . $width . 'x' . $height . '.' . $ext; } /** @@ -205,7 +212,7 @@ function replace_url_link(string $str) * @param int $sort 排序方式 * @return array */ -function arraysSort(array $array, $field, $sort = SORT_DESC) +function arraysSort(array $array, string $field, $sort = SORT_DESC) { array_multisort(array_column($array, $field), $sort, $array); return $array; @@ -214,20 +221,20 @@ function arraysSort(array $array, $field, $sort = SORT_DESC) /** * 判断0或正整数 * - * @param string $int 验证字符串 - * @param bool $isZero 判断是否可为0 + * @param string|int $value 验证字符串 + * @param bool $isZero 判断是否可为0 * @return bool */ -function check_int($int, $isZero = false) +function check_int($value, $isZero = false) { $reg = $isZero ? '/^[+]{0,1}(\d+)$/' : '/^[1-9]\d*$/'; - return is_numeric($int) && preg_match($reg, $int); + return is_numeric($value) && preg_match($reg, $value); } /** * 解析英文逗号',' 拼接的 ID 字符串 * - * @param string $ids 字符串(例如; "1,2,3,4,5,6") + * @param string|int $ids 字符串(例如; "1,2,3,4,5,6") * @return array */ function parse_ids($ids) @@ -247,3 +254,5 @@ function push_amqp(ProducerMessage $message, bool $confirm = false, int $timeout { return container()->get(Producer::class)->produce($message, $confirm, $timeout); } + + diff --git a/config/autoload/listeners.php b/config/autoload/listeners.php index f46bd96..26f769a 100644 --- a/config/autoload/listeners.php +++ b/config/autoload/listeners.php @@ -10,4 +10,5 @@ declare(strict_types=1); * @license https://github.com/hyperf/hyperf/blob/master/LICENSE */ return [ + \Hyperf\ExceptionHandler\Listener\ErrorExceptionHandler::class ]; diff --git a/config/config.php b/config/config.php index 508a247..b8463ea 100644 --- a/config/config.php +++ b/config/config.php @@ -19,18 +19,16 @@ return [ 'app_env' => env('APP_ENV', 'dev'), 'scan_cacheable' => env('SCAN_CACHEABLE', false), - 'ip_address' => env('IP_ADDRESS', ''), - - // 运行模式(预留) - 'run_mode' => 'cluster', - // 域名相关配置 - 'domain' => [ + 'domain' => [ 'web_url' => env('WEB_URL', ''),//Web 端首页地址 'img_url' => env('IMG_URL', ''),//设置文件图片访问的域名 ], - 'upload_dir' => env('UPLOAD_PATH', ''), + 'upload_dir' => env('UPLOAD_PATH', ''), + + // 管理员邮箱 + 'admin_email' => env('ADMIN_EMAIL', ''), StdoutLoggerInterface::class => [ 'log_level' => [ diff --git a/storage/view/emails/error-notice.blade.php b/storage/view/emails/error-notice.blade.php new file mode 100644 index 0000000..4fa9fca --- /dev/null +++ b/storage/view/emails/error-notice.blade.php @@ -0,0 +1,80 @@ + + + + + + + + + + + +
+
+ + + + + + +
+
+
+
+ + 系统报错通知:{{date('Y-m-d H:i:s')}} + +
+
+
{{$throwable}}
+
+
+
+