HIGH 级别修复: - AdminPage.php: 移除重复的 Logger 导入 - AdminPage.php: 修复 auth_token 双重加密问题 - AdminPage.php: 添加 action 参数白名单验证 - CacheManager.php: get_stats() 使用 $wpdb->prepare() - source-editor.php: 不显示加密后的 token,使用占位符 - Validator.php: DNS 解析失败时视为本地地址(SSRF 防护) MEDIUM 级别修复: - BridgeCommand.php: 使用 WordPress 文件系统 API - SourceModel.php: 改进 auth_token 解密回退逻辑 - SourceModel.php: 添加 URL 协议验证 (http/https) - Encryption.php: 使用随机生成的密钥替代站点 URL 哈希 LOW 级别修复: - BackgroundUpdater.php: 移除 PHP 8.0 联合类型语法 - Plugin.php: 使用 wp_cache_flush_group() 如果可用 - Validator.php: 添加 IPv6 私有地址检查 - uninstall.php: 清理 wpbridge_encryption_key 选项 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
179 lines
4 KiB
PHP
179 lines
4 KiB
PHP
<?php
|
|
/**
|
|
* 后台更新器
|
|
*
|
|
* @package WPBridge
|
|
*/
|
|
|
|
namespace WPBridge\Performance;
|
|
|
|
use WPBridge\Core\Settings;
|
|
use WPBridge\Core\Logger;
|
|
use WPBridge\UpdateSource\SourceManager;
|
|
use WPBridge\Cache\CacheManager;
|
|
|
|
// 防止直接访问
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* 后台更新器类
|
|
* 使用 WP-Cron 在后台预先更新缓存
|
|
*/
|
|
class BackgroundUpdater {
|
|
|
|
/**
|
|
* 定时任务钩子名称
|
|
*
|
|
* @var string
|
|
*/
|
|
const CRON_HOOK = 'wpbridge_update_sources';
|
|
|
|
/**
|
|
* 设置实例
|
|
*
|
|
* @var Settings
|
|
*/
|
|
private Settings $settings;
|
|
|
|
/**
|
|
* 源管理器
|
|
*
|
|
* @var SourceManager
|
|
*/
|
|
private SourceManager $source_manager;
|
|
|
|
/**
|
|
* 并行请求管理器
|
|
*
|
|
* @var ParallelRequestManager
|
|
*/
|
|
private ParallelRequestManager $parallel_manager;
|
|
|
|
/**
|
|
* 缓存管理器
|
|
*
|
|
* @var CacheManager
|
|
*/
|
|
private CacheManager $cache;
|
|
|
|
/**
|
|
* 构造函数
|
|
*
|
|
* @param Settings $settings 设置实例
|
|
*/
|
|
public function __construct( Settings $settings ) {
|
|
$this->settings = $settings;
|
|
$this->source_manager = new SourceManager( $settings );
|
|
$this->parallel_manager = new ParallelRequestManager( $settings->get_request_timeout() );
|
|
$this->cache = new CacheManager();
|
|
|
|
$this->init_hooks();
|
|
}
|
|
|
|
/**
|
|
* 初始化钩子
|
|
*/
|
|
private function init_hooks(): void {
|
|
add_action( self::CRON_HOOK, [ $this, 'run_update' ] );
|
|
}
|
|
|
|
/**
|
|
* 调度更新任务
|
|
*/
|
|
public function schedule_update(): void {
|
|
if ( ! wp_next_scheduled( self::CRON_HOOK ) ) {
|
|
wp_schedule_event( time(), 'twicedaily', self::CRON_HOOK );
|
|
Logger::info( '已调度后台更新任务' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 取消调度
|
|
*/
|
|
public function unschedule(): void {
|
|
$timestamp = wp_next_scheduled( self::CRON_HOOK );
|
|
if ( $timestamp ) {
|
|
wp_unschedule_event( $timestamp, self::CRON_HOOK );
|
|
Logger::info( '已取消后台更新任务' );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 执行更新
|
|
*/
|
|
public function run_update(): void {
|
|
Logger::info( '开始后台更新' );
|
|
|
|
$sources = $this->source_manager->get_enabled_sorted();
|
|
|
|
if ( empty( $sources ) ) {
|
|
Logger::debug( '没有启用的更新源' );
|
|
return;
|
|
}
|
|
|
|
// 使用并行请求检查所有源
|
|
$results = $this->parallel_manager->check_multiple_sources( $sources );
|
|
|
|
$success_count = 0;
|
|
$fail_count = 0;
|
|
|
|
foreach ( $results as $source_id => $data ) {
|
|
if ( null !== $data ) {
|
|
// 缓存结果
|
|
$this->cache->set(
|
|
'source_data_' . $source_id,
|
|
$data,
|
|
$this->settings->get_cache_ttl()
|
|
);
|
|
$success_count++;
|
|
} else {
|
|
$fail_count++;
|
|
}
|
|
}
|
|
|
|
Logger::info( '后台更新完成', [
|
|
'success' => $success_count,
|
|
'failed' => $fail_count,
|
|
] );
|
|
}
|
|
|
|
/**
|
|
* 手动触发更新
|
|
*
|
|
* @return array 更新结果
|
|
*/
|
|
public function trigger_update(): array {
|
|
$this->run_update();
|
|
|
|
return [
|
|
'status' => 'completed',
|
|
'time' => current_time( 'mysql' ),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取下次更新时间
|
|
*
|
|
* @return int|false 时间戳或 false
|
|
*/
|
|
public function get_next_scheduled() {
|
|
return wp_next_scheduled( self::CRON_HOOK );
|
|
}
|
|
|
|
/**
|
|
* 获取更新状态
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_status(): array {
|
|
$next = $this->get_next_scheduled();
|
|
|
|
return [
|
|
'scheduled' => (bool) $next,
|
|
'next_run' => $next ? gmdate( 'Y-m-d H:i:s', $next ) : null,
|
|
'next_run_human' => $next ? human_time_diff( time(), $next ) : null,
|
|
];
|
|
}
|
|
}
|