feat: add rate limiting and input validation to contact form
- Rate limit: 5 req/min per IP (file-based) - Email format validation via filter_var - Field length limits: name 100, email 254, phone 30, message 5000 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,25 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Rate limiting (5 requests per minute per IP) ────────────────────────────
|
||||||
|
$ip = $_SERVER['HTTP_X_FORWARDED_FOR']
|
||||||
|
? explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0]
|
||||||
|
: ($_SERVER['REMOTE_ADDR'] ?? 'unknown');
|
||||||
|
$ip = trim($ip);
|
||||||
|
$rate_file = sys_get_temp_dir() . '/rl_' . md5($ip) . '.json';
|
||||||
|
$now = time();
|
||||||
|
$window = 60;
|
||||||
|
$max_req = 5;
|
||||||
|
$rate_data = file_exists($rate_file) ? json_decode(file_get_contents($rate_file), true) : [];
|
||||||
|
$rate_data = array_filter($rate_data ?? [], fn($t) => $t > $now - $window);
|
||||||
|
if (count($rate_data) >= $max_req) {
|
||||||
|
http_response_code(429);
|
||||||
|
echo json_encode(['error' => 'Too many requests. Please try again later.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$rate_data[] = $now;
|
||||||
|
file_put_contents($rate_file, json_encode(array_values($rate_data)));
|
||||||
|
|
||||||
$data = json_decode(file_get_contents('php://input'), true);
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
if (!$data) {
|
if (!$data) {
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
@@ -28,6 +47,17 @@ if (!$name || !$message) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Validation ───────────────────────────────────────────────────────────────
|
||||||
|
if ($email && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => 'Invalid email format']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if (mb_strlen($name) > 100) { http_response_code(400); echo json_encode(['error' => 'Name too long']); exit; }
|
||||||
|
if (mb_strlen($email) > 254) { http_response_code(400); echo json_encode(['error' => 'Email too long']); exit; }
|
||||||
|
if (mb_strlen($phone) > 30) { http_response_code(400); echo json_encode(['error' => 'Phone too long']); exit; }
|
||||||
|
if (mb_strlen($message) > 5000) { http_response_code(400); echo json_encode(['error' => 'Message too long']); exit; }
|
||||||
|
|
||||||
// ─── Telegram (best-effort, not fatal) ───────────────────────────────────────
|
// ─── Telegram (best-effort, not fatal) ───────────────────────────────────────
|
||||||
$BOT_TOKEN = '8138813013:AAElH2L5NspRLSdiFjDz6Qf32n4G24P_cj8';
|
$BOT_TOKEN = '8138813013:AAElH2L5NspRLSdiFjDz6Qf32n4G24P_cj8';
|
||||||
$CHAT_ID = '-5230603582';
|
$CHAT_ID = '-5230603582';
|
||||||
|
|||||||
Reference in New Issue
Block a user