appId = $this->config['appid']; $this->secret = $this->config['secret']; } /** * @link 第一步 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html * @desc 获取授权地址 * @param string $scope 授权类型snsapi_base|snsapi_userinfo * @param string|null $redirect 授权回跳地址 * @return string */ public function authUrl(string $scope = 'snsapi_base', string $redirect = null): string { $redirect = $redirect ? $redirect : "https://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}"; $query = http_build_query([ 'appid' => $this->appId, 'redirect_uri' => $redirect, 'response_type' => 'code', 'scope' => $scope ]); return "https://open.weixin.qq.com/connect/oauth2/authorize?{$query}#wechat_redirect"; } /** * @link 第二步 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html * @desc 使用授权code换取openid * @param string $code * @return array */ public function code2Openid(string $code): array { $url = 'https://api.weixin.qq.com/sns/oauth2/access_token'; $res = Curl::requestCurl($url, 'GET', [], http_build_query([ 'appid' => $this->appId, 'secret' => $this->secret, 'code' => $code, 'grant_type' => 'authorization_code' ])); return $res ? json_decode($res, true) : []; } /** * @link 第四步 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html * @desc 获取用户信息 * @param string $accessToken * @param string $openid * @return bool|mixed|string */ public function userSimpleInfo(string $accessToken, string $openid): array { $url = 'https://api.weixin.qq.com/sns/userinfo'; $res = Curl::requestCurl($url, 'GET', [], http_build_query([ 'access_token' => $accessToken, 'openid' => $openid, 'lang' => 'zh_CN', ])); return $res ? json_decode($res, true) : []; } /** * @link https://developers.weixin.qq.com/doc/offiaccount/User_Management/Get_users_basic_information_UnionID.html#UinonId * @desc 获取用户详细信息 * @param string $openid * @return array */ public function userDetailInfo(string $openid): array { $url = 'https://api.weixin.qq.com/cgi-bin/user/info'; $res = Curl::requestCurl($url, 'GET', [], http_build_query([ 'access_token' => $this->accessToken(), 'openid' => $openid, 'lang' => 'zh_CN', ])); return $res ? json_decode($res, true) : []; } /** * @link 附录1-JS-SDK使用权限签名算法 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html * @desc 获取 JSAPI TICKET * @param int $repeatCnt * @return string */ public function jsApiTicket(&$repeatCnt = 1): string { $drive = $this->config['token_drive'] ?? 'redis'; $key = 'wechat_' . $this->appId . '_jsApiTicket'; switch ($drive) { case 'redis': $redis = Redis::instance(); $redis->select(15); $ticket = $redis->get($key); break; case 'db': default: $ticket = Db::table('configs')->where('c_key', $key)->where('c_expired > ' . time())->value('c_value'); break; } if ($ticket) { return $ticket; } $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket'; $res = Curl::requestCurl($url, 'GET', [], http_build_query([ 'access_token' => $this->accessToken(), 'type' => 'jsapi' ])); $data = json_decode($res, true); if (isset($data['ticket'])) { $ticket = $data['ticket']; switch ($drive) { case 'redis': $redis->setex($key, 7000, $ticket); break; case 'db': default: Db::table('configs') ->where('c_key', $key) ->update([ 'c_value' => $ticket, 'c_expired' => time() + 7000, 'c_updated' => date('Y-m-d H:i:s') ]); break; } return $ticket; } else { if ($repeatCnt <= 3) { $repeatCnt++; return $this->jsApiTicket($repeatCnt); } else { return $data['errcode']; } } } /** * @link https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html * @desc 获取全局唯一接口调用凭据 * @param int $repeatCnt * @return string */ public function accessToken(&$repeatCnt = 1) { $drive = $this->config['token_drive'] ?? 'redis'; $key = 'wechat_' . $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']; } } } }