Files
bsh_sample/app/common/service/WechatService.php
T
2025-12-08 17:37:34 +08:00

236 lines
6.9 KiB
PHP

<?php
namespace app\common\service;
use app\common\model\User;
use EasyWeChat\MiniApp\Application as xcxApplication;
use EasyWeChat\OpenPlatform\Application;
use support\Redis;
use GuzzleHttp\Client;
use support\exception\BusinessException;
class WechatService
{
protected array $web;
protected array $mini;
protected array $login;
protected $app;
public function __construct()
{
$cfg = config('wechat');
$this->web = $cfg['web'];
$this->mini = $cfg['mini'];
$this->login = $cfg['login'];
}
/**
* 获取微信二维码
*/
public function makeQrUrl()
{
try {
$state = bin2hex(random_bytes(16));
$ttl = (int)($this->login['state_ttl'] ?? 300);
// 记录 state
Redis::setEx("wx:login:state:$state", $ttl, json_encode([
'redirect' => $this->web['redirect'],
'ts' => time(),
], JSON_UNESCAPED_UNICODE));
// 组装跳转地址
$qrUrl = sprintf(
'https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=%s&scope=%s&state=%s#wechat_redirect',
$this->web['app_id'],
urlencode($this->web['redirect']),
'code',
'snsapi_login',
$state,
);
$data = [
'state' => $state,
'qr_url' => $qrUrl
];
return $data;
} catch (\Throwable $th) {
// var_dump($th->getFile().'|'.$th->getLine().'|'.$th->getMessage());
throw new BusinessException('获取微信二维码失败');
}
}
/**
* 获取微信access_token
*/
public function wechatWebAccessToken(string $code, string $state): array
{
try {
// 校验 state
$stateJson = Redis::get("wx:login:state:$state");
if (!$stateJson) {
throw new \RuntimeException('state 已过期或无效');
}
// 拼接地址
$tokenUrl = sprintf(
'https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code',
$this->web['app_id'],
$this->web['app_secret'],
$code
);
// code 换 token
$token = $this->httpGetJson($tokenUrl);
if (!isset($token['access_token'], $token['openid'])) {
throw new \RuntimeException('换取 access_token 失败:'. json_encode($token, JSON_UNESCAPED_UNICODE));
}
return $token;
} catch (\Throwable $th) {
throw new BusinessException('获取 access_token 失败');
}
}
/**
* 获取微信用户信息
*
* @param array $token
* @return array
*/
public function wechatWebUserInfo(array $accessToken): array
{
try {
// 拉取用户信息
return $this->httpGetJson(sprintf(
'https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s',
$accessToken['access_token'],
$accessToken['openid']
));
} catch (\Throwable $th) {
// var_dump($th->getFile().'|'.$th->getLine().'|'.$th->getMessage());
throw new BusinessException('获取用户信息失败');
}
}
/**
* tools - httpGetJson
*/
protected function httpGetJson(string $url): array
{
$client = new Client([
'verify' => false, // 禁用 SSL 验证
'timeout' => 10,
]);
$json = $client->get($url)->getBody()->getContents();
return json_decode($json, true) ?: [];
}
//----------------------------小程序登录----------------------------------------
/**
* 获取 openid / session_key
* @param $code
* @return mixed
*/
public function miniCode2Session($code)
{
$appid = $this->mini['app_id'];
$secret = $this->mini['app_secret'];
$url = "https://api.weixin.qq.com/sns/jscode2session?appid=$appid&secret=$secret&js_code=$code&grant_type=authorization_code";
return json_decode(file_get_contents($url), true);
}
/**
* 获取 access_token
* @return mixed
*/
public function getMiniAccessToken()
{
$appid = $this->mini['app_id'];
$secret = $this->mini['app_secret'];
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$appid&secret=$secret";
return json_decode(file_get_contents($url), true);
}
/**
* 调用微信接口取手机号
* @param $access_token
* @param $phone_code
* @return mixed
*/
public function getMiniPhoneNumber($access_token, $phone_code)
{
$url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={$access_token}";
$data = json_encode([
'code' => $phone_code
]);
$options = [
'http' => [
'header' => "Content-type: application/json",
'method' => 'POST',
'content' => $data,
],
];
return json_decode(file_get_contents($url, false, stream_context_create($options)), true);
}
/**
* 小程序获取openid
* @param string $code
* @return array
* @throws BusinessException
*/
public function xcxOpenid(string $code): array
{
$config = [
'app_id' => getenv('WECHAT_MINI_APPID'),
'secret' => getenv('WECHAT_MINI_SECRET'),
'response_type' => 'array',
'log' => [
'level' => 'debug',
'file' => runtime_path().'/mzl/wechat.log',
]
];
// 创建微信小程序对象
$wechat = new xcxApplication($config);
// 获取 session_key 和 openid
return $wechat->getUtils()->codeToSession($code);
}
/**
* 小程序获取手机号
* @param string $phone_code
* @return mixed
* @throws BusinessException
*/
public function xcxPhoneNumber(string $phone_code)
{
$config = [
'app_id' => getenv('WECHAT_MINI_APPID'),
'secret' => getenv('WECHAT_MINI_SECRET'),
'response_type' => 'array',
'log' => [
'level' => 'debug',
'file' => runtime_path().'/mzl/wechat.log',
]
];
// 创建微信小程序对象
$wechat = new xcxApplication($config);
// getPhoneNumber
$data = ['code' => $phone_code];
$result = $wechat->getClient()->postJson('wxa/business/getuserphonenumber', $data);
if (isset($result['phone_info'])) {
// 业务处理 $result['phone_info']['phoneNumber']
return $result;
} else {
throw new BusinessException($result['errmsg']);
}
}
}