diff --git a/app/Controllers/ContactController.php b/app/Controllers/ContactController.php
index 052ad95..b0ff36f 100644
--- a/app/Controllers/ContactController.php
+++ b/app/Controllers/ContactController.php
@@ -1,9 +1,9 @@
getConnection();
- $contact = new ContactModel($pdo);
- $result = $contact->saveContactForm([
- 'first_name' => $firstName,
- 'last_name' => $lastName,
- 'email' => $email,
- 'phone' => $phone,
- 'subject' => $subject,
- 'message' => $message,
- 'ip_address' => $ip,
- 'user_agent' => $userAgent,
- ]);
-
- if (!$result) {
- Logger::error("Contact form submission failed for email: $email");
- Response::serverError('An error occurred while submitting your message. Please try again later.');
- }
-
- Response::json([
- 'success' => true,
- 'message' => 'Your message has been successfully submitted. Thank you!'
- ]);
- } catch (Exception $e) {
- Logger::error("Exception in contact submission: " . $e->getMessage());
- Response::serverError('A server error occurred. Please try again later.');
+{
+ Logger::info("Executing controller: ContactController::submit");
+ Logger::info("π¦ PHP Session ID: " . session_id());
+
+
+ try {
+ $formData = [
+ 'first_name' => Sanitizer::sanitizeString($_POST['first_name'] ?? ''),
+ 'last_name' => Sanitizer::sanitizeString($_POST['last_name'] ?? ''),
+ 'email' => Sanitizer::sanitizeString($_POST['email'] ?? ''),
+ 'phone' => Sanitizer::sanitizeString($_POST['phone'] ?? ''),
+ 'subject' => Sanitizer::sanitizeString($_POST['subject'] ?? ''),
+ 'message' => Sanitizer::sanitizeString($_POST['message'] ?? ''),
+ 'ip_address' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
+ 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
+ ];
+
+ foreach ($formData as $key => $value) {
+ Logger::info("Sanitized input: {$key} = {$value}");
}
+
+ // Validate required fields
+ if (
+ empty($formData['first_name']) ||
+ empty($formData['last_name']) ||
+ empty($formData['email']) ||
+ empty($formData['phone']) ||
+ empty($formData['subject']) ||
+ empty($formData['message']) ||
+ !Validator::isEmail($formData['email'])
+ ) {
+ Logger::info("Validation failed for contact form submission");
+ $_SESSION['contact_error'] = 'An internal error occurred. Please try again later.';
+
+ header("Location: /?contact_error=1#contact");
+
+ exit;
+
+ }
+
+ // Save to DB
+ $db = Database::getConnection();
+ $contactModel = new ContactModel($db);
+ $saveSuccess = $contactModel->saveContactForm($formData);
+
+ // Send to sales team
+ $emailSuccess = EmailHelper::sendContactNotification($formData);
+
+ // Send confirmation to user
+ $confirmationSuccess = EmailHelper::sendConfirmationToUser($formData);
+
+ if ($saveSuccess && $emailSuccess) {
+ $_SESSION['contact_success'] = true;
+
+ } else {
+ Logger::error("Form processed but saveSuccess={$saveSuccess}, emailSuccess={$emailSuccess}");
+ $_SESSION['contact_error'] = 'Your message was received but an internal error occurred. A confirmation may not have been sent.';
+
+ EmailHelper::alertAdmins('ContactController::submit - DB or email failure', 'Partial failure', $formData);
+ }
+
+ if (!$confirmationSuccess) {
+ Logger::error("Confirmation email failed to send to user: {$formData['email']}");
+ // Don't show user error β it's non-critical
+ }
+ Logger::info("β
Writing session flag: contact_success = true");
+ Logger::info("β
Session content before redirect: " . json_encode($_SESSION));
+
+ header("Location: /?contact_submitted=1#contact");
+
+ exit;
+
+ } catch (\Throwable $e) {
+ Logger::error("Fatal error in ContactController::submit: " . $e->getMessage());
+ EmailHelper::alertAdmins('ContactController::submit - Uncaught Exception', $e->getMessage(), $_POST ?? []);
+ $_SESSION['contact_error'] = 'An internal error occurred. Please try again later.';
+
+ Logger::info("β
Writing session flag: catch contact_error = " . $_SESSION['contact_error']);
+ Logger::info("β
Session content before redirect: " . json_encode($_SESSION));
+ header("Location: /?contact_error=2#contact");
+
+ exit;
}
}
+
+}
diff --git a/app/Controllers/LandingController.php b/app/Controllers/LandingController.php
index d71fcf0..7d2af3c 100644
--- a/app/Controllers/LandingController.php
+++ b/app/Controllers/LandingController.php
@@ -1,6 +1,6 @@
'Wizdom Networks | One-Pager'
@@ -21,4 +25,4 @@ class LandingController
View::render('pages/landing', $data, 'arsha');
}
-}
+}
\ No newline at end of file
diff --git a/app/Models/ContactModel.php b/app/Models/ContactModel.php
index 9681de2..9d7218a 100644
--- a/app/Models/ContactModel.php
+++ b/app/Models/ContactModel.php
@@ -1,149 +1,134 @@
db = $db;
}
/**
- * Retrieve a contact by ID.
- *
+ * Legacy method to insert simplified contact into `contacts` table.
+ *
+ * @param array $contactData ['name' => string, 'email' => string, 'message' => string]
+ * @return bool
+ */
+ public function addContact(array $contactData): bool
+ {
+ try {
+ $stmt = $this->db->prepare("
+ INSERT INTO contacts (name, email, message)
+ VALUES (:name, :email, :message)
+ ");
+
+ $name = trim(($contactData['name'] ?? '') ?: (($contactData['first_name'] ?? '') . ' ' . ($contactData['last_name'] ?? '')));
+ $stmt->bindParam(':name', $name);
+ $stmt->bindParam(':email', $contactData['email']);
+ $stmt->bindParam(':message', $contactData['message']);
+
+ return $stmt->execute();
+ } catch (Exception $e) {
+ Logger::error("ContactModel::addContact failed: " . $e->getMessage());
+ ErrorHandler::exception($e);
+ return false;
+ }
+ }
+
+ /**
+ * Saves full contact form submission to the `contact_messages` table.
+ *
+ * @param array $formData Associative array of form input
+ * @return bool True on success, false on failure
+ */
+ public function saveContactForm(array $formData): bool
+ {
+ try {
+ $stmt = $this->db->prepare("
+ INSERT INTO contact_messages (
+ first_name, last_name, email, phone, subject, message,
+ ip_address, user_agent
+ ) VALUES (
+ :first_name, :last_name, :email, :phone, :subject, :message,
+ :ip_address, :user_agent
+ )
+ ");
+
+ $stmt->bindParam(':first_name', $formData['first_name']);
+ $stmt->bindParam(':last_name', $formData['last_name']);
+ $stmt->bindParam(':email', $formData['email']);
+ $stmt->bindParam(':phone', $formData['phone']);
+ $stmt->bindParam(':subject', $formData['subject']);
+ $stmt->bindParam(':message', $formData['message']);
+ $stmt->bindParam(':ip_address', $formData['ip_address']);
+ $stmt->bindParam(':user_agent', $formData['user_agent']);
+
+ return $stmt->execute();
+ } catch (Exception $e) {
+ Logger::error("ContactModel::saveContactForm failed: " . $e->getMessage());
+ ErrorHandler::exception($e);
+ return false;
+ }
+ }
+
+ /**
+ * Retrieves a contact record by ID from `contact_messages`.
+ *
* @param int $id
* @return array|null
*/
public function getContactById(int $id): ?array
{
try {
- Logger::info("[DEBUG] Fetching contact with ID: $id");
-
- $stmt = $this->db->prepare("SELECT * FROM contacts WHERE id = :id");
- $stmt->bindParam(':id', $id, \PDO::PARAM_INT);
+ $stmt = $this->db->prepare("SELECT * FROM contact_messages WHERE id = :id");
+ $stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
+ $result = $stmt->fetch();
- $contact = $stmt->fetch(\PDO::FETCH_ASSOC);
-
- Logger::info("[DEBUG] Contact data retrieved: " . json_encode($contact));
-
- return $contact ?: null;
- } catch (\Exception $e) {
- Logger::error("[ERROR] Failed to fetch contact with ID $id: " . $e->getMessage());
+ return $result ?: null;
+ } catch (Exception $e) {
+ Logger::error("ContactModel::getContactById failed: " . $e->getMessage());
ErrorHandler::exception($e);
return null;
}
}
/**
- * Add a new contact to the database.
- *
- * @param array $contactData
- * @return bool
- */
- public function addContact(array $contactData): bool
- {
- try {
- Logger::info("[DEBUG] Adding new contact: " . json_encode($contactData));
-
- $stmt = $this->db->prepare(
- "INSERT INTO contacts (name, email, message) VALUES (:name, :email, :message)"
- );
- $stmt->bindParam(':name', $contactData['name']);
- $stmt->bindParam(':email', $contactData['email']);
- $stmt->bindParam(':message', $contactData['message']);
-
- $stmt->execute();
-
- Logger::info("[DEBUG] Contact successfully added.");
-
- return true;
- } catch (\Exception $e) {
- Logger::error("[ERROR] Failed to add contact: " . $e->getMessage());
- ErrorHandler::exception($e);
- return false;
- }
- }
-
- /**
- * Delete a contact by ID.
- *
+ * Deletes a contact record by ID from `contact_messages`.
+ *
* @param int $id
* @return bool
*/
public function deleteContactById(int $id): bool
{
try {
- Logger::info("[DEBUG] Deleting contact with ID: $id");
-
- $stmt = $this->db->prepare("DELETE FROM contacts WHERE id = :id");
- $stmt->bindParam(':id', $id, \PDO::PARAM_INT);
- $stmt->execute();
-
- Logger::info("[DEBUG] Contact with ID $id successfully deleted.");
-
- return true;
- } catch (\Exception $e) {
- Logger::error("[ERROR] Failed to delete contact with ID $id: " . $e->getMessage());
+ $stmt = $this->db->prepare("DELETE FROM contact_messages WHERE id = :id");
+ $stmt->bindParam(':id', $id, PDO::PARAM_INT);
+ return $stmt->execute();
+ } catch (Exception $e) {
+ Logger::error("ContactModel::deleteContactById failed: " . $e->getMessage());
ErrorHandler::exception($e);
return false;
}
}
- /**
- * Save a full contact form submission to contact_messages table.
- *
- * @param array $data
- * @return bool
- */
-public function saveContactForm(array $data): bool
-{
- try {
- $sql = "INSERT INTO contact_messages (
- first_name,
- last_name,
- email,
- phone,
- subject,
- message,
- ip_address,
- user_agent
- ) VALUES (
- :first_name,
- :last_name,
- :email,
- :phone,
- :subject,
- :message,
- :ip_address,
- :user_agent
- )";
-
- $stmt = $this->db->prepare($sql);
- $stmt->bindParam(':first_name', $data['first_name']);
- $stmt->bindParam(':last_name', $data['last_name']);
- $stmt->bindParam(':email', $data['email']);
- $stmt->bindParam(':phone', $data['phone']);
- $stmt->bindParam(':subject', $data['subject']);
- $stmt->bindParam(':message', $data['message']);
- $stmt->bindParam(':ip_address', $data['ip_address']);
- $stmt->bindParam(':user_agent', $data['user_agent']);
-
- return $stmt->execute();
- } catch (\Exception $e) {
- Logger::error("Failed to save contact form: " . $e->getMessage());
- return false;
- }
-}
-
}
diff --git a/app/Utilities/Database.php b/app/Utilities/Database.php
index cb656c1..4f4c1c7 100644
--- a/app/Utilities/Database.php
+++ b/app/Utilities/Database.php
@@ -1,78 +1,49 @@
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_PASS']);
- $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
+ public static function getConnection(): PDO
{
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());
+ $host = $_ENV['DB_HOST'];
+ $port = $_ENV['DB_PORT'];
+ $dbname = $_ENV['DB_NAME'];
+ $username = $_ENV['DB_USER'];
+ $password = $_ENV['DB_PASS'];
+
+ $dsn = "mysql:host={$host};port={$port};dbname={$dbname};charset=utf8mb4";
+ $options = [
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
+ PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
+ PDO::ATTR_EMULATE_PREPARES => false,
+ ];
+
+ Logger::info("Database connection established successfully.");
+ return new PDO($dsn, $username, $password, $options);
+ } catch (\Throwable $e) {
+ Logger::error("Database connection failed: " . $e->getMessage());
+ ErrorHandler::exception($e);
throw $e;
}
}
-
- /**
- * Retrieves the PDO connection instance.
- *
- * @return PDO The PDO instance.
- */
- public function getConnection(): PDO
- {
- return $this->connection;
- }
}
diff --git a/app/Utilities/EmailHelper.php b/app/Utilities/EmailHelper.php
new file mode 100644
index 0000000..bb9e136
--- /dev/null
+++ b/app/Utilities/EmailHelper.php
@@ -0,0 +1,218 @@
+isSMTP();
+ $mail->Host = $_ENV['SMTP_HOST'] ?? 'localhost';
+ $mail->Port = $_ENV['SMTP_PORT'] ?? 25;
+
+ $mail->SMTPAuth = filter_var($_ENV['SMTP_AUTH'] ?? false, FILTER_VALIDATE_BOOLEAN);
+ $mail->Username = $_ENV['SMTP_USER'] ?? '';
+ $mail->Password = $_ENV['SMTP_PASS'] ?? '';
+
+ $mail->SMTPAutoTLS = filter_var($_ENV['SMTP_AUTO_TLS'] ?? true, FILTER_VALIDATE_BOOLEAN);
+
+ $encryption = strtolower(trim($_ENV['SMTP_ENCRYPTION'] ?? ''));
+ if ($encryption === 'ssl') {
+ $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
+ } elseif ($encryption === 'tls') {
+ $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
+ } else {
+ $mail->SMTPSecure = '';
+ }
+
+ $fromEmail = $_ENV['SMTP_FROM_EMAIL'] ?? 'no-reply@localhost';
+ $fromName = $_ENV['SMTP_FROM_NAME'] ?? 'Wizdom Mailer';
+ $mail->setFrom($fromEmail, $fromName);
+
+ $mail->SMTPOptions = [
+ 'ssl' => [
+ 'verify_peer' => false,
+ 'verify_peer_name' => false,
+ 'allow_self_signed' => true
+ ]
+ ];
+ }
+
+ private static function parseRecipients(string $rawList): array
+ {
+ $emails = explode(',', $rawList);
+ $validEmails = [];
+
+ foreach ($emails as $email) {
+ $email = trim($email);
+ if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ $validEmails[] = $email;
+ }
+ }
+
+ return $validEmails;
+ }
+
+ private static function buildContactHtmlBody(array $data): string
+ {
+ return "
+ Name: {$data['first_name']} {$data['last_name']}
+ Email: {$data['email']}
+ Phone: {$data['phone']}
+ Subject: {$data['subject']}
+ Message:
+
{$data['message']}
+ ";
+ }
+
+ private static function buildErrorReportHtml(string $context, string $errorMessage, $data = []): string
+ {
+ if (is_string($data)) {
+ $decoded = json_decode($data, true);
+ $data = is_array($decoded) ? $decoded : ['raw_data' => $data];
+ }
+
+ $body = "
+ Context: {$context}{$errorMessage}
+ ";
+
+ if (!empty($data)) {
+ $body .= "New contact submission received on {$submittedAt}.
+{$data['message']}IP: {$data['ip_address']}
User-Agent: {$data['user_agent']}
Hi {$data['first_name']},
+Thank you for contacting Wizdom Networks. This message confirms that we received your inquiry on {$submittedAt}.
+{$data['message']}Weβll be in touch shortly. If itβs urgent, call us at 416-USE-WISE.
+IP: {$data['ip_address']}
User-Agent: {$data['user_agent']}
"; -echo "REQUEST_URI: " . $_SERVER['REQUEST_URI'] . "\n"; -echo "Parsed path: " . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) . "\n"; -echo "Trimmed: " . trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/') . "\n"; -echo ""; -exit; -*/ +// Contact form routes +$router->add('/contact', ContactController::class, 'index', 'GET'); +$router->add('/contact', ContactController::class, 'submit', 'POST'); +// Dispatch the incoming request $requestedPath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $router->dispatch($requestedPath); diff --git a/resources/views/layouts/arsha.php b/resources/views/layouts/arsha.php index bd50c7d..b9b37db 100644 --- a/resources/views/layouts/arsha.php +++ b/resources/views/layouts/arsha.php @@ -1,4 +1,7 @@ "; ?> + + +