暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SmsLogic.php 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. <?php
  2. /**
  3. * 易优CMS
  4. * ============================================================================
  5. * 版权所有 2016-2028 海南赞赞网络科技有限公司,并保留所有权利。
  6. * 网站地址: http://www.eyoucms.com
  7. * ----------------------------------------------------------------------------
  8. * 如果商业用途务必到官方购买正版授权, 以免引起不必要的法律纠纷.
  9. * ============================================================================
  10. * Author: 小虎哥 <1105415366@qq.com>
  11. * Date: 2018-4-3
  12. */
  13. namespace app\common\logic;
  14. use think\Model;
  15. use think\Db;
  16. /**
  17. * Description of SmsLogic
  18. *
  19. * 短信类
  20. */
  21. class SmsLogic extends Model
  22. {
  23. private $config;
  24. public function __construct($sms_config = [])
  25. {
  26. $this->config = !empty($sms_config) ? $sms_config : tpCache('sms');
  27. }
  28. /**
  29. * 发送短信逻辑
  30. * @param unknown $source
  31. */
  32. public function sendSms($source = null, $sender = null, $params = [], $unique_id = 0)
  33. {
  34. $sms_config = $this->config;
  35. $sms_type = isset($sms_config['sms_type']) ? $sms_config['sms_type'] : 1;
  36. $smsTemp = Db::name('sms_template')->where(["send_scene"=>$source,"sms_type"=>$sms_type,'lang'=>get_admin_lang()])->find();
  37. if (empty($smsTemp) || empty($smsTemp['sms_sign']) || empty($smsTemp['sms_tpl_code']) || empty($smsTemp['tpl_content'])){
  38. return $result = ['status' => -1, 'msg' => '尚未正确配置短信模板,请联系管理员!'];
  39. }
  40. if (0 == $smsTemp['is_open']) return $result = ['status' => -1, 'msg' => '模板类型已关闭,请先开启'];
  41. $content = !empty($params['content']) ? $params['content'] : false;
  42. $code = !empty($params['code']) ? $params['code'] : $content;
  43. $express_time = !empty($params['express_time']) ? date('Y-m-d H:i:s', $params['express_time']) : false;
  44. $product_name = !empty($params['product_name']) ? msubstr(trim($params['product_name']), 0, 15).'...' : false;
  45. if(empty($unique_id)){
  46. $session_id = session_id();
  47. }else{
  48. $session_id = $unique_id;
  49. }
  50. if ($sms_type == 1) {
  51. if (strpos($smsTemp['tpl_content'], 'code') !== false) {
  52. $smsParams = array(
  53. 0 => "{\"code\":\"$code\"}",
  54. 1 => "{\"code\":\"$code\"}",
  55. 2 => "{\"code\":\"$code\"}",
  56. 3 => "{\"code\":\"$code\"}",
  57. 4 => "{\"code\":\"$code\"}",
  58. 5 => "{\"code\":\"$code\"}",
  59. 6 => "{\"code\":\"$code\"}",
  60. 7 => "{\"code\":\"$code\"}",
  61. );
  62. } else if (strpos($smsTemp['tpl_content'], 'content') !== false) {
  63. $smsParams = array(
  64. 0 => "{\"content\":\"$content\"}",
  65. 1 => "{\"content\":\"$content\"}",
  66. 2 => "{\"content\":\"$content\"}",
  67. 3 => "{\"content\":\"$content\"}",
  68. 4 => "{\"content\":\"$content\"}",
  69. 5 => "{\"content\":\"$content\"}",
  70. 6 => "{\"content\":\"$content\"}",
  71. 7 => "{\"content\":\"$content\"}",
  72. );
  73. } else if (strpos($smsTemp['tpl_content'], 'name') !== false) {
  74. $smsParams = array(
  75. 0 => "{\"name\":\"$name\"}",
  76. 1 => "{\"name\":\"$name\"}",
  77. 2 => "{\"name\":\"$name\"}",
  78. 3 => "{\"name\":\"$name\"}",
  79. 4 => "{\"name\":\"$name\"}",
  80. 5 => "{\"name\":\"$name\"}",
  81. 6 => "{\"name\":\"$name\"}",
  82. 7 => "{\"name\":\"$name\"}",
  83. );
  84. } else if (20 === intval($source)) {
  85. $smsParams[20] = "{\"content\":\"$content\"}";
  86. } else {
  87. $smsParams[6] = "{\"goods_title\":\"$product_name\",\"express_time\":\"$express_time\"}";
  88. }
  89. $smsParam = $smsParams[$source];
  90. // 提取发送短信内容
  91. $msg = $smsTemp['tpl_content'];
  92. $params_arr = json_decode($smsParam);
  93. foreach ($params_arr as $k => $v) {
  94. $msg = str_replace('${' . $k . '}', $v, $msg);
  95. }
  96. } else {
  97. $params_arr = $smsParam = array_values($params);
  98. //提取发送短信内容
  99. $msg = $smsTemp['tpl_content'];
  100. foreach ($params_arr as $k => $v) {
  101. $index = $k+1;
  102. $msg = str_replace('{' . $index . '}', $v, $msg);
  103. }
  104. }
  105. //发送记录存储数据库
  106. $smsData = [];
  107. $time = getTime();
  108. $sender_arr = explode(',', $sender);
  109. foreach ($sender_arr as $key => $val) {
  110. $val = trim($val);
  111. if (empty($val) || !check_mobile($val)) {
  112. unset($sender_arr[$key]);
  113. continue;
  114. }
  115. $smsData[] = [
  116. 'source' => $source,
  117. 'sms_type' => $sms_type,
  118. 'mobile' => $val,
  119. 'code' => $code,
  120. 'add_time' => $time,
  121. 'status' => 0,
  122. 'msg' => $msg,
  123. 'is_use' => 0,
  124. 'error_msg' => '',
  125. 'ip' => clientIP(),
  126. 'update_time' => $time,
  127. ];
  128. }
  129. $sender = implode(',', $sender_arr);
  130. try{
  131. Db::name('sms_log')->insertAll($smsData);
  132. }catch (\Exception $e){
  133. }
  134. if (!empty($sender)) {
  135. // 如果是正常的手机号码才发送
  136. try {
  137. $resp = $this->realSendSms($sender, $smsTemp['sms_sign'], $smsParam, $smsTemp['sms_tpl_code'], $msg);
  138. } catch (\Exception $e) {
  139. $resp = ['status' => -1, 'msg' => $e->getMessage()];
  140. }
  141. if (!empty($resp['status']) && $resp['status'] == 1) {
  142. // 修改发送状态为成功
  143. Db::name('sms_log')->where(['mobile'=>['IN', $sender_arr], 'update_time'=>$time])->save(['status'=>1, 'update_time'=>getTime()]);
  144. } else {
  145. // 发送失败, 将发送失败信息保存数据库
  146. Db::name('sms_log')->where(['mobile'=>['IN', $sender_arr], 'update_time'=>$time])->update(['error_msg'=>$resp['msg'], 'update_time'=>getTime()]);
  147. }
  148. return $resp;
  149. } else {
  150. return $result = ['status' => -1, 'msg' => '接收手机号不正确['.$sender.']'];
  151. }
  152. }
  153. private function realSendSms($mobile, $smsSign, $smsParam, $templateCode, $msg = '')
  154. {
  155. if (config('sms_debug') == true) {
  156. return array('status' => 1, 'msg' => '专用于越过短信发送');
  157. }
  158. $param = input('param.');
  159. if (!isset($param['sms_type'])) {
  160. $type = (int)$this->config['sms_type'] ?: 1;
  161. }else{
  162. $type = $param['sms_type'];
  163. }
  164. switch($type) {
  165. case 1:
  166. $result = $this->sendSmsByAliyun($mobile, $smsSign, $smsParam, $templateCode);
  167. break;
  168. case 2:
  169. $result = $this->sendSmsByTencentCloud($mobile, $smsSign, $smsParam, $templateCode);
  170. break;
  171. default:
  172. $result = ['status' => -1, 'msg' => '不支持的短信平台'];
  173. }
  174. return $result;
  175. }
  176. /**
  177. * 发送短信(阿里云短信)
  178. * @param $mobile 手机号码
  179. * @param $code 验证码
  180. * @return bool 短信发送成功返回true失败返回false
  181. */
  182. private function sendSmsByAliyun($mobile, $smsSign, $smsParam, $templateCode)
  183. {
  184. include_once './vendor/aliyun-php-sdk-core/Config.php';
  185. include_once './vendor/Dysmsapi/Request/V20170525/SendSmsRequest.php';
  186. $accessKeyId = $this->config['sms_appkey'];
  187. $accessKeySecret = $this->config['sms_secretkey'];
  188. if (empty($accessKeyId) || empty($accessKeySecret)){
  189. return array('status' => -1, 'msg' => '请设置短信平台appkey和secretKey');
  190. }
  191. //短信API产品名
  192. $product = "Dysmsapi";
  193. //短信API产品域名
  194. $domain = "dysmsapi.aliyuncs.com";
  195. //暂时不支持多Region
  196. $region = "cn-hangzhou";
  197. //初始化访问的acsCleint
  198. $profile = \DefaultProfile::getProfile($region, $accessKeyId, $accessKeySecret);
  199. \DefaultProfile::addEndpoint("cn-hangzhou", "cn-hangzhou", $product, $domain);
  200. $acsClient= new \DefaultAcsClient($profile);
  201. $request = new \Dysmsapi\Request\V20170525\SendSmsRequest;
  202. //必填-短信接收号码
  203. $request->setPhoneNumbers($mobile);
  204. //必填-短信签名
  205. $request->setSignName($smsSign);
  206. //必填-短信模板Code
  207. $request->setTemplateCode($templateCode);
  208. //选填-假如模板中存在变量需要替换则为必填(JSON格式)
  209. $request->setTemplateParam($smsParam);
  210. //选填-发送短信流水号
  211. //$request->setOutId("1234");
  212. //发起访问请求
  213. $resp = $acsClient->getAcsResponse($request);
  214. //短信发送成功返回True,失败返回false
  215. if ($resp && $resp->Code == 'OK') {
  216. return array('status' => 1, 'msg' => $resp->Code);
  217. } else {
  218. return array('status' => -1, 'msg' => $resp->Message . '. Code: ' . $resp->Code);
  219. }
  220. }
  221. /**
  222. * 发送短信(腾讯云短信)
  223. * @param $mobile 手机号码
  224. * @param $code 验证码
  225. * @return bool 短信发送成功返回true失败返回false
  226. */
  227. private function sendSmsByTencentCloud($mobile, $smsSign, $smsParam, $templateCode)
  228. {
  229. // 短信应用SDK AppID 1400开头
  230. $appid = $this->config['sms_appid_tx'];
  231. // 短信应用SDK AppKey
  232. $appkey = $this->config['sms_appkey_tx'];
  233. if (empty($appid) || empty($appkey)) {
  234. return array('status' => -1, 'msg' => '请设置短信平台appkid和appkey');
  235. }
  236. // 需要发送短信的手机号码
  237. $phoneNumbers = $mobile;
  238. // 短信模板ID,需要在短信应用中申请
  239. $templateId = $templateCode; // NOTE: 这里的模板ID`7839`只是一个示例,真实的模板ID需要在短信控制台中申请
  240. // 签名
  241. $smsSign = $smsSign; // NOTE: 这里的签名只是示例,请使用真实的已申请的签名,签名参数使用的是`签名内容`,而不是`签名ID`
  242. // var_dump($smsParam);exit;
  243. // 单发短信
  244. Vendor('tencentsms.SmsSingleSender');
  245. $ssender = new \SmsSingleSender($appid, $appkey);
  246. $params = $smsParam;//数组具体的元素个数和模板中变量个数必须一致,例如事例中 templateId:5678对应一个变量,参数数组中元素个数也必须是一个
  247. $result = $ssender->sendWithParam("86", $phoneNumbers, $templateId,
  248. $params, $smsSign, "", ""); // 签名参数未提供或者为空时,会使用默认签名发送短信
  249. $resp = json_decode($result,TRUE);
  250. //短信发送成功返回True,失败返回false
  251. if ($resp && $resp['errmsg'] == 'OK') {
  252. return array('status' => 1, 'msg' => $resp['errmsg']);
  253. } else {
  254. return array('status' => -1, 'msg' => $resp['errmsg']);
  255. }
  256. }
  257. }