queries_per_minutes_all * 60); $query = $this->pdo->prepare("SELECT COUNT(*) FROM `search_queries` WHERE `ip` = :ip AND `time` > :time AND `time` <= :expiry_limit"); $query->bindValue(':ip', $ip); $query->bindValue(':time', $now - ($this->queries_per_minutes_single * 60), \PDO::PARAM_INT); $query->bindValue(':expiry_limit', $expiry_limit, \PDO::PARAM_INT); $query->execute(); if ($query->fetchColumn() > $this->queries_per_minutes_single) { return false; } $query = $this->pdo->prepare("SELECT COUNT(*) FROM `search_queries` WHERE `time` > :time AND `time` <= :expiry_limit"); $query->bindValue(':time', $now - ($this->queries_per_minutes_all * 60), \PDO::PARAM_INT); $query->bindValue(':expiry_limit', $expiry_limit, \PDO::PARAM_INT); $query->execute(); if ($query->fetchColumn() > $this->queries_per_minutes_all) { return false; } $query = $this->pdo->prepare("INSERT INTO `search_queries` VALUES (:ip, :time, :query)"); $query->bindValue(':ip', $ip); $query->bindValue(':time', $now, \PDO::PARAM_INT); $query->bindValue(':query', $phrase); $query->execute(); if ($this->auto_gc) { $this->purgeExpired(); } return true; } public function __construct(\PDO $pdo, int $queries_per_minutes_single, int $queries_per_minutes_all, bool $auto_gc) { $this->pdo = $pdo; $this->queries_per_minutes_single = $queries_per_minutes_single; $this->queries_per_minutes_all = $queries_per_minutes_all; $this->auto_gc = $auto_gc; } /** * Check if the IP-query pair overflows the limit. * * @param string $ip Source IP. * @param string $phrase The search query. * @return bool True if the request goes over the limit */ public function checkFlood(string $ip, string $phrase): bool { $this->pdo->beginTransaction(); try { $ret = $this->checkFloodImpl($ip, $phrase); $this->pdo->commit(); return $ret; } catch (\Exception $e) { $this->pdo->rollBack(); throw $e; } } public function purgeExpired(): int { // Cleanup search queries table. $query = prepare("DELETE FROM `search_queries` WHERE `time` <= :expiry_limit"); $query->bindValue(':expiry_limit', \time() - ($this->queries_per_minutes_all * 60), \PDO::PARAM_INT); $query->execute(); return $query->rowCount(); } }