Mini.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <?php
  2. namespace App\libs\wechat\auth\Gateways;
  3. use App\libs\cache\redis\Redis;
  4. use App\libs\helpers\Curl;
  5. use Illuminate\Support\Facades\DB;
  6. /**
  7. * @desc 微信小程序类
  8. * @package lc\wechat\auth\Gateways
  9. */
  10. class Mini extends Base
  11. {
  12. private $appId;
  13. private $secret;
  14. public function __construct()
  15. {
  16. parent::__construct();
  17. $this->appId = $this->config['appid'];
  18. $this->secret = $this->config['secret'];
  19. }
  20. /**
  21. * @link https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
  22. * @desc 使用授权code换取openid
  23. * @param string $code
  24. * @return array
  25. */
  26. public function code2Openid(string $code): array
  27. {
  28. $url = 'https://api.weixin.qq.com/sns/jscode2session';
  29. $res = Curl::requestCurl($url, 'GET', [], http_build_query([
  30. 'appid' => $this->appId,
  31. 'secret' => $this->secret,
  32. 'js_code' => $code,
  33. 'grant_type' => 'authorization_code'
  34. ]));
  35. return $res ? json_decode($res, true) : [];
  36. }
  37. /**
  38. * @link https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html
  39. * @desc 解密小程序信息
  40. * @param string $sessionKey session_key
  41. * @param string $encryptedData 加密字符
  42. * @param string $iv 偏移量
  43. * @return array
  44. */
  45. public function decrypt($sessionKey, $encryptedData, $iv): array
  46. {
  47. if (strlen($iv) != 24) {
  48. // 偏移量错误
  49. return ['code' => 41002, 'data' => '', 'msg' => 'iv解密失败'];
  50. }
  51. if (strlen($sessionKey) != 24) {
  52. // sessionkey 错误
  53. return ['code' => 41001, 'data' => '', 'msg' => 'sessionKey解密失败'];
  54. }
  55. $data = openssl_decrypt(base64_decode($encryptedData), 'AES-128-CBC', base64_decode($sessionKey), OPENSSL_RAW_DATA, base64_decode($iv));
  56. if (!$data) {
  57. return ['code' => 41001, 'data' => '', 'msg' => '解密失败'];
  58. }
  59. $userInfo = json_decode($data, true);
  60. if ($userInfo['watermark']['appid'] != $this->appId) {
  61. return ['code' => 41003, 'data' => '', 'msg' => 'appid不匹配'];
  62. }
  63. $userInfo['nickName'] = !empty($userInfo['nickName']) ? $userInfo['nickName'] : '';
  64. return ['code' => 0, 'data' => $userInfo, 'msg' => 'success'];
  65. }
  66. /**
  67. * @link https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.createQRCode.html
  68. * @desc 获取小程序码(限量)
  69. * @param string $path 页面路径
  70. * @param int $width 二维码宽度
  71. *
  72. */
  73. public function qrcode(string $path, $width = 430)
  74. {
  75. $params = ['path' => $path, 'width' => $width];
  76. $url = 'https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=' . $this->accessToken();
  77. return Curl::requestCurl($url, 'POST', [], json_encode($params));
  78. }
  79. /**
  80. * @link https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html
  81. * @desc 获取小程序码(不限量)
  82. * @param string $scene 场景值
  83. * @param array $extra 额外参数,详见
  84. * @return bool|mixed|string
  85. */
  86. public function qrcodeUnlimited(string $scene, $extra = [])
  87. {
  88. $params = array_merge($extra, ['scene' => $scene]);
  89. $url = 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=' . $this->accessToken();
  90. return Curl::requestCurl($url, 'POST', [], json_encode($params));
  91. }
  92. /**
  93. * @link https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html
  94. * @desc 生成短链接
  95. * @param array $params
  96. * @return bool|string
  97. */
  98. public function urlLink(array $params)
  99. {
  100. $url = 'https://api.weixin.qq.com/wxa/generate_urllink?access_token=' . $this->accessToken();
  101. return Curl::requestCurl($url, 'POST', [], json_encode($params));
  102. }
  103. /**
  104. * @link https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
  105. * @desc 发送模板消息
  106. * @param string $openid 小程序openid
  107. * @param string $template 模板ID
  108. * @param array $data 小程序数据
  109. * @param string $page 跳转页面
  110. * @param string $state 小程序状态
  111. * @return bool|mixed
  112. */
  113. public function sendMiniMsg(string $openid, string $template, array $data, string $page = null, string $state = 'normal'): array
  114. {
  115. $params = [
  116. 'touser' => $openid,
  117. 'template_id' => $template,
  118. 'miniprogram_state' => $state,
  119. 'data' => $data
  120. ];
  121. if ($page) {
  122. $params['page'] = $page;
  123. }
  124. $url = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=' . $this->accessToken();
  125. $res = Curl::requestCurl($url, 'POST', [], json_encode($params));
  126. return $res ? json_decode($res, true) : [];
  127. }
  128. /**
  129. * @link https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html
  130. * @desc 获取全局唯一接口调用凭据
  131. * @param int $repeatCnt
  132. * @return string
  133. */
  134. public function accessToken(&$repeatCnt = 0)
  135. {
  136. $drive = $this->config['token_drive'] ?? 'redis';
  137. $key = 'mini_' . $this->appId . '_accessToken';
  138. switch ($drive) {
  139. case 'redis':
  140. $redis = Redis::instance();
  141. $redis->select(15);
  142. $token = $redis->get($key);
  143. break;
  144. case 'db':
  145. default:
  146. $token = Db::table('configs')->where('c_key', $key)->where('c_expired > ' . time())->value('c_value');
  147. break;
  148. }
  149. var_dump($token);
  150. if ($token) {
  151. return $token;
  152. }
  153. var_dump('jinru');
  154. $url = 'https://api.weixin.qq.com/cgi-bin/token';
  155. $res = Curl::requestCurl($url, 'GET', [], http_build_query([
  156. 'grant_type' => 'client_credential',
  157. 'appid' => $this->appId,
  158. 'secret' => $this->secret
  159. ]));
  160. $data = json_decode($res, true);
  161. if (isset($data['access_token'])) {
  162. $token = $data['access_token'];
  163. switch ($drive) {
  164. case 'redis':
  165. $redis->setex($key, 7000, $token);
  166. break;
  167. case 'db':
  168. default:
  169. $isWin = Db::table('configs')->where('c_key',$key)->value('c_value');
  170. if ($isWin){
  171. Db::table('configs')
  172. ->where('c_key', $key)
  173. ->update([
  174. 'c_value' => $token,
  175. 'c_expired' => time() + 7000,
  176. 'c_updated' => date('Y-m-d H:i:s')
  177. ]);
  178. }else{
  179. Db::table('configs')
  180. ->insert([
  181. 'c_key' => $key,
  182. 'c_value' => $token,
  183. 'c_expired' => time() + 7000,
  184. 'c_updated' => date('Y-m-d H:i:s')
  185. ]);
  186. }
  187. break;
  188. }
  189. return $token;
  190. } else {
  191. if ($repeatCnt <= 3) {
  192. $repeatCnt++;
  193. return $this->accessToken($repeatCnt);
  194. } else {
  195. return $data['errcode'];
  196. }
  197. }
  198. }
  199. }