Цитата мудреца

Голосование

Что Вам нужно для счастья?
 
Система Orphus. Если вы заметили ошибку на сайте, нажмите сюда.
Загружается, подождите...
Начало сайта Материалы сайта Программы PHP-скрипты
Версия для слабовидящих
Версия для печати

Ограничение на скорость выдачи страниц одному пользователю

Здесь представлены некоторые мои разработки на PHP. Это в, основном, служебные скрипты, которые работают в составе других скриптов и не могут быть протестированы здесь непосредственно.

Re: Ограничение на скорость выдачи страниц одному пользователю

Connie писал(а):Я так понимаю в коде Вашего скрипта нужно ввести какой то флаг, а уже в функции редиректа проверять установлен ли он и только тогда писать во временный каталог


Как раз наоборот. При редиректе флаг (файл специального имени) устанавливается, а при работе скрипта он проверяется. И если он стоит, то скрипт пропускает этого пользователя.

Нет, я имею ввиду, что эта функция редиректа будет вызываться и из других файлов.
Защиту я хочу поставить в файл viewtopic.php
А такие файлы как: viewforum.php, index.php оставить без изменений, но дело в том, что эти два скрипта так же используют функцию редиректа и я опасаюсь, что во временном каталоге будут созданы файлы, которые удалять будет некому, т.е. не будет происходить в этом случае очистки.

Поэтому я и думаю, что в файле защиты (antiddos.php) нужно установить какой то флажок, а уже в функции редиректа проверять его, если установлен, то делаем запись во временный каталог, а если не установлен или не определен, то ничего не делаем и работаем как обычно.

Такой финт позволит, в случае необходимости, отключить защитный скрипт и не нужно будет изменять файл functions.php

Т.е. мне нужно в файле antiddos.php определить какую то переменную, которая будет видна в файле functions.php (в функции redirect)
Ответить


Сам подход в принципе неверный, потому что все действия производятся в файле antiddos.php, и именно там надо решать, выполнять действия или нет. Соответственно, "действие" не должно происходить, когда идёт внутренний редирект.

А почему Вы не хотите поставить вызов скрипта во все файлы?

Есть ещё вариант, сделать в описании функции редиректа ещё один параметр со значением по умолчанию:
Код: Выделить всё
function redirect($url, $a_d = false)

А потом в самой функции проверять:
Код: Выделить всё
if ($a_d)
{
    $f_name = $_SERVER['DOCUMENT_ROOT'] . 'tmp_dir/r' . $_SERVER['REMOTE_ADDR'];
    $f = fopen($f_name, 'w');
    fclose($f);
}

После этого, во все вызовы редиректа из viewtopic.php повставлять вторым параметром true. Тогда файл будет создаваться лишь в нужных случаях.
Но здесь тоже может быть проблема: возможно есть какие-то общие модули, которые загружаются из разных файлов и из которых идёт редирект. И получится накладка.
Мне кажется, что лучше бы было ставить этот модуль на все запускаемые файлы.
Ответить


На вики, как оказалось, так же есть редирект и там я по Вашему рецепту все наладил, единственно включение в функцию редиректа я сделал так
Код: Выделить всё
function send_redirect($url){
    // always close the session
    session_write_close();
   
   //Изменение скрипта от DDos атаки
   if (defined('AD_DIRNAME')){
      $f_name   = AD_DIRNAME . '/r' . $_SERVER['REMOTE_ADDR'];
      $f = fopen($f_name, 'w');
      fclose($f);
   }
   //Конец изменеия скрипта
    // check if running on IIS < 6 with CGI-PHP
    if( isset($_SERVER['SERVER_SOFTWARE']) && isset($_SERVER['GATEWAY_INTERFACE']) &&
        (strpos($_SERVER['GATEWAY_INTERFACE'],'CGI') !== false) &&
        (preg_match('|^Microsoft-IIS/(\d)\.\d$|', trim($_SERVER['SERVER_SOFTWARE']), $matches)) &&
        $matches[1] < 6 ){
        header('Refresh: 0;url='.$url);
    }else{
        header('Location: '.$url);
    }
    exit;
}

Т.е. если я уберу включение Вашего скрипта или же вызов этой функции произойдёт из какого то файла, не имеющего включение скрипта защиты, то мне не потребуется лезть изменять эту функцию

А вот на форуме никак не получается его прикрутить, проблема в том, что у меня все работает на разных системах, компьютерах, IP, а у некоторых юзеров упрямо появляется 503 :(

Если победю, найду причину, то отпишусь

Спасибо!
Ответить


Connie писал(а):Т.е. если я уберу включение Вашего скрипта или же вызов этой функции произойдёт из какого то файла, не имеющего включение скрипта защиты, то мне не потребуется лезть изменять эту функцию

Всё правильно. Хитро! :)

Connie писал(а):проблема в том, что у меня все работает на разных системах, компьютерах, IP

Это как? В пределах одного сайта?

Connie писал(а):а у некоторых юзеров упрямо появляется 503

А Вы сами можете инициировать эту ошибку, чтобы проверить, где и в каких случаях она вылазит?
Ответить


Re: Ограничение на скорость выдачи страниц одному пользователю

А Вы сами можете инициировать эту ошибку, чтобы проверить, где и в каких случаях она вылазит?
если бы! У меня все четко работает.

Я сделал так:
Код: Выделить всё
/*** Выводить или не выводить сообщение об ошибке ***/
       if ($ad_before_trying > 1)
       {
          /* Если обращение было недавно, то выводим сообщение об ошибке */
          header ('HTTP/1.0 503 Service Unavailable');
...

Я обратил внимание, что файлы создаваемые во временном каталоге имеют всегда на конце 1, т.е. одно обращение, теперь если более 2 обращений, то выводится ошибка, вроде, судя по отзывам тех, у кого не работало, сейчас работает, но будут тестировать еще.

Попробовал с своего компа качнуть сайт - получил 503-ю, так что думаю нормально, время покажет верно ли я все сделал.

Спасибо еще раз :)
Ответить


Я сделал так:
ввел еще одну константу
Код: Выделить всё
/* время хранения файла в секундах */
    define ('AD_FILE_STORE_TIME', 60*60*12 );


И изменил кусок так
Код: Выделить всё
if (!$ad_IsRobot && не редирект)
    {
       /*** Чтение каталога и удаление старых файлов ***/
       $ad_dir      = opendir(AD_DIRNAME) or
          die('Отсутствует директория для временных файлов');
       $ad_now = time();       
       $ad_forbid   = $ad_now - AD_DELAY;
       /* IP-адрес в имени файла, начинающегося на букву a,
       а время обращения - время изменения файла */
       $ad_before_trying = 0;
       
       while (false !== ($ad_FName = readdir($ad_dir)))
       {
          $ad_fileage = $ad_now - @ filemtime(AD_DIRNAME . '/' . $ad_FName);
          if ($ad_fileage > AD_FILE_STORE_TIME ) @ unlink(AD_DIRNAME . '/' . $ad_FName);//удаляем старые файлы         
          elseif (ereg('^a[1-9]', $ad_FName))
          {  //Если мы пришли с того же ip, что и был записан
             //тогда считаем кол-во обращений
             
             if ( ereg('^a' . str_replace('.', '\\.',
                $_SERVER['REMOTE_ADDR']) . '_([0-9]+)$', $ad_FName, $ad_match ) ){
                //ip тот же! Если время файла менее необходимого, то считаем кол-во обращений
                if ($ad_fileage < AD_DELAY){
                    $ad_before_trying = intval($ad_match[1]);
                }
                @ unlink(AD_DIRNAME . '/' . $ad_FName);//файл при совпадении имени и ip удаляется в любом случае
             }
          }
       }

возросло кол-во файлов соответствующих ip реальным посетителям во временном каталоге, ранее новый пользователь очищал временный каталог, а потому и не было возможности поймать качальщика, т.е. во временном каталоге у меня было 1-2 файла. Вместе с тем теперь возможно увеличение "забытых" файлов, поэтому я сделал удаление их по прошествии AD_FILE_STORE_TIME, сейчас это 12 часов, но я думаю поставить около 1 часа, хватит?

Сейчас нас как раз долбит кто то, скачивает форум, вот и проверю, как теперь скрипт работает.

Покритикуйте :) я ведь в php не мастак, может напортачил чего?
Ответить


Re: Ограничение на скорость выдачи страниц одному пользователю

Connie писал(а):
А Вы сами можете инициировать эту ошибку, чтобы проверить, где и в каких случаях она вылазит?
если бы! У меня все четко работает.

Посмотрите по логам. Будет видно, куда человек ходил. Хотя, если у Вас не стоят SEO-моды на форуме, то логи дадут лишь файлы скриптов без параметров.

Connie писал(а):Я обратил внимание, что файлы создаваемые во временном каталоге имеют всегда на конце 1, т.е. одно обращение, теперь если более 2 обращений, то выводится ошибка, вроде, судя по отзывам тех, у кого не работало, сейчас работает, но будут тестировать еще.

В общем, конечно, вариант... Пропускать первый раз...
Лучше бы, конечно, разобраться, в каких случаях это вылазит, чтобы устранить суть проблемы.

Добавлено спустя 4 минуты 54 секунды:
Connie писал(а):ранее новый пользователь очищал временный каталог, а потому и не было возможности поймать качальщика

Совершенно нет необходимости ловить качальщика. После указанного числа попыток качальщик банится окончательно в .htacces, а Вам приходит письмо на электронную почту о том, что забанен такой-то товарищ (для проверки, не бот ли это полезный.
У меня в день по паре таких красавцев вылазит. Правда я вычищаю htaccess через пару месяцев. Ибо за это время, пока сайт для них недоступен, они забывают о том, что он им был нужен.
А если качальщик сильно хитрый, что не доводит до бана, то можно, опять-таки, в логах его посмотреть.
Ответить


Добавил задержку в выдаче страницы роботам.
К сожалению, не все роботы корректно читают сайт и обращают внимание на соответствующие директивы файла robots.txt. Поэтому пришлось просить их подождать несколько секунд перед тем, как они получат страницу.

И ещё, список подсетей поисковых роботов постоянно обновляется. Следите за номером версии скрипта!
Ответить


Re: Ограничение на скорость выдачи страниц одному пользователю

Здравствуйте!
Успешно использую Ваш скрипт и несколько его модифицировал (сразу уточно что имена почти всех переменных я изменил, так что не стоит этот кусок кода вставлять в оригинальный скрипт):
Код: Выделить всё
function writeIP($count)
{
   $count++;
   if ($count > TRYING)
   {
     //Определение предварительного IP-адреса
      $hostIp = $_SERVER['REMOTE_ADDR'];
      //Определение реального IP-адреса
      $realIp = $_SERVER['HTTP_X_FORWARDED_FOR'];
   
      if ($realIp > 0)
      {
         $proxy = "###PROXY###\n\n";
         $banIp = $realIp;   // Используется для блокирования реального IP адреса через .htaccess.
      }
      else
      {
      $banIp = $hostIp; 
      }
           
     //Баним ip-адрес
     $f = fopen($_SERVER['DOCUMENT_ROOT'] . '/.htaccess', 'a');   // ------- ПРАВА НА ФАЙЛ .htaccess - 666 !!! -------
      fwrite($f, "\ndeny from " . $hostIp . "\ndeny from " . $banIp);
      fclose($f);
            
     // Открыть комментарии, если нужно уведомлять по почте
    
     $brows = $_SERVER['HTTP_USER_AGENT'];
     $page = $_SERVER['REQUEST_URI'];
     $refer = $_SERVER['HTTP_REFERER'];
     $query = $_SERVER['QUERY_STRING'];
     // $time = date('H:i:s (M d)'); // Текущее время
     // $time2 = $_SERVER['REQUEST_TIME']; // Время запроса
     // $clntIp = $_SERVER['HTTP_CLIENT_IP'];
    
      //Получаем хост (в некоторых логах он может быть вместо ip
      $host = gethostbyaddr($_SERVER['REMOTE_ADDR']);
    
     /*
     Лучше использовать оператор сравнения. Он выполняется быстрей, нежели конкретное сравнение значений.
     $i = 0;
      Плохо:
      if ($i != 0)
      Хорошо:
      if ($i > 0)
    
     Вместо сравнения строки со строкой, для выявления ее пустоты, также можно использовать сравнение с нулем, которые выполнится быстрее.
    
     Используйте одинарные кавычки там где это возможно и пользуйтесь оператором "." для склейки строк,
     вместо прямой подстановки переменный в строку, заключенную в кавычки.
      Лучший вариант(самый быстрый):
      echo 'Вес равен: '.$weight;
    
      Худший вариант(медленный):
      echo "Вес равен: $weight";
      */
      
     // Двойные кавычки ("") нужны, если в строке присутствуют метасимволы \n.
   
     $mess =
     ''
     . $proxy .
     ' IP:       ' . $hostIp .
     "\n\n Domain:   " . $host .
     "\n\n Real IP:  " . $realIp .
     "\n\n Browser:  " . $brows .
     "\n\n Page:     " . $page .
     "\n\n Referer: " . $refer .
     "\n\n Query: " . $query .
     ''
     ;
      
      // Сообщение не будет отсылатся, если переменные типа . $_SERVER['REMOTE_ADDR'] . ставить после переменных типа . $realIp .
     // В начале и конце сообщения обязательно ставить ''.
    
    
      //Выполняем запрос к логам. Нужно указать путь и имя лог-файла
     /*
      exec('cat /home/your_dir/logs/access_log | egrep \'(' .
         str_replace('.', '\\.', $_SERVER['REMOTE_ADDR']) . ')|(' .
         str_replace('.', '\\.', $host) . ')\' | sort -k 4 >' .
         DIRTMP . '/dump.txt');
      $mess .= file_get_contents(DIRTMP . '/dump.txt');
      @ unlink(DIRTMP . '/dump.txt');
     */
    
     // mail (string to, string subject, string message [, string additional_headers [, string additional_parameters]])
      $email = 'my_box@myhost.ru'; //Укажите свой e-mail
     $sbjMl = $_SERVER['HTTP_HOST'];
      mail($email, $sbjMl, $mess,
       'From: ' . $email .
         "\nReply-To: " . $email .
         "\nContent-Type: text/plain; charset=Windows-1251" .
         "\nContent-Transfer-Encoding: 8bit");
     
   }
   else
   {
      //Записываем файл с ip-адресом и количеством обращений
      $f = fopen(DIRTMP . '/a' . $_SERVER['REMOTE_ADDR'] . '_' .
         $count, 'w');
      fclose($f);
   }
}
Ответить


Re: Ограничение на скорость выдачи страниц одному пользователю

Теперь конкретнее по коду.

1. Почему бы не использовать проверку возможного использования качальщиком прокси-сервера?
Код: Выделить всё
//Определение предварительного IP-адреса
$hostIp = $_SERVER['REMOTE_ADDR'];
//Определение реального IP-адреса
$realIp = $_SERVER['HTTP_X_FORWARDED_FOR'];


2. В коде закомментированы некоторые приемы ускорения PHP кода. Не знаю, насколько они эффективны, но хуже от них точно не должно быть.

3. Этот кусок кода я сразу закомментировал и не видел его работу.
Код: Выделить всё
//Выполняем запрос к логам. Нужно указать путь и имя лог-файла
     /*
      exec('cat /home/your_dir/logs/access_log | egrep \'(' .
         str_replace('.', '\\.', $_SERVER['REMOTE_ADDR']) . ')|(' .
         str_replace('.', '\\.', $host) . ')\' | sort -k 4 >' .
         DIRTMP . '/dump.txt');
      $mess .= file_get_contents(DIRTMP . '/dump.txt');
      @ unlink(DIRTMP . '/dump.txt');
     */

Я так понимаю нам в сообщении приходит информация из лога апача. Но что там особенно полезного? Мне кажется, что на эту обработку уходит приличное количество процессорного времени. Логи могут достигать десятки мегабайт. Или я не прав?

4. Не знаю как у кого, но у меня на сервере скрипт работает, если на папку tmp_path выставлены права 777, а на файл .htaccess - 666.

А автору скрипта - респект!
Ответить


Пред.След.

Вернуться в PHP-скрипты



Кто сейчас на сайте

Зарегистрированные пользователи: Yahoo [Bot]