WizdomWeb/app/Services/ResendVerificationService.php

111 lines
4.7 KiB
PHP

<?php
/**
* File: ResendVerificationService.php
* Version: 1.4
* Path: /app/Services/ResendVerificationService.php
* Purpose: Encapsulates logic for validating, logging, and processing verification email resends.
* Project: Wizdom Networks Website
*/
namespace WizdomNetworks\WizeWeb\Services;
use WizdomNetworks\WizeWeb\Utilities\Database;
use WizdomNetworks\WizeWeb\Utilities\Logger;
use WizdomNetworks\WizeWeb\Services\EmailService;
use WizdomNetworks\WizeWeb\Services\VerificationService;
class ResendVerificationService
{
/**
* @var EmailService Handles email composition and delivery.
*/
private EmailService $emailService;
/**
* @var VerificationService Handles generation and storage of verification codes.
*/
private VerificationService $verificationService;
/**
* Constructor initializes email and verification services.
*/
public function __construct()
{
$this->emailService = new EmailService();
$this->verificationService = new VerificationService();
}
/**
* Attempts to resend a verification email for a given type and address.
* Performs rate limiting checks and logs the attempt if permitted.
* Generates and assigns a new verification code and triggers an email send.
*
* @param string $type Either 'contact' or 'newsletter'
* @param string $email Email address to resend to
* @return array ['success' => bool, 'message' => string] Outcome and message for user feedback
*/
public function attemptResend(string $type, string $email): array
{
try {
$db = Database::getConnection();
// Rate limit: no more than 3 per day
$stmt = $db->prepare("SELECT COUNT(*) FROM verification_attempts WHERE email = ? AND type = ? AND attempted_at >= NOW() - INTERVAL 1 DAY");
$stmt->execute([$email, $type]);
if ((int)$stmt->fetchColumn() >= 3) {
return ['success' => false, 'message' => 'You have reached the daily resend limit. Please try again tomorrow.'];
}
// Rate limit: no more than 1 every 5 minutes
$stmt = $db->prepare("SELECT COUNT(*) FROM verification_attempts WHERE email = ? AND type = ? AND attempted_at >= NOW() - INTERVAL 5 MINUTE");
$stmt->execute([$email, $type]);
if ((int)$stmt->fetchColumn() > 0) {
return ['success' => false, 'message' => 'You must wait a few minutes before requesting another verification email.'];
}
// Log attempt
$stmt = $db->prepare("INSERT INTO verification_attempts (email, type, attempted_at, ip_address, user_agent) VALUES (?, ?, NOW(), ?, ?)");
$stmt->execute([
$email,
$type,
$_SERVER['REMOTE_ADDR'] ?? 'unknown',
$_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
]);
$code = $this->verificationService->generateCode();
$expiry = $this->verificationService->getExpirationTime();
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) {
return ['success' => false, 'message' => 'Email is already verified or not found.'];
}
$this->verificationService->assignCodeToRecord('subscribers', $row['id'], $code, $expiry);
$this->emailService->sendVerificationEmail($email, $code, 'verify_newsletter');
} elseif ($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) {
return ['success' => false, 'message' => 'Email is already verified or not found.'];
}
$this->verificationService->assignCodeToRecord('contact_messages', $row['id'], $code, $expiry);
$this->emailService->sendVerificationEmail($email, $code, 'verify_contact');
} else {
return ['success' => false, 'message' => 'Invalid verification type specified.'];
}
return ['success' => true, 'message' => 'We just sent you a new verification link.'];
} catch (\Throwable $e) {
Logger::error("ResendVerificationService::attemptResend exception: " . $e->getMessage());
return ['success' => false, 'message' => 'An unexpected error occurred.'];
}
}
}