Topic 21 of 48 · Full Stack Essentials

Form Submission (Task)

Lesson TL;DRTopic 6: Form Submission (Task) 📖 15 min read · 🎯 intermediate · 🧭 Prerequisites: cssadvance, divpagedesign Why this matters Before we dive in, think about the last time you filled out a form onlin...
15 min read·intermediate·php · html-forms · mysql · mysqli

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 mysqli in 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.

  1. Task Details — Collect the task's title, description, assigned person, priority, and due date from the user.
  2. Validation — All fields are required; the form must not submit if any are blank.
  3. Database Storage — Persist the submitted data in a MySQL table called Tasks inside the TaskManagement database.
  4. 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.
  • required on every input — the browser enforces client-side presence before the POST fires.
  • The priority field is a <select> with exactly three valid values: low, medium, high.
  • type="date" gives the browser's native date picker, producing a YYYY-MM-DD string that MySQL's DATE column 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.
  • SubmissionDateTIMESTAMP DEFAULT CURRENT_TIMESTAMP means MySQL writes the current server time automatically on every INSERT, 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 $_POST holds 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. Returns true on success.
  • Always close $stmt and $conn to 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 plain SELECT * (no user input, so no prepared statement is needed here).
  • $tasksResult->num_rows — the count of rows returned. If zero, the else branch prints a single spanning cell with "No tasks found".
  • fetch_assoc() in a while loop — 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 table border-collapse: collapse, consistent 12 px cell padding, a 1 px #ddd border on every cell, and a #f2f2f2 background 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.

  1. Start Apache and MySQL in your XAMPP/WAMP control panel.
  2. Open phpMyAdmin, run the CREATE DATABASE and CREATE TABLE SQL from Chapter 3.
  3. Save the HTML form as task_form.html in your htdocs folder (XAMPP) or www folder (WAMP).
  4. Save submit_task.php and view_tasks.php in the same folder.
  5. Visit http://localhost/task_form.html in 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 correct SubmissionDate filled 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" and action="submit_task.php" sends field values to a PHP script as $_POST entries.
  • new mysqli($host, $user, $pass, $db) opens the database connection; always check connect_error before continuing.
  • Prepared statements (preparebind_paramexecute) are the correct way to INSERT user-supplied data — they prevent SQL injection by design.
  • TIMESTAMP DEFAULT CURRENT_TIMESTAMP lets MySQL handle submission timestamps automatically, with no PHP code required.
  • $result->num_rows tells you whether any rows were returned before you enter the fetch_assoc() loop, preventing warnings on an empty table.

📚 Further Reading

Like this topic? It’s one of 48 in Full Stack Essentials.

Block your seat for ₹2,500 and join the next cohort.