123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- <?php
- namespace App\libs\wechat\auth\Gateways;
- use App\libs\cache\redis\Redis;
- use App\libs\helpers\Curl;
- use Illuminate\Support\Facades\DB;
- /**
- * @desc 微信小程序类
- * @package lc\wechat\auth\Gateways
- */
- class Mini extends Base
- {
- private $appId;
- private $secret;
- public function __construct()
- {
- parent::__construct();
- $this->appId = $this->config['appid'];
- $this->secret = $this->config['secret'];
- }
- /**
- * @link https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
- * @desc 使用授权code换取openid
- * @param string $code
- * @return array
- */
- public function code2Openid(string $code): array
- {
- $url = 'https://api.weixin.qq.com/sns/jscode2session';
- $res = Curl::requestCurl($url, 'GET', [], http_build_query([
- 'appid' => $this->appId,
- 'secret' => $this->secret,
- 'js_code' => $code,
- 'grant_type' => 'authorization_code'
- ]));
- return $res ? json_decode($res, true) : [];
- }
- /**
- * @link https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html
- * @desc 解密小程序信息
- * @param string $sessionKey session_key
- * @param string $encryptedData 加密字符
- * @param string $iv 偏移量
- * @return array
- */
- public function decrypt($sessionKey, $encryptedData, $iv): array
- {
- if (strlen($iv) != 24) {
- // 偏移量错误
- return ['code' => 41002, 'data' => '', 'msg' => 'iv解密失败'];
- }
- if (strlen($sessionKey) != 24) {
- // sessionkey 错误
- return ['code' => 41001, 'data' => '', 'msg' => 'sessionKey解密失败'];
- }
- $data = openssl_decrypt(base64_decode($encryptedData), 'AES-128-CBC', base64_decode($sessionKey), OPENSSL_RAW_DATA, base64_decode($iv));
- if (!$data) {
- return ['code' => 41001, 'data' => '', 'msg' => '解密失败'];
- }
- $userInfo = json_decode($data, true);
- if ($userInfo['watermark']['appid'] != $this->appId) {
- return ['code' => 41003, 'data' => '', 'msg' => 'appid不匹配'];
- }
- $userInfo['nickName'] = !empty($userInfo['nickName']) ? $userInfo['nickName'] : '';
- return ['code' => 0, 'data' => $userInfo, 'msg' => 'success'];
- }
- /**
- * @link https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.createQRCode.html
- * @desc 获取小程序码(限量)
- * @param string $path 页面路径
- * @param int $width 二维码宽度
- *
- */
- public function qrcode(string $path, $width = 430)
- {
- $params = ['path' => $path, 'width' => $width];
- $url = 'https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=' . $this->accessToken();
- return Curl::requestCurl($url, 'POST', [], json_encode($params));
- }
- /**
- * @link https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html
- * @desc 获取小程序码(不限量)
- * @param string $scene 场景值
- * @param array $extra 额外参数,详见
- * @return bool|mixed|string
- */
- public function qrcodeUnlimited(string $scene, $extra = [])
- {
- $params = array_merge($extra, ['scene' => $scene]);
- $url = 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=' . $this->accessToken();
- return Curl::requestCurl($url, 'POST', [], json_encode($params));
- }
- /**
- * @link https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-link/urllink.generate.html
- * @desc 生成短链接
- * @param array $params
- * @return bool|string
- */
- public function urlLink(array $params)
- {
- $url = 'https://api.weixin.qq.com/wxa/generate_urllink?access_token=' . $this->accessToken();
- return Curl::requestCurl($url, 'POST', [], json_encode($params));
- }
- /**
- * @link https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
- * @desc 发送模板消息
- * @param string $openid 小程序openid
- * @param string $template 模板ID
- * @param array $data 小程序数据
- * @param string $page 跳转页面
- * @param string $state 小程序状态
- * @return bool|mixed
- */
- public function sendMiniMsg(string $openid, string $template, array $data, string $page = null, string $state = 'normal'): array
- {
- $params = [
- 'touser' => $openid,
- 'template_id' => $template,
- 'miniprogram_state' => $state,
- 'data' => $data
- ];
- if ($page) {
- $params['page'] = $page;
- }
- $url = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=' . $this->accessToken();
- $res = Curl::requestCurl($url, 'POST', [], json_encode($params));
- return $res ? json_decode($res, true) : [];
- }
- /**
- * @link https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html
- * @desc 获取全局唯一接口调用凭据
- * @param int $repeatCnt
- * @return string
- */
- public function accessToken(&$repeatCnt = 0)
- {
- $drive = $this->config['token_drive'] ?? 'redis';
- $key = 'mini_' . $this->appId . '_accessToken';
- switch ($drive) {
- case 'redis':
- $redis = Redis::instance();
- $redis->select(15);
- $token = $redis->get($key);
- break;
- case 'db':
- default:
- $token = Db::table('configs')->where('c_key', $key)->where('c_expired > ' . time())->value('c_value');
- break;
- }
- if ($token) {
- return $token;
- }
- $url = 'https://api.weixin.qq.com/cgi-bin/token';
- $res = Curl::requestCurl($url, 'GET', [], http_build_query([
- 'grant_type' => 'client_credential',
- 'appid' => $this->appId,
- 'secret' => $this->secret
- ]));
- $data = json_decode($res, true);
- if (isset($data['access_token'])) {
- $token = $data['access_token'];
- switch ($drive) {
- case 'redis':
- $redis->setex($key, 7000, $token);
- break;
- case 'db':
- default:
- Db::table('configs')
- ->where('c_key', $key)
- ->update([
- 'c_value' => $token,
- 'c_expired' => time() + 7000,
- 'c_updated' => date('Y-m-d H:i:s')
- ]);
- break;
- }
- return $token;
- } else {
- if ($repeatCnt <= 3) {
- $repeatCnt++;
- return $this->accessToken($repeatCnt);
- } else {
- return $data['errcode'];
- }
- }
- }
- }
|