123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- <?php
- // +----------------------------------------------------------------------
- // | WeChatDeveloper
- // +----------------------------------------------------------------------
- // | 版权所有 2014~2022 广州楚才信息科技有限公司 [ 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 $accessToken
- * @throws \WeChat\Exceptions\LocalCacheException
- * @author 高一平 <iam@gaoyiping.com>
- *
- * 当用户使用自己的缓存驱动时,直接实例化对象后可直接设置 AccessToken
- * - 多用于分布式项目时保持 AccessToken 统一
- * - 使用此方法后就由用户来保证传入的 AccessToken 为有效 AccessToken
- */
- public function setAccessToken($accessToken)
- {
- if (!is_string($accessToken)) {
- throw new InvalidArgumentException("Invalid AccessToken type, need string.");
- }
- $cache = $this->config->get('appid') . '_access_token';
- Tools::setCache($cache, $this->access_token = $accessToken);
- }
- /**
- * 清理删除 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 $exception) {
- if (isset($this->currentMethod['method']) && empty($this->isTry)) {
- if (in_array($exception->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($exception->getMessage(), $exception->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 {
- $options = [];
- if ($buildToJson) $options['headers'] = ['Content-Type: application/json'];
- return Tools::json2arr(Tools::post($url, $buildToJson ? Tools::arr2json($data) : $data, $options));
- } catch (InvalidResponseException $exception) {
- if (!$this->isTry && in_array($exception->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($exception->getMessage(), $exception->getCode());
- }
- }
- /**
- * 注册当前请求接口
- * @param string $url 接口地址
- * @param string $method 当前接口方法
- * @param array $arguments 请求参数
- * @return string
- * @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', urlencode($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);
- }
- }
|