Files

136 lines
4.9 KiB
PHP
Raw Permalink Normal View History

2026-06-15 22:42:59 +08:00
<?php
/**
* 访客日志列表查询与行格式化(datalist / sdatalist 共用,避免重复重逻辑)
*/
class VisitorLogListHelper
{
/**
* @param mysqli $conn
* @param array $get
*/
public static function buildWhere($conn, array $get)
{
$where = '1';
$where .= cloak_visitor_log_apply_result_filter($conn, $get['result'] ?? '');
$map = [];
if (!empty($get['visit_date'])) {
$day = trim((string) $get['visit_date']);
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $day)) {
$dayEsc = cloak_db_escape($conn, $day);
$map[] = "`visit_date` >= '{$dayEsc} 00:00:00' AND `visit_date` < DATE_ADD('{$dayEsc} 00:00:00', INTERVAL 1 DAY)";
}
}
if (!empty($get['country'])) {
$map[] = "country LIKE '" . cloak_db_escape($conn, $get['country']) . "'";
}
if (!empty($get['IP'])) {
$map[] = "IP LIKE '" . cloak_db_escape($conn, $get['IP']) . "'";
}
if (!empty($get['domain'])) {
$map[] = "domain LIKE '%" . cloak_db_escape($conn, $get['domain']) . "%'";
}
if (!empty($get['spage'])) {
$map[] = "page LIKE '%" . cloak_db_escape($conn, $get['spage']) . "%'";
}
if ($map !== []) {
$where .= ' AND ' . implode(' AND ', $map);
}
return $where;
}
/**
* 列表轻量 SELECT(不拉取 fp_hdata / api_* 等大 TEXT
*
* @param bool $withSimulation
*/
public static function listSelectSql($where, $startPosition, $recordsPerPage, $withSimulation = true)
{
$cols = '`id`, `campagin_id`, `visit_md5_code`, `domain`, `visit_date`, `IP`, `country`, `result`, `reason`, `fp_url`, `referer`, `vtimes`, `client`, `browser`, `page`, `language`, `device`, `judge_timing`, '
. '(CASE WHEN `fp_hdata` IS NOT NULL AND `fp_hdata` <> \'\' THEN 1 ELSE 0 END) AS `has_fp_hdata`, '
. '(CASE WHEN `api_by_request` IS NOT NULL AND `api_by_request` <> \'\' THEN 1 ELSE 0 END) AS `has_api_by_request`, '
. '(CASE WHEN `api_by_response` IS NOT NULL AND `api_by_response` <> \'\' THEN 1 ELSE 0 END) AS `has_api_by_response`, '
. '(CASE WHEN `api_risk_request` IS NOT NULL AND `api_risk_request` <> \'\' THEN 1 ELSE 0 END) AS `has_api_risk_request`, '
. '(CASE WHEN `api_risk_response` IS NOT NULL AND `api_risk_response` <> \'\' THEN 1 ELSE 0 END) AS `has_api_risk_response`, '
. '`add_time`';
if ($withSimulation) {
$cols .= ', `is_simulation`, `sim_source_log_id`';
}
$startPosition = (int) $startPosition;
$recordsPerPage = (int) $recordsPerPage;
return "SELECT {$cols} FROM `visitor_logs` WHERE {$where} ORDER BY `id` DESC LIMIT {$startPosition}, {$recordsPerPage}";
}
/**
* @param array $row
* @param array $countries
* @param array $reasons
*/
public static function formatListRow(array $row, array $countries, array $reasons)
{
if (!empty($row['country'])) {
$row['country'] = $countries[$row['country']] ?? '无';
} else {
$row['country'] = '无';
}
if (isset($reasons[$row['reason']])) {
$row['reason'] = $reasons[$row['reason']];
}
if (($row['result'] ?? '') === 'wait') {
$row['result'] = '检测中';
}
$row['judge_timing_text'] = cloak_visitor_log_format_timing($row['judge_timing'] ?? '');
if (!empty($row['has_fp_hdata'])) {
$row['fp_hdata_text'] = '有指纹数据';
} else {
$row['fp_hdata_text'] = '';
}
$row['api_by_request_text'] = self::auditPlaceholder($row, 'has_api_by_request');
$row['api_by_response_text'] = self::auditPlaceholder($row, 'has_api_by_response');
$row['api_risk_request_text'] = self::auditPlaceholder($row, 'has_api_risk_request');
$row['api_risk_response_text'] = self::auditPlaceholder($row, 'has_api_risk_response');
unset(
$row['has_fp_hdata'],
$row['has_api_by_request'],
$row['has_api_by_response'],
$row['has_api_risk_request'],
$row['has_api_risk_response']
);
return $row;
}
/**
* @param array $row
* @param string $flagKey
*/
private static function auditPlaceholder(array $row, $flagKey)
{
return !empty($row[$flagKey]) ? '__LAZY__' : '-';
}
/**
* @param mysqli $conn
* @param string $where
*/
public static function countWhere($conn, $where)
{
$sql = "SELECT COUNT(*) AS `total` FROM `visitor_logs` WHERE {$where}";
$res = $conn->query($sql);
if (!$res) {
return 0;
}
$row = $res->fetch_assoc();
$res->free();
return (int) ($row['total'] ?? 0);
}
}