php分析nginx日志,自动屏蔽ip地址
·
每当用户访问nginx服务器上的web时都会留下访问记录,这些记录被记录在access_log,可在配置文件中看到。
比如宝塔面板可直接在配置文件中看到:

没有自定义的情况下这个文件打开是这样的:

以下脚本实现,
1、可以自动执行,即使用命令行执行,每5分钟执行一次,已被注释
2、使用宝塔面板的计划任务定时访问地址,这样比较简单
3、分析最近的1万条记录,如果总条数小于700条,则跳出;如果最早和最小ip之间时间相隔小于12小时,则跳出;ip访问数大于300次,则符合条件,并与stopip文件中已保存的ip对比,如果stopip文件中没有,则添加至文件。
<?php
header('Content-type:text/html;charset=utf-8');
//打开日志文件
$ipstop_log_file_path='d:/BtSoft/wwwlogs/stopip_log.log';
if(file_exists($ipstop_log_file_path)){
$ipstop_log = fopen($ipstop_log_file_path, "a+");//追加内容,w为覆盖内容
fwrite($ipstop_log, "-----------开始执行:".date("Y/m/d h:i:s")."------------------\r\n");
fwrite($ipstop_log, "本次执行会分析nginx_access_log中响应日志中最近10000条数据,在12小时内请求数大于700次的ip会被屏蔽\r\n");
}
/**
* 取文件最后$n行
* @param string $filename 文件路径
* @param int $n 最后几行
* @return mixed false表示有错误,成功则返回字符串
*/
function FileLastLines($filename,$n,$ipstop_log){
if(!$fp=fopen($filename,'r')){
echo "打开文件失败,请检查文件路径是否正确,路径和文件名不要包含中文";
fwrite($ipstop_log, "打开文件失败,请检查文件路径是否正确,路径和文件名不要包含中文\r\n\r\n");
fclose($ipstop_log);
return false;
}
$pos=-2;
$eof="";//是否一行的终止
$first_time='';//第一个ip的请求时间
$arr=array();
$last_row_num=0;//读取的最大行数
//当输入的行数大于0
while($n>0){
//没到一行的结束
while($eof!="\n"){
//打开的文件中定位
if(!fseek($fp,$pos,SEEK_END)){
//获取一个单一字符,看是否\n
$eof=fgetc($fp);
$pos--;
//读取一行
$now_row=fgets($fp);
$ip=explode(' - ', $now_row)[0];
}else{
$n=0;
$last_row_num--;
break;
}
}
//如果已有ip键名,则累加
if(isset($arr[$ip])){
$arr[$ip]++;
$last_row_num++;
$wz1=mb_strpos($now_row, '[');
$wz2=mb_strpos($now_row, ']');
$first_time=mb_substr($now_row, $wz1+1, $wz2-$wz1-1);
}else if(!empty($ip) && strlen($ip)<16){
$arr[$ip]=1;//否则新建键名
$last_row_num++;
$wz1=mb_strpos($now_row, '[');
$wz2=mb_strpos($now_row, ']');
$first_time=mb_substr($now_row, $wz1+1, $wz2-$wz1-1);
}
$eof="";
$n--;
}
if($last_row_num<700){
$ech_str="-----------由于少于700行,本次执行结束:".date("Y/m/d h:i:s")."------------------\r\n\r\n";
echo $ech_str;//打印
fwrite($ipstop_log, $ech_str);//写入log
fclose($ipstop_log);
return false;
}else if(time()-strtotime($first_time)<43200){
$ech_str="第一个ip请求的时间为".$first_time.",时间戳为".strtotime($first_time).",不足12小时,不具备分析条件,本次执行结束:".date("Y/m/d h:i:s")."------------------\r\n\r\n";
echo $ech_str;//打印
fwrite($ipstop_log, $ech_str);//写入log
fclose($ipstop_log);
return false;
}else{
$ech_str= "已分析:".$last_row_num."条数据, 第一个ip请求的时间为".$first_time."\r\n";
echo $ech_str;//打印
fwrite($ipstop_log, $ech_str);//写入log
compara_ip($arr,$ipstop_log);
}
}
//比较ip
function compara_ip($arr,$ipstop_log){
//先读取频闭ip文件
$file_path = "d:/BtSoft/wwwlogs/stopip.log";
if(file_exists($file_path)){
$stop_ip_str = file_get_contents($file_path);//将整个文件内容读入到一个字符串中
}
$str='';//要写入屏蔽ip的字符串
//遍历数组
foreach($arr as $key => $value){
//如果ip已经在屏蔽文件中,则不做处理
if($value && $value>300 && !strpos($stop_ip_str, $key)){
$str.='deny '.$key.";\r\n";
}
}
$myfile = fopen($file_path, "a+");//追加内容,w为覆盖内容
fwrite($myfile, $str);
fclose($myfile);
$ech_str="-----------执行结束:".date("Y/m/d h:i:s")."------------------\r\n\r\n";
echo $ech_str;//打印
fwrite($ipstop_log, $ech_str);//写入log
fclose($ipstop_log);
}
//手动定时执行
FileLastLines('d:/BtSoft/wwwlogs/waterwx.log',10000,$ipstop_log);
//自动定时执行, 每300s执行一次
// function executeEverySecond($function,$file_path, $num) {
// while (true) {
// echo "\r\n";
// echo "\r\n";
// echo "-----------开始执行:".date("Y/m/d h:i:s")."------------------\r\n";
// echo "本次执行会分析nginx_access_log中响应日志中最近".$num."条数据,在12小时内请求数大于700次的ip会被屏蔽\r\n";
// $function($file_path,$num);
// sleep(300);
// }
// }
// executeEverySecond('FileLastLines','d:/BtSoft/wwwlogs/waterwx.weblf.cn.log',10000,$ipstop_log);
stopip:

最后在nginx配置文件中引入stopip.log

执行日志:

更多推荐



所有评论(0)