url = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']; $this->config = $config; $this->lang = $lang ? $lang : 'zh_CN'; } /** * 获取access_token * @return mixed * @throws WeChatAPIException */ private function getAccessToken() { $file = './access_token.json'; if (file_exists($file)) { $content = file_get_contents($file); $result = json_decode($content, true); $expires = $result['expires_in'] - (time() - filemtime($file)); if ($expires <= 5) { @unlink($file); return $this->getAccessToken(); } return $result; } else { $api = $this->accessTokenAPI . "grant_type=client_credential&appid={$this->config['appid']}"; $api .= "&secret={$this->config['appsecret']}"; $result = $this->createHttpRequest($api, null, true); file_put_contents($file, $result[0]); return $result[1]; } } /** * 获取CODE * @param $scope */ private function getCode($scope) { $redirect = $this->url; $api = $this->codeAPI . "appid={$this->config['appid']}&redirect_uri={$redirect}"; $api .= "&response_type=code&scope={$scope}&state=0#wechat_redirect"; exit(header('location:' . $api)); } /** * 获取OAuth的access_token * @param string $scope * @return mixed * @throws WeChatAPIException */ private function getOAuthAccessToken($scope = 'snsapi_base') { if (isset($_SESSION['oauth_access_token']) && !empty($_SESSION['oauth_access_token'])) { $session = $_SESSION['oauth_access_token']; $content = $session['content']; $result = json_decode($content, true); $expires = $result['expires_in'] - (time() - $session['time']); if ($expires <= 5) { unset($_SESSION['oauth_access_token']); return $this->getOAuthAccessToken(); } return $result; } else { $code = isset($_GET['code']) ? $_GET['code'] : null; if (!$code) { $this->getCode($scope); } $api = $this->oauthAccessTokenAPI . "appid={$this->config['appid']}"; $api .= "&secret={$this->config['appsecret']}&code={$code}&grant_type=authorization_code"; $result = $this->createHttpRequest($api, null, true); $_SESSION['oauth_access_token'] = [ 'time' => time(), 'content' => $result[0] ]; return $result[1]; } } /** * 拉取用户信息 * @param null $openid * @return bool|mixed * @throws WeChatAPIException */ public function getUserInfo($openid = null) { $postData = []; if ($openid) { $accessToken = $this->getAccessToken(); $api = $this->userinfoUnionIdAPI . "access_token={$accessToken['access_token']}"; if (is_array($openid)) { $postData = json_encode([ 'user_list' => $openid ]); } else { $api .= "&openid={$openid}&lang={$this->lang}"; } } else { $accessToken = $this->getOAuthAccessToken('snsapi_userinfo'); $api = $this->userinfoAPI . "access_token={$accessToken['access_token']}"; $api .= "&openid={$accessToken['openid']}&lang={$this->lang}"; } $result = $this->createHttpRequest($api, $postData); return $result; } /** * 创建公众号菜单 * $menu数据示例 * [ * [ * 'type' => 'view', * 'name' => 'TOP糯米', * 'url' => 'https://www.topnuomi.com/' * ], * [ * 'name' => '测试多级', * 'sub_button' => [ * [ * 'type' => 'view', * 'name' => '我的主页', * 'url' => 'https://topnuomi.com/' * ], * [ * 'type' => 'click', * 'name' => '点击', * 'key' => 'V1001_TODAY_MUSIC' * ] * ] * ] * ] * @param array $menu * @param array $matchrule * @return bool * @throws WeChatAPIException */ public function createMenu($menu = [], $matchrule = []) { // 公众号菜单 $menu = [ 'button' => $menu ]; // 个性化菜单 $matchrule = (!empty($matchrule)) ? [ 'matchrule' => $matchrule ] : []; $menu = array_merge($menu, $matchrule); $menuJson = json_encode($menu, JSON_UNESCAPED_UNICODE); $type = (!empty($matchrule)) ? 'addconditional' : 'create'; return $this->menuAction($type, $menuJson); } /** * 获取公众号菜单 * @return mixed * @throws WeChatAPIException */ public function getMenu() { return $this->menuAction('get'); } /** * 删除公众号自定义菜单 * @return mixed * @throws WeChatAPIException */ public function deleteMenu($menuid = null) { $json = null; if ($menuid) { $json = json_encode([ 'menuid' => $menuid ]); } $type = ($menuid) ? 'delconditional' : 'delete'; return $this->menuAction($type, $json, $menuid); } /** * 公众号菜单的基础操作 * @param null $type * @param null $postData * @return bool|mixed * @throws WeChatAPIException */ private function menuAction($type = null, $postData = null, $menuid = null) { $typePool = ['create', 'get', 'delete', 'addconditional', 'delconditional']; if (in_array($type, $typePool)) { $accessToken = $this->getAccessToken(); $api = $this->menuAPI . "/{$type}?access_token={$accessToken['access_token']}"; $result = $this->createHttpRequest($api, $postData); return ($type == 'get' || $type == 'addconditional') ? $result : true; } else { throw new WeChatAPIException('对公众号菜单的操作不在允许列表'); } } /** * 获取自定义菜单配置 * @return mixed * @throws WeChatAPIException */ public function getCurrentSelfmenuInfo() { $accessToken = $this->getAccessToken(); $api = $this->currentSelfmenuAPI . "access_token={$accessToken['access_token']}"; $result = $this->createHttpRequest($api); return $result; } /** * 设置所属行业 * post数据示例 * { * "industry_id1":"1", * "industry_id2":"4" * } * @param $id1 * @param $id2 * @return bool * @throws WeChatAPIException */ public function setIndustry($id1, $id2) { $accessToken = $this->getAccessToken(); $api = $this->templateAPI . "api_set_industry?access_token={$accessToken['access_token']}"; $postData = json_encode([ 'industry_id1' => $id1, 'industry_id2' => $id2 ]); $this->createHttpRequest($api, $postData); return true; } /** * 获取设置的行业信息 * @return mixed */ public function getIndustry() { $accessToken = $this->getAccessToken(); $api = $this->templateAPI . "get_industry?access_token={$accessToken['access_token']}"; $result = $this->createHttpRequest($api); return $result; } /** * 获取模板列表 * @return mixed */ public function getTemplateList() { $accessToken = $this->getAccessToken(); $api = $this->templateAPI . "get_all_private_template?access_token={$accessToken['access_token']}"; $result = $this->createHttpRequest($api); return $result; } /** * 创建HTTP请求 * @param $api * @param array $data * @param bool $includeJson * @return mixed */ private function createHttpRequest($api, $data = [], $includeJson = false) { $json = create_http_request($api, $data); $result = json_decode($json, true); if (isset($result['errcode']) && $result['errcode'] != 0) { throw new WeChatAPIException("code:{$result['errcode']}, {$result['errmsg']}"); } return ($includeJson) ? [$json, $result] : $result; } /** * 获取错误信息 * @return null */ public function getError() { return $this->error; } }