Files
lgp-admin-plus-api/app/Service/wx/WxMiniService.php
LQ bcf54c2727 初始化
缺陷:主题配色需要优化整体的同风格
2026-08-14 23:21:21 +08:00

95 lines
3.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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'];
}
}