You are here

class AntiFlood in Anti Spam by CleanTalk 8.4

Same name and namespace in other branches
  1. 9.1.x src/lib/Cleantalk/Common/Firewall/Modules/AntiFlood.php \Cleantalk\Common\Firewall\Modules\AntiFlood

Hierarchy

Expanded class hierarchy of AntiFlood

1 file declares its use of AntiFlood
BootSubscriber.php in src/EventSubscriber/BootSubscriber.php

File

src/lib/Cleantalk/Common/Firewall/Modules/AntiFlood.php, line 11

Namespace

Cleantalk\Common\Firewall\Modules
View source
class AntiFlood extends FirewallModule {
  public $module_name = 'ANTIFLOOD';

  /**
   * @var mixed|null
   */
  private $db__table__logs;

  /**
   * @var mixed|null
   */
  private $db__table__ac_logs;

  /**
   * @var string|null
   */
  private $db__table__ac_ua_bl;

  /**
   * @var mixed|null
   */
  private $view_limit;
  private $store_interval = 60;
  private $chance_to_clean = 20;

  /**
   * @var string
   */
  private $sign;
  public function __construct($log_table, $params = array()) {
    $db = DB::getInstance();
    $this->db__table__logs = $db->prefix . $log_table ?: null;
    $this->db__table__ac_logs = $params['db__table__ac_logs'] ? $db->prefix . $params['db__table__ac_logs'] : null;
    $this->db__table__ac_ua_bl = defined('APBCT_TBL_AC_UA_BL') ? $db->prefix . APBCT_TBL_AC_UA_BL : null;
    $this->sign = md5(Server::get('HTTP_USER_AGENT') . Server::get('HTTPS') . Server::get('HTTP_HOST'));
    $this->view_limit = $params['view_limit'] ?: null;
  }
  public function check() {
    $results = array();
    $this
      ->clear_table();
    $time = time() - $this->store_interval;
    foreach ($this->ip_array as $current_ip) {

      // UA check
      $ua_bl_results = $this->db
        ->fetch_all("SELECT * FROM " . $this->db__table__ac_ua_bl . " ORDER BY `ua_status` DESC;");
      if (!empty($ua_bl_results)) {
        foreach ($ua_bl_results as $ua_bl_result) {
          if (!empty($ua_bl_result['ua_template']) && preg_match("%" . str_replace('"', '', $ua_bl_result['ua_template']) . "%i", Server::get('HTTP_USER_AGENT'))) {
            if ($ua_bl_result['ua_status'] == 1) {

              // Whitelisted
              $results[] = array(
                'ip' => $current_ip,
                'is_personal' => false,
                'status' => 'PASS_ANTIFLOOD_UA',
              );
              return $results;
            }
          }
        }
      }

      // Passed
      if (CleantalkFuncs::apbct_getcookie('apbct_antiflood_passed') === md5($current_ip . $this->api_key)) {
        if (!headers_sent()) {
          CleantalkFuncs::apbct_setcookie('apbct_antiflood_passed', '0');
        }

        // Do logging an one passed request
        $this
          ->update_log($current_ip, 'PASS_ANTIFLOOD');
        $results[] = array(
          'ip' => $current_ip,
          'is_personal' => false,
          'status' => 'PASS_ANTIFLOOD',
        );
        return $results;
      }

      // @todo Rename ip column to sign. Use IP + UserAgent for it.
      $result = $this->db
        ->fetch("SELECT SUM(entries) as total_count" . ' FROM ' . $this->db__table__ac_logs . '' . " WHERE ip = '{$current_ip}' AND interval_start > '{$time}' AND " . rand(1, 100000) . ";");
      if (!empty($result) && isset($result['total_count']) && $result['total_count'] >= $this->view_limit) {
        $results[] = array(
          'ip' => $current_ip,
          'is_personal' => false,
          'status' => 'DENY_ANTIFLOOD',
        );
      }
    }
    if (!empty($results)) {

      // Do block page
      return $results;
    }
    else {
      $this
        ->update_ac_log();
    }
    return $results;
  }
  public function actionsForDenied($result) {

    // TODO: Implement actionsForDenied() method.
  }
  public function actionsForPassed($result) {

    // TODO: Implement actionsForPassed() method.
  }
  public function clear_table() {
    if (rand(0, 100) < $this->chance_to_clean) {
      $interval_start = Helper::time__get_interval_start($this->store_interval);
      $this->db
        ->execute("DELETE\n\t\t\t\tFROM " . $this->db__table__ac_logs . "\n\t\t\t\tWHERE interval_start < " . $interval_start . "\n\t\t\t\tAND ua = '{$this->sign}'\n\t\t\t\tLIMIT 100000;");
    }
  }

  /**
   * Add entry to SFW log.
   * Writes to database.
   *
   * @param string $ip
   * @param $status
   */
  public function update_log($ip, $status, $network = null, $source = null) {
    $id = md5($ip . $this->module_name);
    $time = time();
    if (!$source) {
      $source = 'NULL';
    }
    if (!$network) {
      $network = 'NULL';
    }
    $query = "INSERT INTO `{$this->db__table__logs}`\n\t\tSET\n\t\t\t`id` = '{$id}',\n\t\t\t`ip` = '{$ip}',\n\t\t\t`status` = '{$status}',\n\t\t\t`all_entries` = 1,\n\t\t\t`blocked_entries` = " . (strpos($status, 'DENY') !== false ? 1 : 0) . ",\n\t\t\t`entries_timestamp` = '{$time}',\n\t\t\t`ua_name` = '" . Server::get('HTTP_USER_AGENT') . "',\n\t\t\t`source` = {$source},\n\t\t\t`network` = '{$network}',\n      `first_url` = '" . substr(Server::get('HTTP_HOST') . Server::get('REQUEST_URI'), 0, 100) . "',\n      `last_url` = '" . substr(Server::get('HTTP_HOST') . Server::get('REQUEST_URI'), 0, 100) . "'\n\t\tON DUPLICATE KEY\n\t\tUPDATE\n\t\t\t`status` = '{$status}',\n\t\t\t`source` = {$source},\n\t\t\t`all_entries` = `all_entries` + 1,\n\t\t\t`blocked_entries` = `blocked_entries`" . (strpos($status, 'DENY') !== false ? ' + 1' : '') . ",\n\t\t\t`entries_timestamp` = '{$time}',\n\t\t\t`ua_name` = '" . Server::get('HTTP_USER_AGENT') . "',\n\t\t\t`network` = '{$network}',\n      `last_url` = '" . substr(Server::get('HTTP_HOST') . Server::get('REQUEST_URI'), 0, 100) . "'";
    $this->db
      ->execute(str_replace(';', '', $query));
  }

  /**
   * Update ac logs table
   */
  public function update_ac_log() {
    $interval_time = Helper::time__get_interval_start($this->store_interval);
    foreach ($this->ip_array as $current_ip) {
      $id = md5($current_ip . $this->sign . $interval_time);
      $this->db
        ->execute("INSERT INTO " . $this->db__table__ac_logs . " SET\n\t\t\t\t\tid = '{$id}',\n\t\t\t\t\tip = '{$current_ip}',\n\t\t\t\t\tua = '{$this->sign}',\n\t\t\t\t\tentries = 1,\n\t\t\t\t\tinterval_start = {$interval_time}\n\t\t\t\tON DUPLICATE KEY UPDATE\n\t\t\t\t\tip = ip,\n\t\t\t\t\tentries = entries + 1,\n\t\t\t\t\tinterval_start = {$interval_time};");
    }
  }
  public function _die($result) {
    parent::_die($result);

    // File exists?
    if (file_exists(__DIR__ . '/die_page_antiflood.html')) {
      $die_page = file_get_contents(__DIR__ . '/die_page_antiflood.html');
      $net_count = $this->db
        ->fetch('SELECT COUNT(*) as net_count FROM ' . $this->db__table__ac_logs)['net_count'];

      // Translation
      $replaces = array(
        '{SFW_DIE_NOTICE_IP}' => $this
          ->__('Anti-Flood is activated for your IP', 'cleantalk-spam-protect'),
        '{SFW_DIE_MAKE_SURE_JS_ENABLED}' => $this
          ->__('To continue working with the web site, please make sure that you have enabled JavaScript.', 'cleantalk-spam-protect'),
        '{SFW_DIE_YOU_WILL_BE_REDIRECTED}' => sprintf($this
          ->__('You will be automatically redirected to the requested page after %d seconds.', 'cleantalk-spam-protect'), 30),
        '{CLEANTALK_TITLE}' => $this
          ->__('Antispam by CleanTalk', 'cleantalk-spam-protect'),
        '{REMOTE_ADDRESS}' => $result['ip'],
        '{REQUEST_URI}' => Server::get('REQUEST_URI'),
        '{SERVICE_ID}' => $net_count,
        '{HOST}' => '',
        '{GENERATED}' => '<p>The page was generated at&nbsp;' . date('D, d M Y H:i:s') . "</p>",
        '{COOKIE_ANTIFLOOD_PASSED}' => md5($result['ip'] . $this->api_key),
        '{USE_ALT_COOKIES}' => \Drupal::config('cleantalk.settings')
          ->get('cleantalk_alternative_cookies_session') ? 1 : 0,
      );
      foreach ($replaces as $place_holder => $replace) {
        $die_page = str_replace($place_holder, $replace, $die_page);
      }
      die($die_page);
    }
    die("IP BLACKLISTED. Blocked by AntiFlood " . $result['ip']);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AntiFlood::$chance_to_clean private property
AntiFlood::$db__table__ac_logs private property
AntiFlood::$db__table__ac_ua_bl private property
AntiFlood::$db__table__logs private property
AntiFlood::$module_name public property Overrides FirewallModule::$module_name
AntiFlood::$sign private property
AntiFlood::$store_interval private property
AntiFlood::$view_limit private property
AntiFlood::actionsForDenied public function Do logic for denied request. Overrides FirewallModule::actionsForDenied
AntiFlood::actionsForPassed public function Do logic for allowed request. Overrides FirewallModule::actionsForPassed
AntiFlood::check public function Use this method to execute main logic of the module. Overrides FirewallModule::check
AntiFlood::clear_table public function
AntiFlood::update_ac_log public function Update ac logs table
AntiFlood::update_log public function Add entry to SFW log. Writes to database.
AntiFlood::_die public function Default die page for blocked requests. Overrides FirewallModule::_die
AntiFlood::__construct public function * FirewallModule constructor. * Use this method to prepare any data for the module working. * * Overrides FirewallModule::__construct
FirewallModule::$api_key protected property
FirewallModule::$db protected property
FirewallModule::$db_data_table_name protected property
FirewallModule::$db_log_table_name protected property
FirewallModule::$debug protected property
FirewallModule::$debug_data protected property
FirewallModule::$helper protected property
FirewallModule::$ip_array protected property
FirewallModule::$real_ip protected property *
FirewallModule::$test protected property *
FirewallModule::$test_ip protected property *
FirewallModule::ipAppendAdditional public function Configure and set additional properties: real_ip, test_ip, test
FirewallModule::setApiKey public function Set API KEY
FirewallModule::setDb public function Set specify CMS based DB instance
FirewallModule::setHelper public function Set specify CMS based Helper instance
FirewallModule::setIpArray public function Set visitor's IP
FirewallModule::setIsDebug public function Set is debug property.
FirewallModule::setLogTableName public function Set Log Table name
FirewallModule::__ public function This is a placeholder for WP translation function. For compatibility with any CMS.