Sms.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. <?php
  2. namespace app\common\library;
  3. use think\Cache;
  4. use app\common\model\Setting;
  5. use THink\Env;
  6. /**
  7. * 短信发送类
  8. *
  9. */
  10. class Sms
  11. {
  12. protected $_XML_string; // 提交服务商的请求数据
  13. protected $_accessKeyId = '';
  14. protected $_accessKeySecret = '';
  15. protected $_signName = "祈盟文化";
  16. protected $_signName2 = "祈盟文化";
  17. protected $_domain = 'dysmsapi.aliyuncs.com';
  18. protected $sp_code = ''; // 长号码,选填
  19. protected $uid = ""; // 业务标识,选填,由客户自行填写不超过20位的数字
  20. protected $_is_error = false; // 是否存在错误
  21. protected $_status = false;
  22. protected $_error_msg = null;
  23. protected $_last_time = null; // 最后一次发送短信的时间
  24. protected $_times = 0; // 同一号码当日发送的次数
  25. protected $_key = null; // redis缓存中保存的key
  26. protected $_mobile = null; // 发送的手机号
  27. public $_validate_content = 'SMS_462250586'; //'短信验证码:%d,有效期为10分钟,请勿向任何人提供您收到的短信验证码。'; // 验证码短信内容模板
  28. protected $_notify_content = '您的验证码为 ${code} ,该验证码3分钟内有效,请勿泄露于他人。'; // 通知短信内容模板
  29. protected $_appeal_fail_content = 'SMS_462250586'; //'【矩戮信息】您申诉的账号[%s]因提供的资料不完善而未通过,申诉编码为:[%s]。您可以稍后重新进行申诉,或联系矩戮信息客服咨询。';
  30. protected $_appeal_success_content = 'SMS_462250586'; //'【矩戮信息】您的账号[%s]的申诉已通过,申诉编码为:[%s], 成功凭证为:[%s]。请进入客服中心内的“申诉查询”http://www.srjl.net/kefu/sscx/,输入申诉编码和成功凭证后重置密码。';
  31. protected $_appeal_content = 'SMS_462250586'; //'您的账号:[%s]的申诉已受理,申诉编码号为:[%s],请妥善保存此申诉编码,以备后续使用。申诉结果将在%s个工作日内发送至您的手机,请勿重复申诉。申诉进度查询:http://www.srjl.net/kefu/sscx/'; //发送申诉编码内容模版
  32. protected $_settleaudit_fail_content = 'SMS_462250586'; //'您的账号[%s]的结算申请(订单编号为:[%s]),审核不通过。您可以登录后台查看原因,或联系星空互娱客服咨询。';
  33. protected $_settleaudit_success_content = 'SMS_462250586'; //'尊敬的会长,您的账号[%s],结算订单[%s]申请已通过,请及时在后台发起提现申请。有任何疑问请联系我们,谢谢!';
  34. protected $_identifyaudit_fail_content = 'SMS_462250586'; //'您的账号[%s]登记的身份认证信息,审核不通过。请尽快登录平台查看原因,或联系星空互娱客服咨询。';
  35. protected $_identifyaudit_success_content = 'SMS_462250586'; //'您的账号[%s]登记的身份认证信息,已审核通过。您可以登录后台查看。';
  36. protected $_code = null; // 六位数验证码
  37. protected $_redis = null; // redis连接实例
  38. protected $_expire_time = 180; // 过期时间
  39. protected $_interval = 60; // 发送间隔
  40. protected $_now_time = null; // 当前时间戳
  41. protected $_times_limit = 20; // 同一号码发送次数限制
  42. protected $_params = null; // 参数
  43. public function __construct()
  44. {
  45. $this->_key = 'clearable_sms:' . date('Ymd');
  46. $this->_redis = Cache::store('default');
  47. $this->_now_time= time();
  48. $this->_accessKeyId = Env::get('ali_oss.access_keysid');
  49. $this->_accessKeySecret = Env::get('ali_oss.access_keysecrt');
  50. }
  51. /**
  52. * 校验短信验证码是否正确,同时判断是否发送过,
  53. */
  54. public function checkCode($mobile, $code)
  55. {
  56. $this->_mobile = $mobile;
  57. if (!$this->_isMobile()) {
  58. $this->_is_error = true;
  59. $this->_error_msg = '手机号错误';
  60. }
  61. if (!$this->_is_error && (empty($this->_getLastTime()) || empty($this->_getCode()))) {
  62. $this->_is_error = true;
  63. $this->_error_msg = '短信验证码不存在,请先发送';
  64. }
  65. if (!$this->_is_error && ($this->_now_time - $this->_last_time > $this->_expire_time)) { // 判断是否过期
  66. $this->_is_error = true;
  67. $this->_error_msg = '验证码已失效';
  68. }
  69. if (!$this->_is_error && $code != $this->_code) {
  70. $this->_is_error = true;
  71. $this->_error_msg = '验证码输入错误';
  72. }
  73. if (!$this->_is_error) {
  74. $this->_status = true;
  75. $this->clearLastTime($mobile);
  76. }
  77. return array('status' => $this->_status, 'msg' => $this->_error_msg);
  78. }
  79. /**
  80. * 发送验证码
  81. * @param string $mobile
  82. * @return array('status'=>bool, 'msg'=>处理结果);
  83. */
  84. public function sendCode($mobile,$content='')
  85. {
  86. $this->_mobile = $mobile;
  87. $this->_sendRuler(); // 发送规则限制
  88. if (!$this->_is_error) {
  89. if (!empty($content)) $this->_validate_content = $content;
  90. $this->_formatString();
  91. $result = $this->sendSms($mobile,$this->_validate_content,$this->_params);
  92. $this->_error_msg = '';
  93. switch ($result->Code){
  94. case 'OK':
  95. break;
  96. case 'isv.DAY_LIMIT_CONTROL':
  97. $this->_error_msg = '短信每日发送上限';
  98. break;
  99. case 'isv.MONTH_LIMIT_CONTROL':
  100. $this->_error_msg = '短信每月发送上限';
  101. break;
  102. case 'isv.BUSINESS_LIMIT_CONTROL':
  103. $this->_error_msg = '短信每分钟内发送上限为一条';
  104. break;
  105. case 'isv.AMOUNT_NOT_ENOUGH':
  106. $this->_error_msg = '短信账户余额不足';
  107. break;
  108. }
  109. if($result && !$this->_error_msg) { // 发送成功,写入redis
  110. $this->_status = true;
  111. $this->_setRedisData();
  112. }else{
  113. $this->_is_error = true;
  114. }
  115. }
  116. return array('status' => $this->_status, 'msg' => $this->_error_msg);
  117. }
  118. /**
  119. * 发送申诉编码
  120. * @param string $mobile
  121. * @return array('status'=>bool, 'msg'=>处理结果);
  122. */
  123. public function sendAppealCode($username, $code, $mobile, $day, $certificate, $status)
  124. {
  125. $this->_formatAppealContent($username, $code, $day, $certificate, $status);
  126. $this->_mobile = $mobile;
  127. $this->_formatString('appeal');
  128. $result = $this->sendSms($mobile,$this->_appeal_content,$this->_params);
  129. if($result) { // 发送成功,写入redis
  130. $this->_status = true;
  131. $this->_setRedisData();
  132. }else{
  133. $this->_is_error = true;
  134. }
  135. return array('status' => $this->_status, 'msg' => $this->_error_msg);
  136. }
  137. /**
  138. * 发送结算审核通知
  139. * @param string $mobile
  140. * @return array('status'=>bool, 'msg'=>处理结果);
  141. */
  142. public function sendSettleAuditInfo($username, $mobile, $orderid, $status)
  143. {
  144. $this->_formatSettleAuditContent($username, $orderid, $status);
  145. $this->_mobile = $mobile;
  146. $this->_formatString('settleaudit');
  147. $result = $this->sendSms($mobile,$this->_settleaudit_content,$this->_params);
  148. if($result) { // 发送成功,写入redis
  149. $this->_status = true;
  150. $this->_setRedisData();
  151. }else{
  152. $this->_is_error = true;
  153. }
  154. return array('status' => $this->_status, 'msg' => $this->_error_msg);
  155. }
  156. /**
  157. * 发送身份认证审核通知
  158. * @param string $mobile
  159. * @return array('status'=>bool, 'msg'=>处理结果);
  160. */
  161. public function sendIdentifyAuditInfo($username, $mobile, $status)
  162. {
  163. $this->_formatIdentifyAuditContent($username, $status);
  164. $this->_mobile = $mobile;
  165. $this->_formatString('identifyaudit');
  166. $result = $this->sendSms($mobile,$this->_identifyaudit_content,$this->_params);
  167. if($result) { // 发送成功,写入redis
  168. $this->_status = true;
  169. $this->_setRedisData();
  170. }else{
  171. $this->_is_error = true;
  172. }
  173. return array('status' => $this->_status, 'msg' => $this->_error_msg);
  174. }
  175. /**
  176. * 发送通知短信
  177. * @param string $mobile 手机号
  178. * @param string $content 短信内容
  179. *
  180. * @return array('status'=>bool, 'msg'=>'处理结果');
  181. */
  182. public function sendNotify($mobile, $content, $params)
  183. {
  184. $this->_mobile = $mobile;
  185. //手机号码验证
  186. if (!$this->_isMobile()) {
  187. $this->_is_error = true;
  188. $this->_error_msg = '手机号错误';
  189. }
  190. if (!$this->_is_error) {
  191. $result = $this->sendSms($mobile,$content,$params);
  192. if($result) { // 发送成功,写入redis
  193. $this->_status = true;
  194. $this->_setRedisData();
  195. }else{
  196. $this->_is_error = true;
  197. }
  198. }
  199. return array('status' => $this->_status, 'msg' => $this->_error_msg);
  200. }
  201. /**
  202. * 清除最后发送时间,用于连续发送验证短信的场景
  203. */
  204. public function clearLastTime($mobile)
  205. {
  206. $this->_mobile = $mobile;
  207. if ($this->_redis->has($this->_key)) {
  208. $data = $this->_redis->get($this->_key);
  209. $data = json_decode($data, true);
  210. if (isset($data[ $mobile ]['sendtime'])) {
  211. $data[ $mobile ]['sendtime'] = 0;
  212. }
  213. $this->_redis->set($this->_key, json_encode($data), 86400);
  214. }
  215. }
  216. /**
  217. * 格式化短信内容
  218. * @param string $type 要发送的内容类型,validate为验证码,否则为通知
  219. * @param string $content 要发送的短息内容
  220. *
  221. * @return null
  222. */
  223. protected function _formatString($type = 'validate',$content='')
  224. {
  225. if ('validate' == $type) {
  226. $content = $this->_formatValidateContent();
  227. }
  228. elseif ('appeal' == $type) {
  229. $content = $this->_appeal_content;
  230. }
  231. /*
  232. // 签名
  233. $sign = md5($content.$this->_password);
  234. $data = array('cust_code'=>$this->_account,'sp_code'=>$this->sp_code,'content'=>$content,'destMobiles'=>$this->_mobile,'uid'=>$this->uid,'need_report'=>'yes','sign'=>$sign);
  235. $this->_XML_string = json_encode($data);
  236. */
  237. }
  238. /**
  239. * 格式化验证码短信内容
  240. * @return string 格式化后的内容
  241. */
  242. protected function _formatValidateContent()
  243. {
  244. $this->_makeCode();
  245. $this->_params = Array (
  246. "code" => $this->_code,
  247. );
  248. /*
  249. $content = sprintf($this->_validate_content, $this->_code);
  250. $this->_validate_content = $content;
  251. return $content;
  252. */
  253. }
  254. /**
  255. * 格式化结算审核结果短信内容
  256. * @return null
  257. */
  258. protected function _formatSettleAuditContent($username, $orderid, $status)
  259. {
  260. if ($status == 2) {
  261. $this->_settleaudit_content = $this->_settleaudit_fail_content;
  262. $this->_params = Array (
  263. "account" => $username,
  264. "orderid" => '******'.substr($orderid,-10),
  265. );
  266. } elseif ($status == 1) {
  267. $this->_settleaudit_content = $this->_settleaudit_success_content;
  268. $this->_params = Array (
  269. "account" => $username,
  270. "orderid" => '******'.substr($orderid,-10),
  271. );
  272. } else {
  273. $this->_settleaudit_content = $this->_settleaudit_fail_content;
  274. $this->_params = Array (
  275. "account" => $username,
  276. "orderid" => '******'.substr($orderid,-10),
  277. );
  278. }
  279. }
  280. /**
  281. * 格式化身份认证审核结果短信内容
  282. * @return null
  283. */
  284. protected function _formatIdentifyAuditContent($username, $status)
  285. {
  286. if ($status == 2) {
  287. $this->_identifyaudit_content = $this->_identifyaudit_fail_content;
  288. $this->_params = Array (
  289. "account" => $username,
  290. );
  291. } elseif ($status == 1) {
  292. $this->_identifyaudit_content = $this->_identifyaudit_success_content;
  293. $this->_params = Array (
  294. "account" => $username,
  295. );
  296. } else {
  297. $this->_identifyaudit_content = $this->_identifyaudit_fail_content;
  298. $this->_params = Array (
  299. "account" => $username,
  300. );
  301. }
  302. }
  303. /**
  304. * 格式化申诉编码短信内容
  305. * @return null
  306. */
  307. protected function _formatAppealContent($username, $code, $day, $certificate, $status)
  308. {
  309. if ($status == 2 || $status == 4) {
  310. $this->_appeal_content = $this->_appeal_fail_content;
  311. $this->_params = Array (
  312. "account" => $username,
  313. "number" => $code,
  314. );
  315. // $this->_appeal_content = sprintf($this->_appeal_fail_content, $username, $code);
  316. } elseif ($status == 1) {
  317. $this->_appeal_content = $this->_appeal_success_content;
  318. $this->_params = Array (
  319. "account" => $username,
  320. "number" => $code,
  321. "pincode" => $certificate,
  322. );
  323. // $this->_appeal_content = sprintf($this->_appeal_success_content, $username, $code, $certificate);
  324. } else {
  325. $this->_appeal_content = $this->_appeal_content;
  326. $this->_params = Array (
  327. "account" => $username,
  328. "number" => $code,
  329. "days" => $day,
  330. );
  331. // $this->_appeal_content = sprintf($this->_appeal_content, $username, $code, $day);
  332. }
  333. }
  334. /**
  335. * 发送验证码前规则验证
  336. * @return null
  337. */
  338. protected function _sendRuler()
  339. {
  340. $settingModel = new Setting();
  341. if ($this->_getTimes() >= $this->_times_limit) {
  342. $this->_is_error = true;
  343. $this->_error_msg = '短信发送达到限制';
  344. }
  345. //白名单
  346. $white_list = explode('|',$settingModel::getSetting('SMS_WHITE_LIST'));
  347. if (!$this->_is_error && !empty($this->_getLastTime())) { // 最后发送时间对比
  348. if (!in_array($this->_mobile,$white_list) && ($this->_now_time - $this->_last_time) < $this->_interval) {
  349. $this->_is_error = true;
  350. $this->_error_msg = '发送验证码操作太频繁,请稍后再试';
  351. }
  352. }
  353. if (!$this->_is_error && !$this->_isMobile()) {
  354. $this->_is_error = true;
  355. $this->_error_msg = '手机号错误';
  356. }
  357. }
  358. /**
  359. * 判断是否正确的手机号格式
  360. * @param string $mobile
  361. * @return bool
  362. */
  363. protected function _isMobile()
  364. {
  365. $validate = new ValidateExtend();
  366. $array = explode(',', $this->_mobile);
  367. foreach ( $array as $k => $v ) {
  368. if ( ! $validate->is($v, 'mobile') ) {
  369. unset($array[$k]);
  370. }
  371. }
  372. if ( empty($array) ) {
  373. return false;
  374. }
  375. $this->_mobile = join(',', $array);
  376. return true;
  377. }
  378. /**
  379. * 获取最后一次发送时间
  380. * @return string
  381. */
  382. protected function _getLastTime()
  383. {
  384. $this->_last_time = $this->_getValue('sendtime');
  385. return $this->_last_time;
  386. }
  387. /**
  388. * 获取redis中该手机号的某个key的值
  389. */
  390. protected function _getValue($key)
  391. {
  392. $response = null;
  393. if ($this->_redis->has($this->_key)) { // 存在这个key
  394. $data = $this->_redis->get($this->_key);
  395. $data = json_decode($data, true);
  396. if (isset($data[ $this->_mobile ])) { // 该号码已经有发送记录
  397. $response = $data[ $this->_mobile ][ $key ];
  398. }
  399. }
  400. return $response;
  401. }
  402. /**
  403. * 获取redis中保存的该手机号的验证码
  404. */
  405. protected function _getCode()
  406. {
  407. $this->_code = $this->_getValue('code');
  408. return $this->_code;
  409. }
  410. /**
  411. * 写入redis数据
  412. * @return null
  413. */
  414. protected function _setRedisData()
  415. {
  416. $this->_mobile = strval($this->_mobile);
  417. // 存在这个key
  418. if ($this->_redis->has($this->_key)) {
  419. $data = $this->_redis->get($this->_key);
  420. $data = json_decode($data, true);
  421. if (!isset($data[ $this->_mobile ])) {
  422. $data[ $this->_mobile ] = array(
  423. 'times' => 1,
  424. 'sendtime' => $this->_now_time,
  425. 'code' => $this->_code,
  426. );
  427. } else {
  428. $data[ $this->_mobile ]['times'] = ++$data[ $this->_mobile ]['times'];
  429. $data[ $this->_mobile ]['sendtime'] = $this->_now_time;
  430. $data[ $this->_mobile ]['code'] = $this->_code;
  431. }
  432. } else { // 不存在这个key,新建
  433. $data = array(
  434. $this->_mobile => array(
  435. 'times' => 1,
  436. 'sendtime' => time(),
  437. 'code' => $this->_code,
  438. ),
  439. ); //now-here
  440. }
  441. $this->_redis->set($this->_key, json_encode($data), 86400);
  442. }
  443. /**
  444. * 清除验证码,用于需要验证码失效的场景
  445. * @param string $mobile
  446. * @return void
  447. */
  448. public function clearVerifyCode($mobile){
  449. if ($this->_redis->has($this->_key)) {
  450. $data = $this->_redis->get($this->_key);
  451. $data = json_decode($data, true);
  452. if (isset($data[$mobile])) {
  453. $data[$mobile]['code'] = '';
  454. }
  455. $this->_redis->set($this->_key, json_encode($data), 86400);
  456. }
  457. }
  458. /**
  459. * 获取该手机号当天的发送次数
  460. * @return int
  461. */
  462. protected function _getTimes()
  463. {
  464. $this->_times = $this->_getValue('times');
  465. return $this->_times;
  466. }
  467. /**
  468. * 向短信服务商发送短信请求
  469. * @return string 请求结果
  470. */
  471. protected function _post()
  472. {
  473. $header[] = "Content-Type: application/json"; //定义content-type为xml,注意是数组
  474. $header[] = "charset=utf-8"; //定义content-type为xml,注意是数组
  475. $ch = curl_init();
  476. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
  477. curl_setopt($ch, CURLOPT_URL, $this->_url);
  478. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  479. /* 设置超时时间*/
  480. curl_setopt($ch, CURLOPT_TIMEOUT, 300);
  481. curl_setopt($ch, CURLOPT_POST, 1);
  482. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  483. curl_setopt($ch, CURLOPT_POSTFIELDS, $this->_XML_string);
  484. $response = curl_exec($ch);
  485. if (curl_errno($ch)) {
  486. return 'other';
  487. }
  488. curl_close($ch);
  489. return json_decode($response,true);
  490. }
  491. /**
  492. * 生成验证码
  493. * @return null
  494. */
  495. protected function _makeCode()
  496. {
  497. $code = rand(111111, 999999);
  498. $this->_code = $code;
  499. }
  500. /**
  501. * 短信发送后的服务商返回的消息处理
  502. *
  503. * @param $result mix 服务商返回值
  504. */
  505. public function afterSend($result)
  506. {
  507. if(is_array($result)){
  508. if($result['status']=='success'){
  509. $this->_status = true;
  510. }
  511. else{
  512. $this->_is_error = true;
  513. $this->_error_msg = $result['respMsg'];
  514. }
  515. }
  516. else{
  517. $this->_is_error = true;
  518. $this->_error_msg = '未知错误';
  519. }
  520. }
  521. public function sendSms($mobile,$TemplateCode,$TemplateParam = array()) {
  522. $params = array ();
  523. $security = false;
  524. $accessKeyId = $this->_accessKeyId;
  525. $accessKeySecret = $this->_accessKeySecret;
  526. $params["PhoneNumbers"] = $mobile;
  527. if(in_array($TemplateCode, config('ALI_SMS_SIGN'))){
  528. $params["SignName"] = $this->_signName2;
  529. }else{
  530. $params["SignName"] = $this->_signName;
  531. }
  532. $params["TemplateCode"] = $TemplateCode;
  533. // fixme 可选: 设置模板参数, 假如模板中存在变量需要替换则为必填项
  534. if(!empty($TemplateParam) && is_array($TemplateParam)) {
  535. $params["TemplateParam"] = json_encode($TemplateParam, JSON_UNESCAPED_UNICODE);
  536. }
  537. $content = $this->request(
  538. $accessKeyId,
  539. $accessKeySecret,
  540. array_merge($params, array(
  541. "RegionId" => "cn-hangzhou",
  542. "Action" => "SendSms",
  543. "Version" => "2017-05-25",
  544. )),
  545. $security
  546. );
  547. return $content;
  548. }
  549. /**
  550. * 生成签名并发起请求
  551. *
  552. * @param $accessKeyId string AccessKeyId (https://ak-console.aliyun.com/)
  553. * @param $accessKeySecret string AccessKeySecret
  554. * @param $domain string API接口所在域名
  555. * @param $params array API具体参数
  556. * @param $security boolean 使用https
  557. * @param $method boolean 使用GET或POST方法请求,VPC仅支持POST
  558. * @return bool|\stdClass 返回API接口调用结果,当发生错误时返回false
  559. */
  560. public function request($accessKeyId, $accessKeySecret, $params, $security=false, $method='POST') {
  561. $apiParams = array_merge(array (
  562. "SignatureMethod" => "HMAC-SHA1",
  563. "SignatureNonce" => uniqid(mt_rand(0,0xffff), true),
  564. "SignatureVersion" => "1.0",
  565. "AccessKeyId" => $accessKeyId,
  566. "Timestamp" => gmdate("Y-m-d\TH:i:s\Z"),
  567. "Format" => "JSON",
  568. ), $params);
  569. ksort($apiParams);
  570. $sortedQueryStringTmp = "";
  571. foreach ($apiParams as $key => $value) {
  572. $sortedQueryStringTmp .= "&" . $this->encode($key) . "=" . $this->encode($value);
  573. }
  574. $stringToSign = "${method}&%2F&" . $this->encode(substr($sortedQueryStringTmp, 1));
  575. $sign = base64_encode(hash_hmac("sha1", $stringToSign, $accessKeySecret . "&",true));
  576. $signature = $this->encode($sign);
  577. $url = ($security ? 'https' : 'http')."://{$this->_domain}/";
  578. try {
  579. $content = $this->fetchContent($url, $method, "Signature={$signature}{$sortedQueryStringTmp}");
  580. return json_decode($content);
  581. } catch( \Exception $e) {
  582. return false;
  583. }
  584. }
  585. private function encode($str)
  586. {
  587. $res = urlencode($str);
  588. $res = preg_replace("/\+/", "%20", $res);
  589. $res = preg_replace("/\*/", "%2A", $res);
  590. $res = preg_replace("/%7E/", "~", $res);
  591. return $res;
  592. }
  593. private function fetchContent($url, $method, $body) {
  594. $ch = curl_init();
  595. if($method == 'POST') {
  596. curl_setopt($ch, CURLOPT_POST, 1);//post提交方式
  597. curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
  598. } else {
  599. $url .= '?'.$body;
  600. }
  601. curl_setopt($ch, CURLOPT_URL, $url);
  602. curl_setopt($ch, CURLOPT_TIMEOUT, 5);
  603. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  604. curl_setopt($ch, CURLOPT_HTTPHEADER, array(
  605. "x-sdk-client" => "php/2.0.0"
  606. ));
  607. if(substr($url, 0,5) == 'https') {
  608. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  609. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  610. }
  611. $rtn = curl_exec($ch);
  612. if($rtn === false) {
  613. // 大多由设置等原因引起,一般无法保障后续逻辑正常执行,
  614. // 所以这里触发的是E_USER_ERROR,会终止脚本执行,无法被try...catch捕获,需要用户排查环境、网络等故障
  615. trigger_error("[CURL_" . curl_errno($ch) . "]: " . curl_error($ch), E_USER_ERROR);
  616. }
  617. curl_close($ch);
  618. return $rtn;
  619. }
  620. }