This document provides a comprehensive guide to the refactored Event Booking System with MVC pattern, PDO, environment configuration, and logging.
- Located at:
.env - Contains all configuration variables (database, app settings, logging, security)
- Never commit this file to version control
- Create your own
.envfile with your actual credentials
Usage:
require_once 'includes/helpers.php';
loadEnv();
$dbHost = env('DB_HOST');
$debugMode = env('APP_DEBUG') === 'true';// Email validation
isValidEmail($email); // Returns bool
sanitizeEmail($email); // Returns sanitized email or false
sanitizeInput($input); // XSS prevention
// Password handling
validatePassword($password); // Checks strength, returns array
hashPassword($password); // BCrypt hashing
verifyPassword($password, $hash); // Password verification
// Number validation
sanitizeInt($input); // Returns int or false
sanitizeFloat($input); // Returns float or false
// Date validation
isValidDate($date); // Validates YYYY-MM-DD formatisLoggedIn(); // Check if user is authenticated
isAdmin(); // Check if user is admin
requireLogin(); // Redirect if not logged in
requireAdmin(); // Redirect if not admingenerateCSRFToken(); // Generate/retrieve CSRF token
verifyCSRFToken($token); // Verify CSRF token
csrfField(); // HTML hidden field for formsvalidateFileUpload($file, $allowedTypes, $maxSize);
saveUploadedFile($file, $uploadDir);getUserById($pdo, $userId);
getUserByEmail($pdo, $email);
emailExists($pdo, $email);logMessage($message, $level); // Log to fileBefore:
$conn = mysqli_connect($servername, $username, $password, $dbname);After (PDO):
require_once 'includes/helpers.php';
loadEnv();
$conn = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);Benefits:
- Prepared statements prevent SQL injection
- PDO supports multiple database types
- Better error handling
- Configuration from environment variables
app/
├── Models/
│ ├── Model.php # Base model class
│ ├── User.php # User operations
│ ├── Event.php # Event operations
│ └── Booking.php # Booking operations
├── Controllers/
│ ├── Controller.php # Base controller
│ ├── AuthController.php # Authentication logic
│ ├── EventController.php # Event management
│ └── BookingController.php # Booking management
└── Views/ # To be created for templates
├── auth/
│ ├── login.php
│ ├── register.php
│ └── forgot-password.php
├── admin/
│ ├── create-event.php
│ └── edit-event.php
├── bookings/
│ ├── select-seat.php
│ ├── confirm.php
│ └── my-bookings.php
└── events/
├── index.php
├── view.php
└── search.php
All models extend this class and get these methods automatically:
$model = new User($pdo);
// Find operations
$model->find($id); // Get by ID
$model->findBy($column, $value); // Get by column
$model->getAll($limit, $offset); // Get all with pagination
$model->count(); // Count total records
// Create/Update/Delete
$model->insert($data); // Insert record
$model->update($id, $data); // Update record
$model->delete($id); // Delete record
// Transactions
$model->beginTransaction();
$model->commit();
$model->rollback();$user = new User($pdo);
// Create user with validation
$user->create($username, $email, $password, $role);
// Authenticate
$userData = $user->authenticate($email, $password);
// Update profile
$user->updateProfile($userId, $data);
// Change password
$user->changePassword($userId, $oldPassword, $newPassword);
// Get user with stats
$user->getUserWithBookings($userId);
// Get all admins
$user->getAdmins();$event = new Event($pdo);
// Create event
$eventId = $event->createEvent($data, $userId);
// Retrieve events
$event->getEventWithCreator($eventId);
$event->getByCategory($category, $limit, $offset);
$event->search($keyword, $limit, $offset);
$event->getUpcoming($limit, $offset);
// Update/Delete
$event->updateEvent($eventId, $data, $userId);
$event->deleteEvent($eventId, $userId);
// Get user's events
$event->getByCreator($userId);$booking = new Booking($pdo);
// Create booking
$bookingId = $booking->createBooking($userId, $eventId, $seat, $status);
// Retrieve bookings
$booking->getUserBookings($userId);
$booking->getEventBookings($eventId);
$booking->getBookingDetails($bookingId);
// Update payment
$booking->updatePaymentStatus($bookingId, $status);
// Cancel booking
$booking->cancelBooking($bookingId, $userId);
// Bulk operations
$booking->bulkCreate($userId, $eventId, $qty, $seat, $status);
// Statistics
$booking->getEventStats($eventId);Common functionality for all controllers:
class AuthController extends Controller {
public function __construct($pdo, $logger) {
parent::__construct($pdo, $logger);
}
}Available Methods:
// View rendering
$this->render('view/path', $data);
// Redirects
$this->redirect($url);
// JSON responses
$this->json(['key' => 'value'], 200);
// Request checking
$this->isPost();
$this->isGet();
$this->isAjax();
$this->getMethod();
// Flash messages
$this->setFlash('Message', 'success');
$flash = $this->getFlash();$auth = new AuthController($pdo, $logger);
// Authentication
$auth->login(); // Handle login
$auth->register(); // Handle registration
$auth->logout(); // Handle logout
// Utilities
$auth->showLogin(); // Show login form
$auth->showRegister(); // Show register form
$auth->checkEmailAvailability(); // AJAX endpoint$event = new EventController($pdo, $logger);
// CRUD Operations
$event->create();
$event->update();
$event->delete();
// Retrieval
$event->index(); // List events
$event->view(); // View single event
$event->search(); // Search events
$event->filterByCategory(); // Filter by category
// Forms
$event->showCreate();
$event->showEdit();$booking = new BookingController($pdo, $logger);
// Booking operations
$booking->processBooking();
$booking->cancelBooking();
// Display
$booking->showSeatSelection();
$booking->showConfirmation();
$booking->myBookings();
$booking->viewBooking();
// Admin features
$booking->getEventStats();
$booking->exportBookings();$logger = new Logger($logDir);
$logger->log($message, $level, $context);
$logger->debug($message, $context);
$logger->info($message, $context);
$logger->warning($message, $context);
$logger->error($message, $context);
$logger->critical($message, $context);// Security events
$logger->security('Suspicious login attempt', ['email' => $email]);
// Authentication events
$logger->logAuth('login', $userEmail, ['ip' => $ipAddress]);
// Database queries
$logger->logQuery($query, $params, $executionTime);// Retrieve logs
$logs = $logger->getLogs($date, $level);
// Clean old logs
$deleted = $logger->clearOldLogs($daysOld = 30);Log Files Structure:
logs/
├── 2024-01-15-debug.log
├── 2024-01-15-info.log
├── 2024-01-15-warning.log
├── 2024-01-15-error.log
└── debug.log (combined for development)
<?php
include 'config/db.php';
$email = $_POST['email'];
$password = $_POST['password'];
$sql = "SELECT * FROM users WHERE email='$email'";
$result = mysqli_query($conn, $sql);
$user = mysqli_fetch_assoc($result);
if ($user && password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
header("Location: index.php");
} else {
echo "Invalid Email or Password!";
}
?><?php
session_start();
require_once 'config/db.php';
require_once 'includes/helpers.php';
require_once 'includes/Logger.php';
require_once 'app/Controllers/AuthController.php';
$logger = new Logger();
$auth = new AuthController($conn, $logger);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$auth->login();
}
$auth->showLogin();
?>- All database queries use prepared statements
- User input is parameterized
- All user input is sanitized using
htmlspecialchars() - CSRF tokens protect forms
- All forms include CSRF tokens
- Server verifies tokens before processing
- Passwords use BCrypt hashing (cost = 12)
- Password strength validation enforced
- Old passwords verified before changing
- File type validation
- File size limits
- Unique filenames with timestamps
- Authentication checks (requireLogin)
- Authorization checks (requireAdmin)
- Authorization checks in models
- Copy
.envfile from repo - Update
.envwith your credentials - Ensure
logs/directory exists
- Existing
config/db.phpnow uses PDO - All mysqli code automatically uses new connection
- Test database connectivity
<?php
session_start();
require_once 'config/db.php';
require_once 'includes/helpers.php';
require_once 'includes/Logger.php';
require_once 'app/Controllers/AuthController.php';
$logger = new Logger();
$auth = new AuthController($conn, $logger);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$auth->login();
}
$auth->showLogin();
?><?php
session_start();
require_once 'config/db.php';
require_once 'includes/helpers.php';
require_once 'includes/Logger.php';
require_once 'app/Controllers/AuthController.php';
$logger = new Logger();
$auth = new AuthController($conn, $logger);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$auth->register();
}
$auth->showRegister();
?>Create view files in app/Views/ matching the controller render calls.
$email = sanitizeEmail($_POST['email'] ?? '');
$age = sanitizeInt($_POST['age'] ?? 0);
$price = sanitizeFloat($_POST['price'] ?? 0);// ✅ Good
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
// ❌ Never do this
$sql = "SELECT * FROM users WHERE email = '$email'";$logger->info("User registered", ['email' => $email]);
$logger->security("Failed login attempt", ['email' => $email]);// Check ownership
$event = $eventModel->find($eventId);
if ($event['created_by'] !== $_SESSION['user_id']) {
$logger->warning("Unauthorized access attempt");
return false;
}// In forms
<?php echo csrfField(); ?>
// In controller
if (!verifyCSRFToken($_POST['csrf_token'])) {
$this->setFlash('Invalid token', 'error');
return;
}- Navigate to
/login.php - Use test credentials
- Check
logs/folder for login events
- Navigate to
/register.php - Try weak password (should fail)
- Complete registration
- Check logs for registration event
- Login as user
- Navigate to event
- Book tickets
- Check database for booking record
- Check logs for booking event
- Check
.envcredentials - Verify MySQL is running
- Check
logs/error.logfor details
- Ensure session is started before rendering form
- Check token generation/verification in helpers
- Check
uploads/directory permissions - Verify file size in
.env - Check file type in validation
- Email Verification: Add email verification during registration
- Password Reset: Implement forgot password flow
- Rate Limiting: Add rate limiting on login attempts
- API Layer: Build REST API for mobile apps
- Payment Integration: Add payment gateway integration
- Notifications: Add email/SMS notifications
- Analytics: Add user behavior tracking
- PDO Documentation: https://www.php.net/manual/en/book.pdo.php
- OWASP Security: https://owasp.org/www-project-top-ten/
- PHP Password Security: https://www.php.net/manual/en/function.password-hash.php