SmsCodeModel.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Model\Arts;
  4. use App\Master\Enum\RedisKeyEnum;
  5. use App\Master\Framework\Library\AliCloud\AliSms;
  6. use App\Master\Framework\Library\Twilio\Sms;
  7. use App\Model\Model;
  8. use App\Utils\Common;
  9. use App\Utils\RedisUtil;
  10. use function Hyperf\Coroutine\co;
  11. class SmsCodeModel extends Model
  12. {
  13. /**
  14. * The table associated with the model.
  15. *
  16. * @var ?string
  17. */
  18. protected ?string $table = 'sms';
  19. protected ?string $dateFormat = 'U';
  20. public bool $timestamps = false;
  21. protected int $is_status_search = 1;// 默认使用 status = 1 筛选
  22. protected int $is_delete_search = 1;// 默认使用 is_delete = 0 筛选
  23. /**
  24. * 默认查询字段
  25. *
  26. * @var array|string[]
  27. */
  28. public array $select = [
  29. '*'
  30. ];
  31. /**
  32. * 验证码
  33. * @param $mobile
  34. * @param $code
  35. * @param string $event
  36. * @return bool
  37. */
  38. public function check($mobile, $code, string $event = 'default', int $currentLimit = 5, int $timeOut = 300)
  39. {
  40. // 测试验证码
  41. if ($code == 1212) {
  42. return $this->success();
  43. }
  44. if (!RedisUtil::getInstance(RedisKeyEnum::SMS_MOBILE_CHECK, $mobile)->tryTimes($timeOut,$currentLimit)){
  45. return $this->error('校验过于频繁,已被锁定!');
  46. }
  47. if (!$info = self::query()->where(['mobile' => $mobile, 'event' => $event])->orderBy('id', 'desc')->first()) {
  48. return $this->error('验证码错误');
  49. }
  50. if ($info->createtime < time() - 600) {
  51. $this->flush($mobile, $event);
  52. return $this->error('验证码已过期');
  53. }
  54. if ($info->code != $code) {
  55. return $this->error('验证码错误!');
  56. }
  57. return $this->success();
  58. }
  59. /**
  60. * 发送短信
  61. * @param string $mobile
  62. * @param $event
  63. * @param int $currentLimit
  64. * @param int $timeOut
  65. * @return bool
  66. * @throws \Exception
  67. */
  68. public function send(string $mobile, $event = 'default', int $currentLimit = 5, int $timeOut = 300)
  69. {
  70. $code = rand(1000, 9999);
  71. if (!$this->create_code($mobile, $code, $event, $currentLimit, $timeOut)) {
  72. return $this->error($this->getMessage());
  73. }
  74. // 第三方发送短信
  75. return $this->success('发送成功', [
  76. 'code' => $code
  77. ]);
  78. }
  79. /**
  80. * 创建验证码
  81. * @param string $mobile
  82. * @param $code
  83. * @param $event
  84. * @param int $currentLimit
  85. * @param int $timeOut
  86. * @return bool
  87. * @throws \Exception
  88. */
  89. private function create_code(string $mobile, $code, $event = 'default', int $currentLimit = 5, int $timeOut = 300)
  90. {
  91. $time = time();
  92. //验证缓存,如存在则继续限制发送,时间设置 300s
  93. if (RedisUtil::getInstance(RedisKeyEnum::SEND_SMS_MOBILE, $mobile)->get()) {
  94. return $this->error('您的发送过于频繁!');
  95. }
  96. //5分钟之内 次数超过5次,限制发送,并记录缓存
  97. if (!RedisUtil::getInstance(RedisKeyEnum::SEND_SMS_TIMES, $mobile)->tryTimes($timeOut,$currentLimit)) {
  98. //每次锁定 递增 锁定时间,达到最大锁定次数则将当日无法发送
  99. $end_time = Common::todayTimeRemain();//设置次日凌晨过期
  100. if (!$times = RedisUtil::getInstance(RedisKeyEnum::SEND_SMS_TIMEOUT_TIMES, $mobile)->tryTimes($end_time, $currentLimit)) {
  101. $timeOut = $end_time;//如果达到最大锁定次数,则设置当日过期
  102. } else {
  103. $timeOut = $times * $timeOut;//如果未达到最大次数,则依次递增锁定时间
  104. // 如果最大次数过期时间 超过 当日时间,则直接设置当日过期
  105. if ($timeOut > $end_time) {
  106. $timeOut = $end_time;
  107. }
  108. }
  109. RedisUtil::getInstance(RedisKeyEnum::SEND_SMS_MOBILE, $mobile)->setex('1', $timeOut);
  110. $minutes = $timeOut / 60;
  111. return $this->error("发送过于频繁,请{$minutes}分钟后再试");
  112. }
  113. $this->flush($mobile, $event);
  114. $data = [
  115. 'event' => $event,
  116. 'mobile' => $mobile,
  117. 'code' => $code,
  118. 'createtime' => $time
  119. ];
  120. if (!self::query()->insert($data)) {
  121. return $this->error('发送失败');
  122. }
  123. return $this->success('发送成功');
  124. }
  125. /**
  126. * 清除短信
  127. * @param $mobile
  128. * @param $event
  129. * @return bool
  130. */
  131. public function flush($mobile, $event = 'default')
  132. {
  133. self::query()->where(['mobile' => $mobile, 'event' => $event])->delete();
  134. return $this->success();
  135. }
  136. }