Skip to Content
Course content

45: Building a Simple Contact Form Handler

Click on the "Edit" button in the top corner of the screen to edit your slide content.

A few years ago, I was reviewing a project for a junior dev who had built a beautiful landing page for a client. Everything looked polished, but the client complained that they weren't receiving any lead emails. The dev was baffled because, in his tests, the "Submit" button worked perfectly—the page would refresh, and he'd see a success message. It turned out he was checking for the form data using $_GET instead of $_POST, and since he'd accidentally left a query string in his test URL, it worked locally but failed completely in production. It's a classic "ghost in the machine" moment that happens when we forget exactly how the browser and server shake hands during a form submission.

Processing the Request and Capturing Data

When a user hits that submit button, the browser bundles up the input values and sends them to the server. To handle this in PHP, your first move should always be verifying that the request actually happened via the method you expected. I always wrap my handler in a check for $_SERVER["REQUEST_METHOD"]. If you don't, your script might try to process an empty form the moment the page loads, which usually leads to a screen full of "Field required" errors before the user has even typed a single character.


if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $name = $_POST['user_name'] ?? '';
    $email = $_POST['user_email'] ?? '';
    $message = $_POST['user_message'] ?? '';
    
    // Process the data here
}

Notice the null coalescing operator (??) there. I use this instead of isset() because it keeps the code clean. It essentially says, "Give me the value from the POST array, but if it's not there, just make it an empty string." This prevents those annoying "Undefined index" notices from cluttering your logs.

Cleaning and Validating the Input

Now, here is where most people get lazy: they trust the user. Never trust the user. Even if you have required attributes in your HTML, a savvy user (or a bot) can bypass those easily. You need to validate the data on the server side. For a contact form, the email address is the most critical piece. I recommend filter_var() with the FILTER_VALIDATE_EMAIL flag. It's far more reliable than trying to write your own complex regular expression for email patterns.


$errors = [];

if (empty($name)) {
    $errors[] = "Please tell us your name.";
}

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $errors[] = "That doesn't look like a valid email address.";
}

if (strlen($message) < 10) {
    $errors[] = "Your message is a bit too short. Please provide more detail.";
}

By collecting errors in an array, you can loop through them and display them all at once to the user, rather than making them submit the form five times to find five different mistakes. It's a small touch, but it makes the experience feel professional.

Preventing the Double-Submit Loop

Once the data is validated and you've used mail() or a library like PHPMailer to send the message, you'll be tempted to just echo "Thank you!". Don't do that. If the user hits the refresh button on their browser, the browser will attempt to re-send the POST data, and your client will receive the same email again. And again. And again.

The fix is the Post-Redirect-Get (PRG) pattern. After the email is successfully sent, you send a header("Location: ...") redirect to a dedicated "thank you" page or back to the form with a success flag in the URL. This clears the POST buffer and ensures a refresh doesn't trigger a duplicate email.


if (empty($errors)) {
    $to = "admin@example.com";
    $subject = "New Contact Form Submission";
    $body = "From: $name \nEmail: $email \n\n$message";
    
    if (mail($to, $subject, $body)) {
        header("Location: success.php");
        exit;
    } else {
        $errors[] = "Server error: Could not send email.";
    }
}

Remember to call exit; immediately after your header redirect. If you don't, the rest of your script will continue to execute in the background even though the user has been told to go elsewhere. I've seen scripts accidentally send two emails because the developer forgot that header() doesn't actually stop the script from running.




📋 Practical Task

Build a Lead Capture Handler with Validation

Create a PHP script that handles a contact form with three fields: full_name, email_address, and company_size (a dropdown with options like "1-10", "11-50", "51+").

Your script must implement the following:

  • Verify the request method is POST.
  • Validate that the email is a properly formatted email address using filter_var().
  • Ensure full_name is not empty and is at least 3 characters long.
  • Verify that company_size matches one of the three expected options (to prevent injected values).
  • If validation fails, display a list of all errors.
  • If validation succeeds, simulate sending an email (using a var_dump or echo since you may not have a mail server configured) and then redirect the user to a page called thanks.html.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.