代码 Linux 网站访问日志分析脚本

2024-11-18 19:58:45 +0800 CST views 505

Linux 网站访问日志分析脚本

功能概述

该 PHP 脚本用于免入库直接分析 .log 文件,特别是 Linux 网站访问日志文件。它通过解析日志文件,统计各类数据,例如 IP 访问量、状态码分布、返回内容大小、User-Agent 信息、访问路径、访问时间等,帮助用户分析潜在的安全威胁或异常行为。

核心功能

  1. 日志文件读取与解析

    • 使用 fgetcsv 逐行读取日志文件,提取关键字段进行分析。
  2. IP 访问量排序

    • 统计每个 IP 的访问次数,分析高频访问 IP。
  3. 状态码分析

    • 统计各 IP 对不同状态码的请求次数,识别异常状态(如 404、503)。
  4. 返回内容大小分析

    • 分析每个 IP 的返回内容大小,识别可能的大文件下载行为。
  5. User-Agent 分析

    • 通过 User-Agent 信息识别爬虫、攻击行为等。
  6. 访问路径分析

    • 统计访问的路径,识别潜在的攻击路径或异常访问。
  7. 访问时间分析

    • 分析访问集中时段,帮助定位高频访问发生的具体时间。

优化后的代码

<?php
//免入库直接分析.log linux网站访问日志文件
//宝塔下LNMP 7.1开发;请linux nginx PHP5.5-7.3 使用
header("Content-type:text/html;charset=utf-8");
//ob_implicit_flush();
ini_set('memory_limit', '-1'); //-1不限制内存
set_time_limit(0); //0不限制超时时间
$lie0 = "0"; //第几-1列为IP
$lie1 = "6"; //第几-1列为状态码
$lie2 = "7"; //第几-1列为返回内容长度
$lie3 = "9"; //第几-1列为客户端UA
$lie4 = "3"; //第几-1列为时间
$lie5 = "5"; //第几-1列为访问路径
$paths = "./logs/";

/*
宝塔下LNMP 7.1开发;请linux nginx PHP5.5-7.3 使用
免入库直接分析.log linux网站访问日志文件
1. 按IP访问量排序闲时:分析各IP总访问量(便于分析高频访问用户)
2. 显示各IP访问的各反馈状态的数量(降序)用于分析
   2.1 404多则可能在破解你后台或者备份文件
   2.2 503多则可能发生过载访问...
3. 显示各IP访问的回馈页面大小(访问量降序)分析可能大文件被下载...
4. 显示各IP访问的UA信息(访问量降序),可以分析是否蜘蛛/爬虫/UA攻击等...
5. 显示各IP访问的PAGE页面(访问量降序),可以分析是否自己网站页面
   不是则破解后台/get攻击/破解访问/对高消页面的攻击...
6. 显示各IP访问的访问时段(访问量降序):分析高频访问发生时段快速查找对应日志
7. 辅助分析你页面其他维度
*/

$sty = "<style>table{border-top:2px solid #0180CF; margin:0 auto;font-size:12px;width:99%;}
table td{min-width:77px;max-width:300px;border-bottom:1px solid #a2c6d3;padding:5px 0px;word-wrap:break-word;word-break:break-all;}
table tr:nth-child(even){background: #FCFCFC;}
.tt{background:#e5f2fa;line-height:18px;FONT-SIZE:12px;font-weight:600;}
textarea,select{display:block;width;99%;}
</style>";
function readcsv($filex){
    $handle = fopen($filex, "r");
    while ($data = fgetcsv($handle,0," ")) {
    yield $data; //php 5.5+
    }
    fclose($handle);
}
function logF($arr,$fie){
 global $yms;
 $txt = "\r\n\r\n".count($arr)."种/共".array_sum($arr);
 arsort($arr); //键值降序
foreach ($arr as $ti => $tis) { 
if(is_array($tis)) $tis = join("|",$tis);
$txt .= "\r\n$tis\t$ti";
}
if (!file_exists("./$yms/")){ mkdir("./$yms/",0777,true); }
file_put_contents("./$yms/$fie", $txt, FILE_APPEND);
}
function readarr($arr){
$txt = "<h5>".count($arr)."种 /共".array_sum($arr)."</h5>";
 arsort($arr); //键值降序
foreach ($arr as $ti => $tis) { 
if(is_array($tis)) $tis = join("|",$tis);
$txt .= "<p>$ti => $tis</p>\r\n";
}
return $txt;
}
function topuaa($arr,$uax,$tims="20"){
$txts = count($arr); $txt = "<h5>$txts 种/共".array_sum($arr)."</h5>";
$iy = 0;  arsort($arr); 
foreach ($arr as $ti => $tis) { 
$gj = isgong($uax[$ti]);
$txt .= "<p>$tis => $gj => {$uax[$ti]}</p>\r\n";
$iy++; if($iy>$tims) return $txt;
}
 return "".$txt; 
}
function topupg($arr,$uax,$tims="20"){
$txts = count($arr); $txt = "<h5>$txts 种/共".array_sum($arr)."</h5>";
$iy = 0;  arsort($arr); 
foreach ($arr as $ti => $tis) { 
$txt .= "<p>$tis => {$uax[$ti]}</p>\r\n";
$iy++; if($iy>$tims) return $txt;
}
 return "".$txt;
}
function topups($arr,$uax,$tims="20"){
$txts = count($arr); $txt = "<h5>$txts 种/共".array_sum($arr)."</h5>";
$iy = 0;  arsort($arr); 
foreach ($arr as $ti => $tis) { 
$txt .= "<p>$ti => $tis</p>\r\n";
$iy++; if($iy>$tims) return $txt;
}
 return "".$txt;
}
function topvis($arr,$sizs="20"){
$txts = count($arr); $txt = "<h5>$txts 种/共".array_sum($arr)."</h5>";
$iy = 0; krsort($arr); 
foreach ($arr as $ti => $tis) { 
$txt .= "<p>$ti => $tis</p>\r\n";
$iy++; if($iy>$sizs) return $txt;
}
 return $txt; 
}
function isgong($txts){
if($txts=="" || $txts=="-"){
 $zt = "异常空UA";
}elseif(preg_match_all('/(\\\x[a-zA-Z0-9_]{1,4}){2,4}/', $txts)){
 $zt = "异常攻击";
}elseif(preg_match_all('/(spider|bot|crawler|robot)/i', $txts)){
 $zt = "异常蜘蛛";
}elseif(preg_match_all('/(curl|requests|robot|python|urllib3|pantest)/i', $txts)){
 $zt = "异常爬虫";
}elseif(preg_match_all('/(ALittle|Dalvik|is_mobile|Go-http-client|apache-HttpClient|Fuzz)/i', $txts)){
 $zt = "异常爬虫";
}elseif(preg_match("/\@([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61})?\.)+[a-zA-Z]{2,8}/i", $txts)){
 $zt = "异常爬虫邮";
}elseif(preg_match_all('/(http|https|ftp)/i', $txts) && preg_match("/([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61})?\.)+[a-zA-Z]{2,8}/i", $txts)){
 $zt = "异常爬虫网";
}else{
 $zt = "普通";
}
 return $zt;
}
$n = (isset($_POST['n']))?addslashes($_POST['n']):"n"; //日志名称

if($n!="n"){


if(!stristr($n."@",".log@")) exit("必选 .log文件");
$start = microtime(true);
$mstar = memory_get_usage();
$filex= $paths.$n; //修改linux日志文件路径
 if(!file_exists($filex)) exit("$logf 不存在");
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $n . '.html"');
//header('Content-Length: ' . filesize($dadirs));
echo $sty;
echo "分析{$n}高频访问IP,404页面多,大文件疑似下载,蜘蛛否等";
$ii=0; $iz=0; $sqla = array(); $sqlb = array(); $sqlc = array();  $sqlh = array();
 $sqld = array(); $sqle = array(); $sqlf = array(); $sqlg = array();
foreach (readcsv($filex) as $key => $kar) {
$ii++; 
//公共:IP总次数
 $ipx1 = $kar[$lie0];
if(!$sqla[$ipx1]){ $sqla[$ipx1] = 1; }else{ $sqla[$ipx1] += 1;}
//公共:状态分析用于分析是否在破后台网址或下载.zip备份路径等
 $ipx2 = $kar[$lie1]; //STATS;200/404...
if(!$sqlb[$ipx1][$ipx2]){ $sqlb[$ipx1][$ipx2] = 1; }else{ $sqlb[$ipx1][$ipx2] += 1;}
//公共:反馈页面大小用于显示可能的大文件下载
 $ipx3 = $kar[$lie2];
if(!$sqlc[$ipx1][$ipx3]){ $sqlc[$ipx1][$ipx3] = 1; }else{ $sqlc[$ipx1][$ipx3] += 1;}
//公共:UA客户端用于分析用户是否蜘蛛等
 $ipx4 = md5($kar[$lie3]);
if(!$sqld[$ipx1][$ipx4]){ $sqld[$ipx1][$ipx4] = 1; $sqle[$ipx4]=$kar[$lie3]; }else{ $sqld[$ipx1][$ipx4] += 1;}
//公共:访问页面用于分析攻击否等
 $ipx5 = md5($kar[$lie5]);
if(!$sqlg[$ipx1][$ipx5]){ $sqlg[$ipx1][$ipx5] = 1; $sqlf[$ipx5]=$kar[$lie5]; }else{ $sqlg[$ipx1][$ipx5] += 1;}
//公共:访问时段用于分析攻击集中时段
 $ipx61 = Trim($kar[$lie4],"["); $ipx62 = explode(":",$ipx61);
 $ipx6 = $ipx62[0]."_H".$ipx62[1]; //$ipx62[0]年月日[1]时[2]分
if(!$sqlh[$ipx1][$ipx6]){ $sqlh[$ipx1][$ipx6] = 1; }else{ $sqlh[$ipx1][$ipx6] += 1;}
}
arsort($sqla); 
$tix = explode("|", "IP|次数|状态|回馈|UA样|PAGE|时段");
echo "<table>";
echo "<tr class='tt'><td width='80'>".join("</td><td>",$tix)."</td></tr>";
foreach ($sqla as $tip => $tcs) { 
echo "<tr><td>@$tip</td><td>$tcs</td><td>".readarr($sqlb[$tip])."</td><td>".topvis($sqlc[$tip])."</td><td>".topuaa($sqld[$tip],$sqle,"50")."</td><td>".topupg($sqlg[$tip],$sqlf,20)."</td><td>".topups($sqlh[$tip],"",30)."</td></tr>";
} 
echo "</table>";
$sstop = microtime(true); $mstop = memory_get_usage();
$fsize = number_format(filesize($filex)/1024/1024,2);
$us = "<p>分析{$fsize}MB/{$ii}条日志@耗时".number_format($sstop-$start, 2);
$us .= "@耗内存".number_format(($mstop-$mstar)/1024, 2)."KB";
$us .= "/总".number_format(memory_get_peak_usage()/1024,2).'KB</p>';
echo $us;
}else{
$dd = ""; echo $sty;
echo '<form name="q" method="post" action="?w=fee">';
echo '<h3>注意:高耗资源,请闲时操作</h3>放.log文件到logs文件夹下后选择分析';
echo '<p>1核1G配置:分析170MB耗时12秒/50M内存左右!大部分主机可能有限定内存和相应时间。</p>';
echo "<select name=\"n\" id=\"n\" class=\"time\" >";
echo "<option value=\"\">请选择.log文件</option>\r\n";
$handler = opendir($paths);		//打开当前文件夹由$paths指定。
$fileArr = array(); 
while (($fname = readdir($handler)) !== false) {
if ($fname != "." && $fname != "..") {	//文件夹文件
if (is_dir($paths . "" . $fname)) {	//如果是文件夹
} else {
$fTime = filemtime($paths . "" . $fname); 
$fileArr[$fname] = $fTime; 
}
}
}
arsort($fileArr); 
foreach ($fileArr as $fname => $ftime) { 
if(stristr($fname."@",".log@")){echo "<option value=\"$fname\">$fname</option>\r\n";}
}
@closedir($paths);
echo "</select>"; 
echo "<br><input type=\"submit\" name=\"button\" value=\"提交查询\" />";
}
echo '</form>';

总结

该脚本适合在 Linux 环境下直接分析 Nginx 访问日志,具有高效、直观的特点。通过该工具,管理员可以快速分析网站访问日志,检测潜在安全威胁。

复制全文 生成海报 日志分析 安全 PHP Linux Web开发

推荐文章

Rust 与 sqlx:数据库迁移实战指南
2024-11-19 02:38:49 +0800 CST
Boost.Asio: 一个美轮美奂的C++库
2024-11-18 23:09:42 +0800 CST
使用 sync.Pool 优化 Go 程序性能
2024-11-19 05:56:51 +0800 CST
Go的父子类的简单使用
2024-11-18 14:56:32 +0800 CST
js迭代器
2024-11-19 07:49:47 +0800 CST
ElasticSearch简介与安装指南
2024-11-19 02:17:38 +0800 CST
PHP设计模式:单例模式
2024-11-18 18:31:43 +0800 CST
go发送邮件代码
2024-11-18 18:30:31 +0800 CST
Elasticsearch 聚合和分析
2024-11-19 06:44:08 +0800 CST
什么是Vue实例(Vue Instance)?
2024-11-19 06:04:20 +0800 CST
Go 语言实现 API 限流的最佳实践
2024-11-19 01:51:21 +0800 CST
Vue中的`key`属性有什么作用?
2024-11-17 11:49:45 +0800 CST
解决 PHP 中的 HTTP 请求超时问题
2024-11-19 09:10:35 +0800 CST
js函数常见的写法以及调用方法
2024-11-19 08:55:17 +0800 CST
详解 Nginx 的 `sub_filter` 指令
2024-11-19 02:09:49 +0800 CST
程序员茄子在线接单