我找到了这个脚本
Quick and easy flood protection?
我把它变成了一个函数。
大多数情况下效果很好。我不时会看到一个错误:
[<a href='function.unlink'>function.unlink</a>]: No such file or directory
排队:
else if($ diff&gt; 3600){unlink($ path); } //如果第一个请求超过1小时,则新的ip文件
显然某些IP文件因某些原因被删除了?
我试图找到逻辑错误,但我对此并不擅长。也许有人可以提供帮助。
功能:
function ht_request_limiter() {
if (!isset($_SERVER['REMOTE_ADDR'])) { return; } // Maybe its impossible, however we check it first
if (empty($_SERVER['REMOTE_ADDR'])) { return; } // Maybe its impossible, however we check it first
$path = '/home/czivbaby/valuemarket.gr/ip-sec/'; // I use a function to validate a path first and return if false...
$path = $path.$_SERVER['REMOTE_ADDR'].'.txt'; // Real file path (filename = <ip>.txt)
$now = time(); // Current timestamp
if (!file_exists($path)) { // If first request or new request after 1 hour / 24 hour ban, new file with <timestamp>|<counter>
if ($handle = fopen($path, 'w+')) {
if (fwrite($handle, $now.'|0')) { chmod($path, 0700); } // Chmod to prevent access via web
fclose($handle);
}
}
else if (($content = file_get_contents($path)) !== false) { // Load existing file
$content = explode('|',$content); // Create paraset [0] -> timestamp [1] -> counter
$diff = (int)$now-(int)$content[0]; // Time difference in seconds from first request to now
if ($content[1] == 'ban') { // If [1] = ban we check if it was less than 24 hours and die if so
if ($diff>86400) { unlink($path); } // 24 hours in seconds.. if more delete ip file
else {
header("HTTP/1.1 503 Service Unavailable");
exit("Your IP is banned for 24 hours, because of too many requests.");
}
}
else if ($diff>3600) { unlink($path); } // If first request was more than 1 hour, new ip file
else {
$current = ((int)$content[1])+1; // Counter + 1
if ($current>200) { // We check rpm (request per minute) after 200 request to get a good ~value
$rpm = ($current/($diff/60));
if ($rpm>10) { // If there was more than 10 rpm -> ban (if you have a request all 5 secs. you will be banned after ~17 minutes)
if ($handle = fopen($path, 'w+')) {
fwrite($handle, $content[0].'|ban');
fclose($handle);
// Maybe you like to log the ip once -> die after next request
}
return;
}
}
if ($handle = fopen($path, 'w+')) { // else write counter
fwrite($handle, $content[0].'|'.$current .'');
fclose($handle);
}
}
}
}
答案 0 :(得分:0)
您的服务器正在从同一客户端同时处理两个(或更多)请求,并且该脚本似乎无法正确处理此(完全正常)情况。 Web浏览器并行从服务器下载多个对象以加快浏览速度。很可能,浏览器很快就会执行两个请求,然后最终并行执行,以便该脚本的两个副本在大致相同的时间以相同的unlink()调用结束。一个成功删除文件,另一个给出错误消息。
即使您的服务器只有一个CPU,操作系统也会很乐意通过多个PHP进程之间的上下文切换来提供多任务处理,这些进程同时为同一个客户端IP地址执行相同的PHP脚本。
脚本应该使用文件锁定(http://php.net/manual/en/function.flock.php)来锁定文件。或者简单地忽略unlink()错误(通过在unlink前放置@),但是可能会出现其他并发问题。
脚本应该:
$f = fopen($filename, 'r+');
flock($f, LOCK_EX)
调用将阻塞并等待。fseek($f, 0, SEEK_SET)
到文件的开头,ftruncate($f, 0)
使其为空,并在必要时重写文件内容或取消链接()文件。所有编程语言的模式都相同。