Online admissions open for the SEO, PHP web development and networking & cybersecurity courses. Enquire for the next batch.

PHP Sessions and Cookies: Keeping Users Logged In Safely

6 min read Updated By the SkillNewton team

What are sessions and cookies in PHP?

Cookies and sessions are how PHP remembers a visitor between requests. A cookie is a small piece of data the browser stores and sends back with every request. A session keeps data on the server in $_SESSION and links it to the visitor through a single random session ID, which is itself stored in a cookie.

Why HTTP needs cookies and sessions

HTTP is stateless: each request arrives on its own, and the server has no built-in memory that the same person sent the previous one. Logins, shopping carts and language preferences all need some way to connect requests together.

CookieSession
Where data livesIn the browserOn the server
Can the visitor read or edit it?YesNo, only the session ID
Typical sizeA few kilobytes at mostLimited only by server storage
Good forPreferences, consent choices, the session IDUser ID after login, cart contents, flash messages

The rule that follows is simple: never trust a cookie value for anything that matters, because the visitor controls it. Store important state in the session instead.

Cookies are sent as HTTP headers, so setcookie() must run before any HTML or whitespace is output. Since PHP 7.3 you can pass an options array, which is clearer than the long list of positional arguments.

<?php
setcookie('theme', 'dark', [
    'expires'  => time() + 60 * 60 * 24 * 30, // 30 days
    'path'     => '/',
    'secure'   => true,     // only sent over HTTPS
    'httponly' => true,     // hidden from JavaScript
    'samesite' => 'Lax',    // Strict, Lax or None
]);

$theme = $_COOKIE['theme'] ?? 'light';

// Delete a cookie by expiring it with the same path
setcookie('theme', '', ['expires' => time() - 3600, 'path' => '/']);
  • secure stops the cookie travelling over plain HTTP. SameSite=None only works together with secure.
  • httponly stops scripts reading the cookie, which limits the damage of a cross-site scripting bug.
  • samesite controls whether the cookie is sent on requests from other sites, which helps against cross-site request forgery.
  • A new cookie appears in $_COOKIE only on the next request, not the one that set it.

How PHP sessions work behind the scenes

When you call session_start(), PHP looks for a session ID cookie (named PHPSESSID by default). If it finds one, it loads the matching data into $_SESSION; if not, it creates a new random ID and sends it as a cookie. At the end of the request PHP saves $_SESSION back to storage, which is a file on the server unless you configure a database or cache.

<?php
session_start([
    'cookie_secure'   => true,
    'cookie_httponly' => true,
    'cookie_samesite' => 'Lax',
    'use_strict_mode' => true,
]);

$_SESSION['visits'] = ($_SESSION['visits'] ?? 0) + 1;
echo 'Visits this session: ' . $_SESSION['visits'];

Because the session ID is the only key to the data, anyone who steals it can act as that user. That is why the cookie flags matter, and why the site must run over HTTPS.

On a live server, set these options once in php.ini or your framework configuration rather than on every page, so no page can forget them. If your application runs on more than one server behind a load balancer, file-based sessions will not be shared between machines; store them in a database or a cache such as Redis so every server sees the same session data. Keep $_SESSION small and store IDs rather than whole database rows, which can go stale.

Logging in, flash messages and logging out

A secure login stores only the user ID in the session and issues a brand-new session ID at the moment of login.

<?php
// login.php, after password_verify() succeeds
session_regenerate_id(true); // new ID, old session deleted
$_SESSION['user_id'] = $user['id'];
$_SESSION['flash'] = 'Welcome back!';
header('Location: /dashboard');
exit;

// dashboard.php: show the flash message once, then remove it
$flash = $_SESSION['flash'] ?? null;
unset($_SESSION['flash']);

// logout.php
$_SESSION = [];
$params = session_get_cookie_params();
setcookie(session_name(), '', [
    'expires'  => time() - 3600,
    'path'     => $params['path'],
    'domain'   => $params['domain'],
    'secure'   => $params['secure'],
    'httponly' => $params['httponly'],
    'samesite' => $params['samesite'],
]);
session_destroy();

A proper logout does three things: it empties the session array, deletes the session cookie in the browser and destroys the stored data on the server. Make logout a POST request with a CSRF token, as explained in the PHP security guide, so other sites cannot log your users out.

Session fixation and how to prevent it

In a session fixation attack, an attacker gets a victim to use a session ID the attacker already knows, for example through a crafted link. When the victim logs in, the attacker shares the now-authenticated session. Two settings close this gap:

  • Call session_regenerate_id(true) whenever privilege changes: after login, after a password change and when a user gains admin rights.
  • Enable session.use_strict_mode, so PHP refuses session IDs it did not create itself.

A related attack is session hijacking, where the ID is stolen after login rather than planted before it. HTTPS everywhere, the HttpOnly flag and escaping all output against cross-site scripting are your main defences.

Building remember-me login safely, step by step

A remember-me cookie keeps users signed in after the session ends. Never store a user ID or password in that cookie. Use a random token and keep only its hash in the database, so a leaked database cannot be used to log in.

  1. Create a table with columns for an ID, user ID, a selector, a token_hash and an expires_at date.
  2. On login with the box ticked, generate $selector = bin2hex(random_bytes(12)) and $validator = bin2hex(random_bytes(32)).
  3. Store the selector and hash('sha256', $validator) in the table with an expiry date.
  4. Send a cookie containing selector:validator with secure, httponly and samesite set.
  5. On a later visit with no session, look up the row by selector and compare hashes with hash_equals(), which runs in constant time.
  6. If it matches, regenerate the session ID, log the user in, then delete that row and issue a fresh token.
  7. On logout or password change, delete all of that user's tokens.

Practical exercise: a members area with flash messages

Build a three-page site on your own machine: login.php, members.php and logout.php. Hard-code one test user whose password is stored with password_hash().

  • Start every page with the same session_start() options shown above, kept in one included file.
  • Redirect visitors who are not logged in from members.php to the login page with a flash message.
  • Show "Logged in successfully" once after login and confirm it disappears on refresh.
  • Add a theme cookie that switches between light and dark.

You are done when your browser developer tools show a different session ID before and after login, the session cookie carries the HttpOnly and SameSite flags, and after logout the back button no longer shows member content. The PHP foundation course uses this pattern in its project work.

Common mistakes

  • Calling setcookie() or session_start() after HTML has been output, which causes a "headers already sent" warning.
  • Storing a user ID or role in a plain cookie and trusting it to decide who is logged in.
  • Forgetting to regenerate the session ID after login, which leaves the site open to session fixation.
  • Logging out with only session_destroy(), leaving the session array and cookie behind.
  • Saving remember-me tokens in the database as plain text instead of as a hash.
  • Putting large arrays or whole database rows in $_SESSION, which slows every request and leaves stale data behind.

Frequently asked questions

How long does a PHP session last?

By default the session cookie lasts until the browser closes, and the server removes stored data after a period of inactivity controlled by session.gc_maxlifetime. For predictable expiry, track activity time in the session yourself.

Can I use sessions in an API?

You can for a browser-based app on the same site, but APIs called by mobile apps or other servers usually send a token in the Authorization header instead. Our guide to APIs covers token-based requests.

Do I need a cookie consent banner for session cookies?

Privacy rules in many regions treat strictly necessary cookies, such as a login session cookie, differently from analytics or advertising cookies. Check the rules that apply to your audience, and keep essential cookies separate from optional tracking ones.

Why does my page load slowly when two tabs are open?

With file-based storage, PHP locks a session while a request uses it, so a second request waits. Call session_write_close() as soon as you have finished changing $_SESSION to release the lock early.

Want to Learn This Properly?

The PHP Web Development: Foundation & Practical Implementation (Online) turns guides like this into practised skills, with projects on real websites.

WhatsApp Call Us Now

Free counselling

Send an Enquiry

Tell us which course you are interested in. We reply by email or phone with the next batch and how to enrol.

We reply by email or phone within working hours. No spam.