Files
CLOAK/lib/Cloak/VisitorRepository.php
T
2026-06-15 22:42:59 +08:00

391 lines
13 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
/**
* 访客日志与 IP 名单数据访问
*/
require_once dirname(__DIR__) . '/DbHelper.php';
require_once dirname(__DIR__) . '/CloakHttpHelpers.php';
require_once __DIR__ . '/VisitorApiAudit.php';
require_once __DIR__ . '/VisitorLogVtimes.php';
if (!function_exists('cloak_session_mark_real_visitor')) {
/**
* 后台「真实访客」:写入完整判定缓存,访问落地链接时走 Session 快速路径并直达真实页
*/
function cloak_session_mark_real_visitor()
{
$gcuid = !empty($_COOKIE['gfuid']) ? (string) $_COOKIE['gfuid'] : '132456789';
$_SESSION['check_result'] = 'true';
$_SESSION['visit_to_1'] = '1';
$_SESSION['visit_to_2'] = '2';
$_SESSION['visit_to_3'] = '3';
$_SESSION['gcuid'] = $gcuid;
$_SESSION['gcu_ip'] = $_SERVER['REMOTE_ADDR'] ?? '';
if (empty($_SESSION['gcu_country']) && defined('SHOW_SITE_COUNTRY')) {
$_SESSION['gcu_country'] = SHOW_SITE_COUNTRY;
}
setCrossDomainCookie('gfuid', $gcuid, time() + 3600 * 24);
}
}
if (!function_exists('cloak_session_clear_real_visitor')) {
function cloak_session_clear_real_visitor()
{
unset(
$_SESSION['check_result'],
$_SESSION['visit_to_1'],
$_SESSION['visit_to_2'],
$_SESSION['visit_to_3'],
$_SESSION['gcuid'],
$_SESSION['gcu_ip'],
$_SESSION['gcu_country'],
$_SESSION['gcu_Client'],
$_SESSION['gcu_Browser'],
$_SESSION['gcu_referer']
);
if (class_exists('RiskSecondaryCache', false)) {
RiskSecondaryCache::clear();
}
setCrossDomainCookie('gfuid', '', time() - 3600);
}
}
if (!function_exists('ip_group_list_addresses')) {
function ip_group_list_addresses($groupId)
{
$groupId = (int) $groupId;
if ($groupId <= 0) {
return [];
}
$conn = @new mysqli('localhost', DB_USERNAME, DB_PASSWORD, DB_NAME);
if ($conn->connect_error) {
return [];
}
$out = [];
$sql = 'SELECT ip_address FROM ip_list WHERE group_id = ' . $groupId;
if ($res = $conn->query($sql)) {
while ($row = $res->fetch_assoc()) {
$out[] = $row['ip_address'];
}
$res->free();
}
$conn->close();
return $out;
}
}
if (!function_exists('ip_visitor_matches_list_entry')) {
function ip_visitor_matches_list_entry($visitorIp, $entry)
{
$entry = trim($entry);
if ($entry === '') {
return false;
}
if ($visitorIp === $entry) {
return true;
}
if (mb_substr($entry, -1) === '*') {
return strpos($visitorIp, rtrim($entry, '*')) === 0;
}
return false;
}
}
if (!function_exists('ip_visitor_in_blacklist_entries')) {
function ip_visitor_in_blacklist_entries($visitorIp, array $entries)
{
foreach ($entries as $buffer) {
if (ip_visitor_matches_list_entry($visitorIp, $buffer)) {
return true;
}
}
return false;
}
}
if (!function_exists('cloak_visitor_log_request_meta')) {
function cloak_visitor_log_request_meta()
{
return [
'user_agent' => get_SERVER_value('HTTP_USER_AGENT'),
'http_referer' => get_SERVER_value('HTTP_REFERER'),
'accept_language_raw' => get_SERVER_value('HTTP_ACCEPT_LANGUAGE'),
];
}
}
if (!function_exists('cloak_visitor_log_enrich')) {
function cloak_visitor_log_enrich(array $logs)
{
$meta = cloak_visitor_log_request_meta();
foreach ($meta as $key => $value) {
if (!array_key_exists($key, $logs) || $logs[$key] === null || $logs[$key] === '') {
$logs[$key] = $value;
}
}
if (empty($logs['judge_timing']) && !empty($GLOBALS['__cloak_judge_timing'])) {
$logs['judge_timing'] = $GLOBALS['__cloak_judge_timing'];
}
return VisitorApiAudit::mergeIntoLogs($logs);
}
}
if (!function_exists('cloak_visitor_log_async_enabled')) {
function cloak_visitor_log_async_enabled()
{
return defined('VISITOR_LOG_ASYNC') && strtoupper(VISITOR_LOG_ASYNC) === 'ON';
}
}
if (!function_exists('cloak_visitor_log_register_shutdown_drain')) {
function cloak_visitor_log_register_shutdown_drain()
{
static $registered = false;
if ($registered || !cloak_visitor_log_async_enabled()) {
return;
}
$registered = true;
register_shutdown_function(static function () {
if (function_exists('fastcgi_finish_request')) {
@fastcgi_finish_request();
}
VisitorLogQueue::drain(5);
});
}
}
if (!function_exists('cloak_write_log_db_sync')) {
function cloak_write_log_db_sync($logs)
{
return VisitorLogWorker::insertFull($logs);
}
}
if (!function_exists('cloak_write_log_db')) {
function cloak_write_log_db($logs)
{
$logs = cloak_visitor_log_enrich($logs);
if (!empty($GLOBALS['__cloak_force_sync_log'])) {
if (($logs['result'] ?? '') === 'wait') {
$logId = VisitorLogWorker::insertMinimal($logs);
if ($logId !== null) {
VisitorLogWorker::enrich($logId, $logs);
}
return $logId;
}
return cloak_write_log_db_sync($logs);
}
if (defined('WRITE_LOG') && WRITE_LOG == '1') {
$my_url = $_SERVER['PHP_SELF'] ?? '';
$my_file_name = substr($my_url, strrpos($my_url, '/') + 1);
$config_name = str_replace('.php', '', $my_file_name);
$fp = fopen(dirname(__DIR__, 2) . '/jump.txt', 'a+');
fwrite($fp, date('Y-m-d H:i:s') . ' | 写入数据库 ' . ' | ' . ($_SESSION['check_result'] ?? '') . ' | ' . $config_name . ' | async=' . (cloak_visitor_log_async_enabled() ? '1' : '0') . "\n");
fclose($fp);
}
$result = isset($logs['result']) ? (string) $logs['result'] : '';
// 二次风控 wait:同步最小 INSERT 获取 log_idTEXT 字段异步 enrich
if ($result === 'wait') {
$logId = VisitorLogWorker::insertMinimal($logs);
if ($logId === null) {
return cloak_write_log_db_sync($logs);
}
if (cloak_visitor_log_async_enabled()) {
VisitorLogQueue::push([
'type' => 'enrich',
'log_id' => $logId,
'logs' => $logs,
]);
} else {
VisitorLogWorker::enrich($logId, $logs);
}
return $logId;
}
if (!cloak_visitor_log_async_enabled()) {
$conn = new mysqli('localhost', DB_USERNAME, DB_PASSWORD, DB_NAME);
if ($conn->connect_error) {
$error = 'Connection failed: ' . $conn->connect_error;
$handle = fopen(dirname(__DIR__, 2) . '/err.txt', 'a+');
fwrite($handle, date('Y-m-d H:i:s') . ' | ' . $error . "\n");
fclose($handle);
return null;
}
VisitorLogSchema::ensureColumns($conn);
VisitorLogSchema::ensureIndexes($conn);
$logs = VisitorLogVtimes::mergeIntoLogs($logs, $conn);
$data = [];
foreach ($logs as $key => $value) {
$data[$key] = cloak_db_escape($conn, $value);
}
$d = static function ($key) use ($data, $conn) {
return array_key_exists($key, $data) ? $data[$key] : cloak_db_escape($conn, '');
};
$simCols = '';
$simVals = '';
if (!empty($data['is_simulation']) || array_key_exists('sim_source_log_id', $data)) {
$simCols = ', `is_simulation`, `sim_source_log_id`';
$isSim = (int) ($data['is_simulation'] ?? 0);
if (!empty($data['sim_source_log_id'])) {
$simVals = ", '{$isSim}', '" . (int) $data['sim_source_log_id'] . "'";
} else {
$simVals = ", '{$isSim}', NULL";
}
}
$sql = "INSERT INTO `visitor_logs`(`campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `referer`, `vtimes`, `client`, `browser`, `page`, `language`, `user_agent`, `http_referer`, `accept_language_raw`, `judge_timing`, `fp_url`, `device`, `api_by_request`, `api_by_response`, `api_risk_request`, `api_risk_response`{$simCols}) VALUES ('"
. $d('campagin_id') . "','"
. $d('visit_md5_code') . "','"
. $d('site_name') . "','"
. date('Y-m-d H:i:s') . "','"
. $d('customers_ip') . "','"
. $d('country') . "','"
. $d('result') . "','"
. $d('reason') . "','"
. $d('v_referer') . "','"
. (int) ($data['vtimes'] ?? 1) . "','"
. $d('Client') . "','"
. $d('v_Browser') . "','"
. $d('v_PageURL') . "','"
. $d('accept_language') . "','"
. $d('user_agent') . "','"
. $d('http_referer') . "','"
. $d('accept_language_raw') . "','"
. $d('judge_timing') . "','"
. $d('fp_url') . "','"
. $d('device') . "','"
. $d('api_by_request') . "','"
. $d('api_by_response') . "','"
. $d('api_risk_request') . "','"
. $d('api_risk_response') . "'"
. $simVals . ')';
if ($conn->query($sql) === true) {
$last_id = $conn->insert_id;
$conn->close();
return $last_id;
}
$handle = fopen(dirname(__DIR__, 2) . '/err.txt', 'a+');
fwrite($handle, date('Y-m-d H:i:s') . ' | ' . 'Error: ' . $sql . '<br>' . $conn->error . "\n");
fclose($handle);
$conn->close();
return null;
}
if (!VisitorLogQueue::push(['type' => 'insert_full', 'logs' => $logs])) {
return cloak_write_log_db_sync($logs);
}
cloak_visitor_log_register_shutdown_drain();
return null;
}
}
if (!function_exists('write_log_db')) {
function write_log_db($logs)
{
return cloak_write_log_db($logs);
}
}
if (!function_exists('cloak_howmanytimesbyip')) {
function cloak_howmanytimesbyip($ip)
{
$row = ['total' => 0];
$conn = new mysqli('localhost', DB_USERNAME, DB_PASSWORD, DB_NAME);
if ($conn->connect_error) {
$handle = fopen(dirname(__DIR__, 2) . '/err.txt', 'a+');
fwrite($handle, date('Y-m-d H:i:s') . ' | Connection failed: ' . $conn->connect_error . "\n");
fclose($handle);
return 0;
}
$ipEsc = cloak_db_escape($conn, $ip);
$sql = "SELECT count(*) as `total` FROM `visitor_logs` WHERE `IP`='" . $ipEsc . "'";
if ($conn->query($sql) == true) {
$result = $conn->query($sql);
$row = $result->fetch_array();
$conn->close();
} else {
$handle = fopen(dirname(__DIR__, 2) . '/err.txt', 'a+');
fwrite($handle, date('Y-m-d H:i:s') . ' | Error: ' . $sql . '<br>' . $conn->error . "\n");
fclose($handle);
$conn->close();
return 0;
}
return $row['total'];
}
}
if (!function_exists('howmanytimesbyip')) {
function howmanytimesbyip($ip)
{
return cloak_howmanytimesbyip($ip);
}
}
if (!function_exists('cloak_write_black_list')) {
function cloak_write_black_list($ip)
{
if (!defined('BLACKLIST_GROUP_ID') || (int) BLACKLIST_GROUP_ID <= 0) {
return;
}
$gid = (int) BLACKLIST_GROUP_ID;
$conn = @new mysqli('localhost', DB_USERNAME, DB_PASSWORD, DB_NAME);
if ($conn->connect_error) {
return;
}
$stmt = $conn->prepare('INSERT IGNORE INTO ip_list (group_id, ip_address) VALUES (?, ?)');
if ($stmt) {
$stmt->bind_param('is', $gid, $ip);
$stmt->execute();
$stmt->close();
}
$conn->close();
}
}
if (!function_exists('write_black_list')) {
function write_black_list($ip)
{
cloak_write_black_list($ip);
}
}
if (!function_exists('browser_headers')) {
function browser_headers()
{
$headers = [];
foreach ($_SERVER as $name => $value) {
if (preg_match('/^HTTP_/', $name)) {
$name = strtolower(strtr(substr($name, 5), '_', '-'));
$headers[$name] = $value;
}
}
return $headers;
}
}
if (!function_exists('accept_lang_zh')) {
function accept_lang_zh()
{
if (empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
return false;
}
$lang = substr((string) $_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 4);
if (preg_match('/zh-c/i', $lang) or preg_match('/zh/i', $lang)) {
return true;
}
return false;
}
}
if (!function_exists('is_https')) {
function is_https()
{
return cloak_request_is_https();
}
}