128 lines
4.1 KiB
PHP
128 lines
4.1 KiB
PHP
<?php
|
|
declare (strict_types=1);
|
|
|
|
namespace app\service;
|
|
|
|
use api\Httpcurl;
|
|
use think\facade\Cache;
|
|
use think\facade\Log;
|
|
|
|
class MiniProgramWechatService
|
|
{
|
|
private string $miniAppCode;
|
|
private array $miniApp;
|
|
|
|
public function __construct(string $miniAppCode, array $miniApp)
|
|
{
|
|
$this->miniAppCode = $miniAppCode;
|
|
$this->miniApp = $miniApp;
|
|
}
|
|
|
|
public function openidByLoginCode(string $loginCode, bool $required = false): string
|
|
{
|
|
$config = $this->wechatConfig();
|
|
if ($loginCode === '' || $config['appid'] === '' || $config['secret'] === '') {
|
|
return '';
|
|
}
|
|
|
|
$response = Httpcurl::request('https://api.weixin.qq.com/sns/jscode2session', 'get', [
|
|
'appid' => $config['appid'],
|
|
'secret' => $config['secret'],
|
|
'js_code' => $loginCode,
|
|
'grant_type' => 'authorization_code',
|
|
], [], 8);
|
|
$result = $this->decodeWechatResponse($response, 'miniapi wx code2session');
|
|
if (!empty($result['openid'])) {
|
|
return (string)$result['openid'];
|
|
}
|
|
|
|
if ($required) {
|
|
Log::warning('miniapi wx openid missing: ' . json_encode($result, JSON_UNESCAPED_UNICODE));
|
|
}
|
|
return '';
|
|
}
|
|
|
|
public function mobileByPhoneCode(string $phoneCode): string
|
|
{
|
|
$accessToken = $this->wechatAccessToken();
|
|
if ($phoneCode === '' || $accessToken === '') {
|
|
return '';
|
|
}
|
|
|
|
$response = Httpcurl::request(
|
|
'https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=' . urlencode($accessToken),
|
|
'post',
|
|
json_encode(['code' => $phoneCode], JSON_UNESCAPED_UNICODE),
|
|
['Content-Type: application/json'],
|
|
8
|
|
);
|
|
$result = $this->decodeWechatResponse($response, 'miniapi wx get phone number');
|
|
$phoneInfo = $result['phone_info'] ?? [];
|
|
return (string)($phoneInfo['purePhoneNumber'] ?? $phoneInfo['phoneNumber'] ?? '');
|
|
}
|
|
|
|
private function wechatAccessToken(): string
|
|
{
|
|
$config = $this->wechatConfig();
|
|
if ($config['appid'] === '' || $config['secret'] === '') {
|
|
Log::warning('miniapi wx config missing: ' . $this->miniAppCode);
|
|
return '';
|
|
}
|
|
|
|
$cacheKey = 'miniapp_access_token_' . $this->miniAppCode;
|
|
$cached = Cache::get($cacheKey);
|
|
if (!empty($cached)) {
|
|
return (string)$cached;
|
|
}
|
|
|
|
$response = Httpcurl::request('https://api.weixin.qq.com/cgi-bin/token', 'get', [
|
|
'grant_type' => 'client_credential',
|
|
'appid' => $config['appid'],
|
|
'secret' => $config['secret'],
|
|
], [], 8);
|
|
$result = $this->decodeWechatResponse($response, 'miniapi wx access token');
|
|
if (empty($result['access_token'])) {
|
|
return '';
|
|
}
|
|
|
|
$ttl = max(60, intval($result['expires_in'] ?? 7200) - 300);
|
|
Cache::set($cacheKey, $result['access_token'], $ttl);
|
|
return (string)$result['access_token'];
|
|
}
|
|
|
|
private function wechatConfig(): array
|
|
{
|
|
return [
|
|
'appid' => trim((string)($this->miniApp['wechat_appid'] ?? '')),
|
|
'secret' => trim((string)($this->miniApp['wechat_secret'] ?? '')),
|
|
];
|
|
}
|
|
|
|
private function decodeWechatResponse($response, string $scene): array
|
|
{
|
|
$result = $this->decodeResponse($response, $scene);
|
|
if (isset($result['errcode']) && intval($result['errcode']) !== 0) {
|
|
Log::warning($scene . ' failed: ' . json_encode($result, JSON_UNESCAPED_UNICODE));
|
|
return [];
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
private function decodeResponse($response, string $scene): array
|
|
{
|
|
if (!is_array($response) || !isset($response[0]) || !empty($response[3])) {
|
|
Log::error($scene . ' request failed: ' . json_encode($response, JSON_UNESCAPED_UNICODE));
|
|
return [];
|
|
}
|
|
|
|
$result = json_decode($response[0], true);
|
|
if (!is_array($result)) {
|
|
Log::error($scene . ' response decode failed: ' . $response[0]);
|
|
return [];
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
}
|