chore: 重写初始提交(清空历史,整理后全量提交)
This commit is contained in:
@@ -0,0 +1,348 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: ywxapp<admin@ywxapp.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace addon\wxchat\middleware;
|
||||
|
||||
use addon\wxchat\model\WxchatAppVersion as AppVersion;
|
||||
use think\facade\Log;
|
||||
use think\facade\Request;
|
||||
use think\Response;
|
||||
|
||||
/**
|
||||
* AppVersionCheck 类
|
||||
*
|
||||
* @author ywxapp <admin@ywxapp.cn>
|
||||
*/
|
||||
class AppVersionCheck
|
||||
{
|
||||
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param \Closure $next
|
||||
* @return Response
|
||||
*/
|
||||
// 需要跳过的路由(不需要版本检查的接口)
|
||||
protected array $except = [
|
||||
'app/version/check',
|
||||
'app/version/latest',
|
||||
'api/auth/login',
|
||||
'api/auth/register',
|
||||
'api/public/*',
|
||||
];
|
||||
|
||||
// 需要强制版本检查的路由(版本过低直接拒绝)
|
||||
protected array $forceCheck = [
|
||||
'api/user/*',
|
||||
'api/order/*',
|
||||
'api/payment/*',
|
||||
'api/wallet/*',
|
||||
];
|
||||
|
||||
// 最低支持的版本号(硬性要求)
|
||||
protected array $minVersions = [
|
||||
'android' => 100,
|
||||
'ios' => 100,
|
||||
'harmony' => 100,
|
||||
];
|
||||
/**
|
||||
* 版本检查结果
|
||||
*/
|
||||
protected array $result = [
|
||||
'need_update' => false, // 是否需要更新
|
||||
'is_force_update' => false, // 是否强制更新
|
||||
'is_compatible' => true, // 是否兼容
|
||||
'update_type' => 'none', // 更新类型: none/optional/recommended/required
|
||||
'current_version' => null, // 当前版本信息
|
||||
'latest_version' => null, // 最新版本信息
|
||||
'min_support_version' => 0, // 最低支持版本
|
||||
'version_diff' => 0, // 版本差异
|
||||
'message' => '', // 提示信息
|
||||
'download_url' => '', // 下载地址
|
||||
'update_content' => '', // 更新内容
|
||||
'size' => '', // 安装包大小
|
||||
];
|
||||
|
||||
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
// 获取Header信息
|
||||
$platform = Request::header('App-Platform', Request::header('X-App-Platform', ''));
|
||||
$versionCode = (int) Request::header('App-Version-Code', Request::header('X-App-Version-Code', 0));
|
||||
$versionName = Request::header('App-Version-Name', Request::header('X-App-Version-Name', ''));
|
||||
$channel = Request::header('App-Channel', Request::header('X-App-Channel', ''));
|
||||
// 记录请求信息(用于日志分析)
|
||||
// $this->logRequestInfo($platform, $versionCode, $versionName, $channel);
|
||||
// 检查是否需要跳过版本检查
|
||||
// if ($this->shouldExcept()) {
|
||||
// return $next($request);
|
||||
// }
|
||||
// 验证Header必填字段
|
||||
if (empty($platform) || $versionCode <= 0) {
|
||||
// 如果是强制检查的接口,直接拒绝
|
||||
if ($this->isForceCheck()) {
|
||||
return $this->errorResponse(
|
||||
400,
|
||||
'缺少APP版本信息,请升级到最新版本',
|
||||
['required_headers' => ['App-Platform', 'App-Version-Code']]
|
||||
);
|
||||
}
|
||||
// 非强制检查,记录警告但继续
|
||||
Log::warning('请求缺少版本信息', [
|
||||
'path' => Request::url(),
|
||||
'ip' => Request::ip(),
|
||||
]);
|
||||
return $next($request);
|
||||
}
|
||||
// 验证平台合法性
|
||||
if (! in_array($platform, ['android', 'ios', 'harmony', 'web'])) {
|
||||
return $this->errorResponse(400, '无效的平台类型');
|
||||
}
|
||||
// 检查最低版本要求
|
||||
if ($versionCode < ($this->minVersions[$platform] ?? 0)) {
|
||||
return $this->errorResponse(
|
||||
426, // Upgrade Required
|
||||
"当前版本过低,请升级到最新版本",
|
||||
[
|
||||
'min_version_code' => $this->minVersions[$platform],
|
||||
'current_version_code' => $versionCode,
|
||||
'platform' => $platform,
|
||||
]
|
||||
);
|
||||
}
|
||||
// 执行版本检查逻辑
|
||||
$checkResult = $this->checkVersion($platform, $versionCode);
|
||||
// 如果版本不兼容且是强制检查接口,拒绝访问
|
||||
if (! $checkResult['is_compatible'] && $this->isForceCheck()) {
|
||||
return $this->errorResponse(
|
||||
426,
|
||||
$checkResult['message'] ?? '版本不兼容,请升级到最新版本',
|
||||
[
|
||||
'need_update' => true,
|
||||
'is_force_update' => true,
|
||||
'latest_version' => $checkResult['latest_version'],
|
||||
'download_url' => $checkResult['download_url'] ?? '',
|
||||
]
|
||||
);
|
||||
}
|
||||
// 将版本信息存入Request,供后续控制器使用
|
||||
$request->appPlatform = $platform;
|
||||
$request->appVersionCode = $versionCode;
|
||||
$request->appVersionName = $versionName;
|
||||
$request->appChannel = $channel;
|
||||
// 继续执行
|
||||
$response = $next($request);
|
||||
// 在响应Header中返回版本检查结果(可选)
|
||||
if ($checkResult['need_update']) {
|
||||
$response->header([
|
||||
'X-App-Need-Update' => 'true',
|
||||
'X-App-Update-Type' => $checkResult['update_type'] ?? 'optional',
|
||||
'X-App-Latest-Version' => $checkResult['latest_version']['version_name'] ?? '',
|
||||
]);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查版本
|
||||
* @param string $platform 平台: android/ios/harmony
|
||||
* @param int $currentVersionCode 当前版本号
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function checkVersion(string $platform, int $currentVersionCode): array
|
||||
{
|
||||
// 验证平台
|
||||
$validPlatforms = ['android', 'ios', 'harmony'];
|
||||
if (! in_array($platform, $validPlatforms)) {
|
||||
throw new Exception('无效的平台类型');
|
||||
}
|
||||
|
||||
// 获取最新版本
|
||||
$latestVersion = AppVersion::getLatestVersion($platform);
|
||||
if (! $latestVersion) {
|
||||
throw new Exception('未找到该平台的版本信息');
|
||||
}
|
||||
|
||||
// 获取当前版本信息
|
||||
$currentVersion = AppVersion::getVersion($platform, $currentVersionCode);
|
||||
|
||||
// 设置最新版本信息
|
||||
$this->result['latest_version'] = [
|
||||
'version_code' => $latestVersion->version_code,
|
||||
'version_name' => $latestVersion->version_name,
|
||||
'release_time' => $latestVersion->release_time,
|
||||
];
|
||||
|
||||
// 设置当前版本信息
|
||||
$this->result['current_version'] = $currentVersion ? [
|
||||
'version_code' => $currentVersion->version_code,
|
||||
'version_name' => $currentVersion->version_name,
|
||||
] : null;
|
||||
|
||||
// 设置最低支持版本
|
||||
$this->result['min_support_version'] = $latestVersion->min_support_version;
|
||||
|
||||
// 计算版本差异
|
||||
$this->result['version_diff'] = $latestVersion->version_code - $currentVersionCode;
|
||||
|
||||
// 判断是否需要更新
|
||||
if ($currentVersionCode < $latestVersion->version_code) {
|
||||
$this->result['need_update'] = true;
|
||||
$this->result['is_force_update'] = (bool) $latestVersion->is_force_update;
|
||||
$this->result['is_compatible'] = (bool) $latestVersion->is_compatible;
|
||||
$this->result['update_type'] = $latestVersion->update_type;
|
||||
$this->result['download_url'] = $latestVersion->download_url;
|
||||
$this->result['update_content'] = $latestVersion->update_content;
|
||||
$this->result['size'] = $latestVersion->size;
|
||||
|
||||
// 生成提示信息
|
||||
$this->generateMessage($latestVersion, $currentVersionCode);
|
||||
} else {
|
||||
$this->result['message'] = '当前已是最新版本';
|
||||
}
|
||||
|
||||
// 检查是否低于最低支持版本
|
||||
if ($currentVersionCode < $latestVersion->min_support_version) {
|
||||
$this->result['need_update'] = true;
|
||||
$this->result['is_force_update'] = true;
|
||||
$this->result['is_compatible'] = false;
|
||||
$this->result['update_type'] = 'required';
|
||||
$this->result['message'] = '当前版本过低,必须升级到最新版本才能继续使用';
|
||||
}
|
||||
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否需要跳过版本检查
|
||||
*/
|
||||
protected function shouldExcept(): bool
|
||||
{
|
||||
$path = Request::path();
|
||||
foreach ($this->except as $except) {
|
||||
if ($except === $path || fnmatch($except, $path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否需要强制版本检查
|
||||
*/
|
||||
protected function isForceCheck(): bool
|
||||
{
|
||||
$path = Request::controller() . '/' . Request::action();
|
||||
|
||||
foreach ($this->forceCheck as $check) {
|
||||
if ($check === $path || fnmatch($check, $path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录请求信息
|
||||
*/
|
||||
protected function logRequestInfo(string $platform, int $versionCode, string $versionName, string $channel): void
|
||||
{
|
||||
// 只记录特定接口的日志(避免日志过多)
|
||||
$logPaths = [
|
||||
'api/user/*',
|
||||
'api/order/*',
|
||||
'api/payment/*',
|
||||
];
|
||||
|
||||
$path = Request::path();
|
||||
foreach ($logPaths as $logPath) {
|
||||
if (fnmatch($logPath, $path)) {
|
||||
Log::info('APP请求', [
|
||||
'path' => $path,
|
||||
'method' => Request::method(),
|
||||
'platform' => $platform,
|
||||
'version_code' => $versionCode,
|
||||
'version_name' => $versionName,
|
||||
'channel' => $channel,
|
||||
'ip' => Request::ip(),
|
||||
'user_agent' => Request::header('Member-Agent', ''),
|
||||
]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误响应
|
||||
*/
|
||||
protected function errorResponse(int $code, string $message, array $data = []): Response
|
||||
{
|
||||
return json([
|
||||
'code' => $code,
|
||||
'message' => $message,
|
||||
'data' => $data,
|
||||
'timestamp' => time(),
|
||||
], $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成提示信息
|
||||
* @param AppVersion $latestVersion 最新版本
|
||||
* @param int $currentVersionCode 当前版本号
|
||||
*/
|
||||
protected function generateMessage(AppVersion $latestVersion, int $currentVersionCode): void
|
||||
{
|
||||
$versionName = $latestVersion->version_name;
|
||||
|
||||
if ($latestVersion->is_force_update) {
|
||||
$this->result['message'] = "发现新版本 {$versionName},请立即升级";
|
||||
} elseif ($latestVersion->update_type === 'required') {
|
||||
$this->result['message'] = "发现重要更新 {$versionName},建议立即升级";
|
||||
} elseif ($latestVersion->update_type === 'recommended') {
|
||||
$this->result['message'] = "发现新版本 {$versionName},建议升级";
|
||||
} else {
|
||||
$this->result['message'] = "发现新版本 {$versionName},可选择升级";
|
||||
}
|
||||
|
||||
// 如果不兼容,添加警告
|
||||
if (!$latestVersion->is_compatible) {
|
||||
$this->result['message'] .= "(当前版本将无法继续使用)";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 版本号转换为版本名称
|
||||
* @param int $versionCode 版本号 101
|
||||
* @return string 版本名称 1.0.1
|
||||
*/
|
||||
public static function versionCodeToName(int $versionCode): string
|
||||
{
|
||||
$major = floor($versionCode / 100);
|
||||
$minor = floor(($versionCode % 100) / 10);
|
||||
$patch = $versionCode % 10;
|
||||
return "{$major}.{$minor}.{$patch}";
|
||||
}
|
||||
|
||||
/**
|
||||
* 版本名称转换为版本号
|
||||
* @param string $versionName 版本名称 1.0.1
|
||||
* @return int 版本号 101
|
||||
*/
|
||||
public static function versionNameToCode(string $versionName): int
|
||||
{
|
||||
$parts = explode('.', $versionName);
|
||||
$parts = array_pad($parts, 3, 0);
|
||||
return (int)($parts[0] * 100 + $parts[1] * 10 + $parts[2]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user