Magyar zászlóMagyar

Practice 9 - PHP: POST Forms and Input Validation

2025-04-10 2 min read GitHub

Introduction

Last session we handled a simple two-field form using GET. This session covers:

  • POST forms and when to use them instead of GET
  • trim() — removing accidental whitespace from user input
  • Validating different input types: email, word count, password length, non-negative integer, checkbox
  • Sticky forms — preserving the user’s input values after a validation failure
  • The ternary operator and chained null coalescing (??)

1. GET vs POST

Both methods submit form data to the server. The difference is where the data travels:

GETPOST
Data locationURL query string (?a=1&b=2)Request body (not visible in URL)
BookmarkableYesNo
Use forRead-only queries, searchesAny form that submits or modifies data
PHP superglobal$_GET$_POST

For a login form, a registration form, or any form where you collect sensitive data, always use POST:

<form method="POST" action="task1.php">
    ...
</form>

On submission, $_POST is populated just like $_GET was before:

if ($_POST) {
    $email = $_POST['email'];
}
💡

if ($_POST) is truthy when the superglobal array is non-empty, i.e. when the form was submitted. An empty array [] is falsy in PHP.


2. trim — removing whitespace

Users often accidentally type a leading or trailing space. trim removes it:

$email = trim($_POST['email']);
// " a@a.com " -> "a@a.com"

Always trim text inputs before validating them. A correct email with a trailing space would otherwise fail validation.


3. Validating an email address

if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
    $errors["email"] = "The email you entered is not valid";
}

FILTER_VALIDATE_EMAIL checks that the string matches the expected format (user@domain.tld). As with numbers, use === false so that a legal email that happens to be falsy-looking is not rejected.


4. Validating word count — explode + count

$twoWords = trim($_POST['two_words']);
$words = explode(" ", $twoWords);

if (count($words) < 2) {
    $errors["two_words"] = "The input cannot consist of less than 2 words";
}

explode(" ", $str) splits the string on every space and returns an array. If the result has fewer than 2 elements, fewer than 2 words were entered.

ℹ️

This is a minimal check. A production validator would also handle multiple consecutive spaces (e.g. using preg_split('/\s+/', trim($str))). For a classroom exercise, single-space splitting is sufficient.


5. Validating password length — strlen

$password = trim($_POST['password']);

if (strlen($password) < 7) {
    $errors["password"] = "Your password must be at least 7 characters.";
}

strlen returns the number of bytes in the string (for ASCII passwords this equals the character count).

JavaScript equivalent:

if (password.length < 7) { ... }

6. Validating a non-negative integer

Two rules in sequence: first check that the value is a valid integer, then check the sign.

$num = trim($_POST['non-negative-number']);

if (filter_var($num, FILTER_VALIDATE_INT) === false) {
    $errors["non-negative-number"] = "This is not a valid number";
} else if ($num < 0) {
    $errors["non-negative-number"] = "Must not be a negative number";
}

PHP automatically coerces the string "5" to the integer 5 in the comparison $num < 0, so no explicit cast is needed here.


7. Handling checkboxes

Checkboxes are different from text inputs: if the checkbox is unchecked, the browser does not send the field at all — the key will be absent from $_POST.

Use the null coalescing operator to safely read it:

$tickme = $_POST['tickme'] ?? false;

if ($tickme != "on") {
    $errors["tickme"] = "Must be checked";
}

When a checkbox is checked, the browser sends the string "on" as its value (unless a different value attribute is set). When unchecked, the key is missing, so $_POST['tickme'] would throw a notice — ?? false catches that and gives a safe default.


8. The ternary operator

PHP has the same ternary as JavaScript:

echo $condition ? "yes" : "no";
// condition ? value_if_true : value_if_false

Example — re-checking the checked state for the checkbox:

echo ($tickme ?? false) == "on" ? "checked" : "";

The parentheses around ($tickme ?? false) are important: ?? has lower precedence than ==, so without them PHP would evaluate false == "on" first.


9. Chained ?? — multiple fallbacks

?? chains: each operand is tried left to right; the first one that is set and not null wins.

echo $errors['email'] ?? $defaultEmail ?? "I cannot fallback to any emails";
  • If $errors['email'] is set → use it
  • Else if $defaultEmail is set → use it
  • Otherwise → use the final string literal

JavaScript equivalent:

errors.email ?? defaultEmail ?? "I cannot fallback to any emails"

10. Sticky form values

After a validation failure, the form is re-displayed with the user’s previous input pre-filled. Without this, every error forces the user to retype everything.

Use the short echo tag and ?? to either echo the submitted value or fall back to an empty string:

<input type="text" name="email"
       value="<?= $email ?? "" ?>" />
  • On first visit ($_POST is empty) → $email is undefined → falls back to ""
  • After a failed submission → $email holds the trimmed submitted value → it is echoed into the attribute

For the checkbox, you need to conditionally add the checked attribute:

<input type="checkbox" name="tickme"
       <?= ($tickme ?? false) == "on" ? "checked" : "" ?> />

11. Commenting in PHP

// Single line comment

# Also a single line comment (less common)

/*
   Multi-line
   comment
*/

Complete task1.php

<?php

$errors = [];

if ($_POST) {
    $email = trim($_POST['email']);
    if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
        $errors["email"] = "The email you entered is not valid";
    }

    $twoWords = trim($_POST['two_words']);
    $words = explode(" ", $twoWords);
    if (count($words) < 2) {
        $errors["two_words"] = "The input cannot consist of less than 2 words";
    }

    $password = trim($_POST['password']);
    if (strlen($password) < 7) {
        $errors["password"] = "Your password must be at least 7 characters.";
    }

    $nonNegativeNumber = trim($_POST['non-negative-number']);
    if (filter_var($nonNegativeNumber, FILTER_VALIDATE_INT) === false) {
        $errors["non-negative-number"] = "This is not a valid number";
    } else if ($nonNegativeNumber < 0) {
        $errors["non-negative-number"] = "Must not be a negative number";
    }

    $tickme = $_POST['tickme'] ?? false;
    if ($tickme != "on") {
        $errors["tickme"] = "Must be checked";
    }
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Form:</h1>

    <form method="POST" action="task1.php">

        E-mail:
        <input type="text" name="email" value="<?= $email ?? "" ?>" />
        <?= $errors['email'] ?? "" ?>
        <br>

        At least two words:
        <input type="text" name="two_words" value="<?= $twoWords ?? "" ?>" />
        <?= $errors['two_words'] ?? "" ?>
        <br>

        Password:
        <input type="password" name="password" />
        <?= $errors['password'] ?? "" ?>
        <br>

        Non-negative number:
        <input type="text" name="non-negative-number"
               value="<?= $nonNegativeNumber ?? "" ?>" />
        <?= $errors['non-negative-number'] ?? "" ?>
        <br>

        <input type="checkbox" name="tickme"
               <?= ($tickme ?? false) == "on" ? "checked" : "" ?> />
        Accept the terms &amp; conditions
        <?= $errors['tickme'] ?? "" ?>
        <br>

        <button type="submit">Send form</button>
    </form>
</body>
</html>

Summary

ConceptPHP
POST form<form method="POST">$_POST["name"]
Strip whitespacetrim($str)
Validate emailfilter_var($v, FILTER_VALIDATE_EMAIL) === false
Split by spaceexplode(" ", $str)
String lengthstrlen($str)
Validate integerfilter_var($v, FILTER_VALIDATE_INT) === false
Checkbox value$_POST['name'] ?? false"on" when checked, absent when not
Ternary$cond ? $a : $b
Chained fallback$a ?? $b ?? $c
Sticky input valuevalue="<?= $var ?? "" ?>"
Sticky checkbox<?= ($v ?? false) == "on" ? "checked" : "" ?>
Comment styles//, #, /* */