SmsCaptcha.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2017~2024 https://www.yiovo.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
  8. // +----------------------------------------------------------------------
  9. // | Author: 萤火科技 <admin@yiovo.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\api\service\passport;
  13. use yiovo\cache\facade\Cache;
  14. use yiovo\captcha\facade\CaptchaApi;
  15. use app\api\validate\passport\SmsCaptcha as ValidateSmsCaptcha;
  16. use app\common\service\BaseService;
  17. use app\common\service\Message as MessageService;
  18. use cores\exception\BaseException;
  19. /**
  20. * 服务类:发送短信验证码
  21. * Class SmsCaptcha
  22. * @package app\api\service\passport
  23. */
  24. class SmsCaptcha extends BaseService
  25. {
  26. // 最大发送次数,默认10次
  27. protected int $sendTimes = 10;
  28. // 发送限制间隔时间,默认24小时
  29. protected int $safeTime = 86400;
  30. /**
  31. * 发送短信验证码
  32. * @param array $data
  33. * @return bool
  34. * @throws BaseException
  35. */
  36. public function handle(array $data): bool
  37. {
  38. // 数据验证
  39. $this->validate($data);
  40. // 执行发送短信
  41. if (!$this->sendCaptcha($data['mobile'])) {
  42. return false;
  43. }
  44. return true;
  45. }
  46. /**
  47. * 执行发送短信
  48. * @param string $mobile
  49. * @return bool
  50. */
  51. private function sendCaptcha(string $mobile): bool
  52. {
  53. // 缓存发送记录并判断次数
  54. if (!$this->record($mobile)) {
  55. return false;
  56. }
  57. // 生成验证码
  58. $smsCaptcha = CaptchaApi::createSMS($mobile);
  59. // 发送短信
  60. MessageService::send('passport.captcha', [
  61. 'code' => $smsCaptcha['code'],
  62. 'mobile' => $smsCaptcha['key']
  63. ], $this->storeId);
  64. return true;
  65. }
  66. /**
  67. * 记录短信验证码发送记录并判断是否超出发送限制
  68. * @param string $mobile
  69. * @return bool
  70. */
  71. private function record(string $mobile): bool
  72. {
  73. // 获取发送记录缓存
  74. $record = Cache::get("sendCaptchaSMS.$mobile");
  75. // 写入缓存:记录剩余发送次数
  76. if (empty($record)) {
  77. Cache::set("sendCaptchaSMS.$mobile", ['times' => $this->sendTimes - 1], $this->safeTime);
  78. return true;
  79. }
  80. // 判断发送次数是否合法
  81. if ($record['times'] <= 0) {
  82. $this->error = '很抱歉,已超出今日最大发送次数限制';
  83. return false;
  84. }
  85. // 发送次数递减
  86. Cache::update("sendCaptchaSMS.$mobile", ['times' => $record['times'] - 1]);
  87. return true;
  88. }
  89. /**
  90. * 数据验证
  91. * @param array $data
  92. * @throws BaseException
  93. */
  94. private function validate(array $data)
  95. {
  96. // 数据验证
  97. $validate = new ValidateSmsCaptcha;
  98. if (!$validate->check($data)) {
  99. throwError($validate->getError());
  100. }
  101. // 验证图形验证码
  102. if (!CaptchaApi::check($data['captchaCode'], $data['captchaKey'])) {
  103. throwError('很抱歉,图形验证码不正确');
  104. }
  105. }
  106. }