PHP
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Object-Oriented PHP
-
Section 5: Working with Data
-
Section 6: Modern PHP (PHP 8)
-
Section 7: Working with Files and Networking
-
Section 8: Common PHP Frameworks Overview
-
Section 9: Tooling and Ecosystem
-
Section 10: Practical Projects
-
Section 11: Interview Practice
-
Section 12: More Standard Library
-
Section 13: Data Structures and Algorithms in PHP
-
Section 14: More Practice Exercises
-
Section 15: More Security and Best Practices
-
Section 16: More Testing and Tooling
-
Section 17: WordPress-Style CMS Concepts
-
Section 18: Advanced OOP Practice
-
Section 19: More Web Fundamentals
-
Section 20: Database Practice
-
Section 21: PHP Manual: Array Functions
-
Section 22: PHP Manual: Date and Calendar Functions
-
Section 23: PHP Manual: Filesystem and Directory Functions
-
Section 24: PHP Manual: Filter and Var Handling
-
Section 25: PHP Manual: Math Functions
-
Section 26: PHP Manual: JSON and XML
-
Section 27: PHP Manual: Network and Stream Functions
-
Section 28: PHP Manual: Error and Exception Handling
-
Section 29: PHP Manual: Output Control and Misc
-
Section 30: PHP Manual: FTP, Zip, and Mail
-
Section 31: Modern PHP Frameworks Deep Dive
-
Section 32: PHP Design Patterns
-
Section 33: More Practice Exercises
-
Section 34: PHP Performance and Deployment
-
Section 35: More Interview Practice
-
Section 36: More PHP Standard Library
-
Section 37: PHP Concurrency and Async
-
Section 38: More Web Development Practice
-
Section 39: PHP Testing Deep Dive
-
Section 40: Composer and Package Development
-
Section 41: PHP Security Deep Dive
-
Section 42: More Practical Projects
-
Section 43: Legacy PHP Maintenance
-
Section 44: More Algorithm Practice
-
Section 45: Final Practice and Review
-
Section 46: PHP for E-Commerce Patterns
-
Section 47: PHP API Design Deep Dive
-
Section 48: PHP Caching Strategies
-
Section 49: PHP Queue and Background Jobs
-
Section 50: PHP Multi-Tenancy Patterns
-
Section 51: PHP Real-Time Features
-
Section 52: PHP CMS and Content Modeling
-
Section 53: PHP Internationalization
-
Section 54: More Framework-Specific Practice
-
Section 55: PHP Legacy Code Refactoring
-
Section 56: More Practice Projects Round 2
-
Section 57: PHP Command-Line Applications
-
Section 58: PHP and Microservices
-
Section 59: More Interview and Review Round 2
160: Building a Session-Based Authentication System
I want to start this lesson with a snippet of code that I've seen a lot of developers struggle with. It looks perfectly logical on the surface, but it fails every single time. Imagine you've just built a login page that successfully verifies a user's password and sets a session variable. Now, you've created a dashboard.php page that should only be accessible to logged-in users.
// dashboard.php
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
echo "Welcome to your dashboard, " . $_SESSION['username'] . "!";
You test it, and no matter how many times you log in, you are immediately kicked back to the login page. You check your login.php and the session is definitely being set. You check your browser cookies and the session ID is there. You're staring at the screen wondering why PHP is "forgetting" who you are.
The Ghost Session Problem
The issue here is subtle because it's an omission rather than a syntax error. In PHP, the $_SESSION superglobal isn't magically available on every page just because you started a session on a previous page. PHP is stateless. Every time a new request hits the server, PHP starts from scratch.
When you call $_SESSION['user_id'] in the code above, PHP looks at the $_SESSION array. Since you haven't told PHP to resume the session for this specific request, that array is empty. The isset() check fails, and you get redirected. I've spent more hours than I'd like to admit debugging this exact thing in my early years.
Resuming the Session State
To fix this, you have to call session_start() at the very top of every single file that needs to access session data. This function tells PHP to look for the session ID cookie sent by the browser, find the corresponding data file on the server, and populate the $_SESSION array for you.
// dashboard.php
session_start(); // This must come before any output!
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
echo "Welcome to your dashboard, " . $_SESSION['username'] . "!";
One pro tip: always put session_start() before any HTML tags or even a single whitespace character. If PHP sends a single byte of output to the browser, it sends the HTTP headers. Since sessions rely on cookies (which are sent in the headers), calling session_start() after output will trigger a "headers already sent" warning and the session won't initialize.
Structuring the Authentication Flow
When building a full system, I recommend separating your "auth check" into its own file. You don't want to copy-paste that if(!isset...) block into twenty different pages. Instead, create a file called auth_check.php:
// auth_check.php
session_start();
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
Now, your protected pages become incredibly clean. You just require that file at the top, and if the user isn't logged in, the script dies and redirects them before any sensitive content is rendered.
Tearing Down the Session
Logging in is the easy part; logging out is where people often leave security holes. Simply calling unset($_SESSION['user_id']) removes the variable from the current script, but the session file still exists on the server, and the cookie still exists in the browser. To properly kill a session, you need to clear the array and destroy the server-side data.
// logout.php session_start(); // 1. Clear all session variables $_SESSION = []; // 2. Destroy the session cookie in the browser if (ini_get("session.use_cookies")) { $params = session_get_cookie_params(); setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"] ); } // 3. Destroy the session on the server session_destroy(); header("Location: login.php"); exit();I know that looks like a lot of boilerplate for a logout script, but it's the only way to ensure the session is truly gone. This prevents "session replay" attacks where someone might try to use an old session ID to gain access.
📋 Practical Task
Build a Protected User Settings Page with Session Validation
Your task is to create a mini-authentication system consisting of three files. You don't need a real database for this; you can simulate a user check with a hardcoded array.
- login.php: Create a form that accepts a username and password. If the username is "admin" and password is "secret123", start a session and store
user_id = 1andusername = 'Admin'in the$_SESSIONarray, then redirect to the settings page. - settings.php: This page must be protected. Use a separate include file (e.g.,
auth_check.php) to ensure the user is logged in. If they are, display a "User Settings" heading and a link to the logout page. - logout.php: Implement a full session teardown that clears the
$_SESSIONarray, deletes the session cookie, and destroys the session on the server before redirecting back tologin.php.
Requirement: Ensure that if a user tries to access settings.php directly via the URL without logging in, they are immediately redirected to the login page.
There are no comments for now.