Все ленты — последние статьи

Ограничение количества запросов с одного IP — изучить , переделать

Ограничение количества запросов с одного IP

Боты могут доставить много неприятностей, для борьбы с ними существуют различные способы. Не безызвестная каптча тому пример, но не всегда она применима. Одной из альтернатив, является ограничение количества запросов за период времени. Разумно подобрав параметры вы не создадите неудобств вашим посетителям, при этом создав огромные проблемы боту.

Этот сниппет использует базу данных для хранения записей о попытках запроса:

1
2
3
4
5
6
7
8
9
10
11
--
-- Структура таблицы `check_ip`
--
CREATE TABLE IF NOT EXISTS `check_ip` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ip` bigint(11) NOT NULL,
  `cnt` int(11) NOT NULL DEFAULT '0',
  `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `ip` (`ip`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

А вот собственно и сама реализация:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
$dbuser='dbuser'//Пользователь базы данных
$dbpass='dbpass'//Пароль пользователя базы данных
$db='db'; //Имя базы данных
$try_count=3; //Лимиты попыток
$try_time=60; //Период лимита попыток в секундах
 
try {
    //Подключение к БД
    $mysqli = new mysqli("localhost", $dbuser, $dbpass, $db);
    if ($mysqli->connect_errno) {
        throw new Exception('Не удалось подключиться к БД');
    }
    //Определяем IP адрес
    $ip=$_SERVER['REMOTE_ADDR'];
    $long = ip2long($ip);
    if ($long == -1 || $long === FALSE) {
        throw new Exception('Ошибка определения IP');
    }
    //Подготавливаем данные для запросов
    $long = sprintf('%u', $long);
    $time=date('Y-m-d H:i:s',time()-$try_time);
    //Ищем запись о попытках подключения
    $res = $mysqli->query("SELECT `id`,`cnt` FROM `check_ip` where `ip`='$long' and `date`>='$time'");
    if ($res->num_rows>0){
        $row = $res->fetch_assoc();
        if ($row['cnt']>=$try_count){
            throw new Exception('Превышено количество попыток, повторите запрос через 1-2 минуты');
        }else{
            //Увеличиваем счетчик попыток
            $mysqli->query("update `check_ip` set `cnt`=`cnt`+1 where `id`='{$row['id']}'");
        }
    }else{
        //Вставляем запись о попытка запроса
        $time=date('Y-m-d H:i:s',time());
        $mysqli->query("INSERT INTO `check_ip` ( `ip`, `cnt`, `date`) VALUES ('$long', 1, '$time')");
    }
    /*
        Здесь выполняем полезные действия
    */
    echo "Ok";
} catch ( Exception $e ) {
    //Обработка ошибочных ситуаций
    echo $e->getMessage();
}

Код довольно простой и комментированный, если будут вопросы не стесняйтесь. По мере возможностей постараюсь ответить всем.