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) { |
|
|
|
|
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) { |
|
|
|
|
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
|
|
|
|
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.