18. PHP Forms

What you will learn

  • How a form sends data to PHP
  • How to handle a form in the same file
  • How to read text, choices, and checkboxes
  • Why you redirect after a successful POST

How it works

  1. The visitor fills in an HTML form and presses submit.
  2. The browser sends the values to the address in action, using the method.
  3. PHP receives them in $_POST (or $_GET).
  4. Your code checks them, does the work, and shows a result.

Each field’s name attribute becomes the key in the array. A field without a name is never sent.

A first form

An empty action (or leaving it out) sends the form back to the same file. This is the simplest set-up for learning.

PHP code: hello-form.php

<?php
$message = "";

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $name = trim($_POST["name"] ?? "");
    $message = "Hello, " . htmlspecialchars($name, ENT_QUOTES, "UTF-8") . "!";
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Hello form</title>
</head>
<body>
  <form method="post">
    <label for="name">Your name</label>
    <input type="text" id="name" name="name">
    <button type="submit">Say hello</button>
  </form>

  <p><?php echo $message; ?></p>
</body>
</html>

What you see (a display-only demo)


After typing Sam and submitting, the paragraph below the form shows: Hello, Sam!

Step by step

  1. The first time the page loads, the method is GET, so the if block is skipped and the message is empty.
  2. When the form is submitted, the method is POST, so PHP reads name, makes it safe, and builds the message.
  3. The page is then drawn, with the message under the form.

Different kinds of field

Field How it arrives in $_POST
Text, email, textarea A string
Number A string (convert it)
Radio buttons The value of the chosen one. Missing if none is chosen
Single checkbox Its value if ticked. Missing if not ticked
Several checkboxes (name="tags[]") An array of the ticked values
Select drop-down The chosen value

PHP code: survey.php (the processing part)

<?php
if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $level = $_POST["level"] ?? "";          // radio
    $topics = $_POST["topics"] ?? [];        // checkboxes, an array
    $news = isset($_POST["newsletter"]);     // single checkbox

    echo "Level: " . htmlspecialchars($level, ENT_QUOTES, "UTF-8") . "<br>";
    echo "Topics: " . htmlspecialchars(implode(", ", $topics), ENT_QUOTES, "UTF-8") . "<br>";
    echo "Newsletter: " . ($news ? "yes" : "no");
}

HTML code: survey.php (the form part)

<form method="post">
  <fieldset>
    <legend>Your level</legend>
    <input type="radio" id="l1" name="level" value="beginner">
    <label for="l1">Beginner</label>
    <input type="radio" id="l2" name="level" value="advanced">
    <label for="l2">Advanced</label>
  </fieldset>

  <fieldset>
    <legend>Topics</legend>
    <input type="checkbox" id="t1" name="topics[]" value="html">
    <label for="t1">HTML</label>
    <input type="checkbox" id="t2" name="topics[]" value="php">
    <label for="t2">PHP</label>
  </fieldset>

  <input type="checkbox" id="n" name="newsletter" value="yes">
  <label for="n">Send me the newsletter</label>

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

Output after choosing Beginner, HTML and PHP, and ticking the newsletter

Level: beginner
Topics: html, php
Newsletter: yes

The square brackets in name="topics[]" tell PHP to collect every ticked box into an array.

Redirect after POST

If a visitor refreshes a page that was just reached by a POST, the browser offers to send the form again, which could create a second order or message. The fix is the Post / Redirect / Get pattern: after a successful POST, send the browser to a normal page with header().

PHP code

<?php
if ($_SERVER["REQUEST_METHOD"] === "POST") {
    // ...validate and save the data here...

    header("Location: thanks.php");
    exit;
}
  • header() must run before any output, including blank lines before <?php. Otherwise you get “headers already sent”.
  • Always call exit straight after, or the rest of the script keeps running.

Fake requests: why a token matters

A malicious site can trick a logged-in visitor’s browser into sending a form to your site. This is called CSRF. The defence is a secret, random token stored in the session and placed in the form as a hidden field, which PHP checks on submit. You will build one in the Security lesson. WordPress has its own version, called a nonce, which you saw in the plugin code for this site.

Sending email from a form

A contact form often emails you. Putting visitor text straight into email headers allows header injection, where an attacker adds extra recipients. In real projects, use a well-tested mail library or a service, and validate carefully. On WordPress, use wp_mail() and a form plugin that handles this for you.

Local sites cannot usually send real email. LocalWP includes a tool to catch outgoing mail for testing, so use that rather than expecting delivery.

Common mistakes

  • Forgetting method="post", so the form sends GET and nothing is in $_POST.
  • Fields with no name, so nothing arrives.
  • Reading $_POST without checking the keys exist.
  • Treating a missing checkbox as “no” without testing isset().
  • Printing the values without htmlspecialchars().
  • Not redirecting after a successful POST.
  • Output before header().

Exercise

Build a form with one text field called city. When it is submitted, print You live in and the city, safely. If the field is empty, print Please enter a city.

Show solution
<?php
$message = "";

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    $city = trim($_POST["city"] ?? "");

    if ($city === "") {
        $message = "Please enter a city.";
    } else {
        $message = "You live in " . htmlspecialchars($city, ENT_QUOTES, "UTF-8");
    }
}
?>
<form method="post">
  <label for="city">City</label>
  <input type="text" id="city" name="city">
  <button type="submit">Send</button>
</form>
<p><?php echo $message; ?></p>

Knowledge check

1. Which attribute becomes the key in $_POST?

The field’s name.

2. How do you collect several ticked checkboxes into an array?

Give them the same name ending in [], such as topics[].

3. Why redirect after a successful POST?

So refreshing the page does not send the form a second time.

Summary

  • Fields arrive in $_POST by their name, and a form can post to its own file.
  • Unticked checkboxes are missing, and grouped checkboxes arrive as an array.
  • Escape output, redirect after success, and protect real forms against CSRF.
Scroll to Top