| Server IP : 202.61.199.114 / Your IP : 216.73.217.139 Web Server : nginx/1.22.1 System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64 User : web20 ( 1018) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /var/www/safemyident.de/web/api/lib/ |
Upload File : |
<?php
/**
* Einfaches, dateibasiertes Rate-Limit pro IP (Token-Fenster).
* Speichert nur anonyme Zähler – KEINE Eingaben (DSGVO).
*
* @package SafeMyIdent\Api
*/
declare(strict_types=1);
/**
* Prüft, ob die aktuelle IP im Zeitfenster noch Anfragen frei hat.
*
* @param int $limit Maximale Anfragen im Fenster.
* @param int $window Fenster in Sekunden.
* @return bool True = erlaubt.
*/
function smi_rate_ok(int $limit, int $window): bool
{
$ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
// IP nur gehasht ablegen (kein Klartext-Personenbezug).
$key = hash('sha256', $ip . '|smi-rate');
$dir = sys_get_temp_dir() . '/smi-rl';
if (!is_dir($dir)) {
@mkdir($dir, 0700, true);
}
$file = $dir . '/' . $key;
$now = time();
$data = ['start' => $now, 'count' => 0];
$fh = @fopen($file, 'c+');
if ($fh === false) {
return true; // Im Zweifel nicht blockieren.
}
flock($fh, LOCK_EX);
$raw = stream_get_contents($fh);
if ($raw !== false && $raw !== '') {
$decoded = json_decode($raw, true);
if (is_array($decoded) && isset($decoded['start'], $decoded['count'])) {
$data = $decoded;
}
}
if (($now - (int) $data['start']) >= $window) {
$data = ['start' => $now, 'count' => 0];
}
$data['count']++;
$allowed = $data['count'] <= $limit;
ftruncate($fh, 0);
rewind($fh);
fwrite($fh, json_encode($data));
flock($fh, LOCK_UN);
fclose($fh);
header('X-RateLimit-Limit: ' . $limit);
header('X-RateLimit-Remaining: ' . max(0, $limit - (int) $data['count']));
return $allowed;
}