app_id = $app_id; $this->app_secret = $app_secret; } /** * 获取微信授权链接 * * @return string */ public function getAuthorizeUrl() { $redirect_uri = addon_url('epay/api/wechat', [], true, true); $redirect_uri = urlencode($redirect_uri); $state = \fast\Random::alnum(); Session::set('state', $state); return "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->app_id}&redirect_uri={$redirect_uri}&response_type=code&scope={$this->scope}&state={$state}#wechat_redirect"; } /** * 获取微信openid * * @return mixed|string */ public function getOpenid() { $openid = Session::get('openid'); if (!$openid) { if (!isset($_GET['code'])) { $url = $this->getAuthorizeUrl(); Header("Location: $url"); exit(); } else { /*$state = Session::get('state'); if ($state == $_GET['state']) {*/ $code = $_GET['code']; $token = $this->getAccessToken($code); if (!isset($token['openid']) && isset($token['errmsg'])) { exception($token['errmsg']); } $openid = isset($token['openid']) ? $token['openid'] : ''; if ($openid) { Session::set("openid", $openid); } /* }*/ } } return $openid; } /** * 获取授权token网页授权 * * @param string $code * @return mixed|string */ public function getAccessToken($code = '') { $params = [ 'appid' => $this->app_id, 'secret' => $this->app_secret, 'code' => $code, 'grant_type' => 'authorization_code' ]; $ret = Http::sendRequest('https://api.weixin.qq.com/sns/oauth2/access_token', $params, 'GET'); if ($ret['ret']) { $ar = json_decode($ret['msg'], true); return $ar; } return []; } public function getJsticket($code = '') { $jsticket = Session::get('jsticket'); if (!$jsticket) { $token = $this->getAccessToken($code); $params = [ 'access_token' => 'token', 'type' => 'jsapi', ]; $ret = Http::sendRequest('https://api.weixin.qq.com/cgi-bin/ticket/getticket', $params, 'GET'); if ($ret['ret']) { $ar = json_decode($ret['msg'], true); return $ar; } } return $jsticket; } public function getSignPackage($url) { $jsapiTicket = $this->getWechatJsApiTicket(); // 注意 URL 一定要动态获取,不能 hardcode. // $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://"; // $url = $this->url?$this->url:"$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; $timestamp = time(); $nonceStr = $this->getRandString(16); // 这里参数的顺序要按照 key 值 ASCII 码升序排序 $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url"; $signature = sha1($string); $signPackage = array( "appId" => $this->app_id, "nonceStr" => $nonceStr, "timestamp" => $timestamp, "url" => $url, "signature" => $signature, "rawString" => $string ); return $signPackage; } /** * 获取微信基础access_token * @param bool $updatenow 是否立即刷新 * @return string */ public function getWechatBasicAccesstoken($updatenow = false) { //有效期一般为7200秒,开发者必须在自己的服务全局缓存access_token //此处保存的access_token为基础的,并非授权的(授权的需要实时获取) //读取缓存 $access_token = cache('access_token'); //过期或强制刷新时,需重新请求 if(!$access_token || $updatenow) { $rs = json_decode(curl_get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$this->app_id.'&secret='.$this->app_secret), true); if(!empty($rs['errmsg'])) { abort(500, $rs['errmsg']); //请求失败 } //缓存存储 $access_token = $rs['access_token']; cache('access_token', $access_token, $rs['expires_in'] - 1000); } return $access_token; } /** * 获取微信jsapi_ticket * @param string $updatenow 是否立即更新 * @return string */ private function getWechatJsApiTicket($updatenow = false) { //有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket //读取缓存 $ticket = cache('jsapi_ticket'); //过期或强制刷新时,需重新请求 if(!$ticket || $updatenow) { //读取access_token $access_token = $this->getWechatBasicAccesstoken(); //请求ticket $rs = json_decode(curl_get('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='.$access_token.'&type=jsapi'), true); if($rs['errmsg'] != 'ok') { //失败时,强制刷新access_token,再次请求 $access_token = $this->getWechatBasicAccesstoken(true); $rs = json_decode(curl_get('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='.$access_token.'&type=jsapi'), true); if($rs['errmsg'] != 'ok') { abort(500, $rs['errmsg']); //请求失败 } } //缓存存储 $ticket = $rs['ticket']; cache('jsapi_ticket', $ticket, $rs['expires_in'] - 1000); } return $ticket; } /** * 获取随机字符串 * @param int $length 字符串长度 * @return null|string */ private function getRandString($length = 1) { $str = null; $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; $max = strlen($strPol) - 1; for($i = 0; $i < $length; $i++) { $str .= $strPol[rand(0, $max)]; } return $str; } }