104 lines
4.4 KiB
PHP
104 lines
4.4 KiB
PHP
<?php
|
|
/**
|
|
* File: ResendVerificationController.php
|
|
* Version: 1.2
|
|
* Path: /app/Controllers/ResendVerificationController.php
|
|
* Purpose: Handles logic for resending verification emails for both newsletter and contact types with rate-limiting and expiration.
|
|
* Project: Wizdom Networks Website
|
|
*/
|
|
|
|
namespace WizdomNetworks\WizeWeb\Controllers;
|
|
|
|
use WizdomNetworks\WizeWeb\Core\View;
|
|
use WizdomNetworks\WizeWeb\Utils\Database;
|
|
use WizdomNetworks\WizeWeb\Utils\Logger;
|
|
use WizdomNetworks\WizeWeb\Services\NewsletterService;
|
|
use WizdomNetworks\WizeWeb\Services\ContactService;
|
|
|
|
class ResendVerificationController
|
|
{
|
|
public function handle(): void
|
|
{
|
|
$email = trim($_POST['email'] ?? '');
|
|
$type = trim($_POST['type'] ?? '');
|
|
|
|
if (!$email || !$type || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
|
View::render('pages/verify_failed', ['reason' => 'Invalid email or type.']);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$db = Database::getConnection();
|
|
|
|
// Rate limit: no more than 3 per day
|
|
$dailyCheck = $db->prepare("SELECT COUNT(*) FROM verification_attempts WHERE email = ? AND type = ? AND attempted_at >= NOW() - INTERVAL 1 DAY");
|
|
$dailyCheck->execute([$email, $type]);
|
|
$dailyCount = $dailyCheck->fetchColumn();
|
|
|
|
if ($dailyCount >= 3) {
|
|
View::render('pages/verify_failed', ['reason' => 'You have reached the daily resend limit. Please try again tomorrow.']);
|
|
return;
|
|
}
|
|
|
|
// Rate limit: no more than 1 every 5 minutes
|
|
$recentCheck = $db->prepare("SELECT COUNT(*) FROM verification_attempts WHERE email = ? AND type = ? AND attempted_at >= NOW() - INTERVAL 5 MINUTE");
|
|
$recentCheck->execute([$email, $type]);
|
|
$recentCount = $recentCheck->fetchColumn();
|
|
|
|
if ($recentCount > 0) {
|
|
View::render('pages/verify_failed', ['reason' => 'You must wait a few minutes before requesting another verification email.']);
|
|
return;
|
|
}
|
|
|
|
// Log attempt
|
|
$log = $db->prepare("INSERT INTO verification_attempts (email, type, attempted_at, ip_address, user_agent) VALUES (?, ?, NOW(), ?, ?)");
|
|
$log->execute([
|
|
$email,
|
|
$type,
|
|
$_SERVER['REMOTE_ADDR'] ?? 'unknown',
|
|
$_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
|
|
]);
|
|
|
|
$code = bin2hex(random_bytes(16));
|
|
$expiry = (new \DateTime())->modify('+72 hours')->format('Y-m-d H:i:s');
|
|
|
|
if ($type === 'newsletter') {
|
|
$stmt = $db->prepare("SELECT id, is_verified FROM subscribers WHERE email = ?");
|
|
$stmt->execute([$email]);
|
|
$row = $stmt->fetch();
|
|
|
|
if (!$row || (int)$row['is_verified'] === 1) {
|
|
View::render('pages/verify_failed', ['reason' => 'Email is already verified or not found.']);
|
|
return;
|
|
}
|
|
|
|
$update = $db->prepare("UPDATE subscribers SET verification_code = ?, is_verified = 0, verification_expires_at = ? WHERE id = ?");
|
|
$update->execute([$code, $expiry, $row['id']]);
|
|
NewsletterService::sendVerificationEmail($email, $code);
|
|
}
|
|
|
|
if ($type === 'contact') {
|
|
$stmt = $db->prepare("SELECT id, is_verified FROM contact_messages WHERE email = ? ORDER BY created_at DESC LIMIT 1");
|
|
$stmt->execute([$email]);
|
|
$row = $stmt->fetch();
|
|
|
|
if (!$row || (int)$row['is_verified'] === 1) {
|
|
View::render('pages/verify_failed', ['reason' => 'Email is already verified or not found.']);
|
|
return;
|
|
}
|
|
|
|
$update = $db->prepare("UPDATE contact_messages SET verification_code = ?, is_verified = 0, verification_expires_at = ? WHERE id = ?");
|
|
$update->execute([$code, $expiry, $row['id']]);
|
|
ContactService::sendVerificationEmail($email, $code);
|
|
}
|
|
|
|
View::render('pages/verify_success', [
|
|
'type' => $type,
|
|
'message' => 'We just sent you a new verification link.'
|
|
]);
|
|
} catch (\Throwable $e) {
|
|
Logger::error("Resend verification failed: " . $e->getMessage());
|
|
View::render('pages/verify_failed', ['reason' => 'Unexpected error occurred.']);
|
|
}
|
|
}
|
|
} |