Thursday, September 10, 2026
PHP Projects

Full-Stack Online Examination System with PHP & MySQL — Complete Guide

Lav 8 min read
Full-Stack Online Examination System with PHP & MySQL — Complete Guide

Project Overview

This project is a complete Online Examination System that allows institutions, coaching centres, and educators to create and conduct exams online. Students can register, browse available exams, attempt them in a secure proctored environment, and view instant results.

Why this project?

Most open-source exam systems are either too heavy (WordPress plugins, Laravel monoliths) or too minimal. This system hits the sweet spot — it's lightweight, self-contained, easy to deploy, and feature-complete enough for real-world use.

Who is it for?

Audience Use Case
Educators & Schools Conduct class tests and final exams online
Coaching Institutes Create mock exams and track student performance
HR Departments Screening tests for job applicants
Developers Learn MVC architecture with pure PHP
YouTubers / Bloggers Build & showcase as a portfolio project

Live Demo Features

🌐 Public Homepage (/)

  • Lists all published exams with live status indicators
  • Registration and login CTAs
  • Exam details: duration, marks, pass criteria, negative marking info
  • Smart buttons based on user role and exam status (Live / Upcoming / Ended)

🛡️ Admin Panel (/admin/dashboard)

  • Dashboard — Stats overview (total exams, users, submissions, pass rate, avg score, integrity flags)
  • Exams Module — Card grid view with live badge, pass rate, attempt count; search & status filter
  • Questions Module — Add MCQ questions with dynamic options (2–∞), image upload per question, AJAX pagination & search, bulk CSV import
  • Students Module — View all registered students with exam activity stats, status toggle, profile modal with exam history
  • Results Module — Pass/Fail donut chart, score distribution bar chart, filters by exam/result/name, answer review modal per attempt
  • Users Module — Manage all roles (Admin / Examiner / Student), create/edit/delete users, role-based colour themes

🎓 Student Portal (/student/dashboard)

  • Browse available exams
  • Fullscreen exam engine with auto-save answers
  • Tab-switch violation detection & logging
  • Timer with auto-submit
  • Instant result page with score breakdown

Tech Stack

Layer Technology
Backend Language PHP 8.1+
Architecture Custom MVC (no framework)
Database MySQL 8.0+
Frontend Bootstrap 5.3, Vanilla JS
Charts Chart.js 4.4
Icons Bootstrap Icons 1.11
Fonts Google Fonts — Inter
Server (Dev) PHP Built-in Server
Server (Prod) Apache / Nginx

Project Architecture

Online Examination System/
├── index.php                    # Front controller & router
├── database.sql                 # Complete DB schema + seed data
├── README.md
│
├── app/
│   ├── Config/
│   │   └── Database.php         # PDO connection config
│   │
│   ├── Controllers/
│   │   ├── HomeController.php   # Public homepage
│   │   ├── AuthController.php   # Login / Register / Logout
│   │   ├── AdminController.php  # All admin operations (CRUD)
│   │   └── StudentController.php# Exam engine, results
│   │
│   ├── Models/
│   │   ├── User.php             # User CRUD, stats, role management
│   │   ├── Exam.php             # Exam CRUD with aggregated stats
│   │   ├── Question.php         # MCQ CRUD with options, image
│   │   └── Attempt.php          # Exam attempts, scoring, evaluation
│   │
│   ├── Views/
│   │   ├── home.php             # Public landing page
│   │   ├── layouts/
│   │   │   └── admin.php        # Admin shell layout + sidebar
│   │   ├── auth/
│   │   │   ├── login.php
│   │   │   └── register.php
│   │   ├── admin/
│   │   │   ├── dashboard.php
│   │   │   ├── exams/           # index, create, edit, questions, question_edit
│   │   │   ├── students/        # index, edit
│   │   │   ├── results/         # index
│   │   │   └── users/           # index, create, edit
│   │   └── student/             # dashboard, exam views, result
│   │
│   └── Helpers/
│       └── AuthHelper.php       # Session-based role guard
│
└── public/
    └── uploads/
        └── questions/           # Uploaded question images

MVC Request Lifecycle

Browser Request
      │
      ▼
  index.php  ──── parses URI ────► Router (switch/case)
      │
      ▼
  Controller  ──── calls Model ──► Database (PDO)
      │                                  │
      │         ◄─── data ───────────────┘
      ▼
   View (PHP template)
      │
      ▼
  HTML Response

Database Schema

The system uses 5 core tables with foreign key constraints and ON DELETE CASCADE for data integrity.

-- Users table (all roles) CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(150) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, -- bcrypt hashed role ENUM('admin','examiner','student') DEFAULT 'student', city VARCHAR(100), status ENUM('active','inactive') DEFAULT 'active', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Exams table CREATE TABLE exams ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL, description TEXT, duration_minutes INT NOT NULL, start_time DATETIME NOT NULL, end_time DATETIME NOT NULL, total_marks DECIMAL(8,2) DEFAULT 100, passing_marks DECIMAL(8,2) DEFAULT 40, negative_marking_ratio DECIMAL(4,2) DEFAULT 0, status ENUM('draft','published','completed') DEFAULT 'draft', created_by INT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (created_by) REFERENCES users(id) ); -- Questions table CREATE TABLE questions ( id INT AUTO_INCREMENT PRIMARY KEY, exam_id INT NOT NULL, question_text TEXT NOT NULL, image_url VARCHAR(500), -- optional image per question marks DECIMAL(5,2) DEFAULT 1.00, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (exam_id) REFERENCES exams(id) ON DELETE CASCADE ); -- Options table (MCQ choices) CREATE TABLE options ( id INT AUTO_INCREMENT PRIMARY KEY, question_id INT NOT NULL, option_text VARCHAR(500) NOT NULL, is_correct TINYINT(1) DEFAULT 0, FOREIGN KEY (question_id) REFERENCES questions(id) ON DELETE CASCADE ); -- Exam Attempts table CREATE TABLE exam_attempts ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, exam_id INT NOT NULL, start_time DATETIME, end_time DATETIME, score DECIMAL(8,2), status ENUM('in_progress','submitted','evaluated') DEFAULT 'in_progress', tab_switches INT DEFAULT 0, -- proctoring violations FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (exam_id) REFERENCES exams(id) ON DELETE CASCADE ); -- Student Answers table CREATE TABLE student_answers ( id INT AUTO_INCREMENT PRIMARY KEY, attempt_id INT NOT NULL, question_id INT NOT NULL, selected_option_id INT, marks_obtained DECIMAL(5,2) DEFAULT 0, FOREIGN KEY (attempt_id) REFERENCES exam_attempts(id) ON DELETE CASCADE );

Module Breakdown

1. Authentication System

  • Session-based login/logout
  • bcrypt password hashing
  • Role-based access guard (AuthHelper::requireRole())
  • Duplicate email check on registration

2. Exam Management

  • Create, Edit, Delete exams with draft/published/completed states
  • Set duration, marks, passing marks, negative marking ratio, start/end times
  • Real-time LIVE badge when exam is currently active
  • View question count, attempt count, pass rate per exam

3. Question Management

  • Add MCQ questions with 2 to unlimited options (dynamic JS)
  • Upload an image per question (PNG/JPG/GIF)
  • Bulk import via CSV — import hundreds of questions at once
  • Download sample CSV template
  • AJAX-powered question list with pagination and live search
  • Edit/Delete individual questions

4. Student Management

  • View all registered students with exam activity data
  • Toggle student status (Active/Inactive) via AJAX
  • Student profile modal showing exam history, avg score, violation count
  • Edit student details and reset password

5. Results & Analytics

  • Pass/Fail donut chart + score distribution bar chart (Chart.js)
  • Filter results by exam, result (pass/fail), student name
  • Per-attempt Answer Review Modal — see every question with student's answer vs correct answer
  • Integrity flag count per attempt

6. User Management

  • Full CRUD for all user roles: Admin, Examiner, Student
  • Role-colored profile pages (purple=admin, green=student, amber=examiner)
  • Cannot delete the last active admin (safety guard)
  • Toggle status AJAX (live badge update without page reload)

7. Exam Engine (Student Side)

  • Fullscreen enforcement on exam start
  • Auto-save answers via AJAX on every selection
  • Tab-switch / focus-loss detection → violation logged to DB
  • Countdown timer with auto-submit when time expires
  • Instant result page with score, correct/incorrect breakdown, pass/fail verdict

Installation & Local Setup

Prerequisites

Requirement Version
PHP 8.1 or higher
MySQL 8.0 or higher
Composer Not required
Web Server Apache / Nginx / PHP built-in

 

Step 1 — Clone the Repository

git clone https://github.com/yourusername/online-examination-system.git
cd online-examination-system

Step 2 — Create the Database

mysql -u root -p
CREATE DATABASE exam_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
EXIT;
mysql -u root -p exam_system < database.sql

Step 3 — Configure Database Connection

Open app/Config/Database.php and update:

private $host     = 'localhost';
private $db_name  = 'exam_system';       // your DB name
private $username = 'root';              // your MySQL user
private $password = '';                  // your MySQL password

Step 4 — Create Upload Directory

mkdir -p public/uploads/questions
chmod 755 public/uploads/questions

Step 5 — Start the Development Server

php -S localhost:8000

Open your browser → http://localhost:8000

Deployment Guide

Option 1: Shared Hosting (cPanel)

This is the easiest option — suitable for beginners.

Step 1 — Prepare your files

# Zip your project folder
zip -r exam-system.zip "Online Examination System/"

Step 2 — Upload via File Manager

  1. Log in to cPanel
  2. Open File Manager → navigate to public_html/
  3. Upload and extract exam-system.zip
  4. Move the contents so index.php is directly inside public_html/

Step 3 — Create MySQL Database in cPanel

  1. Go to MySQL Databases
  2. Create a new database, e.g., youruser_examdb
  3. Create a MySQL user with a strong password
  4. Grant ALL privileges to the user on that database

Step 4 — Import the SQL Schema

  1. Open phpMyAdmin
  2. Select your database
  3. Click Import tab → choose database.sql → click Go

Step 5 — Update Database Config

Edit app/Config/Database.php with your cPanel DB credentials:

private $host     = 'localhost';
private $db_name  = 'youruser_examdb';
private $username = 'youruser_dbuser';
private $password = 'your_strong_password';

Step 6 — Set up .htaccess (Apache)

Create or verify public_html/.htaccess:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]

Step 7 — Set folder permissions

public/uploads/questions/   →  755
app/                        →  644 (files), 755 (dirs)

✅ Visit your domain — the homepage should load!

Configuration Reference

app/Config/Database.php

private $host     = 'localhost';    // DB host
private $db_name  = 'exam_system';  // DB name
private $username = 'root';         // DB user
private $password = '';             // DB password
private $charset  = 'utf8mb4';      // Always use utf8mb4

File Upload Config

Image uploads are stored in:

public/uploads/questions/

Supported formats: JPG, PNG, GIF, WebP
Maximum size: Controlled by your php.ini:

upload_max_filesize = 10M
post_max_size = 12M 

CSV Question Import Format

To bulk-import questions, use the following CSV format:

question_text,marks,option_a,option_b,option_c,option_d,correct_option
What is the capital of France?,1,Berlin,Paris,Rome,Madrid,B
Which planet is closest to the sun?,2,Earth,Venus,Mercury,Mars,C
True or False: Water is H2O.,1,True,False,,,A
PHP stands for?,1,Personal Home Page,Hypertext Preprocessor,Public Homepage Protocol,Private Handle Protocol,B

Rules:

  • First row is the header — always keep it, it will be skipped
  • correct_option must be A, B, C, or D
  • option_c and option_d can be empty (for True/False questions)
  • marks defaults to 1.0 if left empty or invalid
  • Blank question rows are silently skipped

📥 Download the sample CSV template from Admin → Questions → Import CSV → Download Sample CSV.


Default Credentials

After importing database.sql, use these credentials to log in:

Role Email Password
Admin admin@example.com password
Student Register via the homepage

⚠️ Security Warning: Change the default admin password immediately after first login in production.

Author

Built with ❤️ by Lavkush K.


If this project helped you, please ⭐ star the repository and subscribe to the YouTube channel for more full-stack PHP tutorials!

Download File Project Link

Related Articles

0 Comments

Leave a Comment