You are here

public function QueryErrors::run in Security Review 8

The actual procedure of carrying out the check.

Return value

\Drupal\security_review\CheckResult The result of running the check.

Overrides Check::run

File

src/Checks/QueryErrors.php, line 31

Class

QueryErrors
Checks for abundant query errors.

Namespace

Drupal\security_review\Checks

Code

public function run() {

  // If dblog is not enabled return with hidden INFO.
  if (!$this
    ->moduleHandler()
    ->moduleExists('dblog')) {
    return $this
      ->createResult(CheckResult::INFO, [], FALSE);
  }
  $result = CheckResult::SUCCESS;
  $findings = [];
  $last_result = $this
    ->lastResult();
  $visible = FALSE;

  // Prepare the query.
  $query = $this
    ->database()
    ->select('watchdog', 'w');
  $query
    ->fields('w', [
    'severity',
    'type',
    'timestamp',
    'message',
    'variables',
    'hostname',
  ]);
  $query
    ->condition('type', 'php')
    ->condition('severity', RfcLogLevel::ERROR);
  if ($last_result instanceof CheckResult) {

    // Only check entries that got recorded since the last run of the check.
    $query
      ->condition('timestamp', $last_result
      ->time(), '>=');
  }

  // Execute the query.
  $db_result = $query
    ->execute();

  // Count the number of query errors per IP.
  $entries = [];
  foreach ($db_result as $row) {

    // Get the message.
    if ($row->variables === 'N;') {
      $message = $row->message;
    }
    else {
      $message = $this
        ->t($row->message, unserialize($row->variables));
    }

    // Get the IP.
    $ip = $row->hostname;

    // Search for query errors.
    $message_contains_sql = strpos($message, 'SQL') !== FALSE;
    $message_contains_select = strpos($message, 'SELECT') !== FALSE;
    if ($message_contains_sql && $message_contains_select) {
      $entry_for_ip =& $entries[$ip];
      if (!isset($entry_for_ip)) {
        $entry_for_ip = 0;
      }
      $entry_for_ip++;
    }
  }

  // Filter the IPs with more than 10 query errors.
  if (!empty($entries)) {
    foreach ($entries as $ip => $count) {
      if ($count > 10) {
        $findings[] = $ip;
      }
    }
  }
  if (!empty($findings)) {
    $result = CheckResult::FAIL;
    $visible = TRUE;
  }
  return $this
    ->createResult($result, $findings, $visible);
}