478 lines
17 KiB
PHP
Executable File
478 lines
17 KiB
PHP
Executable File
<?php
|
|
require_once("cong.php");
|
|
session_start();
|
|
|
|
if(empty($_SESSION['password']) || $_SESSION['password'] != LOGIN_PASSWORD) {
|
|
unset($_SESSION['password']);
|
|
unset($_SESSION['check_result']);
|
|
echo("<script language=javascript>alert('密码错误!');window.location='ip_check_edit.php'; </script>");
|
|
//die("输入的密码不正确,请重新输入。");
|
|
}
|
|
|
|
?>
|
|
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>访问判断日志</title>
|
|
<meta name="renderer" content="webkit">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<link href="//cdn.staticfile.org/layui/2.9.2/css/layui.css" rel="stylesheet">
|
|
<style>
|
|
:root {
|
|
--log-primary: #16baaa;
|
|
--log-primary-dark: #0e8d81;
|
|
--log-bg: #f0f2f5;
|
|
--log-card: #ffffff;
|
|
--log-border: #e8ecf1;
|
|
--log-header-bg: #f4f7fb;
|
|
--log-text: #2c3e50;
|
|
--log-muted: #8c98a4;
|
|
}
|
|
* { box-sizing: border-box; }
|
|
body {
|
|
margin: 0;
|
|
background: var(--log-bg);
|
|
color: var(--log-text);
|
|
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
|
|
}
|
|
.log-page {
|
|
max-width: 1680px;
|
|
margin: 0 auto;
|
|
padding: 24px 28px 40px;
|
|
}
|
|
.log-page-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-bottom: 20px;
|
|
flex-wrap: wrap;
|
|
gap: 12px;
|
|
}
|
|
.log-page-header h1 {
|
|
margin: 0;
|
|
font-size: 1.35rem;
|
|
font-weight: 600;
|
|
color: var(--log-text);
|
|
}
|
|
.log-page-header p {
|
|
margin: 4px 0 0;
|
|
font-size: .85rem;
|
|
color: var(--log-muted);
|
|
}
|
|
.log-card {
|
|
background: var(--log-card);
|
|
border: 1px solid var(--log-border);
|
|
border-radius: 10px;
|
|
box-shadow: 0 2px 12px rgba(15, 23, 42, .04);
|
|
margin-bottom: 16px;
|
|
overflow: hidden;
|
|
}
|
|
.log-card-body { padding: 18px 20px; }
|
|
.log-filter-grid .layui-col-md3 { margin-bottom: 12px; }
|
|
.log-filter-grid .layui-input,
|
|
.log-filter-grid .layui-select-title input {
|
|
border-radius: 6px;
|
|
border-color: var(--log-border);
|
|
}
|
|
.log-actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 14px 20px;
|
|
border-top: 1px solid var(--log-border);
|
|
background: #fafbfc;
|
|
}
|
|
.log-actions .layui-btn { border-radius: 6px; }
|
|
.log-actions .layui-btn-primary { background: #fff; }
|
|
.log-count {
|
|
margin-left: auto;
|
|
font-size: .88rem;
|
|
color: var(--log-muted);
|
|
}
|
|
.log-count strong {
|
|
color: var(--log-primary-dark);
|
|
font-size: 1rem;
|
|
margin: 0 4px;
|
|
}
|
|
#btn-clear { background: #e74c3c !important; border-color: #e74c3c !important; }
|
|
.log-table-wrap { padding: 0; }
|
|
.log-table-wrap .layui-table-view {
|
|
border: none;
|
|
border-radius: 0 0 10px 10px;
|
|
margin: 0;
|
|
}
|
|
/* Sticky header */
|
|
.log-table-wrap .layui-table-header {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 20;
|
|
border-radius: 0;
|
|
}
|
|
.log-table-wrap .layui-table-header .layui-table {
|
|
background: linear-gradient(180deg, #eef3f9 0%, #e4ebf5 100%);
|
|
}
|
|
.log-table-wrap .layui-table-header th {
|
|
color: #3d5167 !important;
|
|
font-weight: 600 !important;
|
|
font-size: 12.5px;
|
|
border-color: #d8e0ea !important;
|
|
padding: 11px 10px !important;
|
|
}
|
|
/* Zebra + hover */
|
|
.log-table-wrap .layui-table-body tr:nth-child(even) td {
|
|
background-color: #fafbfc;
|
|
}
|
|
.log-table-wrap .layui-table-body tr:hover td {
|
|
background-color: #eef6ff !important;
|
|
}
|
|
.log-table-wrap .layui-table-body td {
|
|
border-color: #eef1f5 !important;
|
|
padding: 9px 10px !important;
|
|
font-size: 12.5px;
|
|
line-height: 1.45;
|
|
transition: background-color .15s ease;
|
|
}
|
|
.log-table-wrap .layui-table-page {
|
|
border-top: 1px solid var(--log-border);
|
|
padding: 12px 16px;
|
|
background: #fafbfc;
|
|
}
|
|
/* Badges */
|
|
.cloak-badge {
|
|
display: inline-block;
|
|
padding: 2px 9px;
|
|
border-radius: 999px;
|
|
font-size: 11.5px;
|
|
font-weight: 600;
|
|
line-height: 1.5;
|
|
white-space: nowrap;
|
|
letter-spacing: .02em;
|
|
}
|
|
.badge-success { background: #d4edda; color: #155724; }
|
|
.badge-error { background: #f8d7da; color: #721c24; }
|
|
.badge-warning { background: #fff3cd; color: #856404; }
|
|
.badge-info { background: #d1ecf1; color: #0c5460; }
|
|
.badge-muted { background: #e9ecef; color: #495057; }
|
|
.reason-badge {
|
|
max-width: 100%;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
vertical-align: middle;
|
|
}
|
|
/* Truncation + mono timestamp */
|
|
.cell-ellipsis {
|
|
display: block;
|
|
max-width: 100%;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
cursor: default;
|
|
}
|
|
.cell-mono {
|
|
font-family: 'SF Mono', 'Consolas', 'Monaco', monospace;
|
|
font-size: 12px;
|
|
color: #4a5568;
|
|
letter-spacing: -.02em;
|
|
}
|
|
.cell-ip { font-family: 'SF Mono', 'Consolas', monospace; font-size: 12px; }
|
|
.text-muted { color: #adb5bd; }
|
|
@media (max-width: 768px) {
|
|
.log-page { padding: 16px 12px 32px; }
|
|
.log-count { margin-left: 0; width: 100%; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="log-page">
|
|
<div class="log-page-header">
|
|
<div>
|
|
<h1>访问判断日志</h1>
|
|
<p>访客判定记录 · 支持筛选、导出与分页浏览</p>
|
|
</div>
|
|
<div class="log-nav" style="display:flex;gap:8px;">
|
|
<a href="table.php" style="display:inline-block;padding:6px 14px;border-radius:6px;font-size:.85rem;text-decoration:none;border:1px solid #e8ecf1;background:#16baaa;color:#fff;">访问日志</a>
|
|
<a href="log_analytics.php" style="display:inline-block;padding:6px 14px;border-radius:6px;font-size:.85rem;text-decoration:none;border:1px solid #e8ecf1;background:#fff;color:#2c3e50;">数据分析</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="log-card">
|
|
<div class="log-card-body">
|
|
<form class="layui-form layui-row layui-col-space16 log-filter-grid">
|
|
<div class="layui-col-md3">
|
|
<div class="layui-input-wrap">
|
|
<div class="layui-input-prefix">
|
|
<i class="layui-icon layui-icon-username"></i>
|
|
</div>
|
|
<input type="text" name="domain" value="" placeholder="域名" class="layui-input" lay-affix="clear">
|
|
</div>
|
|
</div>
|
|
<div class="layui-col-md3">
|
|
<div class="layui-input-wrap">
|
|
<input type="text" name="spage" value="" placeholder="访问页面,可输入配置名称搜索" class="layui-input" lay-affix="clear">
|
|
</div>
|
|
</div>
|
|
<div class="layui-col-md3">
|
|
<div class="layui-input-wrap">
|
|
<select name="result">
|
|
<option value="">全部(不含检测中)</option>
|
|
<option value="true">TRUE(通过访问)</option>
|
|
<option value="false">FALSE(禁止访问)</option>
|
|
<option value="wait">检测中</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="layui-col-md3">
|
|
<div class="layui-input-wrap">
|
|
<input type="text" name="country" placeholder="国家" lay-affix="clear" class="layui-input">
|
|
</div>
|
|
</div>
|
|
<div class="layui-col-md3">
|
|
<div class="layui-input-wrap">
|
|
<input type="text" name="IP" placeholder="IP" lay-affix="clear" class="layui-input">
|
|
</div>
|
|
</div>
|
|
<div class="layui-col-md3">
|
|
<div class="layui-input-wrap">
|
|
<div class="layui-input-prefix">
|
|
<i class="layui-icon layui-icon-date"></i>
|
|
</div>
|
|
<input type="text" name="visit_date" readonly placeholder="访问日期" class="layui-input demo-table-search-date">
|
|
</div>
|
|
</div>
|
|
<div class="layui-btn-container layui-col-xs12">
|
|
<a class="layui-btn" lay-submit href="javascript:void(0);" id="export" target="_blank">导出</a>
|
|
<button class="layui-btn" lay-submit lay-filter="demo-table-search">搜索</button>
|
|
<button type="reset" class="layui-btn layui-btn-primary">清除条件</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="log-actions">
|
|
<button class="layui-btn layui-btn-sm" id="btn-refresh" onclick="resetTable()" lay-event="footerDemoBtn1">刷新</button>
|
|
<button class="layui-btn layui-btn-sm layui-btn-normal" id="btn-show-more" type="button">显示更多</button>
|
|
<button class="layui-btn layui-btn-sm btn-danger" id="btn-clear" lay-on="confirm" lay-event="footerDemoBtn2">清空数据库</button>
|
|
<span class="log-count">当前查询数量:<strong id="total_nums">—</strong></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="log-card log-table-wrap">
|
|
<div id="demo-laypage-all"></div>
|
|
<table class="layui-hide" id="ID-table-demo-search" lay-filter="test"></table>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="/dist/layui.js"></script>
|
|
<script src="/dist/jquery.min.js"></script>
|
|
<script>
|
|
|
|
layui.use(function(){
|
|
var table = layui.table;
|
|
var form = layui.form;
|
|
var laydate = layui.laydate;
|
|
var showMoreCols = false;
|
|
|
|
function escapeHtml(s) {
|
|
if (s == null || s === '') return '';
|
|
return String(s)
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"');
|
|
}
|
|
|
|
function cellEllipsis(value, maxLen) {
|
|
var text = value == null ? '' : String(value);
|
|
if (!text) return '<span class="text-muted">—</span>';
|
|
var esc = escapeHtml(text);
|
|
var display = text.length > maxLen ? escapeHtml(text.slice(0, maxLen)) + '…' : esc;
|
|
return '<span class="cell-ellipsis" title="' + esc + '">' + display + '</span>';
|
|
}
|
|
|
|
function badgeResult(val) {
|
|
var raw = val == null ? '' : String(val);
|
|
var v = raw.toLowerCase();
|
|
if (v === 'true' || v === '1') {
|
|
return '<span class="cloak-badge badge-success">TRUE</span>';
|
|
}
|
|
if (v === 'false' || v === '0') {
|
|
return '<span class="cloak-badge badge-error">FALSE</span>';
|
|
}
|
|
if (v === 'wait' || raw.indexOf('检测') !== -1) {
|
|
return '<span class="cloak-badge badge-info">检测中</span>';
|
|
}
|
|
return '<span class="cloak-badge badge-muted">' + escapeHtml(raw) + '</span>';
|
|
}
|
|
|
|
function badgeReason(reason) {
|
|
if (reason == null || reason === '') {
|
|
return '<span class="text-muted">—</span>';
|
|
}
|
|
var text = String(reason);
|
|
var cls = 'badge-info';
|
|
if (text.indexOf('未确定流量来源') !== -1) {
|
|
cls = 'badge-warning';
|
|
} else if (/过滤|黑名单|无效|代理|VPN|禁止|欺骗|无来源/i.test(text)) {
|
|
cls = 'badge-error';
|
|
} else if (/白名单|允许|通过/i.test(text)) {
|
|
cls = 'badge-success';
|
|
}
|
|
var esc = escapeHtml(text);
|
|
var short = text.length > 26 ? escapeHtml(text.slice(0, 26)) + '…' : esc;
|
|
return '<span class="cloak-badge ' + cls + ' reason-badge" title="' + esc + '">' + short + '</span>';
|
|
}
|
|
|
|
function buildCols(showMore) {
|
|
return [[
|
|
{field:'id', title: 'ID', width:56, fixed: true},
|
|
{field:'domain', title: '域名', width:120, templet: function(d){ return cellEllipsis(d.domain, 18); }},
|
|
{field:'visit_date', title: '访问日期', width:130, templet: function(d){
|
|
return '<span class="cell-mono" title="' + escapeHtml(d.visit_date) + '">' + escapeHtml(d.visit_date) + '</span>';
|
|
}},
|
|
{field:'country', title: '国家', width:100, templet: function(d){ return cellEllipsis(d.country, 12); }},
|
|
{field:'result', title: '是否正常', width:88, templet: function(d){ return badgeResult(d.result); }},
|
|
{field:'reason', title: '理由', width:140, templet: function(d){ return badgeReason(d.reason); }},
|
|
{field:'judge_timing_text', title: '判断用时', width:240, templet: function(d){ return cellEllipsis(d.judge_timing_text, 36); }},
|
|
{field:'vtimes', title: '第几次访问', width:96},
|
|
{field:'fp_url', title: '跳转至', width:180, templet: function(d){ return cellEllipsis(d.fp_url, 28); }},
|
|
{field:'device', title: '访问设备', width:200, templet: function(d){ return cellEllipsis(d.device, 32); }},
|
|
{field:'referer', title: '来源', width:200, templet: function(d){ return cellEllipsis(d.referer, 32); }},
|
|
{field:'IP', title: 'IP(支持IPV6)', width:130, templet: function(d){
|
|
return '<span class="cell-ip" title="' + escapeHtml(d.IP) + '">' + escapeHtml(d.IP) + '</span>';
|
|
}},
|
|
{field:'client', title: '客户端', width:80, templet: function(d){ return cellEllipsis(d.client, 10); }},
|
|
{field:'language', title: '语言', width:80, templet: function(d){ return cellEllipsis(d.language, 10); }},
|
|
{field:'browser', title: '浏览器', width:88, templet: function(d){ return cellEllipsis(d.browser, 10); }},
|
|
{field:'page', title: '访问页面', width:200, templet: function(d){ return cellEllipsis(d.page, 32); }},
|
|
{field:'campagin_id', title: '广告策略', width:88, templet: function(d){ return cellEllipsis(d.campagin_id, 10); }},
|
|
{field:'user_agent', title: 'User-Agent', width:320, hide: !showMore, templet: function(d){ return cellEllipsis(d.user_agent, 48); }},
|
|
{field:'http_referer', title: 'HTTP-Referer', width:260, hide: !showMore, templet: function(d){ return cellEllipsis(d.http_referer, 40); }},
|
|
{field:'accept_language_raw', title: 'Accept-Language', width:220, hide: !showMore, templet: function(d){ return cellEllipsis(d.accept_language_raw, 32); }},
|
|
]];
|
|
}
|
|
|
|
table.render({
|
|
elem: '#ID-table-demo-search',
|
|
url: 'datatable/datalist.php',
|
|
cols: buildCols(false),
|
|
page: true,
|
|
limit: 50,
|
|
height: 800,
|
|
size: "sm",
|
|
skin: "line",
|
|
even: true,
|
|
rowStyle: function(row) {
|
|
if (row.reason && row.reason.indexOf('未确定流量来源') !== -1) {
|
|
return 'color:#856404;background-color:#fff8e6;';
|
|
}
|
|
},
|
|
done: function(res, curr, count, origin){
|
|
console.log(res); // 得到当前渲染的数据
|
|
console.log(curr); // 得到当前页码
|
|
console.log(count); // 得到数据总量
|
|
console.log(origin); // 回调函数所执行的来源 --- 2.8.7+
|
|
$("#total_nums").text(count);
|
|
},
|
|
});
|
|
|
|
$('#btn-show-more').on('click', function() {
|
|
showMoreCols = !showMoreCols;
|
|
$(this).text(showMoreCols ? '收起更多' : '显示更多');
|
|
table.reload('ID-table-demo-search', { cols: buildCols(showMoreCols) });
|
|
});
|
|
|
|
// 日期
|
|
laydate.render({
|
|
elem: '.demo-table-search-date'
|
|
});
|
|
// 搜索提交
|
|
form.on('submit(demo-table-search)', function(data){
|
|
var field = data.field; // 获得表单字段
|
|
// 执行搜索重载
|
|
table.reload('ID-table-demo-search', {
|
|
page: {
|
|
curr: 1 // 重新从第 1 页开始
|
|
},
|
|
where: field // 搜索的字段
|
|
});
|
|
// layer.msg('搜索成功<br>此处为静态模拟数据,实际使用时换成真实接口即可');
|
|
return false; // 阻止默认 form 跳转
|
|
});
|
|
// table.reload('ID-table-demo-search', {
|
|
// page: {
|
|
// curr: 1 // 重新从第 1 页开始
|
|
// },
|
|
// });
|
|
var layer = layui.layer;
|
|
var util = layui.util;
|
|
util.on('lay-on', {
|
|
confirm: function(){
|
|
layer.confirm('确定清除所有日志数据?', {
|
|
btn: ['确定', '关闭'] //按钮
|
|
}, function(){
|
|
$.get("datatable/datalist.php", {clear: "true"}, function(result){
|
|
layer.msg('清除成功', {icon: 1});
|
|
window.location.reload();
|
|
});
|
|
}, function(){
|
|
|
|
});
|
|
},
|
|
});
|
|
});
|
|
|
|
// 刷新按钮
|
|
function resetTable() {
|
|
var table = layui.table;
|
|
table.reload('ID-table-demo-search', {
|
|
page: {
|
|
curr: 1 // 重新从第 1 页开始
|
|
},
|
|
});
|
|
}
|
|
|
|
$("#export").click(function() {
|
|
var visit_date = $("input[name=visit_date]").val();
|
|
var domain = $("input[name=domain]").val();
|
|
var spage = $("input[name=spage]").val();
|
|
var country = $("input[name=country]").val();
|
|
var IP = $("input[name=IP]").val();
|
|
var result = $("select[name=result]").val();
|
|
|
|
var url = 'datatable/export.php?';
|
|
var args = [];
|
|
|
|
if(visit_date) {
|
|
args.push( "visit_date=" + visit_date );
|
|
}
|
|
|
|
if(domain) {
|
|
args.push( "domain=" + domain );
|
|
}
|
|
|
|
if(spage) {
|
|
args.push( "spage=" + spage );
|
|
}
|
|
|
|
if(country) {
|
|
args.push( "country=" + country );
|
|
}
|
|
|
|
if(IP) {
|
|
args.push( "IP=" + IP );
|
|
}
|
|
|
|
if(result) {
|
|
args.push( "result=" + encodeURIComponent(result) );
|
|
}
|
|
|
|
window.location.href=url + args.join("&");
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|