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
- Log in to cPanel
- Open File Manager → navigate to
public_html/ - Upload and extract
exam-system.zip - Move the contents so
index.phpis directly insidepublic_html/
Step 3 — Create MySQL Database in cPanel
- Go to MySQL Databases
- Create a new database, e.g.,
youruser_examdb - Create a MySQL user with a strong password
- Grant ALL privileges to the user on that database
Step 4 — Import the SQL Schema
- Open phpMyAdmin
- Select your database
- 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_optionmust be A, B, C, or Doption_candoption_dcan be empty (for True/False questions)marksdefaults to1.0if 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 | 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.
- 🎬 YouTube: CodingCush
- 🐙 GitHub: CodingCush
If this project helped you, please ⭐ star the repository and subscribe to the YouTube channel for more full-stack PHP tutorials!
0 Comments
Leave a Comment