PHP: Form Handling in PHP

If PHP has a trump card, it's form handling. Tasks that other languages need a framework to accomplish, PHP has been able to do since day one. This lesson teaches you the single most practical skill in web development.

1. HTML Form Refresher

HTML
<form method="POST" action="process.php">
    <!-- Form fields go here -->
    <button type="submit">Submit</button>
</form>
Attribute Value Description
method GET or POST GET = fetch data, POST = modify data
action URL ("" = same page) Where the data is sent
name Field name Required — PHP uses this to access the value
🔥 Common Mistake: Every form field must have a name attribute. If a field is missing name, PHP will never receive its value.


2. Receiving Different Field Types

(1) Text Fields

PHP
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name     = $_POST['name'] ?? '';
    $email    = $_POST['email'] ?? '';
    $password = $_POST['password'] ?? '';
    $bio      = $_POST['bio'] ?? '';
}
?>

<form method="POST" action="">
    <input type="text" name="name" placeholder="Username"><br>
    <input type="email" name="email" placeholder="Email"><br>
    <input type="password" name="password" placeholder="Password"><br>
    <textarea name="bio" placeholder="About yourself"></textarea><br>
    <button type="submit">Register</button>
</form>

(2) Selection Fields (Radio, Checkbox, Dropdown)

▶ Example: Handling Selection Fields

Output:

TEXT 📖 Display only
Gender: {value}<br>
Skills: " . implode(', ', value) . "<br>
City: {New York}<br>
PHP
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $gender = $_POST['gender'] ?? '';
    $skills = $_POST['skills'] ?? [];   // Checkboxes come as an array
    $city   = $_POST['city'] ?? '';

    echo "Gender: {$gender}<br>";
    echo "Skills: " . implode(', ', $skills) . "<br>";
    echo "City: {$city}<br>";
}
?>

<form method="POST" action="">
    <label>Gender:</label>
    <input type="radio" name="gender" value="male"> Male
    <input type="radio" name="gender" value="female"> Female
    <br>

    <label>Skills:</label>
    <input type="checkbox" name="skills[]" value="php"> PHP
    <input type="checkbox" name="skills[]" value="mysql"> MySQL
    <input type="checkbox" name="skills[]" value="js"> JavaScript
    <br>

    <label>City:</label>
    <select name="city">
        <option value="">Choose...</option>
        <option value="beijing">Beijing</option>
        <option value="shanghai">Shanghai</option>
    </select>
    <br>

    <button type="submit">Submit</button>
</form>

Output:

TEXT 📖 Display only
Gender: male
Skills: php, mysql
City: beijing
⚠️ Warning: Checkbox groups must use name="skills[]" (with square brackets) so PHP collects all checked values into an array. Without the brackets, you'll only receive the last checked value.


3. Form Repopulation (Preserving User Input)

The worst user experience is filling out a form, hitting submit, getting an error, and losing everything you typed. PHP makes this trivially easy to fix:

▶ Example: Form with Error Handling and Repopulation

Output:

TEXT 📖 Display only
<h3 style='color:green'>Registration successful! Welcome, {Alice}!</h3>
<ul style='color:red'>
</ul>
PHP
<?php
$errors = [];
$name = $email = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name  = trim($_POST['name'] ?? '');
    $email = trim($_POST['email'] ?? '');

    if ($name === '') {
        $errors[] = 'Username is required';
    }
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $errors[] = 'Invalid email format';
    }

    if (empty($errors)) {
        echo "<h3 style='color:green'>Registration successful! Welcome, {$name}!</h3>";
        $name = $email = '';  // Clear fields on success
    } else {
        echo "<ul style='color:red'>";
        foreach ($errors as $e) echo "<li>{$e}</li>";
        echo "</ul>";
    }
}
?>

<form method="POST" action="">
    <input type="text" name="name" placeholder="Username"
           value="<?= htmlspecialchars($name) ?>"><br>
    <input type="email" name="email" placeholder="Email"
           value="<?= htmlspecialchars($email) ?>"><br>
    <button type="submit">Register</button>
</form>

Output:

TEXT 📖 Display only
Name must be at least 2 characters
A valid email is required
Password must be at least 6 characters
💡 Tip: htmlspecialchars() is essential here — it prevents characters like ", <, and > in user input from breaking your HTML or injecting scripts (XSS attacks). We'll cover this in depth in Lesson 18.


4. Repopulating Radio Buttons and Checkboxes

PHP
<?php
$gender = $_POST['gender'] ?? 'male';
$skills = $_POST['skills'] ?? [];
?>

<!-- Radio buttons: use the checked attribute -->
<input type="radio" name="gender" value="male"
       <?= $gender === 'male' ? 'checked' : '' ?>> Male

<!-- Checkboxes: check with in_array -->
<input type="checkbox" name="skills[]" value="php"
       <?= in_array('php', $skills) ? 'checked' : '' ?>> PHP

<!-- Dropdown: use the selected attribute -->
<select name="city">
    <option value="beijing" <?= $city === 'beijing' ? 'selected' : '' ?>>Beijing</option>
</select>

5. Detecting Form Submissions

PHP
<?php
// Method 1: Check the request method (recommended)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Process the form
}

// Method 2: Check for the submit button
if (isset($_POST['submit'])) {
    // Process the form
}

// Method 3: Check if any POST data arrived
if (!empty($_POST)) {
    // Process the form
}
?>

6. The PRG Pattern (Post-Redirect-Get)

Ever submitted a form, hit refresh, and seen that dreaded "Confirm form resubmission" dialog? The PRG pattern fixes it for good:

PHP
<?php
// prg.php
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Process the data
    $name = trim($_POST['name'] ?? '');
    
    // Store a flash message in the session
    $_SESSION['flash_message'] = "Welcome, {$name}!";
    
    // Redirect to the same page with a GET request
    header("Location: " . $_SERVER['PHP_SELF']);
    exit;
}

// Display any flash message
if (isset($_SESSION['flash_message'])) {
    echo "<div style='color:green'>{$_SESSION['flash_message']}</div>";
    unset($_SESSION['flash_message']);
}
?>

<form method="POST" action="">
    <input type="text" name="name" placeholder="Username">
    <button type="submit">Register</button>
</form>
💡 Tip: header("Location: ...") issues a redirect; exit stops the script immediately. The PRG flow: POST → process data → redirect to GET → user refreshes the GET page safely, no duplicate submission.

▶ Example: Server-Side Form Validation Function

Output:

TEXT 📖 Display only
false
PHP
<?php
function validateForm(array $data): array {
    $errors = [];
    if (strlen(trim($data['name'] ?? '')) < 2) {
        $errors[] = "Name must be at least 2 characters";
    }
    if (!filter_var($data['email'] ?? '', FILTER_VALIDATE_EMAIL)) {
        $errors[] = "A valid email is required";
    }
    if (strlen($data['password'] ?? '') < 6) {
        $errors[] = "Password must be at least 6 characters";
    }
    return $errors;
}

$errors = validateForm(['name' => 'A', 'email' => 'bad', 'password' => '12']);
echo empty($errors) ? "Valid!" : implode("<br>", $errors);

Output:

TEXT 📖 Display only
Output displayed

❓ FAQ

Q Why aren't my checkboxes showing up in PHP?
A Check if the name attribute includes [] (e.g., skills[]). Without the brackets, only the last checked value is sent. With name[], PHP collects them all into an array.
Q Will my forms still work if the user disables JavaScript?
A Absolutely. PHP form processing happens entirely on the server — it doesn't depend on JavaScript at all. JavaScript only improves the experience (client-side validation, AJAX submissions), but the core functionality works without it.
Q header("Location: ...") throws an error. What's wrong?
A The most common cause is output before header(). Anything — an echo, raw HTML, even a blank line or BOM before the <?php tag — counts as output. Make sure header() runs before any output, and save your file as UTF-8 without BOM.

📖 Summary

📝 Exercises

  1. Build a full registration form with: username, email, password, gender (radio), interests (checkboxes), and city (dropdown). Use var_dump() to inspect all received data on submission.
  2. Add validation and repopulation to the form: username must not be empty, email must be valid, gender must be selected. Preserve all user input when validation fails.
  3. Implement the PRG pattern: after successful registration, redirect to the same page and display a green "Registration successful" message.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏