<?php
require_once __DIR__.'/SecurityHelper.php';
class RateLimiter
{
/**
* @param $userId
*/
private static function getRateLimitFile($userId)
{
$secureUserId = SecurityHelper::securePath($userId);
return __DIR__."/../../logs/rate_limit_{$secureUserId}.json";
}
/**
* ตรวจสอบ rate limit สำหรับผู้ใช้
*/
public static function checkRateLimit($userId, $limit = null, $timeWindow = null)
{
$limit = $limit ?? (defined('RATE_LIMIT_REQUESTS') ? RATE_LIMIT_REQUESTS : 10);
$timeWindow = $timeWindow ?? (defined('RATE_LIMIT_WINDOW') ? RATE_LIMIT_WINDOW : 60);
$file = self::getRateLimitFile($userId);
$now = time();
// สร้าง directory ถ้าไม่มี
$dir = dirname($file);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
if (file_exists($file)) {
$content = file_get_contents($file);
$data = json_decode($content, true);
if (!$data || !isset($data['requests'])) {
$requests = [];
} else {
// กรองเอาเฉพาะ request ที่อยู่ใน time window
$requests = array_filter($data['requests'], function ($time) use ($now, $timeWindow) {
return ($now - $time) < $timeWindow;
});
}
} else {
$requests = [];
}
// ตรวจสอบว่าเกิน limit หรือไม่
if (count($requests) >= $limit) {
SecurityHelper::logSecurityEvent('rate_limit_exceeded', $userId, [
'requests_count' => count($requests),
'limit' => $limit,
'time_window' => $timeWindow
]);
return false; // Rate limit exceeded
}
// เพิ่ม request ปัจจุบัน
$requests[] = $now;
// บันทึกข้อมูลกลับ
$data = ['requests' => array_values($requests)];
file_put_contents($file, json_encode($data), LOCK_EX);
return true;
}
/**
* ล้างข้อมูล rate limit สำหรับผู้ใช้
*/
public static function clearRateLimit($userId)
{
$file = self::getRateLimitFile($userId);
if (file_exists($file)) {
unlink($file);
}
}
/**
* ล้างข้อมูล rate limit ที่หมดอายุ
*/
public static function cleanupExpiredLimits()
{
$logsDir = __DIR__."/../../logs";
if (!is_dir($logsDir)) {
return;
}
$files = glob($logsDir."/rate_limit_*.json");
$now = time();
$maxAge = defined('RATE_LIMIT_WINDOW') ? RATE_LIMIT_WINDOW : 60;
foreach ($files as $file) {
if (filemtime($file) < ($now - $maxAge * 2)) {
unlink($file);
}
}
}
}