WechatService.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. <?php
  2. namespace app\extra\wechat;
  3. /**
  4. * 微信接口调度服务
  5. * @package app\extra\wechat
  6. * @method \WeChat\Oauth WeChatOauth() static 微信网页授权
  7. */
  8. class WechatService
  9. {
  10. /**
  11. * 静态初始化对象
  12. * @param string $name
  13. * @param array $arguments
  14. * @return mixed
  15. * @throws \think\admin\Exception
  16. */
  17. public static function __callStatic(string $name, array $arguments)
  18. {
  19. [$type, $base, $class] = static::parseName($name);
  20. if ("{$type}{$base}" !== $name) {
  21. throw new \Exception("抱歉,实例 {$name} 不符合规则!");
  22. }
  23. if (class_exists($class)) {
  24. return new $class(static::getConfig());
  25. } else {
  26. throw new \Exception("抱歉,接口模式无法实例 {$class} 对象!");
  27. }
  28. }
  29. /**
  30. * 解析调用对象名称
  31. * @param string $name
  32. * @return array
  33. */
  34. private static function parseName(string $name): array
  35. {
  36. foreach (['WeChat', 'WeMini', 'WeOpen', 'WePayV3', 'WePay', 'ThinkService'] as $type) {
  37. if (strpos($name, $type) === 0) {
  38. [, $base] = explode($type, $name);
  39. return [$type, $base, "\\{$type}\\{$base}"];
  40. }
  41. }
  42. return ['-', '-', $name];
  43. }
  44. /**
  45. * 获取当前微信APPID
  46. * @return string
  47. */
  48. public static function getAppid(): string
  49. {
  50. return sConf('wechat.appid');
  51. }
  52. /**
  53. * 获取接口授权模式
  54. * @return string
  55. */
  56. public static function getType(): string
  57. {
  58. $type = strtolower(sConf('wechat.type'));
  59. if (in_array($type, ['api', 'thr'])) return $type;
  60. throw new \Exception('请在后台配置微信对接授权模式');
  61. }
  62. /**
  63. * 获取公众号配置参数
  64. * @return array
  65. */
  66. public static function getConfig(): array
  67. {
  68. return [
  69. 'appid' => static::getAppid(),
  70. 'token' => sConf('wechat.token'),
  71. 'appsecret' => sConf('wechat.secret'),
  72. 'encodingaeskey' => sConf('wechat.aeskey'),
  73. 'mch_id' => sConf('wechat.mch_id'),
  74. 'mch_key' => sConf('wechat.mch_key')
  75. ];
  76. }
  77. /**
  78. * 通过网页授权获取粉丝信息
  79. * @param string $source 回跳URL地址
  80. * @param integer $isfull 获取资料模式
  81. * @param boolean $redirect 是否直接跳转
  82. * @return array
  83. */
  84. public static function getWebOauthInfo(string $source, int $isfull = 0, bool $redirect = true): array
  85. {
  86. try {
  87. $appid = static::getAppid();
  88. $openid = request()->session()->get("{$appid}_openid");
  89. $userinfo = request()->session()->get("{$appid}_fansinfo");
  90. if ((empty($isfull) && !empty($openid)) || (!empty($isfull) && !empty($openid) && !empty($userinfo))) {
  91. return ['openid' => $openid,"url" => "", 'fansinfo' => $userinfo];
  92. }
  93. // 解析 GET 参数
  94. $queryString = parse_url($source, PHP_URL_QUERY);
  95. // 初始化参数数组
  96. $params = [];
  97. // 只有当有查询字符串时才解析
  98. if ($queryString !== null && $queryString !== '') {
  99. parse_str($queryString, $params);
  100. }
  101. // parse_str(parse_url($source, PHP_URL_QUERY), $params);
  102. $getVars = [
  103. 'code' => $params['code'] ?? input('code', ''),
  104. 'rcode' => $params['rcode'] ?? input('rcode', ''),
  105. 'state' => $params['state'] ?? input('state', ''),
  106. ];
  107. $wechat = static::WeChatOauth();
  108. if ($getVars['state'] !== $appid || empty($getVars['code'])) {
  109. $params['rcode'] = enbase64url($source);
  110. $location = strstr("{$source}?", '?', true) . '?' . http_build_query($params);
  111. $oauthurl = $wechat->getOauthRedirect($location, $appid, $isfull ? 'snsapi_userinfo' : 'snsapi_base');
  112. return ['openid' => "","url" => $oauthurl ,"fansinfo" => ""];
  113. } elseif (($token = $wechat->getOauthAccessToken($getVars['code'])) && isset($token['openid'])) {
  114. request()->session()->set("{$appid}_openid", $openid = $token['openid']);
  115. if ($isfull && isset($token['access_token'])) {
  116. $userinfo = $wechat->getUserInfo($token['access_token'], $openid);
  117. request()->session()->set("{$appid}_fansinfo", $userinfo);
  118. }
  119. }
  120. if ($getVars['rcode']) {
  121. $location = debase64url($getVars['rcode']);
  122. return ['openid' => "","url" => $location ,"fansinfo" => ""];
  123. } elseif ((empty($isfull) && !empty($openid)) || (!empty($isfull) && !empty($openid) && !empty($userinfo))) {
  124. return ['openid' => $openid, 'url' => '', 'fansinfo' => $userinfo];
  125. } else {
  126. throw new \Exception('Query params [rcode] not find.');
  127. }
  128. } catch (\Throwable $th) {
  129. echo $th->getMessage();
  130. }
  131. }
  132. //
  133. // /**
  134. // * 获取微信网页JSSDK签名参数
  135. // * @param null|string $location 签名地址
  136. // * @return array
  137. // * @throws \WeChat\Exceptions\InvalidResponseException
  138. // * @throws \WeChat\Exceptions\LocalCacheException
  139. // * @throws \think\admin\Exception
  140. // */
  141. // public static function getWebJssdkSign(?string $location = null): array
  142. // {
  143. // $location = $location ?: Library::$sapp->request->url(true);
  144. // if (static::getType() === 'api') {
  145. // return static::WeChatScript()->getJsSign($location);
  146. // } else {
  147. // return static::ThinkServiceConfig()->jsSign($location);
  148. // }
  149. // }
  150. }