PHP Forms — Handling, Validation & Security Complete Guide
PHP forms are how users send data to your web server — collecting, validating, and processing input safely is the most common task in web development and the most common source of security vulnerabilities.
What You’ll Learn
By the end of this tutorial, you’ll build secure forms with proper validation, error handling, file uploads, CSRF protection, and sticky form persistence.
Why Form Handling Matters
Forms are the gateway between users and your application. Durga Antivirus Pro uses forms for license activation, threat report submissions, and scan configuration. Doda Browser uses forms for login, sync settings, and bookmark import. DodaZIP uses forms for file upload and extraction options. Every interaction starts with a form — if it’s insecure, your entire application is at risk.
Forms Learning Path
flowchart LR
A[Functions] --> B[Arrays]
B --> C[Forms]
C --> D[Advanced OOP]
D --> E[Frameworks]
C --> F{You Are Here}
style F fill:#f90,color:#fff
How Form Data Flows (The “Why” First)
Think of a form like a paper application form. The user fills it out (browser), puts it in an envelope (HTTP request), and mails it to you (server). You open the envelope, read the answers ($_GET or $_POST), and decide what to do.
flowchart LR
A[User fills form] --> B[Browser submits]
B --> C{Method?}
C -->|GET| D[URL parameters]
C -->|POST| E[Request body]
D --> F[$_GET]
E --> F
F --> G{Validate}
G -->|Valid| H[Process data]
G -->|Invalid| I[Show errors]
I --> A
GET vs POST — Which to Use?
| Feature | GET | POST |
|---|---|---|
| Data location | URL query string | Request body |
| Visible in URL | Yes | No |
| Bookmarkable | Yes | No |
| Size limit | ~2000 chars | Large (file uploads) |
| Security | Low | Better |
| Use case | Searches, filters | Logins, orders, uploads |
Rule of thumb: Use GET for reading data (search pages, filters). Use POST for writing data (signups, orders, file uploads).
Basic Form with Validation
<?php
$name = $email = "";
$nameErr = $emailErr = "";
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$name = trim($_POST["name"] ?? "");
$email = trim($_POST["email"] ?? "");
if (empty($name)) {
$nameErr = "Name is required";
} elseif (!preg_match("/^[a-zA-Z\s]+$/", $name)) {
$nameErr = "Only letters and spaces allowed";
}
if (empty($email)) {
$emailErr = "Email is required";
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$emailErr = "Invalid email format";
}
}
?>
<form method="post">
Name: <input type="text" name="name" value="<?= htmlspecialchars($name) ?>">
<span style="color:red;"><?= $nameErr ?></span><br>
Email: <input type="text" name="email" value="<?= htmlspecialchars($email) ?>">
<span style="color:red;"><?= $emailErr ?></span><br>
<input type="submit" value="Submit">
</form>
Line by line:
$_SERVER["REQUEST_METHOD"] === "POST"— check if the form was submittedtrim()— remove whitespace from both endspreg_match()— validate format using regex patternfilter_var(... FILTER_VALIDATE_EMAIL)— PHP’s built-in email validatorhtmlspecialchars()— critical: prevents XSS by escaping HTML characters
File Uploads
<form method="post" enctype="multipart/form-data">
<input type="file" name="document">
<input type="submit" value="Upload">
</form>
<?php
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_FILES["document"])) {
$file = $_FILES["document"];
$allowedTypes = ["application/pdf", "image/jpeg", "image/png"];
$maxSize = 5 * 1024 * 1024; // 5MB
if ($file["error"] !== UPLOAD_ERR_OK) {
echo "Upload failed";
} elseif (!in_array($file["type"], $allowedTypes)) {
echo "File type not allowed";
} elseif ($file["size"] > $maxSize) {
echo "File too large";
} else {
$ext = pathinfo($file["name"], PATHINFO_EXTENSION);
$dest = "uploads/" . uniqid() . "." . $ext;
move_uploaded_file($file["tmp_name"], $dest);
echo "Uploaded successfully";
}
}
?>
Critical: Always validate MIME type, not just file extension. A file named virus.php.jpg might be executed as PHP.
CSRF Protection — The Hidden Token
Cross-Site Request Forgery (CSRF) tricks authenticated users into submitting unwanted actions. The fix is a unique token in each form:
<?php session_start();
if (empty($_SESSION["csrf_token"])) {
$_SESSION["csrf_token"] = bin2hex(random_bytes(32));
} ?>
<form method="post">
<input type="hidden" name="csrf_token" value="<?= $_SESSION["csrf_token"] ?>">
<button type="submit">Update Email</button>
</form>
<?php
if ($_SERVER["REQUEST_METHOD"] === "POST") {
if (!hash_equals($_SESSION["csrf_token"], $_POST["csrf_token"] ?? "")) {
die("CSRF validation failed");
}
// Process form...
}
?>
Common Mistakes
1. No Server-Side Validation
JavaScript validation is for UX only. Malicious users can bypass client-side checks or send raw POST requests. Always validate on the server.
2. Directly Echoing Raw Input (XSS)
// DANGEROUS
echo "Hello, " . $_GET["name"];
// SAFE
echo "Hello, " . htmlspecialchars($_GET["name"], ENT_QUOTES, "UTF-8");3. Trusting File Extensions
Check the MIME type with finfo_file(), not just the extension. Attackers can rename shell.php to shell.pdf.
4. Forgetting enctype=“multipart/form-data”
File uploads won’t work without this attribute on the <form> tag.
5. Not Regenerating CSRF Tokens
Using the same token for the entire session weakens security. Regenerate after successful submission.
Practice Questions
1. What’s the difference between $_GET, $_POST, and $_REQUEST?
$_GET has URL query parameters. $_POST has request body data. $_REQUEST combines both plus cookies. Use $_GET and $_POST explicitly.
2. Why is htmlspecialchars() necessary when outputting form values?
It prevents XSS (Cross-Site Scripting). If a user submits <script>alert('xss')</script>, without escaping, the script runs in your page.
3. How do you validate an email address in PHP?
filter_var($email, FILTER_VALIDATE_EMAIL) — returns the email if valid, false otherwise.
4. What must you add to a form for file uploads?
enctype="multipart/form-data" on the <form> tag.
5. Challenge: Build a registration form that validates username (3-20 chars, alphanumeric), email, password (min 8 chars), and password confirmation match.
<?php
$errors = [];
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$username = trim($_POST["username"] ?? "");
$email = trim($_POST["email"] ?? "");
$password = $_POST["password"] ?? "";
$confirm = $_POST["confirm"] ?? "";
if (!preg_match("/^[a-zA-Z0-9_]{3,20}$/", $username))
$errors[] = "Invalid username";
if (!filter_var($email, FILTER_VALIDATE_EMAIL))
$errors[] = "Invalid email";
if (strlen($password) < 8)
$errors[] = "Password too short";
if ($password !== $confirm)
$errors[] = "Passwords don't match";
if (empty($errors)) echo "Registration successful!";
}
?>
FAQ
Try It Yourself
Create a secure registration form combining validation, CSRF protection, and sticky fields. Run with php -S localhost:8000 and test submitting invalid and valid data.
What’s Next
| Lesson | Description |
|---|---|
| https://tutorials.dodatech.com/backend/php/php-advanced/ | Sessions, OOP, PDO database |
| https://tutorials.dodatech.com/backend/php/php-reference/ | PHP functions cheatsheet |
| https://tutorials.dodatech.com/backend/nodejs/nodejs-basics/ | Server-side JavaScript |
| SQL Injection | Preventing SQL injection |
| Laravel | Form handling in Laravel |
What’s Next
Congratulations on completing this Php Forms tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro