Sms.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <?php
  2. namespace app\api\controller;
  3. use app\common\controller\Api;
  4. use app\common\library\Sms as Smslib;
  5. use app\common\model\Sms AS SmsModel;
  6. use app\common\model\User;
  7. use think\Hook;
  8. use fast\Random;
  9. use Exception;
  10. use think\Cache;
  11. use think\exception\PDOException;
  12. use think\exception\ValidateException;
  13. use think\Log;
  14. /**
  15. * 手机短信接口
  16. */
  17. class Sms extends Api
  18. {
  19. protected $noNeedLogin = '*';
  20. protected $noNeedRight = '*';
  21. /**
  22. * 验证码有效时长
  23. * @var int
  24. */
  25. protected static $expire = 120;
  26. /**
  27. * 最大允许检测的次数
  28. * @var int
  29. */
  30. protected static $maxCheckNums = 10;
  31. /**
  32. * 发送验证码
  33. *
  34. * @ApiMethod (POST)
  35. * @param string $mobile 手机号
  36. * @param string $event 事件名称
  37. */
  38. public function send()
  39. {
  40. $mobile = $this->request->post("mobile");
  41. $event = $this->request->post("event");
  42. $event = $event ? $event : 'register';
  43. if (!$mobile || !\think\Validate::regex($mobile, "^1\d{10}$")) {
  44. $this->error(__('手机号不正确'));
  45. }
  46. $last = Smslib::get($mobile, $event);
  47. if ($last && time() - $last['createtime'] < 60) {
  48. $this->error(__('发送频繁'));
  49. }
  50. $ipSendTotal = \app\common\model\Sms::where(['ip' => $this->request->ip()])->whereTime('createtime', '-1 hours')->count();
  51. if ($ipSendTotal >= 5) {
  52. $this->error(__('发送频繁'));
  53. }
  54. if ($event) {
  55. $userinfo = User::getByMobile($mobile);
  56. if ($event == 'register' && $userinfo) {
  57. //已被注册
  58. $this->error(__('已被注册'));
  59. } elseif (in_array($event, ['changemobile']) && $userinfo) {
  60. //被占用
  61. $this->error(__('已被占用'));
  62. } elseif (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo) {
  63. //未注册
  64. $this->error(__('未注册'));
  65. }
  66. }
  67. if (!Hook::get('sms_send')) {
  68. $this->error(__('请在后台插件管理安装短信验证插件'));
  69. }
  70. $ret = Smslib::send($mobile, null, $event);
  71. if ($ret) {
  72. $this->success(__('发送成功'));
  73. } else {
  74. $this->error(__('发送失败,请检查短信配置是否正确'));
  75. }
  76. }
  77. /**
  78. * 向国际手机号码发放短信
  79. * @return void
  80. * @throws \think\Exception
  81. */
  82. public function send_international_sms($country_code, $mobile, $event = '')
  83. {
  84. $last = SmsModel::where(['country_code' => $country_code, 'mobile' => $mobile, 'event' => $event])
  85. ->order('id', 'DESC')
  86. ->find();
  87. if ($last && time() - $last['create_time'] < 60) {
  88. $this->error(__('发送频繁'));
  89. }
  90. $ipSendTotal = SmsModel::where(['ip' => $this->request->ip()])->whereTime('create_time', '-1 hours')->count();
  91. if ($ipSendTotal >= 5) {
  92. $this->error(__('发送频繁'));
  93. }
  94. if ($event == 'register') {
  95. $userinfo = User::getByCodeAndMobile($country_code, $mobile);
  96. if (!empty($userinfo)) {
  97. //已被注册
  98. $this->error(__('已被注册'));
  99. }
  100. // elseif (in_array($event, ['changemobile']) && $userinfo) {
  101. // //被占用
  102. // $this->error(__('已被占用'));
  103. // } elseif (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo) {
  104. // //未注册
  105. // $this->error(__('未注册'));
  106. // }
  107. }
  108. // if (!Hook::get('sms_send')) {
  109. // $this->error(__('请在后台插件管理安装短信验证插件'));
  110. // }
  111. $code = Random::numeric();//验证码
  112. $ret = $this->send_sms_unisms($country_code, $mobile, $code, $event);
  113. if ($ret['code']) {
  114. $time = time();
  115. $ip = request()->ip();
  116. $sms = SmsModel::create([
  117. 'country_code' => $country_code,
  118. 'event' => $event,
  119. 'mobile' => $mobile,
  120. 'code' => $code,
  121. 'ip' => $ip,
  122. ]);
  123. $this->success(__('发送成功') . '-' . $code);
  124. } else {
  125. Log::notice('短信发送失败');
  126. Log::error($ret['msg']);
  127. $this->error(__('发送失败,请检查短信配置是否正确'));
  128. }
  129. }
  130. /**
  131. * 检测验证码
  132. *
  133. */
  134. public function check($country_code, $mobile, $code, $event = 'verify'): bool
  135. {
  136. $time = time() - self::$expire;
  137. $sms = SmsModel::where(['country_code' => $country_code, 'mobile' => $mobile, 'event' => $event])
  138. ->order('id', 'DESC')
  139. ->find();
  140. if ($sms) {
  141. if ($sms['create_time'] > $time && $sms['times'] <= self::$maxCheckNums) {
  142. $correct = $code == $sms['code'];
  143. if (!$correct) {
  144. $sms->times = $sms->times + 1;
  145. $sms->save();
  146. return false;
  147. } else {
  148. //$result = Hook::listen('sms_check', $sms, null, true);
  149. return true;
  150. }
  151. }
  152. }
  153. return false;
  154. }
  155. /**
  156. * 发送短信验证码
  157. * 短信平台:https://unisms.apistd.com/
  158. */
  159. public function send_sms_unisms($country_code, $phone, $code, $event = 'verify')
  160. {
  161. return _success();
  162. $phone = '+' . $country_code . $phone;//拼接国际区号
  163. try {
  164. $url1 = "https://uni.apistd.com";
  165. $query = [
  166. 'action' => 'sms.message.send',
  167. 'accessKeyId' => 'SGnbSrqzJikDxx4PuU83kD9oTTmv7o34unZ2bPX8FqsgCrQkp'
  168. ];
  169. $url = $url1.'/?'.http_build_query($query);
  170. $data = [
  171. 'signature' => 'AEXBTC',
  172. 'to' => $phone,
  173. //'content'=>$content,
  174. 'templateId' => 'd33f1f90',
  175. 'templateData' => ['code' => $code]
  176. ];
  177. $result = xcurl($url,$data);
  178. $result = json_decode($result, true);
  179. } catch (ValidateException|PDOException|Exception $e){
  180. return _error($e->getMessage());
  181. }
  182. if ($result['code'] == 0){
  183. //Cache::set($key, $code,300);
  184. return _success();
  185. }else{
  186. return _error($result['message']);
  187. }
  188. }
  189. }