HOWTO · PHP

How to Return to Previous Page in PHP

This tutorial introduces how to return to previous page in PHP

On this page

To return a visitor to the page that contains a form, read the optional HTTP_REFERER value from $_SERVER, accept only a local destination you allow, and send a Location header with header() before producing a response. A referrer is not guaranteed to be present, so use a safe local fallback.

Use the HTTP_REFERER Request Header to Return to the Previous Page in PHP

A form on index.php can submit to a handler such as home.php. The browser may send the form page’s URL in the HTTP_REFERER request header, which PHP exposes as $_SERVER['HTTP_REFERER']. Browsers and privacy settings can omit this header, and clients can supply arbitrary values, so do not redirect to it without validation. The header is a request hint, not a reliable record of browser history; applications should still work when it is absent.

In index.php, the form can send a message along with the submission:

<form action="home.php" method="post"><input type="hidden" name="message" value="Saved."><button type="submit">Submit</button></form>

The following complete home.php handler accepts only the local /index.php path. This example requires PHP 8.0 or later because it uses str_contains(). It retains that page’s existing query parameters, adds the submitted message, and falls back to /index.php when the referrer is missing or points elsewhere. When run from the command line, it uses a sample request and prints the redirect target so the example has a useful local success path; on a web request, it sends a 303 redirect and exits.

<?php
// home.php
$isCli = PHP_SAPI === 'cli';

// Provide a sample request when running this file directly with PHP CLI.
if ($isCli) {
    $_SERVER['REQUEST_METHOD'] = 'POST';
    $_SERVER['HTTP_REFERER'] = 'https://example.test/index.php?tab=profile';
    $_POST['message'] = 'Saved.';
}

if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
    http_response_code(405);
    exit;
}

$message = $_POST['message'] ?? 'Your form was submitted.';
if (!is_string($message)) {
    $message = 'Your form was submitted.';
}

$destination = '/index.php';
$referrer = $_SERVER['HTTP_REFERER'] ?? '';
$parts = parse_url($referrer);
if (is_array($parts) && ($parts['path'] ?? '') === '/index.php') {
    $query = [];
    parse_str($parts['query'] ?? '', $query);
    $destination = '/index.php';
    if ($query !== []) {
        $destination .= '?' . http_build_query($query);
    }
}

$separator = str_contains($destination, '?') ? '&' : '?';
$target = $destination . $separator . http_build_query(['message' => $message]);

if ($isCli) {
    echo $target, PHP_EOL;
    exit;
}

header('Location: ' . $target, true, 303);
exit;

For the sample request, the handler prints this redirect target:

/index.php?tab=profile&message=Saved.

On the return page, escape the message before inserting it into HTML. First confirm that the query value is a string, since query parameters can also arrive as arrays: htmlspecialchars(is_string($_GET['message'] ?? null) ? $_GET['message'] : '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'). URL encoding in the handler protects the query parameter; HTML escaping on display protects the page. Apply the same string check to any other value that will be passed to a string-only escaping function.

The handler rebuilds the destination from the approved local path instead of using the referrer’s host, so an external URL cannot become the redirect target. Its path allowlist is intentionally narrow: if your application has several form pages, map each accepted local path explicitly and keep a safe local fallback for values outside that list. The example preserves query parameters from the accepted referrer, then adds or replaces the message parameter through http_build_query(); this avoids hand-building URL encoding and keeps the redirect path separate from its query string.

header() must run before any HTML, whitespace, or other response output. The exit after the redirect prevents later handler code from running as though the request had continued normally. The 303 status tells the browser to follow the redirect with a GET request after the form’s POST. The CLI branch is only a demonstration aid; in a web request, PHP sends the response header rather than printing the target as page content. If your hosting environment runs an earlier PHP version, replace str_contains($destination, '?') with a compatible check such as strpos($destination, '?') !== false and confirm the rest of the application supports that version.