A PHP + MySQL attendance register: a weekend project for PHP training students
Most students in PHP training write a "student management system" as their first project. It's a good idea, but it usually ends up as 30 files of copy-pasted SQL. Here is a smaller, cleaner version you can finish in a weekend: a class attendance register with PHP 8 and MySQL, using PDO and prepared statements from the first line.
1. The database
CREATE TABLE students ( id INT AUTO_INCREMENT PRIMARY KEY, roll_no VARCHAR(20) NOT NULL UNIQUE, name VARCHAR(100) NOT NULL ); CREATE TABLE attendance ( id INT AUTO_INCREMENT PRIMARY KEY, student_id INT NOT NULL, class_date DATE NOT NULL, present TINYINT(1) NOT NULL DEFAULT 0, UNIQUE KEY one_mark_per_day (student_id, class_date), FOREIGN KEY (student_id) REFERENCES students(id) ); The UNIQUE KEY stops anyone marking the same student twice on one day. Let the database enforce rules like this instead of hoping your PHP gets it right.
2. One connection file
<?php // db.php $pdo = new PDO( 'mysql:host=localhost;dbname=register;charset=utf8mb4', 'root', '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC] ); 3. Marking attendance (safely)
<?php require 'db.php'; $date = $_POST['class_date'] ?? date('Y-m-d'); $present = $_POST['present'] ?? []; // array of student ids that were ticked $students = $pdo->query('SELECT id FROM students')->fetchAll(); $stmt = $pdo->prepare( 'INSERT INTO attendance (student_id, class_date, present) VALUES (:sid, :d, :p) ON DUPLICATE KEY UPDATE present = VALUES(present)' ); foreach ($students as $s) { $stmt->execute([ ':sid' => $s['id'], ':d' => $date, ':p' => in_array((string)$s['id'], $present, true) ? 1 : 0, ]); } Prepared statements mean a student name like O'Brien (or something nastier) can never break your query. ON DUPLICATE KEY UPDATE lets the teacher re-save the same day without errors.
4. The monthly report
<?php require 'db.php'; $month = $_GET['month'] ?? date('Y-m'); $stmt = $pdo->prepare( 'SELECT s.roll_no, s.name, SUM(a.present) AS days_present, COUNT(a.id) AS days_marked FROM students s LEFT JOIN attendance a ON a.student_id = s.id AND DATE_FORMAT(a.class_date, "%Y-%m") = :m GROUP BY s.id ORDER BY s.roll_no' ); $stmt->execute([':m' => $month]); foreach ($stmt as $row) { $pct = $row['days_marked'] ? round($row['days_present'] * 100 / $row['days_marked']) : 0; echo htmlspecialchars("{$row['roll_no']} {$row['name']}: {$pct}%"), "<br>"; } Note the htmlspecialchars on output: escaping on the way out is the other half of basic security.
5. What to add next
- A login for teachers (
password_hashandpassword_verify, never plain text). - A CSV export of the monthly report.
- Rebuild it in Laravel: migrations, Eloquent models and a Blade view. You'll see how much the framework does for you.
Put it on GitHub with a README and screenshots. In fresher interviews in Mohali and Chandigarh, being able to explain why you used a unique key and prepared statements matters more than the size of the project.
I run Dzimark, and this is one of the starter projects we use at Dzimark Training in Mohali, where the full PHP and Laravel syllabus is listed.