Question

How to Expire a PHP Session After 30 Minutes

phpsessioncookies

Question

I need a PHP session to remain active for 30 minutes and then be destroyed automatically. What is the correct way to implement a 30-minute session timeout in PHP?

Short Answer

By the end of this page, you will understand how PHP sessions work, how to implement a 30-minute inactivity timeout, how to destroy expired sessions safely, and how this pattern is used in real applications.

Concept

PHP sessions let a server remember information about a user across multiple requests. For example, after a user logs in, you can store their user ID in $_SESSION so they stay authenticated while browsing.

A common requirement is to expire a session after a period of inactivity, such as 30 minutes. This is important for:

  • Security: prevents abandoned accounts from staying logged in
  • Privacy: protects users on shared devices
  • Control: lets the application define its own timeout rules

A key detail is that PHP does not automatically mean "30 minutes of inactivity" just because a session exists. There are two related but different ideas:

  • Session cookie lifetime: how long the browser keeps the session cookie
  • Application timeout logic: how your code decides whether a user has been inactive too long

For most login systems, the best approach is to store the user's last activity time in $_SESSION, then on each request:

  1. Start the session
  2. Check the time since the last activity
  3. If more than 30 minutes have passed, destroy the session
  4. Otherwise, update the activity timestamp

This gives you reliable control over session expiration in your application.

Mental Model

Think of a PHP session like a visitor badge at an office.

  • The badge identifies the visitor
  • The office security desk keeps a record of when the visitor was last active
  • If the visitor has been inactive for too long, the badge is invalidated

In PHP:

  • The badge is the session ID stored in the browser cookie
  • The security record is the data in $_SESSION
  • The inactivity rule is your timeout check using a timestamp

So instead of hoping the badge disappears on its own, your application actively checks whether the badge should still be valid.

Take Quiz

Syntax and Examples

The usual pattern is:

<?php
session_start();

$timeoutDuration = 1800; // 30 minutes = 1800 seconds

if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY']) > $timeoutDuration) {
    session_unset();
    session_destroy();
}

$_SESSION['LAST_ACTIVITY'] = time();

What this does

  • session_start() loads the current session
  • $_SESSION['LAST_ACTIVITY'] stores the timestamp of the user's last request
  • time() returns the current Unix timestamp in seconds
  • If the difference is greater than 1800, the session is cleared and destroyed
  • If not expired, the last activity time is updated

A more complete example

<?php
session_start();

$timeoutDuration = 1800;

if (isset($_SESSION['LAST_ACTIVITY'])) {
    $inactiveTime = time() - $_SESSION['LAST_ACTIVITY'];

    if ($inactiveTime > $timeoutDuration) {
        session_unset();
        session_destroy();
        header('Location: login.php?expired=1');
        exit;
    }
}

$_SESSION['LAST_ACTIVITY'] = time();

This version redirects the user to a login page after the session expires.

Optional: regenerate session ID after login

<?php
session_start();

// After successful login
session_regenerate_id(true);
$_SESSION['user_id'] = 123;
$_SESSION['LAST_ACTIVITY'] = time();

This improves security by reducing session fixation risk.

Step by Step Execution

Consider this code:

<?php
session_start();

$timeoutDuration = 1800;

if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY']) > $timeoutDuration) {
    session_unset();
    session_destroy();
    exit('Session expired');
}

$_SESSION['LAST_ACTIVITY'] = time();

echo 'Session is active';

Example walkthrough

Assume:

  • $_SESSION['LAST_ACTIVITY'] = 1000
  • current time() is 2500

Now step through it:

  1. session_start() opens the existing session
  2. $timeoutDuration is set to 1800
  3. PHP checks whether $_SESSION['LAST_ACTIVITY'] exists
    • It does, and its value is 1000
  4. PHP calculates inactivity:
    • 2500 - 1000 = 1500
  5. PHP compares 1500 > 1800
    • This is false
  6. The session is not destroyed
  7. $_SESSION['LAST_ACTIVITY'] is updated to the current time, 2500
  8. The script prints Session is active

If the user was inactive too long

Assume instead:

  • $_SESSION['LAST_ACTIVITY'] = 1000
  • current time() is 2905

Then:

  • 2905 - 1000 = 1905
  • 1905 > 1800 is true
  • PHP clears session data with session_unset()
  • PHP destroys the session with session_destroy()
  • The script exits with Session expired

That is the core timeout logic.

Real World Use Cases

This pattern is used in many real applications:

  • Admin dashboards: log out admins after inactivity for better security
  • Banking or billing apps: expire sessions quickly to reduce risk
  • School or library computers: prevent the next user from accessing someone else's account
  • Internal company tools: enforce inactivity timeouts for compliance rules
  • Customer portals: protect personal data when users leave a tab open

Example scenarios

  • A user logs into a CMS and walks away from their laptop
  • An employee accesses payroll information from a shared machine
  • A support agent leaves an authenticated dashboard open during a break

In each case, inactivity timeout helps protect the account even if the browser stays open.

Take Quiz

Real Codebase Usage

In real PHP projects, session expiration is usually handled in a shared file that runs on every protected page.

Common pattern: authentication guard

<?php
session_start();

$timeoutDuration = 1800;

if (!isset($_SESSION['user_id'])) {
    header('Location: login.php');
    exit;
}

if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY']) > $timeoutDuration) {
    session_unset();
    session_destroy();
    header('Location: login.php?expired=1');
    exit;
}

$_SESSION['LAST_ACTIVITY'] = time();

This is often placed in a file such as auth.php and included at the top of protected pages.

Patterns developers commonly use

  • Guard clauses: immediately redirect if the user is not logged in
  • Early return or exit: stop processing as soon as the session is invalid
  • Centralized validation: keep timeout logic in one reusable file
  • Session regeneration: call session_regenerate_id(true) after login
  • Redirect with reason: add query parameters like ?expired=1
  • Role checks: combine timeout checks with permissions like admin/user

Important note

Many codebases use both:

  • application-level inactivity checking with $_SESSION['LAST_ACTIVITY']
  • server/session configuration for cookie and garbage collection settings

The application-level check is the most direct and predictable way to enforce a 30-minute idle timeout.

Common Mistakes

1. Confusing cookie lifetime with inactivity timeout

Setting a cookie lifetime does not always mean the user is logged out after 30 minutes of inactivity.

Broken idea:

<?php
session_set_cookie_params(1800);
session_start();

Why this is not enough:

  • It affects the browser cookie lifetime
  • It does not by itself check user inactivity in your app logic
  • A session may still exist on the server until garbage collection removes it

2. Forgetting to call session_start()

Broken code:

<?php
if (isset($_SESSION['LAST_ACTIVITY'])) {
    // ...
}

Fix:

<?php
session_start();

You must start the session before reading or writing $_SESSION.

3. Updating the activity time before checking expiration

Broken code:

<?php
session_start();
$_SESSION['LAST_ACTIVITY'] = time();

if ((time() - $_SESSION['LAST_ACTIVITY']) > 1800) {
    session_destroy();
}

Why it fails:

  • You overwrite the old timestamp first
  • The time difference becomes nearly zero
  • The session never expires

4. Destroying the session without stopping the script

Broken code:

<?php
session_start();
session_destroy();
echo 'Welcome back';

Fix:

<?php
session_start();
session_unset();
session_destroy();
exit;

After destroying a session, stop further processing or redirect immediately.

5. Assuming session.gc_maxlifetime alone solves it

This setting controls how long session data may remain before garbage collection, but it is not a precise per-user inactivity timeout.

Use app logic for reliable expiration.

6. Not clearing authentication data properly

If your app stores login information in $_SESSION, make sure it is removed when the session expires.

Typical safe approach:

<?php
session_unset();
session_destroy();

Comparisons

ApproachWhat it doesGood forLimitation
$_SESSION['LAST_ACTIVITY'] checkTracks inactivity in application codeReliable idle timeoutMust run on each protected request
session_set_cookie_params()Sets session cookie lifetimeControlling browser cookie durationNot enough alone for inactivity logout
session.gc_maxlifetimeDefines server-side session data lifetimeServer configurationGarbage collection is not exact timing
Manual logout onlyEnds session when user clicks logoutBasic systemsNo automatic expiration

Inactivity timeout vs absolute timeout

TypeMeaning
Inactivity timeoutLog out after no activity for a period, such as 30 minutes
Absolute timeoutLog out after a fixed total time, even if the user is active

Most apps asking for "expire after 30 minutes" actually mean 30 minutes of inactivity.

session_unset() vs session_destroy()

FunctionPurpose
session_unset()Removes all session variables
session_destroy()Destroys the session data on the server

Developers often use both together when logging a user out or expiring a session.

Take Quiz

Cheat Sheet

session_start();

$timeoutDuration = 1800; // 30 minutes

if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY']) > $timeoutDuration) {
    session_unset();
    session_destroy();
    header('Location: login.php?expired=1');
    exit;
}

$_SESSION['LAST_ACTIVITY'] = time();

Quick rules

  • Call session_start() before using $_SESSION
  • Store last activity with $_SESSION['LAST_ACTIVITY'] = time()
  • Check inactivity before updating the timestamp
  • Use 1800 seconds for 30 minutes
  • After destroying the session, exit or redirect immediately
  • Put this logic on every protected page or in a shared auth file

Useful functions

  • session_start() — starts or resumes a session
  • time() — gets current Unix timestamp
  • session_unset() — clears session variables
  • session_destroy() — destroys session data
  • session_regenerate_id(true) — creates a new session ID securely

Good default flow

  1. Start session
  2. Check if user is logged in
  3. Check inactivity timeout
  4. Destroy expired session if needed
  5. Update last activity time
  6. Continue normal page logic

FAQ

How do I automatically log out a PHP user after 30 minutes?

Store the last activity time in $_SESSION, compare it to time() on each request, and destroy the session if the difference is greater than 1800 seconds.

Is session.gc_maxlifetime enough to expire a PHP session?

No. It affects how long session data may remain on the server, but it is not a reliable way to enforce a precise inactivity timeout for each user.

Should I use session_unset() and session_destroy() together?

Yes, that is a common and safe pattern. session_unset() clears session variables, and session_destroy() removes the session data.

What is 30 minutes in PHP session timeout code?

Use 1800 seconds, because 30 × 60 = 1800.

Where should I put PHP session timeout logic?

Usually in a shared file included at the top of all protected pages, such as auth.php or bootstrap.php.

Does user activity in another browser tab keep the session alive?

Yes. If another tab makes a request to the server before the timeout, your LAST_ACTIVITY value will be updated and the session stays active.

Should I regenerate the session ID after login?

Yes. Using session_regenerate_id(true) after a successful login is a good security practice.

Take Quiz

Mini Project

Description

Build a small PHP page protection system that logs users out after 30 minutes of inactivity. This demonstrates how real applications protect authenticated pages using session checks and redirects.

Goal

Create a protected page that only logged-in users can access, and automatically expire the session after 30 minutes of inactivity.

Requirements

  1. Start a PHP session and simulate a logged-in user.
  2. Store the user's last activity time in the session.
  3. On each page load, check whether more than 1800 seconds have passed.
  4. If the session has expired, destroy it and redirect to a login page.
  5. If the session is still valid, update the last activity timestamp and show protected content.
Take Quiz

Keep learning

Related questions

View more