BaseRequest::updateAccessToken()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 3
eloc 12
c 4
b 0
f 0
nc 2
nop 1
dl 0
loc 19
rs 9.8666
1
<?php
2
3
namespace Abbotton\DouDian\Api;
4
5
use GuzzleHttp\Client;
6
use Illuminate\Http\Client\RequestException;
7
use Illuminate\Support\Facades\Cache;
8
use Psr\SimpleCache\InvalidArgumentException;
9
10
class BaseRequest
11
{
12
    public const OAUTH_CACHE_KEY = 'doudian_oauth_token';
13
    /**
14
     * @var array 配置参数
15
     */
16
    private $config;
17
    private $shop_id;
18
19
    /**
20
     * @var string 接口地址
21
     */
22
    private $baseUrl = 'https://openapi-fxg.jinritemai.com/';
23
24
    /**
25
     * @var Client
26
     */
27
    private $client;
28
29
    public function __construct(array $config, $shop_id)
30
    {
31
        $this->config = $config;
32
        $this->shop_id = $shop_id;
33
        if (! isset($config['app_key']) || ! $config['app_key']) {
34
            throw new \InvalidArgumentException('配置有误, 请填写app_key');
35
        }
36
37
        if (! isset($config['app_secret']) || ! $config['app_secret']) {
38
            throw new \InvalidArgumentException('配置有误, 请填写app_secret');
39
        }
40
        $this->client = new Client();
41
    }
42
43
    /**
44
     * 发起GET请求
45
     *
46
     * @param string $url
47
     * @param array  $params
48
     * @param bool   $needSign
49
     *
50
     * @throws RequestException
51
     * @throws InvalidArgumentException
52
     *
53
     * @return array
54
     */
55
    public function httpGet(string $url, array $params = [], bool $needSign = true): array
56
    {
57
        return $this->request('get', $url, $params, $needSign);
58
    }
59
60
    /**
61
     * 发起HTTP请求
62
     *
63
     * @param string $method
64
     * @param string $url
65
     * @param array  $params
66
     * @param bool   $needSign
67
     *
68
     * @throws RequestException
69
     * @throws InvalidArgumentException
70
     *
71
     * @return array
72
     */
73
    private function request(string $method, string $url, array $params = [], bool $needSign = true): array
74
    {
75
        $options = [];
76
        if ($needSign) {
77
            $params = $this->generateParams($url, $params);
78
        }
79
        $options['headers'] = [
80
            'Content-Type' => 'application/x-www-form-urlencoded',
81
        ];
82
        $key = $method == 'get' ? 'query' : 'form_params';
83
        $options[$key] = $params;
84
85
        $response = $this->client->request($method, $this->baseUrl.$url, $options);
86
87
        return json_decode($response->getBody()->getContents(), true);
88
    }
89
90
    /**
91
     * 组合请求参数.
92
     *
93
     * @param string $url
94
     * @param array  $params
95
     *
96
     * @throws RequestException
97
     * @throws InvalidArgumentException
98
     *
99
     * @return array
100
     */
101
    protected function generateParams(string $url, array $params): array
102
    {
103
        $url = str_replace('/', '.', $url);
104
105
        $accessToken = "";
106
        if (! in_array($url, ["token.create","token.refresh"])) {
107
            $accessToken = $this->getAccessToken();
108
        };
109
110
        $public = [
111
            'app_key' => $this->config['app_key'],
112
            'timestamp' => date('Y-m-d H:i:s'),
113
            'v' => '2',
114
            'method' => $url,
115
            'access_token' => $accessToken,
116
        ];
117
118
        ksort($params);
119
        $param_json = json_encode((object) $params, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
120
121
        $str = 'app_key'.$public['app_key'].'method'.$url.'param_json'.$param_json.'timestamp'.$public['timestamp'].'v'.$public['v'];
122
        $md5_str = $this->config['app_secret'].$str.$this->config['app_secret'];
123
        $sign = md5($md5_str);
124
125
        return array_merge(
126
            $public,
127
            [
128
                'param_json' => $param_json,
129
                'sign' => $sign,
130
            ]
131
        );
132
    }
133
134
    /**
135
     * 获取TOKEN.
136
     *
137
     * @throws RequestException
138
     * @throws InvalidArgumentException
139
     *
140
     * @return mixed|string
141
     */
142
    private function getAccessToken(): string
143
    {
144
        $oauthToken = Cache::get(self::OAUTH_CACHE_KEY.$this->shop_id, []);
145
        if (! $oauthToken || ! $oauthToken['refresh_token']) {
146
            return $this->requestAccessToken();
147
        }
148
149
        if ($oauthToken['access_token_expired_at'] - time() <= 100 && $oauthToken['refresh_token_expired_at'] > time()) {
150
            return $this->updateAccessToken($oauthToken['refresh_token']);
151
        }
152
153
        return $oauthToken['access_token'];
154
    }
155
156
    /**
157
     * 请求TOKEN.
158
     *
159
     * @throws RequestException
160
     * @throws InvalidArgumentException
161
     *
162
     * @return string
163
     */
164
    private function requestAccessToken(): string
165
    {
166
        $param = [
167
            'app_id' => $this->config['app_key'],
168
            'app_secret' => $this->config['app_secret'],
169
            'grant_type' => 'authorization_self',
170
        ];
171
172
        if ($this->shop_id) {
173
            $param['shop_id'] = $this->shop_id;
174
        }
175
176
        $response = $this->httpGet('token/create', $param, true);
177
        if (! $response || $response['code'] > 10000) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $response of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
178
            trigger_error("token/create 接口异常[{$response['code']}]");
179
        }
180
        $response['data']['access_token_expired_at'] = time() + $response['data']['expires_in'];
181
        $response['data']['refresh_token_expired_at'] = strtotime('+14 day');
182
183
        Cache::set(self::OAUTH_CACHE_KEY.$this->shop_id, $response['data']);
184
185
        return $response['data']['access_token'];
186
    }
187
188
    /**
189
     * 刷新TOKEN.
190
     *
191
     * @param string $refreshToken
192
     *
193
     * @throws RequestException
194
     * @throws InvalidArgumentException
195
     *
196
     * @return string
197
     */
198
    private function updateAccessToken(string $refreshToken): string
199
    {
200
        $param = [
201
            'app_id' => $this->config['app_key'],
202
            'app_secret' => $this->config['app_secret'],
203
            'grant_type' => 'refresh_token',
204
            'refresh_token' => $refreshToken,
205
        ];
206
207
        $response = $this->httpGet('token/refresh', $param, true);
208
        if (! $response || $response['code'] > 10000) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $response of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
209
            trigger_error("token/refresh 接口异常[{$response['code']}]");
210
        }
211
        $response['data']['access_token_expired_at'] = time() + $response['data']['expires_in'];
212
        $response['data']['refresh_token_expired_at'] = strtotime('+14 day');
213
214
        Cache::set(self::OAUTH_CACHE_KEY.$this->shop_id, $response['data']);
215
216
        return $response['data']['access_token'];
217
    }
218
219
    /**
220
     * 发起POST请求
221
     *
222
     * @param string $url
223
     * @param array  $params
224
     * @param bool   $needSign
225
     *
226
     * @throws RequestException
227
     * @throws InvalidArgumentException
228
     *
229
     * @return array
230
     */
231
    public function httpPost(string $url, array $params = [], bool $needSign = true): array
232
    {
233
        return $this->request('post', $url, $params, $needSign);
234
    }
235
236
    public function setHttpClient($client)
237
    {
238
        $this->client = $client;
239
240
        return $this;
241
    }
242
}
243