A secure, feature-rich, web-based voting platform built with PHP, MySQL, and XAMPP. Designed for conducting transparent elections with a full-featured Admin Panel, an intuitive Voter Dashboard, Email OTP Verification, Face Recognition identity check, PDF Voter ID Card generation, and live Chart.js election results.
ποΈ Built for Election Commission of India β Elections
- Phone number & password-based login
- Dual-Model Face Recognition during registration β
SsdMobilenetv1analyses the uploaded passport photo;TinyFaceDetectorscans the live webcam feed; both powered byface-api.js(no API key needed) - Webcam-only liveness fallback β if the passport photo face detection fails, the system automatically switches to a liveness-only check to keep registration flowing
- Email OTP Verification β 6-digit OTP with 5-minute countdown timer via EmailJS
- Server-side OTP cross-check in MySQL before registration completes
bcryptpassword hashing (password_hash)- Role-based access control (Admin / Voter)
- Session-based authentication with auto-redirect
- Smart Registration Form with step-by-step verification:
- Fill personal details
- Upload passport photo β face detected automatically
- Webcam opens β
SsdMobilenetv1compares face against uploaded photo (fallback: liveness-only check if photo detection fails) - On match (β₯35% similarity / distance < 0.65) β Email/OTP section reveals
- Verify OTP β Submit registration
- Voter Dashboard with voting status, election status, and quick-action cards
- My Profile Page β view all personal details, update photo, download Voter ID
- PDF Voter ID Card β credit-card sized ID generated and downloaded using
jsPDF - Vote Page β shows candidates only when election is active
- "Election Not Started" message when closed
- One-person-one-vote enforcement
- Dashboard with live stats β Registered Voters, Candidates, Votes Cast, Turnout %
- Results Page (locked while election is active β results only visible after election ends):
- π "Results Are Locked" screen during active voting
- π Animated Winner Popup β auto-appears with winner's photo, name, party & vote share
- Animated Bar Chart (vote distribution)
- Animated Doughnut Chart (vote share percentage)
- Candidate progress bars with vote percentages
- Total votes banner
- π Winner badge on leading candidate
- Candidate Management β Add, Edit, Delete with photo & manifesto
- Voter Management β View all voters (with email), Remove voters
- Election Control β Start/Stop election, Update custom title, Full Reset
- Admin Profile Page β view details, update profile photo, logout
- Glassmorphism design with frosted-glass buttons
- Role-based color themes:
- π Login/Register β Sunshine Orange gradient
- π Admin pages β Peach gradient
- π΅ Voter pages β Light Blue gradient
- Smooth animations & hover effects
- Google Fonts (Outfit)
- Fully responsive layout
| Layer | Technology |
|---|---|
| Frontend | HTML5, CSS3, Vanilla JavaScript |
| Backend | PHP 8+ (MySQLi) |
| Database | MySQL via XAMPP |
| Server | XAMPP (Apache + MySQL) |
| Face Recognition | face-api.js @vladmandic v1.7.13 β SsdMobilenetv1 (photo) + TinyFaceDetector (webcam) |
| Email OTP | EmailJS SDK v4 (free: 200 emails/month) |
| Charts | Chart.js v4.4 (CDN, no API key) |
| PDF Generation | jsPDF v2.5 (CDN, no API key) |
| Fonts | Google Fonts β Outfit |
| Design | Glassmorphism, CSS Gradients, CSS Variables |
flowchart TD
A["π Landing Page"] --> B{"User Action"}
B -->|Login| C["π Login Form"]
B -->|Register| D["π Registration Form"]
D --> D1["Fill personal details"]
D1 --> D2["π· Upload Passport Photo"]
D2 --> D3["π€ SsdMobilenetv1 detects face in photo"]
D3 -->|Face found| D4["πΈ Webcam opens β compare mode"]
D3 -->|No face detected| D4L["πΈ Webcam opens β liveness mode"]
D4 --> D5["Click Capture & Verify Face"]
D4L --> D5
D5 -->|Match β₯35% OR liveness confirmed| D6["β
Face Verified"]
D5 -->|No match / No face| D4
D6 --> D7["π§ Email + OTP Section reveals"]
D7 --> D8["Send OTP via EmailJS"]
D8 --> D9["Enter OTP β Verify"]
D9 -->|Valid| D10["β
OTP Verified"]
D9 -->|Expired/Wrong| D8
D10 --> D11["Click Complete Registration β DB saved"]
D11 --> C
C --> E["Verify Phone + Password"]
E -->|Invalid| C
E -->|Valid| F{"Check Role"}
F -->|Admin| G["π Admin Dashboard"]
F -->|Voter| H["π Voter Dashboard"]
style D6 fill:#C8E6C9,stroke:#4CAF50,color:#333
style D10 fill:#C8E6C9,stroke:#4CAF50,color:#333
style G fill:#FFDAB9,stroke:#FF8C00,color:#333
style H fill:#B3E5FC,stroke:#03A9F4,color:#333
flowchart TD
VD["π Voter Dashboard"] --> Q1["π€ My Profile"]
VD --> Q2["π Voter ID Card"]
VD --> S1{"Election Status?"}
Q1 --> P1["View details, update photo"]
Q2 --> P2["Generate & download PDF"]
S1 -->|"π’ ON"| S2{"Already Voted?"}
S1 -->|"π΄ OFF"| S3["β Election Not Started"]
S2 -->|No| V1["π³οΈ View Candidates & Vote"]
S2 -->|Yes| V2["β
Thank You Message"]
V1 --> V3["Vote Recorded + status = voted"]
style V3 fill:#C8E6C9,stroke:#4CAF50,color:#333
style S3 fill:#FFCDD2,stroke:#E53935,color:#333
style P2 fill:#E8F5E9,stroke:#4CAF50,color:#333
flowchart TD
AD["βοΈ Admin Dashboard"] --> M1["π₯ Candidates"]
AD --> M2["π₯ Voters"]
AD --> M3["π Results"]
AD --> M4["π¦ Election Control"]
AD --> M5["π€ Profile"]
M3 --> R1["π Bar Chart"]
M3 --> R2["π₯§ Doughnut Chart"]
M3 --> R3["Candidate progress bars + %"]
M4 --> E1["βΆοΈ Start / βΉοΈ Stop"]
M4 --> E2["πΎ Update Title"]
M4 --> E3["π Full Reset"]
E3 --> W["Delete votes + candidates + images + reset statuses"]
style AD fill:#FFDAB9,stroke:#FF8C00,color:#333
style W fill:#FFCDD2,stroke:#E53935,color:#333
Online_voting/
β
βββ index.html # π Login & Registration (Face β OTP β Submit)
βββ login.php # π Login authentication handler
βββ register.php # π₯ Registration handler (face + OTP + DB)
βββ logout.php # πͺ Session destroy & redirect
β
βββ generate_otp.php # π API: Generates 6-digit OTP & stores in DB
βββ verify_otp.php # β
API: Verifies OTP code + expiry check
βββ setup_otp_table.php # ποΈ One-time: creates otp_verification table
βββ add_face_column.php # ποΈ One-time: adds face_verified column to users
β
βββ profile.php # π€ Profile page (voter + admin) with photo upload + PDF ID
βββ dashboard.php # π Voter dashboard with quick-action cards
βββ vote.php # π³οΈ Voting page (candidates when election ON)
βββ submit_vote.php # β
Vote submission handler
β
βββ admin_dashboard.php # βοΈ Admin dashboard with live stats
βββ candidates.php # π₯ Manage candidates (list view)
βββ add_candidate.php # β Add candidate form
βββ edit_candidate.php # βοΈ Edit candidate form
βββ delete_candidate.php # ποΈ Delete candidate + image
βββ manage_voters.php # π₯ View & remove voters (with email column)
βββ delete_voter.php # ποΈ Remove voter + cleanup votes
βββ results.php # π Results with Bar Chart + Doughnut Chart (Chart.js)
β
βββ toggle_election.php # π¦ Start/Stop election status
βββ update_title.php # πΎ Update election title
βββ reset.php # π Full election wipe
βββ get_title.php # π‘ API: Returns election title as JSON
β
βββ config.php # π MySQL database connection
βββ navbar.php # π§ Dynamic navbar + role-based background
βββ hash.php # π bcrypt password hash generator
β
βββ style.css # π¨ Full stylesheet (glassmorphism, gradients, animations)
βββ script.js # β‘ Face recognition + OTP + EmailJS logic
β
βββ uploads/ # πΌοΈ Voter passport photos & profile images
βββ assets/ # π Static assets
| Column | Type | Description |
|---|---|---|
id |
INT (PK, AI) | User ID |
name |
VARCHAR(100) | Full name |
phone |
VARCHAR(15) | Phone number (unique) |
email |
VARCHAR(255) | Email (used for OTP) |
aadhaar |
VARCHAR(12) | Aadhaar (unique, 12 digits) |
address |
TEXT | Residential address |
password |
VARCHAR(255) | bcrypt hashed password |
role |
ENUM('voter','admin') | User role |
image |
VARCHAR(255) | Profile/passport photo path |
status |
VARCHAR(20) | approved / voted |
face_verified |
TINYINT(1) | 1 = face matched during registration |
| Column | Type | Description |
|---|---|---|
id |
INT (PK, AI) | OTP record ID |
email |
VARCHAR(255) | Email address |
otp_code |
VARCHAR(6) | 6-digit OTP |
created_at |
DATETIME | When generated |
expires_at |
DATETIME | Expiry (5 min after creation) |
is_verified |
TINYINT(1) | 0 = pending, 1 = verified |
π§Ή OTP records are deleted automatically after successful registration.
| Column | Type | Description |
|---|---|---|
id |
INT (PK, AI) | Candidate ID |
name |
VARCHAR(100) | Candidate name |
party |
VARCHAR(100) | Political party |
manifesto |
TEXT | Election manifesto |
image |
VARCHAR(255) | Candidate photo path |
| Column | Type | Description |
|---|---|---|
id |
INT (PK, AI) | Vote ID |
user_id |
INT (FK) | Voter (β users.id) |
candidate_id |
INT (FK) | Candidate (β candidates.id) |
| Column | Type | Description |
|---|---|---|
id |
INT (PK) | Always 1 |
election_status |
ENUM('ON','OFF') | Election active status |
election_title |
VARCHAR(255) | Custom election title |
- XAMPP (Apache + MySQL)
- PHP 8.0+
- Modern browser (Chrome/Edge recommended for webcam)
- Internet access (for CDN libraries: face-api.js, Chart.js, jsPDF, EmailJS)
- Free EmailJS account
1. Place project in htdocs
C:\xampp\htdocs\Online_voting\
2. Start XAMPP β Start both Apache and MySQL
3. Create Database β Open phpMyAdmin:
CREATE DATABASE online_voting;
USE online_voting;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
phone VARCHAR(15) UNIQUE NOT NULL,
email VARCHAR(255),
aadhaar VARCHAR(12) UNIQUE NOT NULL,
address TEXT,
password VARCHAR(255) NOT NULL,
role ENUM('voter','admin') DEFAULT 'voter',
image VARCHAR(255),
status VARCHAR(20) DEFAULT 'approved',
face_verified TINYINT(1) DEFAULT 0
);
CREATE TABLE otp_verification (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL,
otp_code VARCHAR(6) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
expires_at DATETIME NOT NULL,
is_verified TINYINT(1) DEFAULT 0
);
CREATE TABLE candidates (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
party VARCHAR(100),
manifesto TEXT,
image VARCHAR(255)
);
CREATE TABLE votes (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
candidate_id INT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (candidate_id) REFERENCES candidates(id)
);
CREATE TABLE settings (
id INT PRIMARY KEY DEFAULT 1,
election_status ENUM('ON','OFF') DEFAULT 'OFF',
election_title VARCHAR(255) DEFAULT 'Online Voting System'
);
INSERT INTO settings VALUES (1, 'OFF', 'Online Voting System');4. Create Admin User
- Visit
http://localhost/Online_voting/hash.phpβ generates bcrypt hash - Run in phpMyAdmin:
INSERT INTO users (name, phone, password, role, status)
VALUES ('Admin', '9999999999', 'PASTE_HASH_HERE', 'admin', 'approved');5. Configure EmailJS
- Sign up at emailjs.com β free: 200 emails/month
- Create Gmail Email Service β copy Service ID
- Create Email Template with:
- To Email:
{{email}} - Body must include
{{passcode}}(the OTP code)
- To Email:
- Copy Template ID and Public Key
- Update
script.jslines 80β82:
const EMAILJS_PUBLIC_KEY = "YOUR_PUBLIC_KEY";
const EMAILJS_SERVICE_ID = "YOUR_SERVICE_ID";
const EMAILJS_TEMPLATE_ID = "YOUR_TEMPLATE_ID";6. Run One-Time Setup Scripts
Visit these URLs once in your browser:
http://localhost/Online_voting/setup_otp_table.php β Creates OTP table
http://localhost/Online_voting/add_face_column.php β Adds face_verified column
7. Access the Application
http://localhost/Online_voting/
| Feature | Status |
|---|---|
Dual-model face recognition (SsdMobilenetv1 photo + TinyFaceDetector webcam) |
β |
| Webcam-only liveness fallback if photo detection fails | β |
| Email OTP with 5-min expiry | β |
| Server-side OTP DB cross-check | β |
| OTP records purged after registration | β |
| bcrypt password hashing | β |
| Session-based authentication | β |
| Role-based page protection | β |
| Double-vote prevention | β |
| Election status enforced server-side | β |
| Results hidden during active election | β |
| Voter removal with vote cleanup | β |
| Face verification flag stored in DB | β |
Author -Manoj.
β Star this repo if you found it useful! β