config['sy_email_online'] == 1) { include_once(LIB_PATH . 'email.class.php'); //获取邮件服务器缓存 include(PLUS_PATH . 'emailconfig.cache.php'); //随机选择一组邮件服务器作为当前发信服务器 if ($serverId) { if (isset($emailconfig) && is_array($emailconfig)) { foreach ($emailconfig as $value) { if ($value['id'] == $serverId) { $emailConfig = $value; break; } } } } else { if (isset($emailconfig) && count($emailconfig) > 0) { $rand = array_rand($emailconfig, 1); $emailConfig = $emailconfig[$rand]; } } if ($emailConfig['smtpserver'] && $emailConfig['smtpuser'] && $emailConfig['smtppass']) { if ($emailConfig['smtpport'] == '465') { $smtpserver = 'ssl://' . $emailConfig['smtpserver']; $smtpserverport = '465'; } else { $smtpserver = $emailConfig['smtpserver']; $smtpserverport = '25'; } return new smtp($smtpserver, $smtpserverport, true, $emailConfig['smtpuser'], $emailConfig['smtppass'], $emailConfig['smtpnick']); } else { return false; } } if ($this->config['sy_email_online'] == 2) { include_once(LIB_PATH . 'aliyunemail.class.php'); $accesskey = $this->config['accesskey']; //accessKey $accesssecret = $this->config['accesssecret']; //accessSecret $accountname = $this->config['ali_email']; //控制台创建的发信地址 $fromalias = $this->config['ali_name']; //发信人昵称 $tagname = $this->config['ali_tag']; //控制台创建的标签 return new aliyun_sendemail($accesskey, $accesssecret, $accountname, $fromalias, $tagname); } } private function addErrorLog($uid, $type = '', $content) { require_once('errlog.model.php'); $ErrlogM = new errlog_model($this->db, $this->def); return $ErrlogM->addErrorLog($uid, $type, $content); } /** * 获取邮件、短信模板 * @param array $data 传入参数 * @param string $type 模板类型:email邮箱; msg短信 * @return array */ public function getTpl($data, $type) { $name = $type . $data['type']; $row = $this->select_once('templates', array('name' => $name)); if ($row) { $tpl['title'] = $this->_tpl($row['title'], $data); $tpl['content'] = $this->_tpl($row['content'], $data); $tpl['template_id'] = $row['template_id']; return $tpl; } else { return array('status' => -1, 'msg' => '信息模板有误,请联系管理员'); } } //替换模板中的变量 private function _tpl($tpl, $data) { unset($data['type']); $re = array("{webname}", "{weburl}", "{webtel}"); $re2[] = $this->config['sy_webname']; $re2[] = $this->config['sy_weburl']; $re2[] = $this->config['sy_freewebtel']; $tpl = str_replace($re, $re2, $tpl); foreach ($data as $k => $v) { $tpl = str_replace("{" . $k . "}", $v, $tpl); } return $tpl; } //判断数组的下标是否存在 private function _isKey($key, $arr) { if (array_key_exists($key, $arr) && trim($arr[$key]) != '') { return trim($arr[$key]); } return false; } /** * 传入 email地址、主题、内容等参数,简单发送email方法 * * @param string $data ['email'] email地址 * @param string $data ['subject'] email主题 * @param string $data ['content'] email正文内容 * @return array */ public function sendEmail($data) { if ($this->config['sy_email_online'] == 1) { if (!$this->smtpClass) { $serverId = array_key_exists('smtpServerId', $data) ? $data['smtpServerId'] : ''; $this->smtpClass = $this->_getSmtp($serverId); } if (!$this->smtpClass) { return array('status' => -1, 'msg' => '还没有配置邮箱,请联系管理员!'); } if ($this->_isKey('email', $data) == false || CheckRegEmail($data['email']) == false) { return array('status' => -1, 'msg' => 'email地址错误'); } if (!$this->_isKey('subject', $data) || !$this->_isKey('content', $data)) { return array('status' => -1, 'msg' => 'email主题/正文为空'); } $cc = isset($data['cc']) ? $data['cc'] : ''; $bcc = isset($data['bcc']) ? $data['bcc'] : ''; $additional_headers = isset($data['additional_headers']) ? $data['additional_headers'] : ''; $sendid = $this->smtpClass->sendmail($data['email'], $data['subject'], $data['content'], 'HTML', $cc, $bcc, $additional_headers); if ($sendid) { $state = '1'; $retval = array('status' => 1, 'msg' => 'email发送成功!'); } else { $state = '0'; $retval = array('status' => -1, 'msg' => 'email发送失败!'); $this->addErrorLog($data['uid'], 9, 'email发送失败!'); } } if ($this->config['sy_email_online'] == 2) { if (!$this->smtpClass) { $this->smtpClass = $this->_getSmtp(); } if (!$this->smtpClass) { return array('status' => -1, 'msg' => '还没有配置邮箱,请联系管理员!'); } $sendid = $this->smtpClass->sendemail($data['email'], $data['subject'], $data['content']); if ($sendid) { $state = '1'; $retval = array('status' => 1, 'msg' => 'email发送成功!'); } else { $state = '0'; $retval = array('status' => -1, 'msg' => 'email发送失败!'); $this->addErrorLog($data['uid'], 9, 'email发送失败!'); } } //如果email正文内容太多,允许保存其他简短内容到数据表email_msg $tbContent = isset($data['tbContent']) ? $data['tbContent'] : $data['content']; $email_msg = array( 'uid' => $data['uid'], 'cuid' => isset($data['cuid']) ? $data['cuid'] : 0, 'email' => $data['email'], 'title' => $data['subject'], 'content' => $tbContent, 'state' => $state, 'ctime' => time(), 'smtpserver' => $this->smtpClass->user ); if ($data['email'] && !isset($data['repeat'])) { $this->insert_into('email_msg', $email_msg); } return $retval; } function insertEmail($data) { return $this->insert_into('email_msg', $data); } function insertMsg($data) { return $this->insert_into('moblie_msg', $data); } /** * @desc 根据业务类型,判断后台设置是否开启该类型email提醒,选择设定好的email模板,发送指定类型的邮件 * * @param array $data ['type'] 发送email的类型: * reg注册,yqms邀请面试,fkcg付款成功,zzshtg职位审核成功,sqzw申请职位,getpass找回密码,yqmshf回复面试邀请,login登录验证 * 'birthday', * 'webbirthday', * 'vipmr', * 'useradd', * 'userup', * 'addjob', * 'upjob' * $data数组,网站名称,网站域名和网站电话,不需要加到该数组中,请根据/data/db.tpl.php进行添加数据进来,全部添加 * $data包括email,moblie,$type * email 要发送的邮箱用户 * moblie要发送的手机用户 * */ public function sendEmailType($data, $tpl = NULL) { if (!$this->_isKey('type', $data) || !$this->_isKey('sy_email_' . $data['type'], $this->config) || $this->config['sy_email_' . $data['type']] != 1) { return array( 'status' => -1, 'msg' => '未开启email提醒,请联系管理员!(code:' . $data['type'] . ')' ); } // 邮件内容,如发送的内容相同,可以先把内容处理好传入,减少数据处理 if (!$tpl) { $tpl = $this->getTpl($data, 'email'); if (isset($tpl['status'])) { return $tpl; } } $data['subject'] = $tpl['title']; $data['content'] = html_entity_decode($tpl['content'], ENT_QUOTES); return $this->sendEmail($data); } /** * @desc 发送短信接口 * @param $type * @param $data * @return array */ private function postSMS($type = "msgsend", $data = []) { $sing = $this->config['sy_msg_appsing']; $data['content'] = str_replace(array(" ", " ", "\t", "\n", "\r"), array("", "", "", "", ""), $data['content']); $url = 'http://api.smsbao.com/sms'; $url .= '?u=' . $data['appkey'] . '&p=' . md5($data['appsecret']) . '&m=' . $data['phone'] . '&c=【' . $sing . '】' . $data['content']; if (function_exists('file_get_contents')) { $file_contents = file_get_contents($url); } else { $ch = curl_init(); $timeout = 5; curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); $file_contents = curl_exec($ch); curl_close($ch); } return $file_contents; } /** * 检测手机号 * @param $phone * @return mixed */ private function checkPhone($phone) { $url = ''; $url .= '?appSecret=' . $this->config['sy_kh_appsecret'] . '&appKey=' . $this->config['sy_kh_appkey'] . '&phone=' . $phone; if (extension_loaded('curl')) { $file_contents = CurlGet($url); } else if (function_exists('file_get_contents')) { $file_contents = file_get_contents($url); } if ($file_contents) { $msgInfo = json_decode($file_contents, true); } return $msgInfo; } /** * @desc 发送短信 * $data['moblie'] / $data['mobile'] 手机号(必填) * $data['content'] 短信内容(必填) * * (选填) 保存到moblie_msg表的字段: * uid 接收人uid, * cuid 发送人uid, */ public function sendSMS($data) { if (!checkMsgOpen($this->config)) { return array('status' => -1, 'msg' => '还没有配置短信,请联系管理员!'); } if (!$this->_isKey('mobile', $data) || !CheckMobile($data['mobile'])) { return array('status' => -1, 'msg' => '手机号错误'); } if ($this->config['sy_web_mobile'] != '') { $regnamer = @explode(';', $this->config['sy_web_mobile']); if (in_array($data['mobile'], $regnamer)) { return array('status' => -1, 'msg' => '该手机号已被禁止使用'); } } if (!$this->_isKey('content', $data) || $data['content'] == '') { return array('status' => -1, 'msg' => '短信内容为空'); } //发送短信 $row = array( 'sy_sms_secret_id' => $this->config['sy_sms_secret_id'], 'sy_sms_secret_key' => $this->config['sy_sms_secret_key'], 'sy_sms_sdk_app_id' => $this->config['sy_sms_sdk_app_id'], 'sy_sms_sign_name' => $this->config['sy_sms_sign_name'], 'template_id' => $data['template_id'], 'phone' => $data['mobile'], 'code' => $data['code'], ); $location = ''; //进行空号检测 以及 归属地限制 if ($this->config['sy_kh_isopen'] == '1' && in_array($data['type'], array('login', 'cert', 'regcode'))) { $checkInfo = $this->checkPhone($data['mobile']); $checkData = json_decode($checkInfo['data'], true); //检测出号码不为空号 if ($checkInfo['code'] == '200' && $checkData['phoneList']['phoneStatus'] > 0) { $location = $checkData['phoneList']['province'] . '-' . $checkData['phoneList']['city']; //检测归属地 if ($this->config['sy_kh_city'] && $checkData['phoneList']['province'] != '未知' && $checkData['phoneList']['city'] != '未知') { $re['code'] = '502';//归属地检测失败 $re['message'] = '号码检测有误!'; $kh_province = str_replace(",", ",", $this->config['sy_kh_city']); $kh_province_arr = explode(',', $kh_province); foreach ($kh_province_arr as $key => $value) { $kh_city = @explode('/', $value); //设定市级地区的情况下优先判断 if ((!empty($kh_city[1]) && strpos($checkData['phoneList']['city'], $kh_city[1]) !== false) || (empty($kh_city[1]) && strpos($checkData['phoneList']['province'], $kh_city[0]) !== false)) { unset($re); break; } } } } else { $re['code'] = '501';//空号检测失败 $re['message'] = '号码检测有误!'; } } if (!isset($re['code'])) { ///// 发送短信 ///// // $re = $this->postSMS('msgsend', $row); $re = $this->sendSmsHttpRequest($row); } //短信记录保存数据库 $sql_data = array( 'uid' => $data['uid'], 'cuid' => isset($data['cuid']) ? $data['cuid'] : 0, 'moblie' => $data['mobile'], 'ctime' => time(), 'content' => $data['content'], 'port' => $data['port'], 'location' => $location ); if ($re['code'] == 1) { //检查是否需要发送系统预警 include_once('warning.model.php'); $warning = new warning_model($this->db, $this->def); $warning->warning(5); $sql_data['state'] = 0; $sql_data['ip'] = fun_ip_get(); $sqlResult = $this->insert_into('moblie_msg', $sql_data); return array('status' => 1, 'msg' => '发送成功!'); } else { $sql_data['state'] = $re['code']; $this->insert_into('moblie_msg', $sql_data); $content = '短信发送失败!手机号:' . $data['mobile'] . ',状态:' . $re['code'] . "," . $re['message']; if ($re['code'] == '501') { // 记录空号检测失败,综合平台返回的错误原因 $content .= $checkInfo['message']; } $this->addErrorLog($data['uid'], 8, $content); return array('status' => -1, 'msg' => '发送失败!状态:' . $re['code'] . "," . $re['message']); } } /** * 发送短信 * @param array $data 传入参数 * @param string $content 短信内容 * @return number[]|string[] */ public function sendSMSType($data, $content = NULL) { if (!$this->_isKey('type', $data) || !$this->_isKey('sy_msg_' . $data['type'], $this->config) || $this->config['sy_msg_' . $data['type']] != 1) { //是否后台设置了需要短信提醒 return array('status' => -1, 'msg' => '未开启短信提醒,请联系管理员(code:msg' . $data['type'] . ')'); } //短信内容,如发送的内容相同,可以先把内容处理好传入,减少数据处理 if (!$content) { $tpl = $this->getTpl($data, 'msg'); if (isset($tpl['status'])) { return $tpl; } $content = $tpl['content']; $template_id = $tpl['template_id']; } $data['content'] = $content; $data['template_id'] = $template_id; return $this->sendSMS($data); } public function getBusinessInfo($name) { if ($this->config['sy_tyc_appkey'] && $this->config['sy_tyc_appsecret']) { //查询当前数据库中是否存在该名称 $comNameNum = $this->select_num('company', array('name' => $name)); //企业名称存在 if ($comNameNum > 0) { $url = 'https://u.phpyun.com/company'; $url .= '?appSecret=' . $this->config['sy_tyc_appsecret'] . '&appKey=' . $this->config['sy_tyc_appkey'] . "&companyName=" . $name; if (extension_loaded('curl')) { $file_contents = CurlGet($url); } else if (function_exists('file_get_contents')) { $file_contents = file_get_contents($url); } $return = json_decode($file_contents, true); if (!empty($return['data'])) { $tycData = json_decode($return['data'], true); $Info = $tycData['result']; if ($Info['estiblishTime']) { $msectime = $Info['estiblishTime'] * 0.001; if (strstr($msectime, '.')) { sprintf('%01.3f', $msectime); list($usec, $sec) = explode('.', $msectime); $sec = str_pad($sec, 3, '0', STR_PAD_RIGHT); } else { $usec = $msectime; $sec = '000'; } $est = date('Y-m-d', $usec); $Info['estiblishTime'] = $est; } if ($Info['fromTime']) { $msectime = $Info['fromTime'] * 0.001; if (strstr($msectime, '.')) { sprintf('%01.3f', $msectime); list($usec, $sec) = explode('.', $msectime); $sec = str_pad($sec, 3, '0', STR_PAD_RIGHT); } else { $usec = $msectime; $sec = '000'; } $est = date('Y-m-d', $usec); $Info['fromTime'] = $est; } else { $Info['fromTime'] = '自创立起'; } if ($Info['toTime']) { $toTime = new DateTime('@' . substr($Info['toTime'], 0, 10)); $toTime->setTimezone(new DateTimeZone('PRC')); $Info['toTime'] = $toTime->format('Y-m-d'); } else { $Info['toTime'] = '长期'; } } } return array('content' => $Info); } } /** * @desc 短信验证码时效性 * @param string $data * @return boolean */ public function checkTime($data = 0) { $cert_validity = $this->config['moblie_codetime'] * 60; // 验证码有效时间 if (!$data) { return false; } $time = time(); $data = is_numeric($data) ?: 0; $ctime = round($time - $data, 2); if ($ctime <= $cert_validity) { return true; } else { return false; } } /** * 发送手机短信/邮件验证码 * @param string $sended 手机号/邮箱 * @param string $type 验证码类型:getpass-忘记密码-7; login-登录-2; regcode-注册-2; cert-认证-2; * @param array $user 用户信息 * @param number $length 验证码长度 * @param number $validity 发送间隔 * @param string $kind 类型:msg 短信/email 邮件 * @param string $port 端口:1-PC;2-WAP;5-ADMIN * @return array|number[]|string[] */ public function sendCode($sended, $type, $port = '', $user = array(), $length = 6, $validity = 120, $kind = 'msg') { $time = time(); $overtime = $time - $validity; $today = strtotime('today'); $code = gt_Generate_code($length); //验证码 $lastSend = []; $result = []; if ($kind == 'msg') { ///// 短信 ///// if (!checkMsgOpen($this->config)) { return array('error' => 107, 'msg' => '网站没有配置短信,请联系管理员!'); } $ip = fun_ip_get(); $ipnum = $this->select_num('moblie_msg', array('ip' => $ip, 'ctime' => array('>', strtotime(date('Y-m-d'))))); if ($ipnum >= $this->config['ip_msgnum']) { return array('error' => 107, 'msg' => '当前IP短信发送受限!'); } $num = $this->select_num('moblie_msg', array('moblie' => $sended, 'ctime' => array('>', strtotime(date('Y-m-d'))))); if ($num >= $this->config['moblie_msgnum']) { return array('error' => 107, 'msg' => '请不要频繁发送!'); } if (!CheckMobile($sended)) { return array('error' => 106, 'msg' => '手机号码格式错误'); } if ($type == 'getpass') { ///// 找回密码的情况 ///// $member = $this->select_once('member', array('moblie' => $sended), '`uid`,`username` as `name`, `usertype`'); if (!empty($member)) { $user = array( 'uid' => $member['uid'], 'usertype' => $member['usertype'], 'name' => $member['name'] ); } else { return array('error' => 105, 'msg' => '该手机尚未注册'); } ///// 获取企业认证信息 ///// $lastSend = $this->select_once('company_cert', array('check' => $sended, 'type' => 7, 'orderby' => 'id,desc'), '`ctime`,`type`'); } else { ///// 获取企业认证信息 ///// $lastSend = $this->select_once('company_cert', array('check' => $sended, 'type' => 2, 'orderby' => 'id,desc'), '`ctime`,`type`'); } if ($lastSend['ctime'] > $overtime) { return array('error' => 102, 'msg' => '两次发送间隔需超过' . $validity . '秒'); } if ($type == 'cert') { $certover = $time - ($this->config['cert_msgtime'] * 60); if ($lastSend['ctime'] > $certover) { return array('error' => 102, 'msg' => '手机认证短信发送间隔需超过' . $this->config['cert_msgtime'] . '分钟'); } } $sendToday = $this->select_all('moblie_msg', array('moblie' => $sended, 'ctime' => array('>', $today)), '`ip`'); if (count($sendToday) >= $this->config['moblie_msgnum']) { return array('error' => 103, 'msg' => '同一手机号一天最多发送' . $this->config['moblie_msgnum'] . '条'); } $ipSendNum = 0; foreach ($sendToday as $v) { if ($v['ip'] == $ip) { $ipSendNum++; } } if ($ipSendNum >= $this->config['ip_msgnum']) { return array('error' => 104, 'msg' => '同一IP一天最多发送' . $this->config['ip_msgnum'] . '条'); } $result = $this->sendType($sended, $type, $code, 'msg', $user, $port); } elseif ($kind == 'email') { if (!CheckRegEmail($sended)) { return array('error' => 101, 'msg' => '邮箱格式错误'); } if ($this->config['sy_email_set'] != "1") { return array('error' => 107, 'msg' => '网站邮件服务器暂不可用'); } $num = $this->select_num("company_cert", array('check' => $sended, 'ctime' => array('>', strtotime(date('Y-m-d'))))); if ($num >= 5) { $data['errmsg'] = '请不要频繁发送邮件!'; $data['error'] = 17; echo json_encode($data); die; } if ($type == 'getpass') { $member = $this->select_once('member', array('email' => $sended), '`uid`,`username` as `name`, `usertype`'); if ($this->config['sy_email_getpass'] == "2") { return array('error' => 108, 'msg' => '网站未开启邮件找回密码'); } if ($member) { $user = array( 'uid' => $member['uid'], 'usertype' => $member['usertype'], 'name' => $member['name'] ); } else { return array('error' => 105, 'msg' => '该邮箱尚未注册'); } $num = $this->select_num('company_cert', array('check' => $sended, 'type' => 7, 'ctime' => array('>', $today))); if ($num >= 5) { return array('error' => 106, 'msg' => '请不要频繁发送邮件'); } $lastSend = $this->select_once('company_cert', array('check' => $sended, 'type' => 7), '`ctime`,`type`'); $result = $this->sendType($sended, $type, $code, 'email', $user); } } if ($result['status'] != -1) { $sendData = array( 'uid' => intval($user['uid']), 'status' => 0, 'step' => 1, 'check' => $sended, 'check2' => $code, 'ctime' => $time, 'did' => $this->config['did'], 'statusbody' => $this->codeType($type) ); // 7-找回密码,2-其他短信、邮件验证码 if ($type == 'getpass') { $sendData['type'] = 7; } else { $sendData['type'] = 2; } //只修改短信验证码相关的验证 if ($lastSend && ($lastSend['type'] == 2 || $lastSend['type'] == 7)) { if ($lastSend['type'] == 2) { $this->update_once('company_cert', $sendData, array('check' => $sended, 'type' => 2)); } elseif ($lastSend['type'] == 7) { $this->update_once('company_cert', $sendData, array('check' => $sended, 'type' => 7)); } } else { $this->insert_into('company_cert', $sendData); } } return array('error' => $result['status'], 'msg' => $result['msg']); } /** * 按类别发送验证码 * @param $sended // 发送对象-手机号 * @param $type // 验证码类别 * @param $code // 验证码 * @param $kind // 发送类别 * @param $user // 用户信息 * @param $port // 端口 * @return array|number[]|string[] */ private function sendType($sended, $type, $code, $kind = 'msg', $user = array(), $port = null) { $finfo = $this->forsend($user); //用户信息 $data = array( 'uid' => $finfo['uid'], 'username' => $finfo['name'], 'cuid' => $finfo['cuid'], 'cname' => $finfo['cname'], 'type' => $type, 'code' => $code ); $result = []; if ($kind == 'msg') { $data['mobile'] = $sended; $data['port'] = $port; $result = $this->sendSMSType($data); } elseif ($kind == 'email') { $data['email'] = $sended; $result = $this->sendEmailType($data); } return $result; } /** * 手机验证码类型 * @param $type * @return string */ private function codeType($type) { $status = array( 'login' => '手机登录验证码', 'regcode' => '手机注册验证码', 'cert' => '手机认证', 'getpass' => '找回密码' ); return $status[$type] ?: ''; } /** * 查询接收短信、邮件用户信息 * @param $user * @return array|mixed|string */ private function forsend($user) { $info = array( 'uid' => 0, 'name' => '', 'cuid' => 0, 'cname' => '系统' ); if (!empty($user['uid'])) { if (!empty($user['name'])) { $info['uid'] = $user['uid']; $info['name'] = $user['name']; } else { $info = $this->select_once('member', array('uid' => $user['uid']), '`uid`, `username` as `name`'); } } return $info; } /** * @desc 极验验证 * @param $authcode * @param $tag * @return array */ function jycheck($authcode, $tag) { $image = false; session_start(); if (!empty($tag)) { if (strpos($this->config['code_web'], $tag) !== false) { if ($this->config['code_kind'] > 2) { $check = verifytoken($this->config); if ($check['code'] != '200') { return array('error' => 107, 'msg' => $check['msg']); } } else { $image = true; } } } else { $image = true; } if ($image) { if (md5(strtolower(trim($authcode))) != $_SESSION['authcode'] || trim($authcode) == '') { unset($_SESSION['authcode']); return array('error' => 106, 'msg' => '图片验证码填写错误!'); } else { unset($_SESSION['authcode']); } } } /** * 签名-腾讯云 * @param $key * @param $msg * @return string */ protected function sign($key, $msg) { return hash_hmac("sha256", $msg, $key, true); } /** * 发送短信接口-腾讯云 * @param $data * @return array */ public function sendSmsHttpRequest($data = []) { // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密 // 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305 // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取 $secret_id = $data['sy_sms_secret_id']; $secret_key = $data['sy_sms_secret_key']; $token = ""; $service = "sms"; $host = "sms.tencentcloudapi.com"; $req_region = "ap-guangzhou"; $version = "2021-01-11"; $action = "SendSms"; //////数字转字符串 ////// $params = [ 'PhoneNumberSet' => ['+86' . $data['phone']], 'SmsSdkAppId' => $data['sy_sms_sdk_app_id'], 'TemplateId' => $data['template_id'], 'SignName' => $data['sy_sms_sign_name'], 'TemplateParamSet' => [strval($data['code'])] ]; $payload = json_encode($params, JSON_UNESCAPED_UNICODE); $endpoint = "https://sms.tencentcloudapi.com"; $algorithm = "TC3-HMAC-SHA256"; $timestamp = time(); $date = gmdate("Y-m-d", $timestamp); // ************* 步骤 1:拼接规范请求串 ************* $http_request_method = "POST"; $canonical_uri = "/"; $canonical_querystring = ""; $ct = "application/json; charset=utf-8"; $canonical_headers = "content-type:" . $ct . "\nhost:" . $host . "\nx-tc-action:" . strtolower($action) . "\n"; $signed_headers = "content-type;host;x-tc-action"; $hashed_request_payload = hash("sha256", $payload); $canonical_request = "$http_request_method\n$canonical_uri\n$canonical_querystring\n$canonical_headers\n$signed_headers\n$hashed_request_payload"; // ************* 步骤 2:拼接待签名字符串 ************* $credential_scope = "$date/$service/tc3_request"; $hashed_canonical_request = hash("sha256", $canonical_request); $string_to_sign = "$algorithm\n$timestamp\n$credential_scope\n$hashed_canonical_request"; // ************* 步骤 3:计算签名 ************* $secret_date = $this->sign("TC3" . $secret_key, $date); $secret_service = $this->sign($secret_date, $service); $secret_signing = $this->sign($secret_service, "tc3_request"); $signature = hash_hmac("sha256", $string_to_sign, $secret_signing); // ************* 步骤 4:拼接 Authorization ************* $authorization = "$algorithm Credential=$secret_id/$credential_scope, SignedHeaders=$signed_headers, Signature=$signature"; // ************* 步骤 5:构造并发起请求 ************* $headers = [ "Authorization" => $authorization, "Content-Type" => "application/json; charset=utf-8", "Host" => $host, "X-TC-Action" => $action, "X-TC-Timestamp" => $timestamp, "X-TC-Version" => $version ]; if ($req_region) { $headers["X-TC-Region"] = $req_region; } if ($token) { $headers["X-TC-Token"] = $token; } try { $ch = curl_init(); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($ch, CURLOPT_URL, $endpoint); curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); curl_setopt($ch, CURLOPT_HTTPHEADER, array_map(function ($k, $v) { return "$k: $v"; }, array_keys($headers), $headers)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); $response = curl_exec($ch); curl_close($ch); $result = json_decode($response, TRUE); if (!$result['Response']['RequestId']) { throw new Exception("请求失败", 10000); } $result_result = [ 'code' => 1, 'msg' => 'ok', 'data' => $result['Response'] ]; } catch (Exception $exc) { $result_result = [ 'code' => $exc->getCode(), 'msg' => $exc->getMessage() ]; } return $result_result; } }