* @version : HUOSDK 8.0 * http://wiki.connect.qq.com/%E4%BD%BF%E7%94%A8authorization_code%E8%8E%B7%E5%8F%96access_token */ namespace huolib\oauth\driver; use huolib\constant\MemConst; use huolib\oauth\OAuth; use huolib\tool\Http; use think\Exception; use think\Log; class Qq extends OAuth { /** * 获取requestCode的api接口 * * @var string */ protected $request_code_url = 'https://graph.qq.com/oauth2.0/authorize'; /** * 获取Access token的api接口 * * @var String */ protected $access_token_url = 'https://graph.qq.com/oauth2.0/token'; /** * WAP网站 * * @var string */ protected $access_token_url_m = 'https://graph.z.qq.com/moc2/token'; /** * 更新Access token的api接口 * * @var String */ protected $refresh_token_url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token'; /** * API根路径 * * @var string */ protected $api_base = 'https://graph.qq.com/'; /** * 获取request_code的额外参数,可在配置中修改 URL查询字符串格式 * * @var string */ protected $authorize = 'get_user_info'; /** * WxQrcode constructor. * * @param array $config * @param array|null $token * * @throws \think\Exception */ public function __construct(array $config = [], array $token = null) { $_config = $config; if (empty($config)) { if (file_exists(GLOBAL_CONF_PATH."extra/oauth/qq.php")) { $_config = include GLOBAL_CONF_PATH."extra/oauth/qq.php"; } else { $_config = array(); } } parent::__construct($_config, $token); } /** * * 第一步:获取Authorization Code * 请求Authorize访问地址 * * @param string $display * * @return string 跳转地址 */ public function getRequestCodeUrl($display = 'pc') { $_display = $display; if ('pc' == $_display) { $_display = 'default'; $_request_code_url = $this->request_code_url; } else { $_display = 'mobile'; $_request_code_url = $this->request_code_url; } $params = array( 'client_id' => $this->app_key, 'redirect_uri' => $this->callback, 'response_type' => $this->response_type, 'scope' => $this->authorize, 'state' => $this->getState(), 'display' => $_display, ); return $_request_code_url.'?'.http_build_query($params); } /** * Step2:通过Authorization Code获取Access Token * * @param $code * @param null $extend * * @return array|null * @throws Exception */ public function getAccessToken($code, $extend = null) { $_access_token_url = $this->access_token_url; $_params = array( 'grant_type' => $this->grant_type, 'client_id' => $this->app_key, 'redirect_uri' => $this->callback, 'client_secret' => $this->app_secret, 'code' => $code, ); $_rdata = Http::get($_access_token_url, $_params); if (strpos($_rdata, "callback") !== false) { throw new Exception('没有正确获取到token!'.$_rdata); } $this->token = $this->parseToken($_rdata); return $this->token; } /** * 刷新access_token有效期 * * @param $refresh_token * * * @return array|mixed|null * @throws Exception */ public function getRefreshAccessToken($refresh_token) { $_params = array( 'client_id' => $this->app_key, 'client_secret' => $this->app_secret, 'refresh_token' => $refresh_token, 'grant_type' => $this->grant_type, ); $_rdata = Http::get($this->refresh_token_url, $_params); $this->token = $this->parseToken($_rdata); return $this->token; } /** * * @param string $api API * @param string $param 调用API的额外参数 * @param string $method HTTP请求方法 默认为GET * @param null $multi * * @return mixed * @throws Exception */ public function call($api, $param = '', $method = 'GET', $multi = null) { $params = array( 'access_token' => $this->token['access_token'], 'openid' => $this->getOpenid(), 'oauth_consumer_key' => $this->app_key ); $data = Http::request($this->url($api), $params, $method); return json_decode($data, true); } /** * 获取授权用户的用户信息 * http://wiki.connect.qq.com/get_user_info * * @return array * @throws Exception * ret 返回码 msg 如果ret<0,会有相应的错误信息提示,返回数据全部用UTF-8编码。 * nickname 用户在QQ空间的昵称。 figureurl 大小为30×30像素的QQ空间头像URL。 * figureurl_1 大小为50×50像素的QQ空间头像URL。 * figureurl_2 大小为100×100像素的QQ空间头像URL。 * figureurl_qq_1 大小为40×40像素的QQ头像URL。 * figureurl_qq_2 大小为100×100像素的QQ头像URL。需要注意,不是所有的用户都拥有QQ的100x100的头像,但40x40像素则是一定会有。 * gender 性别。 如果获取不到则默认返回"男" * is_yellow_vip 标识用户是否为黄钻用户(0:不是;1:是)。 * vip 标识用户是否为黄钻用户(0:不是;1:是) * yellow_vip_level 黄钻等级 * level 黄钻等级 * is_yellow_year_vip 标识是否为年费黄钻用户(0:不是; 1:是) * */ public function getUserInfo() { $_response = $this->call('user/get_user_info'); if (empty($_response) || (isset($_response['ret']) && $_response['ret'] != 0)) { throw new Exception('接口访问失败!'.$_response['msg']); } else { $_open_id = $this->getOpenid(); $_unionid = $this->getUnionid(); $_oauth_data = array( 'openid' => $_open_id, 'unionid' => $_unionid, 'channel' => 'qq', 'nickname' => $_response['nickname'], 'gender' => $this->getGender($_response['gender']), 'avatar' => $this->getAvatar($_response['figureurl_qq_1']), 'token' => $this->token ); return $_oauth_data; } } /** * 获取当前授权用户的SNS标识 * * @throws Exception */ public function getOpenid() { $_data = $this->token; if (isset($_data['openid'])) { return $_data['openid']; } elseif ($_data['access_token']) { $_param['access_token'] = $_data['access_token']; $_param['unionid'] = 1; $_response = Http::request($this->url('oauth2.0/me'), $_param); $_rdata = json_decode(trim(substr($_response, 9), " );\n"), true); if (isset($_rdata['openid'])) { return $_rdata['openid']; } else { throw new Exception("获取用户openid出错:{$_rdata['error_description']}"); } } else { throw new Exception('没有获取到openid!'); } } /** * 获取当前授权用户的SNS标识 * * @throws Exception */ public function getUnionid() { $_data = $this->token; if ($_data['access_token']) { $_param['access_token'] = $_data['access_token']; $_param['unionid'] = 1; $_response = Http::request($this->url('oauth2.0/me'), $_param); $_rdata = json_decode(trim(substr($_response, 9), " );\n"), true); if (isset($_rdata['unionid'])) { return $_rdata['unionid']; } else { throw new Exception("获取用户unionid出错:{$_rdata['error_description']}"); } } else { throw new Exception('没有获取到unionid!'); } } /** * 解析access_token方法请求后的返回值 * * @param $result * @param null $extend * * @return mixed * @throws Exception */ protected function parseToken($result, $extend = null) { $_rdata = []; parse_str($result, $_rdata); if ($_rdata['access_token'] && $_rdata['expires_in']) { $this->token = $_rdata; $_rdata['openid'] = $this->getOpenid(); return $_rdata; } else { throw new Exception("获取 ACCESS_token 出错:{$result}"); } } /** * @param string $gender * * @return mixed */ private function getGender($gender = '男') { switch ($gender) { case '男': return MemConst::GENDER_M; case '女': return MemConst::GENDER_F; default : return MemConst::GENDER_N; } } /**头像处理,修改为https * * @param string $avatar * * @return string|string[]|null */ private function getAvatar($avatar = '') { $_avatar = $avatar; if ('http' == parse_url($_avatar, PHP_URL_SCHEME)) { $_avatar = preg_replace("/^http/", "https", $_avatar); } return $_avatar; } }