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}
+ Error Message:
+
{$errorMessage}
+ "; + + if (!empty($data)) { + $body .= "
Associated Data:
"; + } + + return $body; + } + + private static function buildSalesHtmlBody(array $data): string + { + $submittedAt = date('Y-m-d H:i:s'); + return " +

New contact submission received on {$submittedAt}.

+ +
+

IP: {$data['ip_address']}
User-Agent: {$data['user_agent']}

+ "; + } + + private static function buildConfirmationHtmlBody(array $data): string + { + $submittedAt = date('Y-m-d H:i:s'); + return " +

Hi {$data['first_name']},

+

Thank you for contacting Wizdom Networks. This message confirms that we received your inquiry on {$submittedAt}.

+ +

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']}

+ "; + } + + public static function sendContactNotification(array $data): bool + { + try { + $mail = new PHPMailer(true); + self::configureMailer($mail); + + $recipients = self::parseRecipients($_ENV['SALES_EMAILS'] ?? ''); + foreach ($recipients as $email) { + $mail->addAddress($email); + } + + if (empty($mail->getToAddresses())) { + Logger::error("EmailHelper: No valid SALES_EMAILS configured."); + return false; + } + + $mail->isHTML(true); + $mail->Subject = 'New Contact Form Submission'; + $mail->Body = self::buildSalesHtmlBody($data); + + $mail->send(); + return true; + } catch (Exception $e) { + Logger::error("Email send failure to sales: " . $e->getMessage()); + self::alertAdmins("sendContactNotification", $e->getMessage(), $data); + return false; + } + } + + public static function sendConfirmationToUser(array $data): bool + { + try { + $mail = new PHPMailer(true); + self::configureMailer($mail); + + $mail->addAddress($data['email'], "{$data['first_name']} {$data['last_name']}"); + $mail->isHTML(true); + $mail->Subject = 'Your Wizdom Networks Contact Form Submission'; + $mail->Body = self::buildConfirmationHtmlBody($data); + + $mail->send(); + return true; + } catch (Exception $e) { + Logger::error("Email send failure to user: " . $e->getMessage()); + self::alertAdmins("sendConfirmationToUser", $e->getMessage(), $data); + return false; + } + } + + /** + * Sends a system alert to ADMIN_EMAILS with error context and message. + * + * @param string $context + * @param string $errorMessage + * @param array|string $data Data array or JSON string for the report + * @return void + */ +public static function alertAdmins(string $context, string $errorMessage, $data = []): void + { + try { + $mail = new PHPMailer(true); + self::configureMailer($mail); + + $recipients = self::parseRecipients($_ENV['ADMIN_EMAILS'] ?? ''); + foreach ($recipients as $email) { + $mail->addAddress($email); + } + + if (empty($mail->getToAddresses())) { + Logger::error("EmailHelper: No valid ADMIN_EMAILS configured."); + return; + } + + $mail->isHTML(true); + $mail->Subject = "[System Alert] Error in {$context}"; + $mail->Body = self::buildErrorReportHtml($context, $errorMessage, $data); + + $mail->send(); + } catch (Exception $e) { + Logger::error("EmailHelper::alertAdmins failed: " . $e->getMessage()); + } + } +} diff --git a/app/Utilities/HoneypotHelper.php b/app/Utilities/HoneypotHelper.php new file mode 100644 index 0000000..8e1decb --- /dev/null +++ b/app/Utilities/HoneypotHelper.php @@ -0,0 +1,73 @@ +', + self::FIELD_NAME, + self::FIELD_NAME + ); + } +} diff --git a/app/Utilities/SessionHelper.php b/app/Utilities/SessionHelper.php new file mode 100644 index 0000000..b956a8b --- /dev/null +++ b/app/Utilities/SessionHelper.php @@ -0,0 +1,90 @@ + 0, + 'path' => '/', + 'domain' => $_SERVER['HTTP_HOST'], // <- ensures subdomain support + 'secure' => true, // <- required for HTTPS + 'httponly' => true, + 'samesite' => 'Lax' + ]); + session_start([ + 'cookie_secure' => true, + 'cookie_httponly' => true, + 'cookie_samesite' => 'Lax' + ]); + + Logger::info("Session started manually via SessionHelper."); + } else { + Logger::info("Session already active."); + } + + Logger::info("Session status: " . session_status()); +} + + + /** + * Set a session variable. + * + * @param string $key + * @param mixed $value + */ + public static function set(string $key, $value): void + { + $_SESSION[$key] = $value; + } + + /** + * Get a session variable (does not unset). + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public static function get(string $key, $default = null) + { + return $_SESSION[$key] ?? $default; + } + + /** + * Get and remove a session flash variable. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public static function flash(string $key, $default = null) + { + $value = $_SESSION[$key] ?? $default; + unset($_SESSION[$key]); + return $value; + } + + /** + * Check if a session key is set. + * + * @param string $key + * @return bool + */ + public static function has(string $key): bool + { + return isset($_SESSION[$key]); + } +} diff --git a/public/app.log b/public/app.log index b9e925e..a3dd4d0 100644 --- a/public/app.log +++ b/public/app.log @@ -1,2 +1,113 @@ [2025-05-08 00:33:46] [INFO]: Bootstrapping application [2025-05-08 00:33:46] [ERROR]: Route not found: index.php +[2025-05-14 17:15:31] [INFO]: Session started manually via SessionHelper. +[2025-05-14 17:15:31] [INFO]: Session status: 2 +[2025-05-14 17:15:31] [INFO]: Bootstrapping application +[2025-05-14 17:15:31] [INFO]: Executing controller: WizdomNetworks\WizeWeb\Controllers\LandingController::index +[2025-05-14 17:15:31] [INFO]: Session already active. +[2025-05-14 17:15:31] [INFO]: Session status: 2 +[2025-05-14 17:15:31] [INFO]: Session status: 2 +[2025-05-14 17:15:31] [INFO]: πŸ“₯ Landing page session ID: 4s18mr50hk6p8mv7f0kbfntl3c +[2025-05-14 17:15:31] [INFO]: 🟑 Landing page session before render: [] +[2025-05-14 17:15:47] [INFO]: Session started manually via SessionHelper. +[2025-05-14 17:15:47] [INFO]: Session status: 2 +[2025-05-14 17:15:47] [INFO]: Bootstrapping application +[2025-05-14 17:15:47] [INFO]: Executing controller: WizdomNetworks\WizeWeb\Controllers\ContactController::submit +[2025-05-14 17:15:47] [INFO]: Executing controller: ContactController::submit +[2025-05-14 17:15:47] [INFO]: πŸ“¦ PHP Session ID: 4s18mr50hk6p8mv7f0kbfntl3c +[2025-05-14 17:15:47] [INFO]: Sanitized input: Original: John | Sanitized: John +[2025-05-14 17:15:47] [INFO]: Sanitized input: Original: Clement | Sanitized: Clement +[2025-05-14 17:15:47] [INFO]: Sanitized input: Original: essae@wizdom.ca | Sanitized: essae@wizdom.ca +[2025-05-14 17:15:47] [INFO]: Sanitized input: Original: 4168778483 | Sanitized: 4168778483 +[2025-05-14 17:15:47] [INFO]: Sanitized input: Original: second new subject | Sanitized: second new subject +[2025-05-14 17:15:47] [INFO]: Sanitized input: Original: econd new subject | Sanitized: econd new subject +[2025-05-14 17:15:47] [INFO]: Sanitized input: first_name = John +[2025-05-14 17:15:47] [INFO]: Sanitized input: last_name = Clement +[2025-05-14 17:15:47] [INFO]: Sanitized input: email = essae@wizdom.ca +[2025-05-14 17:15:47] [INFO]: Sanitized input: phone = 4168778483 +[2025-05-14 17:15:47] [INFO]: Sanitized input: subject = second new subject +[2025-05-14 17:15:47] [INFO]: Sanitized input: message = econd new subject +[2025-05-14 17:15:47] [INFO]: Sanitized input: ip_address = 10.10.3.1 +[2025-05-14 17:15:47] [INFO]: Sanitized input: user_agent = Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 +[2025-05-14 17:15:47] [INFO]: [DEBUG] Validating email address: essae@wizdom.ca +[2025-05-14 17:15:47] [INFO]: Database connection established successfully. +[2025-05-14 17:15:47] [INFO]: βœ… Writing session flag: contact_success = true +[2025-05-14 17:15:47] [INFO]: βœ… Session content before redirect: {"contact_success":true} +[2025-05-14 17:15:47] [INFO]: Session started manually via SessionHelper. +[2025-05-14 17:15:47] [INFO]: Session status: 2 +[2025-05-14 17:15:47] [INFO]: Bootstrapping application +[2025-05-14 17:15:47] [INFO]: Executing controller: WizdomNetworks\WizeWeb\Controllers\LandingController::index +[2025-05-14 17:15:47] [INFO]: Session already active. +[2025-05-14 17:15:47] [INFO]: Session status: 2 +[2025-05-14 17:15:47] [INFO]: Session status: 2 +[2025-05-14 17:15:47] [INFO]: πŸ“₯ Landing page session ID: 4s18mr50hk6p8mv7f0kbfntl3c +[2025-05-14 17:15:47] [INFO]: 🟑 Landing page session before render: [] +[2025-05-14 17:21:55] [INFO]: Session started manually via SessionHelper. +[2025-05-14 17:21:55] [INFO]: Session status: 2 +[2025-05-14 17:21:55] [INFO]: Bootstrapping application +[2025-05-14 17:21:55] [INFO]: Executing controller: WizdomNetworks\WizeWeb\Controllers\LandingController::index +[2025-05-14 17:21:55] [INFO]: Session already active. +[2025-05-14 17:21:55] [INFO]: Session status: 2 +[2025-05-14 17:21:55] [INFO]: Session status: 2 +[2025-05-14 17:21:55] [INFO]: πŸ“₯ Landing page session ID: 4s18mr50hk6p8mv7f0kbfntl3c +[2025-05-14 17:21:55] [INFO]: 🟑 Landing page session before render: {"contact_success":true} +[2025-05-14 17:22:23] [INFO]: Session started manually via SessionHelper. +[2025-05-14 17:22:23] [INFO]: Session status: 2 +[2025-05-14 17:22:23] [INFO]: Bootstrapping application +[2025-05-14 17:22:23] [INFO]: Executing controller: WizdomNetworks\WizeWeb\Controllers\LandingController::index +[2025-05-14 17:22:23] [INFO]: Session already active. +[2025-05-14 17:22:23] [INFO]: Session status: 2 +[2025-05-14 17:22:23] [INFO]: Session status: 2 +[2025-05-14 17:22:23] [INFO]: πŸ“₯ Landing page session ID: 4s18mr50hk6p8mv7f0kbfntl3c +[2025-05-14 17:22:23] [INFO]: 🟑 Landing page session before render: [] +[2025-05-14 17:22:42] [INFO]: Session started manually via SessionHelper. +[2025-05-14 17:22:42] [INFO]: Session status: 2 +[2025-05-14 17:22:42] [INFO]: Bootstrapping application +[2025-05-14 17:22:42] [INFO]: Executing controller: WizdomNetworks\WizeWeb\Controllers\ContactController::submit +[2025-05-14 17:22:42] [INFO]: Executing controller: ContactController::submit +[2025-05-14 17:22:42] [INFO]: πŸ“¦ PHP Session ID: 4s18mr50hk6p8mv7f0kbfntl3c +[2025-05-14 17:22:42] [INFO]: Sanitized input: Original: Ben | Sanitized: Ben +[2025-05-14 17:22:42] [INFO]: Sanitized input: Original: brown | Sanitized: brown +[2025-05-14 17:22:42] [INFO]: Sanitized input: Original: code@cloudiq.ca | Sanitized: code@cloudiq.ca +[2025-05-14 17:22:42] [INFO]: Sanitized input: Original: 4168778483 | Sanitized: 4168778483 +[2025-05-14 17:22:42] [INFO]: Sanitized input: Original: second new subject | Sanitized: second new subject +[2025-05-14 17:22:42] [INFO]: Sanitized input: Original: second new subject | Sanitized: second new subject +[2025-05-14 17:22:42] [INFO]: Sanitized input: first_name = Ben +[2025-05-14 17:22:42] [INFO]: Sanitized input: last_name = brown +[2025-05-14 17:22:42] [INFO]: Sanitized input: email = code@cloudiq.ca +[2025-05-14 17:22:42] [INFO]: Sanitized input: phone = 4168778483 +[2025-05-14 17:22:42] [INFO]: Sanitized input: subject = second new subject +[2025-05-14 17:22:42] [INFO]: Sanitized input: message = second new subject +[2025-05-14 17:22:42] [INFO]: Sanitized input: ip_address = 10.10.3.1 +[2025-05-14 17:22:42] [INFO]: Sanitized input: user_agent = Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 +[2025-05-14 17:22:42] [INFO]: [DEBUG] Validating email address: code@cloudiq.ca +[2025-05-14 17:22:42] [INFO]: Database connection established successfully. +[2025-05-14 17:22:43] [INFO]: βœ… Writing session flag: contact_success = true +[2025-05-14 17:22:43] [INFO]: βœ… Session content before redirect: {"contact_success":true} +[2025-05-14 17:22:43] [INFO]: Session started manually via SessionHelper. +[2025-05-14 17:22:43] [INFO]: Session status: 2 +[2025-05-14 17:22:43] [INFO]: Bootstrapping application +[2025-05-14 17:22:43] [INFO]: Executing controller: WizdomNetworks\WizeWeb\Controllers\LandingController::index +[2025-05-14 17:22:43] [INFO]: Session already active. +[2025-05-14 17:22:43] [INFO]: Session status: 2 +[2025-05-14 17:22:43] [INFO]: Session status: 2 +[2025-05-14 17:22:43] [INFO]: πŸ“₯ Landing page session ID: 4s18mr50hk6p8mv7f0kbfntl3c +[2025-05-14 17:22:43] [INFO]: 🟑 Landing page session before render: {"contact_success":true} +[2025-05-14 17:27:26] [INFO]: Session started manually via SessionHelper. +[2025-05-14 17:27:26] [INFO]: Session status: 2 +[2025-05-14 17:27:26] [INFO]: Bootstrapping application +[2025-05-14 17:27:26] [INFO]: Executing controller: WizdomNetworks\WizeWeb\Controllers\LandingController::index +[2025-05-14 17:27:26] [INFO]: Session already active. +[2025-05-14 17:27:26] [INFO]: Session status: 2 +[2025-05-14 17:27:26] [INFO]: Session status: 2 +[2025-05-14 17:27:26] [INFO]: πŸ“₯ Landing page session ID: 4s18mr50hk6p8mv7f0kbfntl3c +[2025-05-14 17:27:26] [INFO]: 🟑 Landing page session before render: [] +[2025-05-14 17:31:29] [INFO]: Session started manually via SessionHelper. +[2025-05-14 17:31:29] [INFO]: Session status: 2 +[2025-05-14 17:31:29] [INFO]: Bootstrapping application +[2025-05-14 17:31:29] [INFO]: Executing controller: WizdomNetworks\WizeWeb\Controllers\LandingController::index +[2025-05-14 17:31:29] [INFO]: Session already active. +[2025-05-14 17:31:29] [INFO]: Session status: 2 +[2025-05-14 17:31:29] [INFO]: Session status: 2 +[2025-05-14 17:31:29] [INFO]: πŸ“₯ Landing page session ID: 4s18mr50hk6p8mv7f0kbfntl3c +[2025-05-14 17:31:29] [INFO]: 🟑 Landing page session before render: [] diff --git a/public/assets/css/main.css b/public/assets/css/main.css index e601cb0..9ddd415 100644 --- a/public/assets/css/main.css +++ b/public/assets/css/main.css @@ -2195,6 +2195,7 @@ section, .contact .php-email-form input[type=text], .contact .php-email-form input[type=email], +.contact .php-email-form input[type=tel], .contact .php-email-form textarea { font-size: 14px; padding: 10px 15px; @@ -2207,12 +2208,14 @@ section, .contact .php-email-form input[type=text]:focus, .contact .php-email-form input[type=email]:focus, +.contact .php-email-form input[type=tel]:focus, .contact .php-email-form textarea:focus { border-color: var(--accent-color); } .contact .php-email-form input[type=text]::placeholder, .contact .php-email-form input[type=email]::placeholder, +.contact .php-email-form input[type=tel]::placeholder, .contact .php-email-form textarea::placeholder { color: color-mix(in srgb, var(--default-color), transparent 70%); } diff --git a/public/assets/js/contact-form.js b/public/assets/js/contact-form.js index e64a4dc..994359e 100644 --- a/public/assets/js/contact-form.js +++ b/public/assets/js/contact-form.js @@ -1,3 +1,12 @@ +document.addEventListener('DOMContentLoaded', function () { + const params = new URLSearchParams(window.location.search); + if (params.get('contact_submitted') || params.get('contact_error')) { + const contactSection = document.getElementById('contact'); + if (contactSection) { + contactSection.scrollIntoView({ behavior: 'smooth' }); + } + } + }); document.addEventListener('DOMContentLoaded', function () { const form = document.querySelector('.php-email-form'); if (!form) return; diff --git a/public/index.php b/public/index.php index 9a542a0..afaeb51 100644 --- a/public/index.php +++ b/public/index.php @@ -1,52 +1,53 @@ load(); +// Start session before any router logic +use WizdomNetworks\WizeWeb\Utilities\SessionHelper; +SessionHelper::start(); + +// Import core system utilities +use WizdomNetworks\WizeWeb\Core\Router; +use WizdomNetworks\WizeWeb\Utilities\Logger; +use WizdomNetworks\WizeWeb\Utilities\ErrorHandler; + +// Import controllers +use WizdomNetworks\WizeWeb\Controllers\LandingController; +use WizdomNetworks\WizeWeb\Controllers\ContactController; + +// Boot the application Logger::info("Bootstrapping application"); +// Initialize router and define routes $router = new Router(); -// Arsha landing routes +// Landing page routes $router->add('', LandingController::class, 'index'); $router->add('/', LandingController::class, 'index'); $router->add('index.php', LandingController::class, 'index'); -// Contact form -$router->add('/contact', ContactController::class, 'index', 'GET'); // Show contact form -$router->add('/contact', ContactController::class, 'submit', 'POST'); // Handle submission - - -// Optional: fallback for /contact without leading slash (rare case) -// $router->add('contact', ContactController::class, 'submit', 'POST'); - -// Debug block β€” safe to leave commented -/* -echo "
";
-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 @@ "; ?> + + +
@@ -709,17 +713,43 @@
-
+ + + + +
βœ… Thank you! Your message has been received. We'll be in touch shortly.
+ +
⚠️
+ + + + + + + + +
+
First name is required.
+
Last name is required.
@@ -727,34 +757,34 @@
+
Please enter a valid email address.
+
Phone number is required.
- +
-
- - +
+ + +
Subject is required.
+
+
+
+
Please enter your message.
- +
@@ -902,3 +932,18 @@ +