client = $client; $this->appId = config('wechat.app_id'); $this->appSecret = config('wechat.app_secret'); } public function getAccessToken() { $accessTokenKey = 'wechat:access:key'; $cache = Cache::get($accessTokenKey); if($cache) { return $cache; } $url = 'https://api.weixin.qq.com/cgi-bin/stable_token'; $formParams = [ 'appid' => $this->appId, 'secret' => $this->appSecret, 'grant_type' => 'client_credential' ]; try { $options = [ 'json' => $formParams, 'headers' => [ 'Content-Type' => 'application/json' ] ]; $response = $this->client->request('POST', $url, $options); // 获取响应体并解码为数组 $body = json_decode($response->getBody()->getContents(), true); if (!empty($body['errcode'])) { $this->throwApiError($options, json_encode($body['errcode']).json_encode($body['errmsg'])); } else { Cache::put($accessTokenKey, $body['access_token'], 240); return $body['access_token']; } } catch (RequestException $e) { $this->throwApiError($options, $e->getMessage(), $e->getCode()); } } public function getSessionInfo($code) { $url = 'https://api.weixin.qq.com/sns/jscode2session'; // 准备请求参数 $formParams = [ 'appid' => $this->appId, 'secret' => $this->appSecret, 'js_code' => $code, 'grant_type' => 'authorization_code' ]; try { $options = [ 'query' => $formParams ]; $response = $this->client->request('GET', $url, $options); // 获取响应体并解码为数组 $body = json_decode($response->getBody()->getContents(), true); if (!empty($body['errcode'])) { $this->throwApiError($options, json_encode($body['errcode']).json_encode($body['errmsg'])); } else { // $openid = $data['openid']; // $sessionKey = $data['session_key']; return $body; } } catch (RequestException $e) { $this->throwApiError($options, $e->getMessage(), $e->getCode()); } } public function getUserPhoneNumber($code) { $url = 'https://api.weixin.qq.com/wxa/business/getuserphonenumber'; // 准备请求参数 try { $options = [ 'query' => ['access_token' => $this->getAccessToken()], 'json' => ['code' => $code], 'headers' => [ 'Content-Type' => 'application/json' ] ]; $response = $this->client->request('POST', $url, $options); // 获取响应体并解码为数组 $body = json_decode($response->getBody()->getContents(), true); if (!empty($body['errcode'])) { $this->throwApiError($options, json_encode($body['errcode']).json_encode($body['errmsg'])); } else { /* * { "errcode":0, "errmsg":"ok", "phone_info": { "phoneNumber":"xxxxxx", "purePhoneNumber": "xxxxxx", "countryCode": 86, "watermark": { "timestamp": 1637744274, "appid": "xxxx" } } } */ return $body; } } catch (RequestException $e) { $this->throwApiError($options, $e->getMessage(), $e->getCode()); } } public function getWxaQueryScheme($scheme) { //https://api.weixin.qq.com/wxa/queryscheme?access_token=ACCESS_TOKEN //query_type $keyScheme = 'key:wechat:key:scheme'; $cache = Cache::get($keyScheme); if($cache) { return $cache; } $url = 'https://api.weixin.qq.com/wxa/generatescheme'; // 准备请求参数 try { $options = [ 'query' => ['access_token' => $this->getAccessToken()], 'json' => ['expire_time' => strtotime('+28 day', time()), 'expire_type' => 0], 'headers' => [ 'Content-Type' => 'application/json' ] ]; $response = $this->client->request('POST', $url, $options); // 获取响应体并解码为数组 $body = json_decode($response->getBody()->getContents(), true); if (!empty($body['errcode'])) { $this->throwApiError($options, json_encode($body['errcode']).json_encode($body['errmsg'])); } else { Cache::put($keyScheme, $body['openlink'], 20 * 24 * 60 * 60); return $body['openlink'] ?? ''; } } catch (RequestException $e) { $this->throwApiError($options, $e->getMessage(), $e->getCode()); } } public function decryptData(string $sessionKey, string $iv, string $encrypted) { $decrypted = AES::decrypt( base64_decode($encrypted, false), base64_decode($sessionKey, false), base64_decode($iv, false) ); $decrypted = json_decode($this->pkcs7Unpad($decrypted), true); if (!$decrypted) { $this->throwApiError([$sessionKey, $iv, $encrypted], '解密失败', 500); } return $decrypted; } public function pkcs7Unpad(string $text) { $pad = ord(substr($text, -1)); if ($pad < 1 || $pad > 32) { $pad = 0; } return substr($text, 0, (strlen($text) - $pad)); } private function throwApiError($options, $error, $code = 200) { $key = createGuid(); Log::info('Wechat第三方接口出错key:'.$key); Log::info('Wechat第三方接口出错params:'.json_encode($options)); Log::info('Wechat第三方接口出错:'.$code.','.$error); throw new ApiException(500); } }