Files
lgp-admin-plus-api/app/Service/wx/WxMiniService.php

95 lines
3.4 KiB
PHP
Raw Normal View History

<?php
namespace App\Service\wx;
use App\Service\common\RedisService;
use App\Service\common\UtilsService;
use Illuminate\Support\Facades\Http;
/**
* 微信小程序开放接口客户端
*
* AppID / AppSecret 来自 nl_wx_app加密存储不再硬编码在源码里。
* access_token 7200 秒有效期且并发刷新会互相顶掉,所以缓存进 Redis 复用。
*/
class WxMiniService
{
private static mixed $_instance;
private string $baseUrl = 'https://api.weixin.qq.com/';
public static function getInstance(): null|static
{
$name = get_called_class();
if (!isset(self::$_instance[$name])) {
self::$_instance[$name] = new static();
}
return self::$_instance[$name];
}
/**
* code openid session_key
*/
public function jscode2session(string $code): array
{
$app = WxAppService::getInstance()->current();
if (($app['app_id'] ?? '') === '' || ($app['app_secret'] ?? '') === '') {
UtilsService::getInstance()->errorThrow('小程序 AppID/AppSecret 未配置');
}
$result = Http::asJson()->get($this->baseUrl . 'sns/jscode2session', [
'appid' => $app['app_id'],
'secret' => $app['app_secret'],
'js_code' => $code,
'grant_type' => 'authorization_code',
])->json();
if (!empty($result['errcode'])) {
UtilsService::getInstance()->errorThrow('微信登录失败:' . ($result['errmsg'] ?? '未知错误'));
}
if (empty($result['openid'])) {
UtilsService::getInstance()->errorThrow('微信登录失败:未拿到 openid');
}
$result['app_code'] = (string) ($app['code'] ?? '');
return $result;
}
/**
* 手机号快速验证:前端拿到的 code 换真实号码
*/
public function getPhoneNumber(string $phoneCode): string
{
$token = $this->accessToken();
$result = Http::asJson()->post(
$this->baseUrl . 'wxa/business/getuserphonenumber?access_token=' . $token,
['code' => $phoneCode]
)->json();
if (!empty($result['errcode'])) {
UtilsService::getInstance()->errorThrow('获取手机号失败:' . ($result['errmsg'] ?? '未知错误'));
}
return (string) ($result['phone_info']['phoneNumber'] ?? '');
}
/**
* 接口调用凭证,按 appid 缓存
*/
public function accessToken(): string
{
$app = WxAppService::getInstance()->current();
$redis = RedisService::getInstance()->init(config('nl.redis.wechat_token'));
$cached = $redis->get($app['app_id']);
if (!empty($cached)) {
return (string) $cached;
}
$result = Http::asJson()->get($this->baseUrl . 'cgi-bin/token', [
'grant_type' => 'client_credential',
'appid' => $app['app_id'],
'secret' => $app['app_secret'],
])->json();
if (empty($result['access_token'])) {
UtilsService::getInstance()->errorThrow('获取 access_token 失败:' . ($result['errmsg'] ?? '未知错误'));
}
// 提前 300 秒过期,避免临界点上拿到即将失效的 token
$redis->set($app['app_id'], $result['access_token'], max(60, (int) ($result['expires_in'] ?? 7200) - 300));
return (string) $result['access_token'];
}
}