Publiczna aplikacja fdmtech.pl: renderer CMS, formularz audytu, szablony i logotypy
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FDMTech;
|
||||
|
||||
/** Shared per-IP fixed window. Uses the peer IP only, never untrusted forwarded headers. */
|
||||
final class RateLimiter
|
||||
{
|
||||
public function __construct(private Config $config) {}
|
||||
|
||||
public function consume(string $ip): bool
|
||||
{
|
||||
$key = $this->config->get('APP_KEY');
|
||||
if (strlen($key) < 32) {
|
||||
throw new \RuntimeException('APP_KEY must have at least 32 characters');
|
||||
}
|
||||
$directory = $this->config->get('RATE_LIMIT_DIR') ?: $this->config->root . '/var/rate-limits';
|
||||
if (!is_dir($directory) && !@mkdir($directory, 0700, true) && !is_dir($directory)) {
|
||||
throw new \RuntimeException('Rate limit storage unavailable');
|
||||
}
|
||||
$file = $directory . '/' . hash_hmac('sha256', $ip, $key) . '.json';
|
||||
$handle = @fopen($file, 'c+');
|
||||
if (!$handle) {
|
||||
throw new \RuntimeException('Rate limit storage unavailable');
|
||||
}
|
||||
try {
|
||||
if (!flock($handle, LOCK_EX)) {
|
||||
throw new \RuntimeException('Rate limit lock unavailable');
|
||||
}
|
||||
$now = time();
|
||||
$window = $this->config->number('INQUIRY_RATE_WINDOW', 900);
|
||||
$record = json_decode(stream_get_contents($handle), true);
|
||||
if (!is_array($record) || !isset($record['start'], $record['count']) || $record['start'] + $window <= $now) {
|
||||
$record = ['start' => $now, 'count' => 0];
|
||||
}
|
||||
if ($record['count'] >= $this->config->number('INQUIRY_RATE_MAX', 5)) {
|
||||
return false;
|
||||
}
|
||||
$record['count']++;
|
||||
$payload = json_encode($record, JSON_THROW_ON_ERROR);
|
||||
rewind($handle);
|
||||
if (!ftruncate($handle, 0) || fwrite($handle, $payload) !== strlen($payload) || !fflush($handle)) {
|
||||
throw new \RuntimeException('Rate limit write unavailable');
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
flock($handle, LOCK_UN);
|
||||
fclose($handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user