Integrate EmailUtility, SubmissionCheck, and Response into ContactController; finalize contact form logic and template handling
This commit is contained in:
parent
90b7b0b785
commit
e4ff1f0a59
|
|
@ -4,7 +4,7 @@
|
||||||
* File: ContactController.php
|
* File: ContactController.php
|
||||||
* Path: /app/Controllers/ContactController.php
|
* Path: /app/Controllers/ContactController.php
|
||||||
* Purpose: Handles form submissions from the Arsha contact form
|
* Purpose: Handles form submissions from the Arsha contact form
|
||||||
* Version: 1.0
|
* Version: 1.1
|
||||||
* Author: Wizdom Networks
|
* Author: Wizdom Networks
|
||||||
* Usage: Routed via Router to handle POST /contact
|
* Usage: Routed via Router to handle POST /contact
|
||||||
* ============================================
|
* ============================================
|
||||||
|
|
@ -12,9 +12,15 @@
|
||||||
|
|
||||||
namespace WizdomNetworks\WizeWeb\Controllers;
|
namespace WizdomNetworks\WizeWeb\Controllers;
|
||||||
|
|
||||||
use WizdomNetworks\WizeWeb\Utils\Logger;
|
|
||||||
use WizdomNetworks\WizeWeb\Utils\ErrorHandler;
|
|
||||||
use WizdomNetworks\WizeWeb\Core\View;
|
use WizdomNetworks\WizeWeb\Core\View;
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\Logger;
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\ErrorHandler;
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\EmailUtility;
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\Sanitizer;
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\Validator;
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\Response;
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\SubmissionCheck;
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\Database;
|
||||||
use PHPMailer\PHPMailer\PHPMailer;
|
use PHPMailer\PHPMailer\PHPMailer;
|
||||||
use PHPMailer\PHPMailer\Exception;
|
use PHPMailer\PHPMailer\Exception;
|
||||||
|
|
||||||
|
|
@ -23,24 +29,31 @@ class ContactController
|
||||||
public function submit(): void
|
public function submit(): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// Sanitize and validate input
|
$firstName = Sanitizer::sanitizeString($_POST['first_name'] ?? '');
|
||||||
$firstName = trim($_POST['first_name'] ?? '');
|
$lastName = Sanitizer::sanitizeString($_POST['last_name'] ?? '');
|
||||||
$lastName = trim($_POST['last_name'] ?? '');
|
$email = Sanitizer::sanitizeEmail($_POST['email'] ?? '');
|
||||||
$email = trim($_POST['email'] ?? '');
|
$phone = Sanitizer::sanitizePhone($_POST['phone'] ?? '');
|
||||||
$phone = trim($_POST['phone'] ?? '');
|
$message = Sanitizer::sanitizeText($_POST['message'] ?? '');
|
||||||
$message = trim($_POST['message'] ?? '');
|
|
||||||
|
|
||||||
if (!$firstName || !$lastName || !$email || !$phone || !$message) {
|
if (!$firstName || !$lastName || !$email || !$phone || !$message) {
|
||||||
throw new \Exception("All fields except phone must be filled out.");
|
Response::jsonError('All fields must be filled out.');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
if (!Validator::isValidEmail($email)) {
|
||||||
throw new \Exception("Invalid email address.");
|
Response::jsonError('Please provide a valid email address.');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store in database
|
// Check if email has submitted recently
|
||||||
$pdo = new \PDO($_ENV['DB_DSN'], $_ENV['DB_USER'], $_ENV['DB_PASS']);
|
if (SubmissionCheck::isDuplicateContactEmail($email)) {
|
||||||
$stmt = $pdo->prepare("INSERT INTO contact_messages (first_name, last_name, email, phone, message, ip_address, user_agent)
|
$lastDate = SubmissionCheck::getLastContactSubmissionDate($email);
|
||||||
|
Response::jsonError("This email already submitted a message on $lastDate. Please wait a week before sending another or contact us directly.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = Database::getConnection();
|
||||||
|
$stmt = $db->prepare("INSERT INTO contact_messages (first_name, last_name, email, phone, message, ip_address, user_agent)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?)");
|
VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
$firstName,
|
$firstName,
|
||||||
|
|
@ -54,35 +67,23 @@ class ContactController
|
||||||
|
|
||||||
Logger::info("Contact form submitted by $firstName $lastName <$email>");
|
Logger::info("Contact form submitted by $firstName $lastName <$email>");
|
||||||
|
|
||||||
// Email notification
|
// Send internal notification email
|
||||||
$mail = new PHPMailer(true);
|
EmailUtility::sendInternalContactAlert([
|
||||||
$mail->isSMTP();
|
'first_name' => $firstName,
|
||||||
$mail->Host = $_ENV['SMTP_HOST'];
|
'last_name' => $lastName,
|
||||||
$mail->Port = $_ENV['SMTP_PORT'];
|
'email' => $email,
|
||||||
$mail->SMTPAuth = $_ENV['SMTP_AUTH'] === 'true';
|
'phone' => $phone,
|
||||||
$mail->SMTPSecure = $_ENV['SMTP_ENCRYPTION'] !== 'none' ? $_ENV['SMTP_ENCRYPTION'] : '';
|
'message' => $message
|
||||||
$mail->Username = $_ENV['SMTP_USERNAME'];
|
]);
|
||||||
$mail->Password = $_ENV['SMTP_PASSWORD'];
|
|
||||||
$mail->setFrom($_ENV['SMTP_FROM_EMAIL'], $_ENV['SMTP_FROM_NAME']);
|
|
||||||
$mail->addAddress($_ENV['SALES_EMAILS'] ?? $_ENV['ADMIN_EMAILS']);
|
|
||||||
|
|
||||||
$mail->Subject = "New Contact Message from $firstName $lastName";
|
// Send confirmation to user
|
||||||
$mail->Body = "You received a message from: \n\n"
|
EmailUtility::sendContactConfirmation($email, $firstName);
|
||||||
. "Name: $firstName $lastName\n"
|
|
||||||
. "Email: $email\n"
|
|
||||||
. "Phone: $phone\n"
|
|
||||||
. "Message:\n$message\n";
|
|
||||||
|
|
||||||
$mail->send();
|
Response::jsonSuccess('Thank you. We will be in touch shortly.');
|
||||||
|
|
||||||
http_response_code(200);
|
|
||||||
echo json_encode(['success' => true, 'message' => 'Thank you. We will be in touch.']);
|
|
||||||
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Logger::error("Contact form error: " . $e->getMessage());
|
ErrorHandler::exception($e);
|
||||||
ErrorHandler::handleException($e);
|
Response::jsonError('An internal error occurred. Please try again later.');
|
||||||
http_response_code(400);
|
|
||||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace WizdomNetworks\WizeWeb\Utilities;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
use PDOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database Utility
|
||||||
|
*
|
||||||
|
* A utility for managing database connections and queries.
|
||||||
|
*
|
||||||
|
* Integrates logging for connection status and query execution.
|
||||||
|
*/
|
||||||
|
class Database
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var PDO|null The PDO instance for database connection.
|
||||||
|
*/
|
||||||
|
private ?PDO $connection = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database constructor.
|
||||||
|
*
|
||||||
|
* Initializes the database connection.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Establishes a connection to the database.
|
||||||
|
*/
|
||||||
|
private function connect(): void
|
||||||
|
{
|
||||||
|
$dsn = sprintf('mysql:host=%s;dbname=%s;charset=utf8mb4', $_ENV['DB_HOST'], $_ENV['DB_NAME']);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->connection = new PDO($dsn, $_ENV['DB_USER'], $_ENV['DB_PASSWORD']);
|
||||||
|
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
Logger::info('Database connection established successfully.');
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
Logger::error('Database connection failed: ' . $e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a query and returns the result.
|
||||||
|
*
|
||||||
|
* @param string $query The SQL query to execute.
|
||||||
|
* @param array $params Parameters for prepared statements (optional).
|
||||||
|
* @return array The query result.
|
||||||
|
*/
|
||||||
|
public function query(string $query, array $params = []): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$stmt = $this->connection->prepare($query);
|
||||||
|
$stmt->execute($params);
|
||||||
|
Logger::info('Query executed successfully: ' . $query);
|
||||||
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
Logger::error('Query failed: ' . $query . ' | Error: ' . $e->getMessage());
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the PDO connection instance.
|
||||||
|
*
|
||||||
|
* @return PDO The PDO instance.
|
||||||
|
*/
|
||||||
|
public function getConnection(): PDO
|
||||||
|
{
|
||||||
|
return $this->connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,393 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace WizdomNetworks\WizeWeb\Utilities;
|
||||||
|
|
||||||
|
use PHPMailer\PHPMailer\PHPMailer;
|
||||||
|
use PHPMailer\PHPMailer\Exception;
|
||||||
|
use PHPMAILER\PHPMAILER\SMTP;
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\Logger;
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\Database;
|
||||||
|
|
||||||
|
class EmailUtility
|
||||||
|
{
|
||||||
|
private static QueueUtility $queueUtility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the EmailUtility with the QueueUtility instance.
|
||||||
|
*
|
||||||
|
* @param QueueUtility $queueUtility The queue utility instance for managing email queues.
|
||||||
|
*/
|
||||||
|
public static function initialize(QueueUtility $queueUtility): void
|
||||||
|
{
|
||||||
|
self::$queueUtility = $queueUtility;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve and validate email configuration from environment variables.
|
||||||
|
*
|
||||||
|
* @return array The validated email configuration settings.
|
||||||
|
* @throws \RuntimeException If required email configurations are missing.
|
||||||
|
*/
|
||||||
|
private static function getConfig(): array
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( $_ENV['SMTP_AUTH'] === false ) {
|
||||||
|
|
||||||
|
|
||||||
|
$config = [
|
||||||
|
'host' => $_ENV['SMTP_HOST'] ?? 'localhost',
|
||||||
|
'port' => $_ENV['SMTP_PORT'] ?? '25',
|
||||||
|
'from_email' => $_ENV['SMTP_FROM_EMAIL'] ?? 'concierge@helpdeskplus.ca',
|
||||||
|
'from_name' => $_ENV['SMTP_FROM_NAME'] ?? 'HelpDesk+',
|
||||||
|
'auth' => false
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach (['host', 'port', 'from_email'] as $field) {
|
||||||
|
if (empty($config[$field])) {
|
||||||
|
Logger::logError("Missing email configuration: $field");
|
||||||
|
throw new \RuntimeException("Missing email configuration: $field");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
$config = [
|
||||||
|
'host' => $_ENV['SMTP_HOST'] ?? 'localhost',
|
||||||
|
'username' => $_ENV['SMTP_USERNAME'] ?? null,
|
||||||
|
'password' => $_ENV['SMTP_PASSWORD'] ?? null,
|
||||||
|
'port' => $_ENV['SMTP_PORT'] ?? '25',
|
||||||
|
'encryption' => $_ENV['SMTP_ENCRYPTION'] ?? 'none',
|
||||||
|
'from_email' => $_ENV['SMTP_FROM_EMAIL'] ?? 'concierge@helpdeskplus.ca',
|
||||||
|
'from_name' => $_ENV['SMTP_FROM_NAME'] ?? 'HelpDesk+',
|
||||||
|
'smtpsecure' => $_ENV['SMTP_AUTH'],
|
||||||
|
'auth' => true,
|
||||||
|
'autotls' => true
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach (['host', 'port', 'username', 'password', 'from_email'] as $field) {
|
||||||
|
if (empty($config[$field])) {
|
||||||
|
Logger::logError("Missing email configuration: $field");
|
||||||
|
throw new \RuntimeException("Missing email configuration: $field");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render an email template with dynamic data.
|
||||||
|
*
|
||||||
|
* @param string $templatePath The path to the email template file.
|
||||||
|
* @param array $data Key-value pairs for template placeholders.
|
||||||
|
* @return string The rendered email content.
|
||||||
|
*/
|
||||||
|
public static function renderTemplate(string $templatePath, array $data): string
|
||||||
|
{
|
||||||
|
if (!file_exists($templatePath)) {
|
||||||
|
Logger::logError("Email template not found: $templatePath");
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = file_get_contents($templatePath);
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
$content = str_replace("{{{$key}}}", $value, $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log email status into the database.
|
||||||
|
*
|
||||||
|
* @param string $recipient The recipient email address.
|
||||||
|
* @param string $status The status of the email (e.g., 'queued', 'sent', 'failed').
|
||||||
|
* @param string|null $errorMessage An optional error message.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function logEmailStatus(string $recipient, string $status, ?string $errorMessage = null): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = Database::getInstance();
|
||||||
|
$query = "INSERT INTO email_status (recipient, status, error_message, created_at) VALUES (:recipient, :status, :error_message, NOW())";
|
||||||
|
$params = [
|
||||||
|
':recipient' => $recipient,
|
||||||
|
':status' => $status,
|
||||||
|
':error_message' => $errorMessage,
|
||||||
|
];
|
||||||
|
$db->executeQuery($query, $params);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Logger::logError("Failed to log email status: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify admin or sales team via email.
|
||||||
|
*
|
||||||
|
* @param string $emailType The type of notification (e.g., 'admin', 'sales').
|
||||||
|
* @param string $subject The email subject.
|
||||||
|
* @param string $templatePath Path to the notification template.
|
||||||
|
* @param array $templateData Data for the template placeholders.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function notifyTeam(string $emailType, string $subject, string $templatePath, array $templateData): void
|
||||||
|
{
|
||||||
|
$recipients = $emailType === 'admin' ? explode(',', $_ENV['ADMIN_EMAILS']) : explode(',', $_ENV['SALES_EMAILS']);
|
||||||
|
|
||||||
|
foreach ($recipients as $recipient) {
|
||||||
|
$recipient = trim($recipient);
|
||||||
|
if (!self::sendEmail($recipient, $subject, $templatePath, $templateData)) {
|
||||||
|
Logger::logError("Failed to send $emailType notification to: $recipient");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an email with enhanced error categorization.
|
||||||
|
*
|
||||||
|
* @param string $recipient Recipient email address.
|
||||||
|
* @param string $subject Email subject.
|
||||||
|
* @param string $templatePath Path to the email template.
|
||||||
|
* @param array $templateData Data to replace placeholders in the template.
|
||||||
|
* @param array $options Optional configurations (e.g., CC, BCC).
|
||||||
|
* @param int $retryLimit The maximum number of retries for transient failures.
|
||||||
|
* @return bool Returns true on success, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function sendEmail(string $recipient, string $subject, string $templatePath, array $templateData = [], array $options = [], int $retryLimit = 3): bool
|
||||||
|
{
|
||||||
|
$mail = new PHPMailer(true);
|
||||||
|
$config = self::getConfig();
|
||||||
|
$retryCount = 0;
|
||||||
|
|
||||||
|
while ($retryCount <= $retryLimit) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
$mail->isSMTP();
|
||||||
|
$mail->SMTPAutoTLS = false;
|
||||||
|
$mail->SMTPAuth = false;
|
||||||
|
/* If authentication is enabled setup the connection */
|
||||||
|
if ( $config['auth'] === 'true' ){
|
||||||
|
$mail->SMTPAuth = $config['auth'];
|
||||||
|
$mail->Username = $config['username'];
|
||||||
|
$mail->Password = $config['password'];
|
||||||
|
$mail->SMTPSecure = $config['encryption'];
|
||||||
|
$mail->SMTPAutoTLS = $config['autotls'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$mail->Host = $config['host'];
|
||||||
|
$mail->Port = $config['port'];
|
||||||
|
/******************************
|
||||||
|
$mail->SMTPDebug = $_ENV['APP_ENV'] === 'development' ? 2 : 0;
|
||||||
|
/$mail->Debugoutput = function ($message, $level) {
|
||||||
|
Logger::logInfo("SMTP Debug [$level]: $message");
|
||||||
|
};
|
||||||
|
*******************************/
|
||||||
|
$mail->setFrom($config['from_email'], $config['from_name']);
|
||||||
|
$mail->addAddress($recipient);
|
||||||
|
|
||||||
|
if (!empty($options['cc'])) {
|
||||||
|
foreach ((array)$options['cc'] as $cc) {
|
||||||
|
$mail->addCC($cc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($options['bcc'])) {
|
||||||
|
foreach ((array)$options['bcc'] as $bcc) {
|
||||||
|
$mail->addBCC($bcc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$mail->isHTML(true);
|
||||||
|
$mail->Subject = $subject;
|
||||||
|
$mail->Body = self::renderTemplate($templatePath, $templateData);
|
||||||
|
|
||||||
|
$mail->send();
|
||||||
|
Logger::logInfo("Email sent to $recipient with subject: $subject");
|
||||||
|
self::logEmailStatus($recipient, 'sent');
|
||||||
|
return true;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$retryCount++;
|
||||||
|
$error = $mail->ErrorInfo;
|
||||||
|
Logger::logWarning("Email send failed for $recipient (Attempt $retryCount/$retryLimit): $error");
|
||||||
|
|
||||||
|
if (str_contains($error, '452 4.3.1')) {
|
||||||
|
Logger::logWarning("Transient error detected for $recipient: $error");
|
||||||
|
} elseif (str_contains($error, '550')) {
|
||||||
|
Logger::logError("Permanent error detected for $recipient: $error");
|
||||||
|
self::logEmailStatus($recipient, 'failed', $error);
|
||||||
|
return false;
|
||||||
|
} elseif (str_contains($error, '421')) {
|
||||||
|
Logger::logWarning("Rate-limiting error detected for $recipient: $error");
|
||||||
|
} else {
|
||||||
|
Logger::logError("Unhandled SMTP error for $recipient: $error");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_contains($error, '452') || str_contains($error, '421')) {
|
||||||
|
if ($retryCount > $retryLimit) {
|
||||||
|
Logger::logError("Exceeded retry limit for email to $recipient: $error");
|
||||||
|
self::logEmailStatus($recipient, 'failed', $error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(5);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::logError("Email permanently failed for $recipient: $error");
|
||||||
|
self::logEmailStatus($recipient, 'failed', $error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the email queue and send emails in batches.
|
||||||
|
*
|
||||||
|
* @param int $batchSize Number of emails to process in a single batch.
|
||||||
|
* @param int $maxRetries Maximum retry attempts for failed emails.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function processEmailQueue(int $batchSize = 10, int $maxRetries = 3): void
|
||||||
|
{
|
||||||
|
for ($i = 0; $i < $batchSize; $i++) {
|
||||||
|
$emailData = self::$queueUtility->dequeue('email');
|
||||||
|
|
||||||
|
if ($emailData === null) {
|
||||||
|
Logger::logInfo("No more emails to process in the queue.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$success = self::sendEmail(
|
||||||
|
$emailData['recipient'],
|
||||||
|
$emailData['subject'],
|
||||||
|
$emailData['templatePath'],
|
||||||
|
$emailData['templateData'],
|
||||||
|
$emailData['options']
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$success) {
|
||||||
|
$retries = $emailData['retries'] ?? 0;
|
||||||
|
|
||||||
|
if ($retries < $maxRetries) {
|
||||||
|
$priority = $emailData['priority'] ?? 0;
|
||||||
|
$emailData['retries'] = $retries + 1;
|
||||||
|
self::$queueUtility->enqueue('email', $emailData, $priority);
|
||||||
|
Logger::logWarning(
|
||||||
|
"Email re-queued for recipient: {$emailData['recipient']} (Attempt {$emailData['retries']})"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Logger::logError("Email permanently failed for recipient: {$emailData['recipient']}");
|
||||||
|
self::logEmailStatus($emailData['recipient'], 'failed', 'Max retry limit reached.');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self::logEmailStatus($emailData['recipient'], 'sent');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::logInfo("Email queue processing completed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process contact-related email queue.
|
||||||
|
*
|
||||||
|
* @param int $batchSize Number of emails to process in a single batch.
|
||||||
|
* @param int $maxRetries Maximum retry attempts for failed emails.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function processContactQueue(int $batchSize = 10, int $maxRetries = 3): void
|
||||||
|
{
|
||||||
|
Logger::logInfo("Processing contact email queue...");
|
||||||
|
|
||||||
|
for ($i = 0; $i < $batchSize; $i++) {
|
||||||
|
$emailData = self::$queueUtility->dequeue('contact_email');
|
||||||
|
|
||||||
|
if ($emailData === null) {
|
||||||
|
Logger::logInfo("No more emails to process in the contact queue.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$success = self::sendEmail(
|
||||||
|
$emailData['recipient'],
|
||||||
|
$emailData['subject'],
|
||||||
|
$emailData['templatePath'],
|
||||||
|
$emailData['templateData'],
|
||||||
|
$emailData['options']
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$success) {
|
||||||
|
$retries = $emailData['retries'] ?? 0;
|
||||||
|
|
||||||
|
if ($retries < $maxRetries) {
|
||||||
|
$priority = $emailData['priority'] ?? 0;
|
||||||
|
$emailData['retries'] = $retries + 1;
|
||||||
|
self::$queueUtility->enqueue('contact_email', $emailData, $priority);
|
||||||
|
Logger::logWarning(
|
||||||
|
"Contact email re-queued for recipient: {$emailData['recipient']} (Attempt {$emailData['retries']})"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Logger::logError("Contact email permanently failed for recipient: {$emailData['recipient']}");
|
||||||
|
self::logEmailStatus($emailData['recipient'], 'failed', 'Max retry limit reached.');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self::logEmailStatus($emailData['recipient'], 'sent');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::logInfo("Contact email queue processing completed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the status of a specific email by recipient.
|
||||||
|
*
|
||||||
|
* @param string $recipient Email address of the recipient.
|
||||||
|
* @return array|null The email status or null if not found.
|
||||||
|
*/
|
||||||
|
public static function getEmailStatus(string $recipient): ?array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = Database::getInstance();
|
||||||
|
$query = "SELECT * FROM email_status WHERE recipient = :recipient ORDER BY created_at DESC LIMIT 1";
|
||||||
|
$params = [':recipient' => $recipient];
|
||||||
|
return $db->fetchOne($query, $params);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Logger::logError("Failed to retrieve email status for $recipient: " . $e->getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the email queue.
|
||||||
|
*
|
||||||
|
* @param string $queueName The name of the queue to clear (default: 'email').
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function clearQueue(string $queueName = 'email'): void
|
||||||
|
{
|
||||||
|
Logger::logInfo("Clearing queue: $queueName");
|
||||||
|
|
||||||
|
try {
|
||||||
|
self::$queueUtility->clearQueue($queueName);
|
||||||
|
Logger::logInfo("Queue $queueName cleared successfully.");
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Logger::logError("Failed to clear queue $queueName: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all queued emails in a specific queue.
|
||||||
|
*
|
||||||
|
* @param string $queueName The name of the queue to inspect (default: 'email').
|
||||||
|
* @return array List of queued emails.
|
||||||
|
*/
|
||||||
|
public static function listQueuedEmails(string $queueName = 'email'): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Logger::logInfo("Listing emails in queue: $queueName");
|
||||||
|
return self::$queueUtility->listQueue($queueName);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Logger::logError("Failed to list emails in queue $queueName: " . $e->getMessage());
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace WizdomNetworks\WizeWeb\Utilities;
|
||||||
|
|
||||||
|
class Response
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Send a JSON response.
|
||||||
|
*
|
||||||
|
* @param array $data The response data.
|
||||||
|
* @param int $status HTTP status code (default: 200).
|
||||||
|
* @param array $headers Additional headers to include in the response.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static function json(array $data, int $statusCode = 200): void
|
||||||
|
{
|
||||||
|
if (headers_sent()) {
|
||||||
|
Logger::logError("Headers already sent. Unable to send JSON response.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
http_response_code($statusCode);
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo json_encode($data);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an HTML response.
|
||||||
|
*
|
||||||
|
* @param string $content The HTML content.
|
||||||
|
* @param int $status HTTP status code (default: 200).
|
||||||
|
* @param array $headers Additional headers to include in the response.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function html(string $content, int $status = 200, array $headers = []): void
|
||||||
|
{
|
||||||
|
http_response_code($status);
|
||||||
|
header('Content-Type: text/html');
|
||||||
|
self::sendHeaders($headers);
|
||||||
|
echo $content;
|
||||||
|
self::logResponse(['content' => $content], $status);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a file download response.
|
||||||
|
*
|
||||||
|
* @param string $filePath The file path.
|
||||||
|
* @param string|null $downloadName The name for the downloaded file (optional).
|
||||||
|
* @param array $headers Additional headers to include in the response.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function file(string $filePath, ?string $downloadName = null, array $headers = []): void
|
||||||
|
{
|
||||||
|
if (!file_exists($filePath)) {
|
||||||
|
self::error('File not found.', 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$downloadName = $downloadName ?? basename($filePath);
|
||||||
|
header('Content-Type: application/octet-stream');
|
||||||
|
header("Content-Disposition: attachment; filename=\"$downloadName\"");
|
||||||
|
header('Content-Length: ' . filesize($filePath));
|
||||||
|
self::sendHeaders($headers);
|
||||||
|
readfile($filePath);
|
||||||
|
self::logResponse(['file' => $downloadName], 200);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an error response.
|
||||||
|
*
|
||||||
|
* @param string $message The error message.
|
||||||
|
* @param int $status HTTP status code (default: 500).
|
||||||
|
* @param array $headers Additional headers to include in the response.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function error(string $message, int $status = 500, array $headers = []): void
|
||||||
|
{
|
||||||
|
self::json(['success' => false, 'message' => $message], $status, $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predefined response for 400 Bad Request.
|
||||||
|
*
|
||||||
|
* @param string $message The error message.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function badRequest(string $message): void
|
||||||
|
{
|
||||||
|
self::error($message, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predefined response for 404 Not Found.
|
||||||
|
*
|
||||||
|
* @param string $message The error message.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function notFound(string $message): void
|
||||||
|
{
|
||||||
|
self::error($message, 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predefined response for 500 Internal Server Error.
|
||||||
|
*
|
||||||
|
* @param string $message The error message.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function serverError(string $message): void
|
||||||
|
{
|
||||||
|
self::error($message, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send custom headers.
|
||||||
|
*
|
||||||
|
* @param array $headers Headers to include in the response.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function sendHeaders(array $headers): void
|
||||||
|
{
|
||||||
|
foreach ($headers as $key => $value) {
|
||||||
|
header("$key: $value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the response if debugging is enabled.
|
||||||
|
*
|
||||||
|
* @param array $data The response data.
|
||||||
|
* @param int $status HTTP status code.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function logResponse(array $data, int $status): void
|
||||||
|
{
|
||||||
|
if (getenv('DEBUG') === 'true') {
|
||||||
|
Logger::logInfo("Response sent with status $status: " . json_encode($data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ============================================
|
||||||
|
* File: Sanitizer.php
|
||||||
|
* Path: /app/Utils/
|
||||||
|
* Purpose: Utility class for sanitizing all user input securely
|
||||||
|
* Version: 1.1
|
||||||
|
* Author: Wizdom Networks (merged from HelpDesk+ and WizdomWeb)
|
||||||
|
* Usage: Called wherever input data needs cleaning before use or DB insertion
|
||||||
|
* ============================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WizdomNetworks\WizeWeb\Utilities;
|
||||||
|
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\Logger;
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\ErrorHandler;
|
||||||
|
|
||||||
|
class Sanitizer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Basic string sanitization (removes HTML and encodes entities)
|
||||||
|
*/
|
||||||
|
public static function sanitizeString(string $value): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$sanitized = htmlspecialchars(strip_tags(trim($value)), ENT_QUOTES, 'UTF-8');
|
||||||
|
Logger::debug("Sanitized string: Original: $value | Sanitized: $sanitized");
|
||||||
|
return $sanitized;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ErrorHandler::exception($e);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deep sanitize string using multiple layers (chained method)
|
||||||
|
*/
|
||||||
|
public static function sanitizeChained(string $value): string
|
||||||
|
{
|
||||||
|
return htmlspecialchars(strip_tags(trim(filter_var($value, FILTER_SANITIZE_STRING))), ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitize input with tag stripping and encoding
|
||||||
|
*/
|
||||||
|
public static function sanitizeInput(string $value): string
|
||||||
|
{
|
||||||
|
return htmlspecialchars(strip_tags(trim($value)), ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitize email
|
||||||
|
*/
|
||||||
|
public static function sanitizeEmail(string $value): string
|
||||||
|
{
|
||||||
|
$sanitized = filter_var(trim($value), FILTER_SANITIZE_EMAIL);
|
||||||
|
Logger::debug("Sanitized email: Original: $value | Sanitized: $sanitized");
|
||||||
|
return $sanitized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitize URL
|
||||||
|
*/
|
||||||
|
public static function sanitizeURL(string $value): string
|
||||||
|
{
|
||||||
|
$sanitized = filter_var(trim($value), FILTER_SANITIZE_URL);
|
||||||
|
Logger::debug("Sanitized URL: Original: $value | Sanitized: $sanitized");
|
||||||
|
return $sanitized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively sanitize array
|
||||||
|
*/
|
||||||
|
public static function sanitizeArray(array $data): array
|
||||||
|
{
|
||||||
|
$clean = [];
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
if (is_array($value)) {
|
||||||
|
$clean[$key] = self::sanitizeArray($value);
|
||||||
|
} else {
|
||||||
|
$clean[$key] = self::sanitizeString((string) $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $clean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ============================================
|
||||||
|
* File: SubmissionCheck.php
|
||||||
|
* Path: /app/Utilities/
|
||||||
|
* Purpose: Utility to check for recent form submissions by email
|
||||||
|
* Namespace: WizdomNetworks\WizeWeb\Utilities
|
||||||
|
* Version: 1.0
|
||||||
|
* Author: Wizdom Networks
|
||||||
|
* ============================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WizdomNetworks\WizeWeb\Utilities;
|
||||||
|
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\Database;
|
||||||
|
use PDO;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class SubmissionCheck
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check if the given email has a recent submission in the specified table.
|
||||||
|
*
|
||||||
|
* @param string $email - The email address to check.
|
||||||
|
* @param string $table - The name of the table (e.g., contact_messages, subscribers).
|
||||||
|
* @param string $emailField - The name of the email field in the table.
|
||||||
|
* @param string $timestampField - The name of the datetime/timestamp field.
|
||||||
|
* @param int $days - The number of days to consider as "recent" (default: 7).
|
||||||
|
* @return array|null - Returns array with date of last submission if found, or null if none.
|
||||||
|
* @throws Exception - If query fails.
|
||||||
|
*/
|
||||||
|
public static function hasRecentSubmission(string $email, string $table, string $emailField, string $timestampField, int $days = 7): ?array
|
||||||
|
{
|
||||||
|
$pdo = Database::getConnection();
|
||||||
|
|
||||||
|
$sql = "SELECT $timestampField FROM $table WHERE $emailField = :email ORDER BY $timestampField DESC LIMIT 1";
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute(['email' => $email]);
|
||||||
|
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($row && isset($row[$timestampField])) {
|
||||||
|
$last = new \DateTime($row[$timestampField]);
|
||||||
|
$cutoff = (new \DateTime())->modify("-{$days} days");
|
||||||
|
|
||||||
|
if ($last >= $cutoff) {
|
||||||
|
return ['submitted_at' => $last->format('Y-m-d H:i:s')];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,238 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace WizdomNetworks\WizeWeb\Utilities;
|
||||||
|
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\Logger;
|
||||||
|
use WizdomNetworks\WizeWeb\Utilities\ErrorHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validator Utility
|
||||||
|
*
|
||||||
|
* Provides methods for validating user input.
|
||||||
|
*/
|
||||||
|
class Validator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check if a value is non-empty.
|
||||||
|
*
|
||||||
|
* @param string $value The value to check.
|
||||||
|
* @return bool True if the value is not empty, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function isRequired(string $value): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Logger::info("[DEBUG] Checking if value is required: $value");
|
||||||
|
|
||||||
|
$isValid = !empty(trim($value));
|
||||||
|
|
||||||
|
if (!$isValid) {
|
||||||
|
Logger::warning("[WARNING] Value is required but empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isValid;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ErrorHandler::exception($e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate an email address.
|
||||||
|
*
|
||||||
|
* @param string $email The email address to validate.
|
||||||
|
* @return bool True if the email is valid, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function isEmail(string $email): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Logger::info("[DEBUG] Validating email address: $email");
|
||||||
|
|
||||||
|
$isValid = filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
|
||||||
|
|
||||||
|
if (!$isValid) {
|
||||||
|
Logger::warning("[WARNING] Invalid email address: $email");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isValid;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ErrorHandler::exception($e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a URL.
|
||||||
|
*
|
||||||
|
* @param string $url The URL to validate.
|
||||||
|
* @return bool True if the URL is valid, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function isURL(string $url): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Logger::info("[DEBUG] Validating URL: $url");
|
||||||
|
|
||||||
|
$isValid = filter_var($url, FILTER_VALIDATE_URL) !== false;
|
||||||
|
|
||||||
|
if (!$isValid) {
|
||||||
|
Logger::warning("[WARNING] Invalid URL: $url");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isValid;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ErrorHandler::exception($e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a string matches a given regular expression.
|
||||||
|
*
|
||||||
|
* @param string $string The string to validate.
|
||||||
|
* @param string $pattern The regular expression to match.
|
||||||
|
* @return bool True if the string matches the pattern, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function matchesRegex(string $string, string $pattern): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Logger::info("[DEBUG] Validating string against regex: Pattern=$pattern");
|
||||||
|
|
||||||
|
$isValid = preg_match($pattern, $string) === 1;
|
||||||
|
|
||||||
|
if (!$isValid) {
|
||||||
|
Logger::warning("[WARNING] String does not match regex: $string");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isValid;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ErrorHandler::exception($e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a string has a minimum length.
|
||||||
|
*
|
||||||
|
* @param string $string The string to check.
|
||||||
|
* @param int $minLength The minimum length.
|
||||||
|
* @return bool True if the string meets the minimum length, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function hasMinLength(string $string, int $minLength): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Logger::info("[DEBUG] Checking if string has minimum length: $minLength");
|
||||||
|
|
||||||
|
$isValid = strlen(trim($string)) >= $minLength;
|
||||||
|
|
||||||
|
if (!$isValid) {
|
||||||
|
Logger::warning("[WARNING] String is shorter than minimum length: $string");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isValid;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ErrorHandler::exception($e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a string has a maximum length.
|
||||||
|
*
|
||||||
|
* @param string $string The string to check.
|
||||||
|
* @param int $maxLength The maximum length.
|
||||||
|
* @return bool True if the string meets the maximum length, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function hasMaxLength(string $string, int $maxLength): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Logger::info("[DEBUG] Checking if string has maximum length: $maxLength");
|
||||||
|
|
||||||
|
$isValid = strlen(trim($string)) <= $maxLength;
|
||||||
|
|
||||||
|
if (!$isValid) {
|
||||||
|
Logger::warning("[WARNING] String exceeds maximum length: $string");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isValid;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ErrorHandler::exception($e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a string length.
|
||||||
|
*
|
||||||
|
* @param string $input The string to validate.
|
||||||
|
* @param int $min Minimum length.
|
||||||
|
* @param int $max Maximum length.
|
||||||
|
* @return bool True if the string length is valid, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function validateStringLength(string $input, int $min, int $max): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Logger::info("[DEBUG] Validating string length: Input='$input', Min=$min, Max=$max");
|
||||||
|
|
||||||
|
$length = strlen($input);
|
||||||
|
$isValid = $length >= $min && $length <= $max;
|
||||||
|
|
||||||
|
if (!$isValid) {
|
||||||
|
Logger::warning("[WARNING] Invalid string length: $length (Expected between $min and $max)");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isValid;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ErrorHandler::exception($e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a boolean value.
|
||||||
|
*
|
||||||
|
* @param mixed $input The input to validate as a boolean.
|
||||||
|
* @return bool True if the input is a valid boolean, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function validateBoolean($input): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Logger::info("[DEBUG] Validating boolean input: $input");
|
||||||
|
|
||||||
|
$isValid = is_bool(filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE));
|
||||||
|
|
||||||
|
if (!$isValid) {
|
||||||
|
Logger::warning("[WARNING] Invalid boolean input: $input");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isValid;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ErrorHandler::exception($e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a date format.
|
||||||
|
*
|
||||||
|
* @param string $date The date string to validate.
|
||||||
|
* @param string $format The expected date format (e.g., 'Y-m-d').
|
||||||
|
* @return bool True if the date matches the format, false otherwise.
|
||||||
|
*/
|
||||||
|
public static function validateDate(string $date, string $format = 'Y-m-d'): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Logger::info("[DEBUG] Validating date: $date with format: $format");
|
||||||
|
|
||||||
|
$dateTime = \DateTime::createFromFormat($format, $date);
|
||||||
|
$isValid = $dateTime && $dateTime->format($format) === $date;
|
||||||
|
|
||||||
|
if (!$isValid) {
|
||||||
|
Logger::warning("[WARNING] Invalid date: $date (Expected format: $format)");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isValid;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
ErrorHandler::exception($e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
// Placeholder for email template
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<p>New Contact Form Submission:</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Name:</strong> {{name}}</li>
|
||||||
|
<li><strong>Email:</strong> {{email}}</li>
|
||||||
|
<li><strong>Message:</strong> {{message}}</li>
|
||||||
|
</ul>
|
||||||
Loading…
Reference in New Issue