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

176 lines
4.3 KiB
PHP
Executable File

<?php
/**
* 单次访问(Visit)生命周期:一次独立打开 = 一条日志;同 visit 内续步仅 UPDATE。
*/
class VisitorVisitContext
{
const KEY_LOG_ID = 'cloak_visit_log_id';
const KEY_FINALIZED = 'cloak_visit_finalized';
const KEY_ACTIVE = 'cloak_visit_active';
public static function clear()
{
unset(
$_SESSION[self::KEY_LOG_ID],
$_SESSION[self::KEY_FINALIZED],
$_SESSION[self::KEY_ACTIVE]
);
}
/**
* @return int
*/
public static function currentLogId()
{
return (int) ($_SESSION[self::KEY_LOG_ID] ?? 0);
}
public static function isFinalized()
{
return !empty($_SESSION[self::KEY_FINALIZED]);
}
/**
* ip_check 入口:识别刷新导航并开启新 visit。
*/
public static function evaluateAtEntry()
{
if (self::isFcheckRequest()) {
return;
}
if (self::isRefreshNavigation()) {
self::clear();
}
}
public static function markVisitActive()
{
$_SESSION[self::KEY_ACTIVE] = 1;
}
public static function isFcheckRequest()
{
$script = $_SERVER['SCRIPT_NAME'] ?? $_SERVER['PHP_SELF'] ?? '';
return basename($script) === 'f_check.php';
}
public static function hasContinuationMarker()
{
if (isset($_GET['time']) && (string) $_GET['time'] !== '') {
return true;
}
return self::isFcheckRequest();
}
public static function isRefreshNavigation()
{
if (self::hasContinuationMarker()) {
return false;
}
if (self::currentLogId() <= 0 || self::isFinalized()) {
return false;
}
$mode = strtolower((string) ($_SERVER['HTTP_SEC_FETCH_MODE'] ?? ''));
return $mode === 'navigate';
}
public static function isNewVisit()
{
if (self::isRefreshNavigation()) {
return true;
}
if (self::currentLogId() <= 0) {
return true;
}
if (self::isFinalized()) {
return true;
}
return false;
}
public static function isContinuation()
{
if (self::isRefreshNavigation()) {
return false;
}
if (self::hasContinuationMarker()) {
return true;
}
if (self::currentLogId() > 0 && !self::isFinalized()) {
return true;
}
if (!empty($_SESSION[self::KEY_ACTIVE]) && self::currentLogId() <= 0) {
return true;
}
return false;
}
/**
* INSERT 前:已 finalize 或刷新后的新 visit 清除旧绑定。
*/
public static function prepareForNewInsert()
{
if (!self::isNewVisit()) {
return;
}
$hadFinalized = self::isFinalized();
unset($_SESSION[self::KEY_FINALIZED]);
if ($hadFinalized || self::isRefreshNavigation()) {
unset($_SESSION[self::KEY_LOG_ID]);
}
if (empty($_SESSION[self::KEY_ACTIVE])) {
self::markVisitActive();
}
if (class_exists('VisitorApiAudit', false)) {
VisitorApiAudit::clearByApi();
}
}
public static function shouldPersistAsUpdate()
{
return self::currentLogId() > 0 && !self::isFinalized() && !self::isNewVisit();
}
/**
* @param int $logId
*/
public static function bindLogId($logId)
{
$logId = (int) $logId;
if ($logId > 0) {
$_SESSION[self::KEY_LOG_ID] = $logId;
}
}
/**
* @param string|null $result
*/
public static function finalizeVisit($result = null)
{
$_SESSION[self::KEY_FINALIZED] = 1;
unset($_SESSION[self::KEY_ACTIVE]);
}
/**
* @param string $result
*/
public static function shouldFinalizeOnResult($result)
{
$r = (string) $result;
return $r === 'true' || $r === 'false';
}
/**
* @param array $logs
* @return array
*/
public static function normalizeLogsForDb(array $logs)
{
$result = (string) ($logs['result'] ?? '');
if (function_exists('cloak_normalize_log_reason')) {
$logs['reason'] = cloak_normalize_log_reason($result, $logs['reason'] ?? '');
}
return $logs;
}
}