Разберем вариант логики скрипта, который позволяет заблокировать временно IP, с которого идет много запросов. Рассмотрим сценарий https://raw.githubusercontent.com/ArtNazarov/protector/main/protector.php .
<?php // scripts ban user for // frequently requests define("LOGGER", false); define("HOST_DIR", __DIR__); define("MAX_REQ", 5); define("TIMEOUT_EXPIRE", 60*10); function ipf($ip){ return HOST_DIR . '/ips/'. $ip.'.txt'; } function save_blacklist($ip){ $f_blacklist = fopen(HOST_DIR . '/blacklist.txt', 'a+'); fwrite($f_blacklist, $ip . "\n\r"); fclose($f_blacklist); } function save_ip_stat($ip, $items){ if (LOGGER){ echo "сохраняем файл статистики<br>"; }; $data = implode('|', $items); $fh = fopen(ipf($ip), 'w'); fwrite($fh, $data); fclose($fh); } function get_ip_stat($ip){ if (LOGGER){ echo "считываем файл статистики<br>"; }; $data = file_get_contents( ipf( $ip )); $items = explode('|', $data); return $items; } function get_ms(){ $curTime = microtime(true); return $curTime; } function get_ms_diff($nowTime, $t){ return ($nowTime - $t); } function get_ip(){ if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $user_ip_address = $_SERVER['HTTP_CLIENT_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $user_ip_address = $_SERVER['HTTP_X_FORWARDED_FOR']; } else { $user_ip_address = $_SERVER['REMOTE_ADDR']; }; return $user_ip_address; } function exists_ip($ip){ return file_exists( ipf($ip) ); } function init_stat($ip){ $items = [ $ip, 1, get_ms() ]; save_ip_stat($ip, $items); } function main(){ $ip = get_ip(); if (LOGGER){ echo "Запрос с адреса " . $ip . "<br/>"; }; if (!exists_ip($ip)){ init_stat($ip); } if (exists_ip( $ip ) ){ if (LOGGER){ echo "файл найден"; }; $items = get_ip_stat($ip); $counter = $items[1]; $time = $items[2]; $nowTime = get_ms(); if (LOGGER){ echo "Опрошено раз " . $counter . "<br>"; echo "Время " . $time . "<br>"; echo "Сейчас " . $nowTime . "<br>"; }; $isStatOld = false; $ms_delay = get_ms_diff($nowTime, $time); //echo $ms_delay; if ($ms_delay>TIMEOUT_EXPIRE){ if (LOGGER) { echo "Разница больше " . TIMEOUT_EXPIRE . "<br/>";}; $isStatOld = true; }; if (($counter>MAX_REQ) && (!$isStatOld)) { echo "Временно заблокирован за превышение запросов. Доступ откроется через " . strval(floor((TIMEOUT_EXPIRE-$ms_delay)/60))." минут"; save_blacklist($ip); save_ip_stat($ip, [$ip, $counter+1, $time]); exit(0); } else { if ($isStatOld) { if (LOGGER) {echo "Статистика устарела"; }; init_stat($ip); } else { save_ip_stat($ip, [$ip, $counter+1, get_ms()]); }; } } } main(); ?>Идея состоит в том, чтобы отлавливать тех пользователей, которые превышают максимально допустимое количество запросов за заданное количество секунд. Допустим, мы хотим разрешить не более 5 запросов от одного IP на промежуток времени TIMEOUT_EXPIRE = 60*10 секунд, то есть 10 минут. В этом случае логика в следующем - будем для каждого ip создавать запись в файловой системе, которая содержит время самого первого обращения и счетчик запросов. Если файла нет, т.е. ip новый, то мы создадим новую запись, в которой счетчик будет иметь значение 1. Если файл есть, мы сравниваем максимальное количество запросов с текущим и выясняем, насколько устарела запись (т.е. превышено ли время TIMEOUT_EXPIRE). Если время превышено (бан прошел), то счетчик необходимо сбросить и пустить пользователя дальше. Если время не превышено, а количество запросов за серию обращений больше допустимого, то прерываем выполнение во входной точке (обычно index.php) и сообщаем, через какое время будет разбан ( оно равно в данном варианте TIMEOUT-задержка)/60 в минутах. Другой подход состоит в том, чтобы запретить запросы на основании слишком небольшого промежутка между двумя последними, что также свидетельствует о высокой частоте опроса (чем выше частота, тем меньше времени между последовательными обращениями) ( примером является https://github.com/ArtNazarov/PottoCMS/blob/master/classes/Core/Protector/Protector.library.php ) Теги документа