493 lines
17 KiB
PHP
Executable File
493 lines
17 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* 访客日志与 IP 名单数据访问
|
|
*/
|
|
require_once dirname(__DIR__) . '/DbHelper.php';
|
|
require_once dirname(__DIR__) . '/CloakHttpHelpers.php';
|
|
require_once __DIR__ . '/VisitorApiAudit.php';
|
|
require_once __DIR__ . '/VisitorLogVtimes.php';
|
|
require_once __DIR__ . '/VisitorVisitContext.php';
|
|
require_once __DIR__ . '/RiskSecondarySession.php';
|
|
require_once __DIR__ . '/VisitorLogWorker.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 (class_exists('CloakJudgmentCache', false)) {
|
|
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
|
|
CloakJudgmentCache::storeFromByApiRisk([
|
|
'ip' => $ip,
|
|
'country' => $_SESSION['gcu_country'] ?? '',
|
|
'result' => 'true',
|
|
'reason' => '',
|
|
'fp_url' => '',
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
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'],
|
|
$_SESSION['cloak_whitelist_fast']
|
|
);
|
|
if (class_exists('RiskSecondaryCache', false)) {
|
|
RiskSecondaryCache::clear();
|
|
}
|
|
if (class_exists('CloakJudgmentCache', false)) {
|
|
CloakJudgmentCache::clear();
|
|
}
|
|
if (class_exists('RiskSecondarySession', false)) {
|
|
RiskSecondarySession::clear();
|
|
}
|
|
VisitorVisitContext::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_update_log_db')) {
|
|
/**
|
|
* 同 visit 续步 UPDATE(不新增 vtimes)。
|
|
*
|
|
* @param int $logId
|
|
* @param array $logs
|
|
* @return int|false log id on success
|
|
*/
|
|
function cloak_update_log_db($logId, array $logs, array $options = [])
|
|
{
|
|
$logId = (int) $logId;
|
|
if ($logId <= 0) {
|
|
return false;
|
|
}
|
|
if (empty($options['skip_enrich'])) {
|
|
$logs = cloak_visitor_log_enrich($logs);
|
|
}
|
|
$logs = VisitorVisitContext::normalizeLogsForDb($logs);
|
|
|
|
$ok = false;
|
|
$forceSync = !empty($GLOBALS['__cloak_force_sync_log'])
|
|
|| !cloak_visitor_log_async_enabled()
|
|
|| VisitorVisitContext::shouldFinalizeOnResult($logs['result'] ?? '');
|
|
if ($forceSync) {
|
|
$ok = VisitorLogWorker::updateFromLogs($logId, $logs);
|
|
} else {
|
|
if (VisitorLogQueue::push(['type' => 'update', 'log_id' => $logId, 'logs' => $logs])) {
|
|
cloak_visitor_log_register_shutdown_drain();
|
|
$ok = true;
|
|
} else {
|
|
$ok = VisitorLogWorker::updateFromLogs($logId, $logs);
|
|
}
|
|
}
|
|
|
|
if ($ok && VisitorVisitContext::shouldFinalizeOnResult($logs['result'] ?? '')) {
|
|
VisitorVisitContext::finalizeVisit($logs['result'] ?? '');
|
|
}
|
|
return $ok ? $logId : false;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('cloak_write_log_db_wait_sync')) {
|
|
/**
|
|
* 二次风控 wait:同步完整 INSERT(需立即 log_id,且必须带上 byApi/页面/UA 等字段)。
|
|
*
|
|
* @param array $logs 已 enrich + normalize
|
|
* @return int|null
|
|
*/
|
|
function cloak_write_log_db_wait_sync(array $logs)
|
|
{
|
|
$logId = VisitorLogWorker::insertFull($logs);
|
|
if ($logId === null) {
|
|
$logId = cloak_write_log_db_sync($logs);
|
|
}
|
|
return $logId;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('cloak_write_log_db_insert')) {
|
|
/**
|
|
* @param array $logs
|
|
* @return int|null
|
|
*/
|
|
function cloak_write_log_db_insert(array $logs)
|
|
{
|
|
$result = isset($logs['result']) ? (string) $logs['result'] : '';
|
|
|
|
if ($result === 'wait') {
|
|
return cloak_write_log_db_wait_sync($logs);
|
|
}
|
|
|
|
if (!empty($GLOBALS['__cloak_force_sync_log'])) {
|
|
return cloak_write_log_db_sync($logs);
|
|
}
|
|
|
|
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('cloak_write_log_db')) {
|
|
function cloak_write_log_db($logs)
|
|
{
|
|
$logs = cloak_visitor_log_enrich($logs);
|
|
$logs = VisitorVisitContext::normalizeLogsForDb($logs);
|
|
|
|
if (VisitorVisitContext::shouldPersistAsUpdate()) {
|
|
return cloak_update_log_db(VisitorVisitContext::currentLogId(), $logs);
|
|
}
|
|
|
|
VisitorVisitContext::prepareForNewInsert();
|
|
|
|
if (!empty($GLOBALS['__cloak_force_sync_log'])) {
|
|
if (($logs['result'] ?? '') === 'wait') {
|
|
$logId = cloak_write_log_db_wait_sync($logs);
|
|
if ($logId !== null) {
|
|
VisitorVisitContext::bindLogId($logId);
|
|
}
|
|
return $logId;
|
|
}
|
|
$logId = cloak_write_log_db_sync($logs);
|
|
if ($logId !== null) {
|
|
VisitorVisitContext::bindLogId($logId);
|
|
if (VisitorVisitContext::shouldFinalizeOnResult($logs['result'] ?? '')) {
|
|
VisitorVisitContext::finalizeVisit($logs['result'] ?? '');
|
|
}
|
|
}
|
|
return $logId;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
$logId = cloak_write_log_db_insert($logs);
|
|
if ($logId !== null) {
|
|
VisitorVisitContext::bindLogId($logId);
|
|
if (VisitorVisitContext::shouldFinalizeOnResult($logs['result'] ?? '')) {
|
|
VisitorVisitContext::finalizeVisit($logs['result'] ?? '');
|
|
}
|
|
}
|
|
return $logId;
|
|
}
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|