2026-06-14 14:00:24 +08:00
|
|
|
<?php
|
|
|
|
|
/**
|
|
|
|
|
* visitor_logs 表结构升级(新增请求头与判定时长字段)
|
|
|
|
|
*/
|
|
|
|
|
class VisitorLogSchema
|
|
|
|
|
{
|
|
|
|
|
/** @var bool */
|
|
|
|
|
private static $ensured = false;
|
|
|
|
|
|
|
|
|
|
/** @var bool */
|
|
|
|
|
private static $indexesEnsured = false;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param mysqli $conn
|
|
|
|
|
*/
|
|
|
|
|
public static function ensureColumns($conn)
|
|
|
|
|
{
|
|
|
|
|
if (self::$ensured) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$columns = [
|
|
|
|
|
'user_agent' => "ALTER TABLE `visitor_logs` ADD COLUMN `user_agent` TEXT NULL COMMENT 'User-Agent 完整值' AFTER `language`",
|
|
|
|
|
'http_referer' => "ALTER TABLE `visitor_logs` ADD COLUMN `http_referer` TEXT NULL COMMENT 'HTTP Referer 完整值' AFTER `user_agent`",
|
|
|
|
|
'accept_language_raw' => "ALTER TABLE `visitor_logs` ADD COLUMN `accept_language_raw` TEXT NULL COMMENT 'Accept-Language 完整值' AFTER `http_referer`",
|
|
|
|
|
'judge_timing' => "ALTER TABLE `visitor_logs` ADD COLUMN `judge_timing` TEXT NULL COMMENT '判定用时 JSON' AFTER `accept_language_raw`",
|
2026-06-14 18:30:06 +08:00
|
|
|
'fp_hdata' => "ALTER TABLE `visitor_logs` ADD COLUMN `fp_hdata` TEXT NULL COMMENT '指纹 hdata 解码 JSON' AFTER `judge_timing`",
|
2026-06-14 14:00:24 +08:00
|
|
|
];
|
|
|
|
|
foreach ($columns as $name => $ddl) {
|
|
|
|
|
if (!self::columnExists($conn, 'visitor_logs', $name)) {
|
|
|
|
|
@$conn->query($ddl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
self::$ensured = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param mysqli $conn
|
|
|
|
|
*/
|
|
|
|
|
public static function ensureIndexes($conn)
|
|
|
|
|
{
|
|
|
|
|
if (self::$indexesEnsured) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$indexes = [
|
|
|
|
|
'idx_visit_date' => 'ALTER TABLE `visitor_logs` ADD INDEX `idx_visit_date` (`visit_date`)',
|
|
|
|
|
'idx_result' => 'ALTER TABLE `visitor_logs` ADD INDEX `idx_result` (`result`)',
|
|
|
|
|
'idx_domain_date' => 'ALTER TABLE `visitor_logs` ADD INDEX `idx_domain_date` (`domain`, `visit_date`)',
|
|
|
|
|
'idx_country' => 'ALTER TABLE `visitor_logs` ADD INDEX `idx_country` (`country`)',
|
|
|
|
|
];
|
|
|
|
|
foreach ($indexes as $name => $ddl) {
|
|
|
|
|
if (!self::indexExists($conn, 'visitor_logs', $name)) {
|
|
|
|
|
@$conn->query($ddl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
self::$indexesEnsured = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param mysqli $conn
|
|
|
|
|
* @param string $table
|
|
|
|
|
* @param string $indexName
|
|
|
|
|
*/
|
|
|
|
|
private static function indexExists($conn, $table, $indexName)
|
|
|
|
|
{
|
|
|
|
|
$tableEsc = cloak_db_escape($conn, $table);
|
|
|
|
|
$indexEsc = cloak_db_escape($conn, $indexName);
|
|
|
|
|
$sql = "SHOW INDEX FROM `{$tableEsc}` WHERE Key_name = '{$indexEsc}'";
|
|
|
|
|
if ($res = $conn->query($sql)) {
|
|
|
|
|
$exists = $res->num_rows > 0;
|
|
|
|
|
$res->free();
|
|
|
|
|
return $exists;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param mysqli $conn
|
|
|
|
|
* @param string $table
|
|
|
|
|
* @param string $column
|
|
|
|
|
*/
|
|
|
|
|
private static function columnExists($conn, $table, $column)
|
|
|
|
|
{
|
|
|
|
|
$tableEsc = cloak_db_escape($conn, $table);
|
|
|
|
|
$columnEsc = cloak_db_escape($conn, $column);
|
|
|
|
|
$sql = "SHOW COLUMNS FROM `{$tableEsc}` LIKE '{$columnEsc}'";
|
|
|
|
|
if ($res = $conn->query($sql)) {
|
|
|
|
|
$exists = $res->num_rows > 0;
|
|
|
|
|
$res->free();
|
|
|
|
|
return $exists;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|