Section 1: Forms — GET vs POST
Concept
HTML form sends data to server using 2 methods:
GET = data visible in URL, good for search/filter. POST = data hidden, good for login/submit.
| Feature | GET | POST |
|---|---|---|
| Data in URL? | Yes | No |
| Data size limit | ~2048 chars | No limit (almost) |
| Use for | Search, filter | Login, send data |
| Bookmarkable? | Yes | No |
| PHP variable | $_GET | $_POST |
Code Example
GET Form Demo
POST Form Demo
When to use GET vs POST?
Use GET for:
- Search / Filter
- Bookmark or share links
- Non-sensitive data
Use POST for:
- Login (password)
- Form with sensitive data
- File upload
- Create / Update / Delete
Section 2: Superglobals & Debug Panel
Concept
Superglobals are special PHP variables available everywhere. PHP creates them automatically.
| Variable | Description | Example |
|---|---|---|
$_GET | Data from URL query string | ?name=John |
$_POST | Data from POST form | Login form |
$_REQUEST | GET+POST+COOKIE combined Avoid! | Dangerous - source unclear |
$_SERVER | Server & request info | METHOD, User-Agent |
$_FILES | Uploaded files | Images |
$_SESSION | Session data | Login state |
$_COOKIE | Cookie data | Remember me |
$_REQUEST mixes GET + POST + COOKIE. An attacker can confuse the data source. Always use $_GET or $_POST directly!
Code — Safe Superglobal Access
Debug Panel — Live Superglobal Values
These are real values from the current request, safely escaped with htmlspecialchars().
$_SERVER (selected)
| REQUEST_METHOD | GET |
| SCRIPT_NAME | /php/php_forms_security_login_beginner.php |
| SERVER_NAME | isophal.com |
| SERVER_PORT | 443 |
| HTTP_USER_AGENT | Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com) |
$_SESSION
Array
(
[csrf_token] => 50474e427c1255ef...
)
$_GET
(empty)
$_COOKIE
(empty)
Section 3: Validation & Sanitization
Concept
Validation = Check if data is correct (format, range, required).
Sanitization = Clean data to remove dangerous content.
Both are needed! Validate first, then sanitize for output.
| Function | Purpose | Example |
|---|---|---|
trim() | Remove whitespace | trim(" hello ") = "hello" |
filter_var() | Validate email, URL, int | filter_var($e, FILTER_VALIDATE_EMAIL) |
htmlspecialchars() | Escape HTML (prevent XSS) | htmlspecialchars($input) |
XSS Attack Explained
XSS (Cross-Site Scripting) = attacker injects JavaScript code into your page.
Example: user types <script>alert('hacked')</script> in a form field.
If you echo this without escaping, the browser will run the JavaScript!
BAD (vulnerable):
GOOD (safe):
<script>alert('test')</script> in the validation form below. You will see it displayed as plain text, not executed!
Code — Validation Pattern
Validation Lab — Interactive
Fill in the form and submit. Errors will appear per field. Old values are preserved.
Section 4: Secure File Upload
Concept
File upload is powerful but dangerous if done wrong! An attacker could upload a PHP file and execute it on your server.
Security Checklist:
- Allow-list extensions — only allow jpg, png, webp (reject php, exe!)
- Check MIME type — use
finfo_file()orgetimagesize() - Max file size — enforce limit (e.g., 2 MB)
- Rename file — never trust user filename! Use
bin2hex(random_bytes()) - Use
enctype="multipart/form-data"on the form - Store safely — ideally outside webroot; if not, use random name + safe extension
Code — Secure Upload
Upload Demo — Interactive
Allowed: JPG, PNG, WEBP only. Max 2 MB.
Safe File Delete Pattern
Section 5: Login with Sessions
Concept
Sessions let you store user data across pages. PHP creates a session ID stored in a cookie.
Session Lifecycle:
session_start()— start/resume session (must be before any HTML output!)$_SESSION['key'] = value— store datasession_regenerate_id(true)— regenerate ID after login (security!)session_destroy()— destroy session on logout
Security Rules:
- Always
session_regenerate_id(true)after login to prevent session fixation - Store passwords as hashes:
password_hash()+password_verify() - Never store plain passwords anywhere!
- Destroy session completely on logout
Code — Session Login Pattern
Login Demo — Interactive
Test accounts: admin/admin123 or student/student123
How password_hash works
password_hash('admin123', PASSWORD_DEFAULT) generates:
$2y$10$gVFvtns/DiPqiMM.V70BIuwhzCIHmZVVU72nF5.PyfrOqHFT0ddH6
Each call produces a different hash (unique salt). But password_verify() can check any valid hash:
password_verify('admin123', $hash) returns true.
NEVER store plain text passwords!
Practice Questions (22 items)
Part A: GET/POST & Superglobals (6 questions)
Q1 (MCQ): Which method shows data in the URL?
a) POST b) GET c) PUT d) PATCH
Hint: Think about URL parameters like ?key=value
Q2: When should you use POST instead of GET? Give 2 examples.
Hint: Think about sensitive data and data modification.
2) Forms that create/update/delete data (e.g., registration, file upload)
POST hides data from URL and has no size limit.
Q3 (MCQ): Which superglobal contains data sent via POST?
a) $_GET b) $_SERVER c) $_POST d) $_FILES
Hint: The name matches the method.
Q4: What does $_SERVER['REQUEST_METHOD'] return?
Hint: It tells you HOW the page was requested.
"GET" or "POST" (as a string).Q5 (MCQ): Why should you avoid $_REQUEST?
a) It's slow b) It doesn't work c) It mixes GET+POST+COOKIE (unclear source) d) It's deprecated
Hint: Think about security and knowing where data comes from.
Q6: Write code to safely read and display a GET parameter called name.
Hint: Use htmlspecialchars() and the null coalescing operator ??
Part B: Validation & Sanitization (8 tasks)
Q7: What is the difference between validation and sanitization?
Hint: One checks, the other cleans.
Sanitization = cleaning data to remove/escape dangerous characters.
Example: Validate email format, sanitize output with htmlspecialchars().
Q8: Write code to validate that an email is valid using filter_var().
Hint: Use FILTER_VALIDATE_EMAIL
Q9: Write validation for age (must be integer between 10 and 80).
Hint: filter_var with FILTER_VALIDATE_INT and options
Q10: This code has an XSS vulnerability. Fix it:
Hint: What happens if name contains <script>?
Q11: Write code to trim whitespace and validate username is 3-20 characters.
Hint: Use trim() then mb_strlen()
Q12: Write validation for an optional URL field.
Hint: Only validate if not empty. Use FILTER_VALIDATE_URL.
Q13: Write validation for a password field (min 8 chars, must contain a number).
Hint: Use strlen() and preg_match()
Q14: What does htmlspecialchars() do? Why is it critical?
Hint: Think about < and > characters.
htmlspecialchars() converts special HTML characters to entities:< becomes <, > becomes >, " becomes "This prevents XSS attacks by ensuring user input is displayed as text, not executed as HTML/JS.
Part C: File Upload Security (5 tasks)
Q15: This upload code is insecure. Identify the vulnerability:
Hint: What if someone uploads a file called malware.php?
1) No extension check — user can upload .php files!
2) No MIME type check — file could be disguised
3) No size limit — could fill disk
4) Uses original filename — path traversal risk
5) No XSS protection when echoing filename
Q16: Why should you rename uploaded files instead of using the original name?
Hint: Think about overwriting, special characters, and execution.
2) Prevent directory traversal (names like ../../etc/passwd)
3) Prevent execution (names like shell.php)
4) Remove special characters that could cause issues
Best practice:
bin2hex(random_bytes(12)) . '.' . $safe_ext
Q17: Write code to check if an uploaded file extension is allowed.
Hint: Use pathinfo() and in_array()
Q18: Why is checking only the file extension NOT enough for security?
Hint: Can you rename a .php file to .jpg?
You must also check:
1) MIME type using
finfo_file() or mime_content_type()2) For images:
getimagesize() returns false if not a real imageBoth checks together = much safer.
Q19: Improve this upload code to be secure:
Hint: Add extension check, MIME check, size limit, safe name.
Part D: Sessions & Login (3 tasks)
Q20: This login code has a security issue. Fix it:
Hint: What about session fixation? And plain text password?
Q21: Write code to protect a page so only logged-in users can access it.
Hint: Check $_SESSION and redirect if not logged in.
Q22: Write a complete, safe logout script.
Hint: Clear session data, destroy session, delete cookie.
Mini Challenge
Challenge 1: Build a Secure Contact Form
Build a single-file PHP page with:
- A POST form with fields: name, email, subject, message
trim()all inputs- Validate: all required, email must be valid, message min 10 chars
- Show per-field errors using red text
- Keep old input values after submit
- Use
htmlspecialchars()for ALL output - Add a CSRF token
- If valid, show a success message with the submitted data (safely escaped)
Challenge 2: Protect a Page with Session Login
Create a page that:
- Shows a login form if user is NOT logged in
- Uses password_hash/password_verify (never plain text!)
- On successful login: session_regenerate_id(true)
- Shows protected content only when logged in
- Has a working logout button that fully destroys the session
Answer Key
Click to reveal all answers at once.
| # | Quick Answer |
|---|---|
| Q1 | b) GET |
| Q2 | Login (sensitive data), Create/Update/Delete operations |
| Q3 | c) $_POST |
| Q4 | Returns "GET" or "POST" (the HTTP method string) |
| Q5 | c) It mixes GET+POST+COOKIE (unclear data source) |
| Q6 | htmlspecialchars($_GET['name'] ?? '', ENT_QUOTES, 'UTF-8') |
| Q7 | Validation = check format; Sanitization = clean/escape data |
| Q8 | filter_var($email, FILTER_VALIDATE_EMAIL) |
| Q9 | filter_var($age, FILTER_VALIDATE_INT, [options => [min_range=>10, max_range=>80]]) |
| Q10 | Add htmlspecialchars() around $_GET['name'] |
| Q11 | trim() then check mb_strlen() between 3-20 |
| Q12 | Only validate if not empty; use FILTER_VALIDATE_URL |
| Q13 | strlen() >= 8 and preg_match('/[0-9]/', $pass) |
| Q14 | Converts < > " & to HTML entities to prevent XSS |
| Q15 | No ext check, no MIME check, no size limit, uses original filename |
| Q16 | Prevent collisions, traversal, execution; use random name |
| Q17 | pathinfo() for ext + in_array() against allow-list |
| Q18 | Extensions can be faked; also need finfo MIME check + getimagesize() |
| Q19 | Add ext+MIME+size checks, random filename, getimagesize() |
| Q20 | Use password_hash/verify + session_regenerate_id(true) |
| Q21 | Check $_SESSION['logged_in'], redirect + exit if not set |
| Q22 | $_SESSION=[]; delete cookie; session_destroy(); redirect+exit |