Files
CLOAK/lib/Cloak/CloakJudgmentCache.php
T
2026-06-16 04:58:56 +08:00

273 lines
8.0 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
require_once __DIR__ . '/ClientIpResolver.php';
require_once __DIR__ . '/GeoIpCountryCache.php';
require_once __DIR__ . '/GeoIpCountryResolver.php';
require_once __DIR__ . '/FpUrlHelper.php';
require_once __DIR__ . '/RiskSecondaryGate.php';
/**
* 客户端 SessionPHPSESSID)统一判定缓存:byApi 阶段缓存 + byApiRisk 最终缓存。
*/
class CloakJudgmentCache
{
const SESSION_KEY = 'cloak_judgment_cache';
const STAGE_BYAPI = 'byapi';
const STAGE_FINAL = 'final';
public static function hasSession()
{
return !empty($_SESSION[self::SESSION_KEY])
&& is_array($_SESSION[self::SESSION_KEY]);
}
/**
* @param string|null $currentIp
* @return array|null
*/
public static function get($currentIp = null)
{
if (!self::hasSession()) {
return null;
}
$cached = $_SESSION[self::SESSION_KEY];
if (!self::isConfigValid($cached)) {
self::clear();
$_SESSION['visit_to_3'] = '1';
return null;
}
$ip = ClientIpResolver::normalizeIp(
$currentIp !== null && $currentIp !== '' ? $currentIp : ClientIpResolver::resolve()
);
$cachedIp = ClientIpResolver::normalizeIp($cached['ip'] ?? '');
if ($ip !== null && $cachedIp !== null && $ip !== $cachedIp) {
self::refreshCountryForCurrentIp($ip);
$cached = $_SESSION[self::SESSION_KEY];
}
return $cached;
}
/**
* 二次风控关闭(CLOAK_RISK_NUMBER=0 等)时,byApi 阶段缓存即视为最终缓存。
*
* @param array $cached
*/
public static function isEffectivelyFinal(array $cached)
{
$stage = (string) ($cached['stage'] ?? '');
if ($stage === self::STAGE_FINAL) {
return true;
}
if ($stage === self::STAGE_BYAPI && !RiskSecondaryGate::isEnabled()) {
return true;
}
return false;
}
/**
* 仅返回最终缓存(可短路全流程)。
*
* @param string|null $currentIp
* @return array|null
*/
public static function getFinal($currentIp = null)
{
$cached = self::get($currentIp);
if ($cached === null || !self::isEffectivelyFinal($cached)) {
return null;
}
return $cached;
}
/**
* @param array|null $cached
*/
public static function isFinal($cached = null)
{
if ($cached === null) {
$cached = self::get();
}
return is_array($cached) && self::isEffectivelyFinal($cached);
}
/**
* @param array|null $cached
*/
public static function isPartial($cached = null)
{
if ($cached === null) {
$cached = self::get();
}
if (!is_array($cached) || ($cached['stage'] ?? '') !== self::STAGE_BYAPI) {
return false;
}
return RiskSecondaryGate::isEnabled();
}
/**
* byApi 完成后写入;按风险系数决定 stage。
* CLOAK_RISK_NUMBER=0(或未启用二次风控)时,byApi 结果直接记为 final。
*
* @param array{result:string,reason?:string,ip?:string,country?:string,fp_url?:string} $payload
*/
public static function storeFromByApi(array $payload)
{
$result = ($payload['result'] ?? '') === 'true' ? 'true' : 'false';
$stage = self::STAGE_FINAL;
if ($result === 'true' && RiskSecondaryGate::isEnabled()) {
$stage = self::STAGE_BYAPI;
}
self::writeCache($stage, $payload);
self::applyToSession($_SESSION[self::SESSION_KEY]);
}
/**
* byApiRisk 完成后写入最终缓存。
*
* @param array{result:string,reason?:string,fp_url?:string,ip?:string,country?:string} $payload
*/
public static function storeFromByApiRisk(array $payload)
{
self::writeCache(self::STAGE_FINAL, $payload);
self::applyToSession($_SESSION[self::SESSION_KEY]);
}
/**
* @param array $cached
*/
public static function applyToSession(array $cached)
{
$result = ($cached['result'] ?? '') === 'true' ? 'true' : 'false';
$_SESSION['check_result'] = $result;
$_SESSION['visit_to_2'] = '2';
if (self::isEffectivelyFinal($cached)) {
$_SESSION['visit_to_3'] = '3';
} else {
$_SESSION['visit_to_3'] = '1';
}
if (!empty($cached['ip'])) {
$_SESSION['gcu_ip'] = $cached['ip'];
}
if (array_key_exists('country', $cached)) {
$_SESSION['gcu_country'] = (string) $cached['country'];
}
}
/**
* @param object $v_info visitorInfo
* @param array $cached
*/
public static function applyToVisitorInfo($v_info, array $cached)
{
if (!is_object($v_info)) {
return;
}
if (!empty($cached['ip'])) {
$v_info->v_ip = $cached['ip'];
}
if (array_key_exists('country', $cached) && (string) $cached['country'] !== '') {
$v_info->v_country = (string) $cached['country'];
}
}
public static function clear()
{
unset($_SESSION[self::SESSION_KEY]);
}
public static function hitReason()
{
return '缓存';
}
/**
* @param array $cached
* @return array{result:bool,reason:string,link:string}
*/
public static function toApiResponse(array $cached)
{
$passed = ($cached['result'] ?? '') === 'true';
$link = (string) ($cached['fp_url'] ?? '');
if ($passed && $link === '') {
$link = FpUrlHelper::fallbackUrl();
}
if (!$passed && $link === '' && defined('DB_ZP')) {
$link = (string) DB_ZP;
}
return [
'result' => $passed,
'reason' => self::hitReason(),
'link' => $link,
];
}
/**
* @param string $stage
* @param array $payload
*/
private static function writeCache($stage, array $payload)
{
$ip = ClientIpResolver::normalizeIp($payload['ip'] ?? ClientIpResolver::resolve());
if ($ip === null) {
return;
}
$country = (string) ($payload['country'] ?? '');
if ($country === '' && !empty($_SESSION['gcu_country'])) {
$country = (string) $_SESSION['gcu_country'];
}
if ($country === '') {
$country = (string) (GeoIpCountryResolver::resolve($ip) ?? '');
}
$_SESSION[self::SESSION_KEY] = [
'stage' => $stage,
'ip' => $ip,
'country' => $country,
'result' => ($payload['result'] ?? '') === 'true' ? 'true' : 'false',
'reason' => (string) ($payload['reason'] ?? ''),
'fp_url' => (string) ($payload['fp_url'] ?? ''),
'risk_number' => defined('CLOAK_RISK_NUMBER') ? (int) CLOAK_RISK_NUMBER : 0,
'campaign_id' => defined('COSTM_IP_SCORE') ? (string) COSTM_IP_SCORE : '',
'cached_at' => time(),
];
}
/**
* @param string $currentIp
*/
private static function refreshCountryForCurrentIp($currentIp)
{
if (!self::hasSession()) {
return;
}
$cached = $_SESSION[self::SESSION_KEY];
$cached['ip'] = $currentIp;
$cached['country'] = (string) (GeoIpCountryResolver::resolve($currentIp) ?? '');
$_SESSION[self::SESSION_KEY] = $cached;
$_SESSION['gcu_ip'] = $currentIp;
$_SESSION['gcu_country'] = $cached['country'];
}
/**
* @param array $cached
*/
private static function isConfigValid(array $cached)
{
if (defined('CLOAK_RISK_NUMBER') && (int) ($cached['risk_number'] ?? -1) !== (int) CLOAK_RISK_NUMBER) {
return false;
}
if (defined('COSTM_IP_SCORE') && (string) ($cached['campaign_id'] ?? '') !== (string) COSTM_IP_SCORE) {
return false;
}
return true;
}
}