SmsService.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. <?php
  2. namespace app\common\service;
  3. use think\Cache;
  4. use think\Exception;
  5. use app\common\traits\ServiceTrait;
  6. class SmsService
  7. {
  8. use ServiceTrait;
  9. /**
  10. * 验证码有效期(秒)
  11. */
  12. const CODE_EXPIRE = 300;
  13. /**
  14. * 发送间隔时间(秒)
  15. */
  16. const SEND_INTERVAL = 60;
  17. /**
  18. * 生成验证码
  19. * @return string
  20. */
  21. protected function generateCode(): string
  22. {
  23. return sprintf("%06d", random_int(0, 999999));
  24. }
  25. /**
  26. * 获取缓存key
  27. * @param string $mobile
  28. * @param string $type
  29. * @return string
  30. */
  31. protected function getCacheKey(string $mobile, string $type = 'code'): string
  32. {
  33. return "sms_{$type}_{$mobile}";
  34. }
  35. /**
  36. * 发送验证码
  37. * @param string $mobile 手机号
  38. * @return array
  39. * @throws Exception
  40. */
  41. public function send($mobile, $code = null, $event = 'default'): array
  42. {
  43. // 检查发送间隔
  44. $intervalKey = $this->getCacheKey($mobile, 'interval');
  45. if (Cache::get($intervalKey)) {
  46. throw new Exception('发送太频繁,请稍后再试');
  47. }
  48. try {
  49. // 这里调用具体的短信发送接口
  50. $result = $this->sendSms($mobile, $code);
  51. if (!$result) {
  52. throw new Exception('短信发送失败');
  53. }
  54. // 缓存验证码
  55. $codeKey = $this->getCacheKey($mobile);
  56. Cache::set($codeKey, $code, self::CODE_EXPIRE);
  57. // 设置发送间隔
  58. Cache::set($intervalKey, 1, self::SEND_INTERVAL);
  59. return [
  60. 'mobile' => $mobile,
  61. 'expire' => self::CODE_EXPIRE
  62. ];
  63. } catch (\Exception $e) {
  64. throw new Exception('短信发送失败:' . $e->getMessage());
  65. }
  66. }
  67. /**
  68. * 验证码验证
  69. * @param string $mobile
  70. * @param string $code
  71. * @return bool
  72. * @throws Exception
  73. */
  74. public function check(string $mobile, string $code): bool
  75. {
  76. if (empty($mobile) || empty($code)) {
  77. throw new Exception('手机号和验证码不能为空');
  78. }
  79. $codeKey = $this->getCacheKey($mobile);
  80. $cacheCode = Cache::get($codeKey);
  81. if (!$cacheCode) {
  82. throw new Exception('验证码已过期');
  83. }
  84. if ($cacheCode !== $code) {
  85. throw new Exception('验证码错误');
  86. }
  87. // 验证成功后删除缓存
  88. Cache::rm($codeKey);
  89. return true;
  90. }
  91. /**
  92. * 发送短信
  93. * @param string $mobile
  94. * @param string $code
  95. * @return bool
  96. */
  97. protected function sendSms(string $mobile, string $code): bool
  98. {
  99. // 这里实现具体的短信发送逻辑
  100. // 可以对接阿里云、腾讯云等短信服务
  101. // 示例使用阿里云短信服务
  102. try {
  103. $config = [
  104. 'access_key_id' => config('site.sms.access_key_id'),
  105. 'access_key_secret' => config('site.sms.access_key_secret'),
  106. 'sign_name' => config('site.sms.sign_name'),
  107. 'template_code' => config('site.sms.template_code')
  108. ];
  109. // 测试环境直接返回true
  110. return true;
  111. } catch (\Exception $e) {
  112. // 记录日志
  113. \think\Log::error('短信发送失败:' . $e->getMessage());
  114. return false;
  115. }
  116. }
  117. }