$link) { if (0 === strpos((string) $link, $home)) { unset($links[$index]); } } } /** * 非管理员禁止进入后台(放行 admin-ajax 与定时任务)。 */ public function restrict_admin_access(): void { if (wp_doing_ajax() || wp_doing_cron()) { return; } if (!is_user_logged_in() || current_user_can('manage_options')) { return; } wp_safe_redirect(home_url('/')); exit; } /** * 内容防刷限制:检查并计数(10 分钟窗口 + 当天两个维度,0 = 不限制)。 * * @param string $scope post|comment|upload|register|order * @param string $subject 用户 ID 或 IP 等限流主体 * @param int $cap_10 10 分钟上限 * @param int $cap_day 一天上限 * @return true|string true = 放行(并计数),字符串 = 拒绝原因 */ public static function brush_allow(string $scope, string $subject, int $cap_10, int $cap_day) { if ($cap_10 <= 0 && $cap_day <= 0) { return true; } $scope = sanitize_key($scope); $hash = md5((string) $subject); $minute_key = sprintf('aksrt_brush_%s_m_%s_%s%d', $scope, $hash, wp_date('YmdH'), intdiv((int) wp_date('i'), 10)); $day_key = sprintf('aksrt_brush_%s_d_%s_%s', $scope, $hash, wp_date('Ymd')); if ($cap_10 > 0 && (int) get_transient($minute_key) >= $cap_10) { return __('操作过于频繁,请稍后再试', 'aksrt'); } if ($cap_day > 0 && (int) get_transient($day_key) >= $cap_day) { return __('今日操作次数已达上限,请明天再试', 'aksrt'); } if ($cap_10 > 0) { set_transient($minute_key, (int) get_transient($minute_key) + 1, 10 * MINUTE_IN_SECONDS); } if ($cap_day > 0) { set_transient($day_key, (int) get_transient($day_key) + 1, DAY_IN_SECONDS); } return true; } /** * 错误频率限制:返回下一次验证需等待的秒数(0 = 可立即验证)。 * 错误超过 5 次限 30 秒一次,超过 10 次限 3 分钟一次。 */ public static function error_frequency_wait(): int { $settings = \AKSRT\Settings\ExtensionRuntime::get_security_settings(); if (empty($settings['security_error_frequency_limit'])) { return 0; } $state = get_transient(self::error_frequency_key()); if (!is_array($state)) { return 0; } $count = (int) ($state['count'] ?? 0); $last = (int) ($state['last'] ?? 0); if ($count < 5) { return 0; } $remaining = ($count >= 10 ? 180 : 30) - (time() - $last); return $remaining > 0 ? $remaining : 0; } /** 记录一次验证失败(滑动 10 分钟窗口)。 */ public static function error_frequency_record(): void { $settings = \AKSRT\Settings\ExtensionRuntime::get_security_settings(); if (empty($settings['security_error_frequency_limit'])) { return; } $key = self::error_frequency_key(); $state = get_transient($key); $count = is_array($state) ? (int) ($state['count'] ?? 0) + 1 : 1; set_transient($key, ['count' => $count, 'last' => time()], 10 * MINUTE_IN_SECONDS); } /** 验证成功后清除错误计数。 */ public static function error_frequency_clear(): void { delete_transient(self::error_frequency_key()); } private static function error_frequency_key(): string { $ip = function_exists('aksrt_get_client_ip') ? aksrt_get_client_ip() : (string) ($_SERVER['REMOTE_ADDR'] ?? ''); return 'aksrt_err_freq_' . md5((string) get_current_user_id() . '|' . $ip); } }