BasicWeChat.php
8.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目:https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WeChat\Contracts;
use WeChat\Exceptions\InvalidArgumentException;
use WeChat\Exceptions\InvalidResponseException;
/**
* Class BasicWeChat
* @package WeChat\Contracts
*/
class BasicWeChat
{
/**
* 当前微信配置
* @var DataArray
*/
public $config;
/**
* 访问AccessToken
* @var string
*/
public $access_token = '';
/**
* 当前请求方法参数
* @var array
*/
protected $currentMethod = [];
/**
* 当前模式
* @var bool
*/
protected $isTry = false;
/**
* 静态缓存
* @var static
*/
protected static $cache;
/**
* 注册代替函数
* @var string
*/
protected $GetAccessTokenCallback;
/**
* BasicWeChat constructor.
* @param array $options
*/
public function __construct(array $options)
{
if (empty($options['appid'])) {
throw new InvalidArgumentException("Missing Config -- [appid]");
}
if (empty($options['appsecret'])) {
throw new InvalidArgumentException("Missing Config -- [appsecret]");
}
if (isset($options['GetAccessTokenCallback']) && is_callable($options['GetAccessTokenCallback'])) {
$this->GetAccessTokenCallback = $options['GetAccessTokenCallback'];
}
if (!empty($options['cache_path'])) {
Tools::$cache_path = $options['cache_path'];
}
$this->config = new DataArray($options);
}
/**
* 静态创建对象
* @param array $config
* @return static
*/
public static function instance(array $config)
{
$key = md5(get_called_class() . serialize($config));
if (isset(self::$cache[$key])) return self::$cache[$key];
return self::$cache[$key] = new static($config);
}
/**
* 获取访问accessToken
* @return string
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function getAccessToken()
{
if (!empty($this->access_token)) {
return $this->access_token;
}
$cache = $this->config->get('appid') . '_access_token';
$this->access_token = Tools::getCache($cache);
if (!empty($this->access_token)) {
return $this->access_token;
}
// 处理开放平台授权公众号获取AccessToken
if (!empty($this->GetAccessTokenCallback) && is_callable($this->GetAccessTokenCallback)) {
$this->access_token = call_user_func_array($this->GetAccessTokenCallback, [$this->config->get('appid'), $this]);
if (!empty($this->access_token)) {
Tools::setCache($cache, $this->access_token, 7000);
}
return $this->access_token;
}
list($appid, $secret) = [$this->config->get('appid'), $this->config->get('appsecret')];
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$secret}";
$result = Tools::json2arr(Tools::get($url));
if (!empty($result['access_token'])) {
Tools::setCache($cache, $result['access_token'], 7000);
}
return $this->access_token = $result['access_token'];
}
/**
* 设置外部接口 AccessToken
* @param string $access_token
* @throws \WeChat\Exceptions\LocalCacheException
* @author 高一平 <iam@gaoyiping.com>
*
* 当用户使用自己的缓存驱动时,直接实例化对象后可直接设置 AccessToekn
* - 多用于分布式项目时保持 AccessToken 统一
* - 使用此方法后就由用户来保证传入的 AccessToekn 为有效 AccessToekn
*/
public function setAccessToken($access_token)
{
if (!is_string($access_token)) {
throw new InvalidArgumentException("Invalid AccessToken type, need string.");
}
$cache = $this->config->get('appid') . '_access_token';
Tools::setCache($cache, $this->access_token = $access_token);
}
/**
* 清理删除 AccessToken
* @return bool
*/
public function delAccessToken()
{
$this->access_token = '';
return Tools::delCache($this->config->get('appid') . '_access_token');
}
/**
* 以GET获取接口数据并转为数组
* @param string $url 接口地址
* @return array
* @throws InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
protected function httpGetForJson($url)
{
try {
return Tools::json2arr(Tools::get($url));
} catch (InvalidResponseException $e) {
if (isset($this->currentMethod['method']) && empty($this->isTry)) {
if (in_array($e->getCode(), ['40014', '40001', '41001', '42001'])) {
$this->delAccessToken();
$this->isTry = true;
return call_user_func_array([$this, $this->currentMethod['method']], $this->currentMethod['arguments']);
}
}
throw new InvalidResponseException($e->getMessage(), $e->getCode());
}
}
/**
* 以POST获取接口数据并转为数组
* @param string $url 接口地址
* @param array $data 请求数据
* @param bool $buildToJson
* @return array
* @throws InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
protected function httpPostForJson($url, array $data, $buildToJson = true)
{
try {
return Tools::json2arr(Tools::post($url, $buildToJson ? Tools::arr2json($data) : $data));
} catch (InvalidResponseException $e) {
if (!$this->isTry && in_array($e->getCode(), ['40014', '40001', '41001', '42001'])) {
[$this->delAccessToken(), $this->isTry = true];
return call_user_func_array([$this, $this->currentMethod['method']], $this->currentMethod['arguments']);
}
throw new InvalidResponseException($e->getMessage(), $e->getCode());
}
}
/**
* 注册当前请求接口
* @param string $url 接口地址
* @param string $method 当前接口方法
* @param array $arguments 请求参数
* @return mixed
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
protected function registerApi(&$url, $method, $arguments = [])
{
$this->currentMethod = ['method' => $method, 'arguments' => $arguments];
if (empty($this->access_token)) {
$this->access_token = $this->getAccessToken();
}
return $url = str_replace('ACCESS_TOKEN', $this->access_token, $url);
}
/**
* 接口通用POST请求方法
* @param string $url 接口URL
* @param array $data POST提交接口参数
* @param bool $isBuildJson
* @return array
* @throws InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function callPostApi($url, array $data, $isBuildJson = true)
{
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpPostForJson($url, $data, $isBuildJson);
}
/**
* 接口通用GET请求方法
* @param string $url 接口URL
* @return array
* @throws InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
*/
public function callGetApi($url)
{
$this->registerApi($url, __FUNCTION__, func_get_args());
return $this->httpGetForJson($url);
}
}