Topic 6: Form Submission (Task)
📖 15 min read · 🎯 intermediate · 🧭 Prerequisites: css-advance, div-page-design
Why this matters
Before we dive in, think about the last time you filled out a form online — a job application, a registration page, a feedback box. You typed something, hit submit, and it was saved. That moment — where what you typed gets captured and stored — is exactly what we're building today. You'll write an HTML form on the front, use PHP in the middle to receive the data, and store it in a MySQL database at the back. By the end, you'll have a real task submission system that actually works end to end.
What You'll Learn
- Design an HTML form that posts task data to a PHP script
- Connect to a MySQL database using
mysqliin PHP - Insert submitted form data safely using prepared statements and
bind_param - Query the database and render all tasks in a styled HTML table
The Analogy
Think of this system like a physical suggestion box in a company lobby. Employees fill out a printed form (the HTML form), slide it through the slot (the HTTP POST request), and a clerk behind the wall reads the form, validates it, and files it in a cabinet drawer labelled by category (the MySQL Tasks table). When the manager wants to see all suggestions, the clerk pulls every card from the drawer, lays them out on a table in alphabetical order, and the manager reads them as a neat report — that's view_tasks.php fetching and rendering rows. The box, the clerk, and the cabinet are three separate things that only work because they speak the same language.
Chapter 1: Defining the Requirements
the trainer wrote four bullet points on the board. Every piece of code that follows maps back to one of them.
- Task Details — Collect the task's title, description, assigned person, priority, and due date from the user.
- Validation — All fields are required; the form must not submit if any are blank.
- Database Storage — Persist the submitted data in a MySQL table called
Tasksinside theTaskManagementdatabase. - Task Listing — Display every stored task in a readable HTML table, including the automatic submission timestamp.
These four requirements drive two PHP files (submit_task.php and view_tasks.php) and one SQL schema. Keep them in mind as you read each chapter.
Chapter 2: Creating the Task Submission Form
The class's first deliverable is a plain HTML file. It needs six input controls — one for each task field — and a submit button that POSTs to submit_task.php.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Task Submission Form</title>
</head>
<body>
<h1>Submit a New Task</h1>
<form action="submit_task.php" method="post">
<label for="title">Task Title:</label>
<input type="text" id="title" name="title" required>
<br>
<label for="description">Description:</label>
<textarea id="description" name="description" required></textarea>
<br>
<label for="assigned_to">Assigned To:</label>
<input type="text" id="assigned_to" name="assigned_to" required>
<br>
<label for="priority">Priority:</label>
<select id="priority" name="priority" required>
<option value="low">Low</option>
<option value="medium">Medium</option>
<option value="high">High</option>
</select>
<br>
<label for="due_date">Due Date:</label>
<input type="date" id="due_date" name="due_date" required>
<br>
<button type="submit">Submit Task</button>
</form>
</body>
</html>
Key decisions in this form:
method="post"— task data should not appear in the browser URL bar.action="submit_task.php"— the browser sends all field values to this PHP file on submit.requiredon every input — the browser enforces client-side presence before the POST fires.- The
priorityfield is a<select>with exactly three valid values:low,medium,high. type="date"gives the browser's native date picker, producing aYYYY-MM-DDstring that MySQL'sDATEcolumn understands directly.
Chapter 3: Processing the Form Submission
Database Setup
Before writing a single line of PHP, create the database and table in MySQL. Run these statements in phpMyAdmin or any MySQL client:
CREATE DATABASE TaskManagement;
USE TaskManagement;
CREATE TABLE Tasks (
TaskID INT AUTO_INCREMENT PRIMARY KEY,
Title VARCHAR(255) NOT NULL,
Description TEXT NOT NULL,
AssignedTo VARCHAR(100) NOT NULL,
Priority VARCHAR(50) NOT NULL,
DueDate DATE NOT NULL,
SubmissionDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Column notes:
TaskID— auto-incrementing primary key; MySQL assigns it, you never set it manually.SubmissionDate—TIMESTAMP DEFAULT CURRENT_TIMESTAMPmeans MySQL writes the current server time automatically on everyINSERT, with no PHP code needed.Priority VARCHAR(50)— stores the string"low","medium", or"high"that the form's<select>sends.
PHP Script: submit_task.php
This file runs on the server the moment the HTML form is submitted.
<?php
// Database configuration
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "TaskManagement";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Get form data
$title = $_POST['title'];
$description = $_POST['description'];
$assigned_to = $_POST['assigned_to'];
$priority = $_POST['priority'];
$due_date = $_POST['due_date'];
// Prepare and bind
$stmt = $conn->prepare(
"INSERT INTO Tasks (Title, Description, AssignedTo, Priority, DueDate)
VALUES (?, ?, ?, ?, ?)"
);
$stmt->bind_param("sssss", $title, $description, $assigned_to, $priority, $due_date);
// Execute the statement
if ($stmt->execute()) {
echo "Task submitted successfully!";
} else {
echo "Error: " . $stmt->error;
}
// Close connection
$stmt->close();
$conn->close();
?>
Walk-through of the important lines:
new mysqli(...)— opens a connection to MySQL with the four credentials.$conn->connect_error— if the connection fails,die()halts execution and prints the error.$_POST['title']etc. — PHP's superglobal$_POSTholds the values the form sent.$conn->prepare(...)— creates a prepared statement. The?placeholders prevent SQL injection by keeping data separate from the SQL structure.bind_param("sssss", ...)— the first argument is a type string: one character per?."s"means string. Five columns, five"s"characters.$stmt->execute()— runs the prepared INSERT. Returnstrueon success.- Always close
$stmtand$connto free server resources.
sequenceDiagram
participant Browser
participant submit_task.php
participant MySQL
Browser->>submit_task.php: POST /submit_task.php (form data)
submit_task.php->>MySQL: new mysqli() — open connection
MySQL-->>submit_task.php: connection OK
submit_task.php->>MySQL: prepare INSERT ... VALUES (?,?,?,?,?)
submit_task.php->>MySQL: bind_param + execute()
MySQL-->>submit_task.php: row inserted, TaskID assigned
submit_task.php-->>Browser: "Task submitted successfully!"
Chapter 4: Displaying the Tasks
The second PHP file, view_tasks.php, fetches every row from Tasks and renders it inside an HTML table with inline CSS styling.
<?php
// Database configuration
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "TaskManagement";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Fetch tasks
$tasksQuery = "SELECT * FROM Tasks";
$tasksResult = $conn->query($tasksQuery);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Task List</title>
<style>
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 12px;
border: 1px solid #ddd;
text-align: left;
}
th {
background-color: #f2f2f2;
}
</style>
</head>
<body>
<h1>Task List</h1>
<table>
<thead>
<tr>
<th>Task ID</th>
<th>Title</th>
<th>Description</th>
<th>Assigned To</th>
<th>Priority</th>
<th>Due Date</th>
<th>Submission Date</th>
</tr>
</thead>
<tbody>
<?php
if ($tasksResult->num_rows > 0) {
while ($row = $tasksResult->fetch_assoc()) {
echo "<tr>
<td>" . $row['TaskID'] . "</td>
<td>" . $row['Title'] . "</td>
<td>" . $row['Description'] . "</td>
<td>" . $row['AssignedTo'] . "</td>
<td>" . $row['Priority'] . "</td>
<td>" . $row['DueDate'] . "</td>
<td>" . $row['SubmissionDate'] . "</td>
</tr>";
}
} else {
echo "<tr><td colspan='7'>No tasks found</td></tr>";
}
?>
</tbody>
</table>
</body>
</html>
<?php
$conn->close();
?>
Key points in view_tasks.php:
$conn->query($tasksQuery)— executes a plainSELECT *(no user input, so no prepared statement is needed here).$tasksResult->num_rows— the count of rows returned. If zero, theelsebranch prints a single spanning cell with "No tasks found".fetch_assoc()in awhileloop — pulls one row at a time as an associative array keyed by column name ('TaskID','Title', etc.), until no rows remain.colspan='7'in the empty-state cell spans all seven column headers.- The inline
<style>block gives the tableborder-collapse: collapse, consistent 12 px cell padding, a 1 px#dddborder on every cell, and a#f2f2f2background on header cells. $conn->close()appears after the closing</html>tag — PHP still executes it because it is inside a PHP block, not inside HTML.
🧪 Try It Yourself
Task: Build the full two-file system locally using XAMPP or WAMP.
- Start Apache and MySQL in your XAMPP/WAMP control panel.
- Open phpMyAdmin, run the
CREATE DATABASEandCREATE TABLESQL from Chapter 3. - Save the HTML form as
task_form.htmlin yourhtdocsfolder (XAMPP) orwwwfolder (WAMP). - Save
submit_task.phpandview_tasks.phpin the same folder. - Visit
http://localhost/task_form.htmlin your browser, fill in all five fields, and click Submit Task.
Success criteria:
- You should see
"Task submitted successfully!"in the browser after submitting. - Navigate to
http://localhost/view_tasks.php— your new task should appear as a table row with the correctSubmissionDatefilled in automatically by MySQL.
Starter snippet to verify your DB connection independently:
<?php
$conn = new mysqli("localhost", "root", "", "TaskManagement");
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
echo "Connected successfully";
$conn->close();
?>
Save this as test_conn.php and visit it first. If you see "Connected successfully", your credentials are correct and you can proceed.
🔍 Checkpoint Quiz
Q1. Why does submit_task.php use a prepared statement (prepare + bind_param) instead of building the SQL string with string concatenation?
A) Prepared statements are faster to type
B) They prevent SQL injection by separating SQL structure from user-supplied data
C) mysqli does not support string concatenation in queries
D) $_POST values cannot be placed directly inside strings
Q2. Given this bind_param call:
$stmt->bind_param("sssss", $title, $description, $assigned_to, $priority, $due_date);
What would happen if you changed the type string to "ssssi" (note the final i)?
A) Nothing — "i" and "s" are interchangeable
B) PHP would throw a fatal error immediately
C) The due_date string would be cast to an integer, likely storing 0 or a truncated number in the database
D) MySQL would reject the connection
Q3. In view_tasks.php, the SubmissionDate column is never set in submit_task.php. How does it get a value in the database?
A) PHP's date() function inserts it automatically
B) The HTML form has a hidden field that sends the timestamp
C) The column is defined as TIMESTAMP DEFAULT CURRENT_TIMESTAMP, so MySQL writes the server time on every INSERT
D) fetch_assoc() generates it at read time
Q4. You add a new required field "category" (VARCHAR(100) NOT NULL) to the Tasks table. List the three places in the existing code you must update to make the full system work with this new field.
A1. B — Prepared statements bind user data as typed parameters, so the database engine never interprets the data as SQL syntax. A malicious value like '; DROP TABLE Tasks; -- in a text field cannot affect the query structure.
A2. C — The type character "i" tells bind_param to treat that variable as an integer. A date string like "2026-06-01" would be cast to 2026 (PHP truncates at the first non-numeric character), and MySQL would store an invalid or zero date value.
A3. C — The CREATE TABLE statement defined SubmissionDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP. MySQL automatically fills this column with the current server timestamp whenever a new row is inserted and no explicit value is provided for that column.
A4. You must update: (1) the HTML form — add a new <input> or <select> with name="category"; (2) submit_task.php — read $_POST['category'], add a sixth ? to the INSERT statement, add "s" to the bind_param type string, and pass $category as a new argument; (3) view_tasks.php — add a <th>Category</th> header and a <td>" . $row['Category'] . "</td> cell inside the while loop.
🪞 Recap
- An HTML form with
method="post"andaction="submit_task.php"sends field values to a PHP script as$_POSTentries. new mysqli($host, $user, $pass, $db)opens the database connection; always checkconnect_errorbefore continuing.- Prepared statements (
prepare→bind_param→execute) are the correct way to INSERT user-supplied data — they prevent SQL injection by design. TIMESTAMP DEFAULT CURRENT_TIMESTAMPlets MySQL handle submission timestamps automatically, with no PHP code required.$result->num_rowstells you whether any rows were returned before you enter thefetch_assoc()loop, preventing warnings on an empty table.
📚 Further Reading
- PHP mysqli Manual — the source of truth on every
mysqlimethod used in this lesson - OWASP SQL Injection Prevention Cheat Sheet — why prepared statements matter beyond convenience
- MySQL CREATE TABLE Reference — full syntax for column types, defaults, and constraints
- ⬅️ Previous: DIV - Page Design
- ➡️ Next: JavaScript Validation