What I Learned
Core competencies and skills developed throughout this module
Structuring a Backend Without a Framework
Organised a PHP application so that every request follows a clear path, from the incoming URL through the logic to the rendered page.
- Using page controllers: one file per URL, logic at the top
- Sharing configuration and helpers through require
- Separating processing (POST) from displaying (GET)
- Comparing page controllers with the MVC pattern
Database Access with PDO
Connected PHP to MySQL using PDO and configured it so that errors become visible instead of silently failing.
- Creating one shared PDO connection per request
- Setting the error mode to exceptions
- Fetching results as associative arrays
- Keeping credentials out of the public web root
Preventing SQL Injection
Learned why user input must never be concatenated into SQL and how prepared statements solve the problem for good.
- Passing values as parameters to prepare() and execute()
- Building dynamic search queries safely from optional filters
- Using a whitelist for column names, for example in ORDER BY
- Deleting and changing data only via POST requests
Passwords, Sessions & Access Control
Implemented a login that stores no plain-text passwords and protects every admin page against unauthorised access.
- Hashing passwords with password_hash()
- Checking logins with password_verify()
- Remembering the logged-in user with $_SESSION
- Guarding protected pages with a requireLogin() check
Validating Input & Escaping Output
Treated all external data as untrusted: checked it on the server before saving and escaped it before printing it into HTML.
- Validating required fields, lengths and number ranges on the server
- Showing all validation errors at once
- Escaping output with htmlspecialchars() against XSS
- Using the Post/Redirect/Get pattern after form submissions
Transactions & Data Consistency
Grouped related write operations into transactions so the database never ends up in a half-finished state.
- Starting transactions with beginTransaction()
- Confirming with commit() or undoing with rollBack()
- Handling PDOException without leaking internals
- Implementing search, filtering, sorting and pagination
Code Examples
Practical examples from the module
<?php require __DIR__ . '/db.php'; // creates $pdo session_start(); $error = null; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $email = trim($_POST['email'] ?? ''); $password = $_POST['password'] ?? ''; // Prepared statement: user input never ends up inside the SQL string $stmt = $pdo->prepare('SELECT id, password_hash FROM users WHERE email = ?'); $stmt->execute([$email]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if ($user && password_verify($password, $user['password_hash'])) { session_regenerate_id(true); // prevents session fixation $_SESSION['user_id'] = $user['id']; header('Location: admin/index.php'); exit; } $error = 'E-mail or password is wrong.'; }
<?php // Builds one query from optional filters, always with parameters $where = []; $params = []; if (!empty($_GET['title'])) { $where[] = 'title LIKE ?'; $params[] = '%' . $_GET['title'] . '%'; } if (!empty($_GET['max_price'])) { $where[] = 'price <= ?'; $params[] = (float) $_GET['max_price']; } // Column names cannot be bound as parameters: use a whitelist $allowedSort = ['title', 'price', 'year']; $sort = in_array($_GET['sort'] ?? '', $allowedSort, true) ? $_GET['sort'] : 'title'; $sql = 'SELECT id, title, price FROM books'; if ($where) { $sql .= ' WHERE ' . implode(' AND ', $where); } $sql .= " ORDER BY $sort"; $stmt = $pdo->prepare($sql); $stmt->execute($params); foreach ($stmt as $book) { echo '<li>' . htmlspecialchars($book['title'], ENT_QUOTES) . '</li>'; }
Skills Acquired
Technologies and concepts mastered in this module
Key Takeaways
- Never trust input: Everything coming from the browser is validated on the server.
- Parameters, not strings: Prepared statements make SQL injection impossible by design.
- Hash, never store: Passwords belong in the database only as password_hash() values.
- Escape on output: Every value printed into HTML goes through htmlspecialchars().
- All or nothing: Transactions keep related changes consistent even if something fails.