252 lines
7.9 KiB
PHP
252 lines
7.9 KiB
PHP
<?php
|
||
|
||
namespace App\Services;
|
||
|
||
use App\Models\SystemConfig;
|
||
use App\Models\User;
|
||
use Illuminate\Support\Facades\Cache;
|
||
|
||
class WeChatPlatformService
|
||
{
|
||
/**
|
||
* 获取微信开放平台配置
|
||
*/
|
||
public function getConfig(): array
|
||
{
|
||
$cacheKey = 'wechat_platform_config';
|
||
|
||
return Cache::remember($cacheKey, 3600, function () {
|
||
return [
|
||
'enabled' => SystemConfig::getValue('wechat', 'enabled', false),
|
||
'app_id' => SystemConfig::getValue('wechat', 'app_id', ''),
|
||
'app_secret' => SystemConfig::getValue('wechat', 'app_secret', ''),
|
||
'token' => SystemConfig::getValue('wechat', 'token', ''),
|
||
'encoding_aes_key' => SystemConfig::getValue('wechat', 'encoding_aes_key', ''),
|
||
];
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 小程序登录
|
||
*/
|
||
public function miniProgramLogin(string $code): array
|
||
{
|
||
$config = $this->getConfig();
|
||
|
||
if (!$config['enabled']) {
|
||
return ['success' => false, 'message' => '微信服务未启用'];
|
||
}
|
||
|
||
try {
|
||
$response = \Illuminate\Support\Facades\Http::get('https://api.weixin.qq.com/sns/jscode2session', [
|
||
'appid' => $config['app_id'],
|
||
'secret' => $config['app_secret'],
|
||
'js_code' => $code,
|
||
'grant_type' => 'authorization_code',
|
||
]);
|
||
|
||
$data = $response->json();
|
||
|
||
if (isset($data['errcode']) && $data['errcode'] !== 0) {
|
||
return ['success' => false, 'message' => $data['errmsg'] ?? '微信登录失败'];
|
||
}
|
||
|
||
return [
|
||
'success' => true,
|
||
'data' => [
|
||
'openid' => $data['openid'],
|
||
'unionid' => $data['unionid'] ?? null,
|
||
'session_key' => $data['session_key'] ?? null,
|
||
],
|
||
];
|
||
} catch (\Exception $e) {
|
||
\Log::error('微信小程序登录失败: ' . $e->getMessage());
|
||
return ['success' => false, 'message' => '微信登录失败'];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 公众号登录 - 获取授权URL
|
||
*/
|
||
public function getOauthUrl(string $redirectUri, string $state = ''): string
|
||
{
|
||
$config = $this->getConfig();
|
||
$state = $state ?: md5(uniqid());
|
||
|
||
$params = [
|
||
'appid' => $config['app_id'],
|
||
'redirect_uri' => $redirectUri,
|
||
'response_type' => 'code',
|
||
'scope' => 'snsapi_userinfo',
|
||
'state' => $state,
|
||
];
|
||
|
||
return 'https://open.weixin.qq.com/connect/oauth2/authorize?' . http_build_query($params) . '#wechat_redirect';
|
||
}
|
||
|
||
/**
|
||
* 公众号登录 - 通过code获取用户信息
|
||
*/
|
||
public function officialAccountCallback(string $code): array
|
||
{
|
||
$config = $this->getConfig();
|
||
|
||
if (!$config['enabled']) {
|
||
return ['success' => false, 'message' => '微信服务未启用'];
|
||
}
|
||
|
||
try {
|
||
// 获取 access_token
|
||
$tokenResponse = \Illuminate\Support\Facades\Http::get('https://api.weixin.qq.com/sns/oauth2/access_token', [
|
||
'appid' => $config['app_id'],
|
||
'secret' => $config['app_secret'],
|
||
'code' => $code,
|
||
'grant_type' => 'authorization_code',
|
||
]);
|
||
|
||
$tokenData = $tokenResponse->json();
|
||
|
||
if (isset($tokenData['errcode']) && $tokenData['errcode'] !== 0) {
|
||
return ['success' => false, 'message' => $tokenData['errmsg'] ?? '获取access_token失败'];
|
||
}
|
||
|
||
// 获取用户信息
|
||
$userResponse = \Illuminate\Support\Facades\Http::get('https://api.weixin.qq.com/sns/userinfo', [
|
||
'access_token' => $tokenData['access_token'],
|
||
'openid' => $tokenData['openid'],
|
||
'lang' => 'zh_CN',
|
||
]);
|
||
|
||
$userData = $userResponse->json();
|
||
|
||
return [
|
||
'success' => true,
|
||
'data' => [
|
||
'openid' => $userData['openid'],
|
||
'unionid' => $userData['unionid'] ?? null,
|
||
'nickname' => $userData['nickname'] ?? null,
|
||
'headimgurl' => $userData['headimgurl'] ?? null,
|
||
'sex' => $userData['sex'] ?? null,
|
||
'country' => $userData['country'] ?? null,
|
||
'province' => $userData['province'] ?? null,
|
||
'city' => $userData['city'] ?? null,
|
||
],
|
||
];
|
||
} catch (\Exception $e) {
|
||
\Log::error('微信公众号登录失败: ' . $e->getMessage());
|
||
return ['success' => false, 'message' => '微信登录失败'];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取用户信息(通过openid)
|
||
*/
|
||
public function getUserInfo(string $openid): ?array
|
||
{
|
||
$config = $this->getConfig();
|
||
|
||
try {
|
||
$response = \Illuminate\Support\Facades\Http::get('https://api.weixin.qq.com/cgi-bin/user/info', [
|
||
'access_token' => $this->getComponentAccessToken(),
|
||
'openid' => $openid,
|
||
'lang' => 'zh_CN',
|
||
]);
|
||
|
||
return $response->json();
|
||
} catch (\Exception $e) {
|
||
\Log::error('获取微信用户信息失败: ' . $e->getMessage());
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取第三方平台 component_access_token
|
||
*/
|
||
private function getComponentAccessToken(): ?string
|
||
{
|
||
$cacheKey = 'wechat_component_access_token';
|
||
|
||
$token = Cache::get($cacheKey);
|
||
|
||
if ($token) {
|
||
return $token;
|
||
}
|
||
|
||
$config = $this->getConfig();
|
||
|
||
// 如果是第三方平台模式,需要使用 component_appid 和 component_appsecret
|
||
// 这里简化处理,假设使用的是独立应用
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 发送模板消息
|
||
*/
|
||
public function sendTemplateMessage(string $openid, string $templateId, array $data, string $url = ''): bool
|
||
{
|
||
$config = $this->getConfig();
|
||
|
||
if (!$config['enabled']) {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
$accessToken = $this->getComponentAccessToken();
|
||
|
||
if (!$accessToken) {
|
||
// 使用小程序的 access_token
|
||
$accessToken = $this->getMiniProgramAccessToken();
|
||
}
|
||
|
||
$response = \Illuminate\Support\Facades\Http::post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={$accessToken}", [
|
||
'touser' => $openid,
|
||
'template_id' => $templateId,
|
||
'url' => $url,
|
||
'data' => $data,
|
||
]);
|
||
|
||
$result = $response->json();
|
||
|
||
return ($result['errcode'] ?? 1) === 0;
|
||
} catch (\Exception $e) {
|
||
\Log::error('发送微信模板消息失败: ' . $e->getMessage());
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取小程序 access_token
|
||
*/
|
||
private function getMiniProgramAccessToken(): ?string
|
||
{
|
||
$cacheKey = 'wechat_mini_program_access_token';
|
||
|
||
$token = Cache::get($cacheKey);
|
||
|
||
if ($token) {
|
||
return $token;
|
||
}
|
||
|
||
$config = $this->getConfig();
|
||
|
||
try {
|
||
$response = \Illuminate\Support\Facades\Http::get('https://api.weixin.qq.com/cgi-bin/token', [
|
||
'grant_type' => 'client_credential',
|
||
'appid' => $config['app_id'],
|
||
'secret' => $config['app_secret'],
|
||
]);
|
||
|
||
$data = $response->json();
|
||
|
||
if (isset($data['access_token'])) {
|
||
Cache::put($cacheKey, $data['access_token'], now()->addSeconds($data['expires_in'] - 200));
|
||
return $data['access_token'];
|
||
}
|
||
} catch (\Exception $e) {
|
||
\Log::error('获取小程序access_token失败: ' . $e->getMessage());
|
||
}
|
||
|
||
return null;
|
||
}
|
||
}
|