PHP Superglobals Reference

Superglobals are built-in PHP arrays that are automatically available in every scope of your script – inside functions, methods, and classes – without ever needing a global keyword or a function parameter. They are how PHP hands your code the outside world: the query string, form data, uploaded files, cookies, session data, and details about the server and request itself. Because nearly every real-world PHP script touches user input in some form, understanding superglobals thoroughly – not just their names but how they are populated and how to use them safely – is one of the most important skills in PHP development.

Overview: How Superglobals Work

PHP defines nine superglobals: $GLOBALS, $_SERVER, $_GET, $_POST, $_FILES, $_COOKIE, $_SESSION, $_REQUEST, and $_ENV. They are called “superglobals” because the Zend Engine marks them with a special auto_global flag at compile time. Ordinary variables are scoped to the function or file they are declared in; superglobals bypass that scoping rule entirely, so $_GET inside a deeply nested function refers to the exact same array as $_GET at the top of the script.

Most superglobals are populated once, at the very start of the request, before your script’s first line even runs. The SAPI (Server API – for example PHP-FPM behind Nginx, or the Apache module) hands PHP the raw request: the query string, the request headers, the POST body, and any uploaded file streams. PHP’s request-startup code parses these raw inputs into arrays:

  • $_SERVER is filled from CGI/SAPI variables and HTTP headers (things like REQUEST_METHOD and HTTP_HOST).
  • $_GET is filled by parsing the query string portion of the URL.
  • $_POST and $_FILES are filled only when the request method is POST and the body is application/x-www-form-urlencoded or multipart/form-data.
  • $_COOKIE is filled by parsing the Cookie header sent by the browser.
  • $_ENV is filled from the process environment, subject to the variables_order ini directive.
  • $_SESSION is the odd one out: it does not exist until you explicitly call session_start(), which either creates a new session or resumes one identified by a session-id cookie.
  • $_REQUEST is a merge of GET, POST, and COOKIE data, in an order controlled by the request_order ini setting (by default, GET then POST).
  • $GLOBALS is different again – it is not populated from the request at all. It is a live reference to every variable currently declared in the global scope, which is why writing to $GLOBALS['x'] inside a function actually changes the global $x.

Syntax

Superglobals are just arrays, so you read and write them with normal array syntax. The table below is the quick reference for all nine.

Superglobal Populated from Typical use
$GLOBALS Every variable in the global scope Read or modify a global variable from inside a function
$_SERVER Web server / SAPI and HTTP headers Request method, host, URI, IP address, headers
$_GET URL query string Filter/search parameters, pagination, IDs in links
$_POST Form-encoded or multipart request body Submitted form fields
$_FILES Multipart file uploads Uploaded file name, size, tmp path, error code
$_COOKIE Cookie request header Reading previously-set cookies
$_SESSION Server-side session storage (after session_start()) Login state, shopping carts, flash messages
$_REQUEST Merge of GET + POST + COOKIE Rarely recommended – see Common Mistakes
$_ENV Process environment variables Configuration values, secrets injected by the host

The general access pattern is always the same:

$value = $_SUPERGLOBAL['key'] ?? $default;

Using the null-coalescing operator ?? is the modern, safe way to read a key that might not exist, since accessing a missing array key directly triggers an “Undefined array key” warning.

Examples

Example 1: Reading and validating query string data

<?php
// Assume the request URL is: page.php?name=Alice&age=30
$name = $_GET['name'] ?? 'Guest';
$age  = filter_input(INPUT_GET, 'age', FILTER_VALIDATE_INT);

echo "Hello, " . htmlspecialchars($name, ENT_QUOTES) . "!" . PHP_EOL;
echo "Age: " . ($age !== null && $age !== false ? $age : 'unknown') . PHP_EOL;

Output:

Hello, Alice!
Age: 30

This example shows the two safety habits you should always apply to $_GET: use ?? (or isset()) to avoid warnings on missing keys, and run untrusted values through htmlspecialchars() before echoing them, or through a validating filter like filter_input() when you expect a specific type such as an integer.

Example 2: Inspecting the request with $_SERVER

<?php
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host     = $_SERVER['HTTP_HOST'] ?? 'localhost';
$uri      = $_SERVER['REQUEST_URI'] ?? '/';
$method   = $_SERVER['REQUEST_METHOD'] ?? 'GET';

$fullUrl = "{$protocol}://{$host}{$uri}";

echo "Method: {$method}" . PHP_EOL;
echo "Full URL: {$fullUrl}" . PHP_EOL;

Output (assuming a GET request to http://example.com/products?id=42):

Method: GET
Full URL: http://example.com/products?id=42

$_SERVER is the most information-dense superglobal. Beyond REQUEST_METHOD and HTTP_HOST, it holds the client IP (REMOTE_ADDR), the script path (SCRIPT_NAME), and every incoming HTTP header, exposed as HTTP_* keys (a header named X-Custom-Token appears as $_SERVER['HTTP_X_CUSTOM_TOKEN']).

Example 3: Tracking state across requests with $_SESSION

<?php
session_start();

$_SESSION['views'] = ($_SESSION['views'] ?? 0) + 1;

$status = match (true) {
    $_SESSION['views'] === 1 => 'first visit',
    $_SESSION['views'] < 5   => 'returning visitor',
    default                  => 'frequent visitor',
};

echo "View count: " . $_SESSION['views'] . PHP_EOL;
echo "Status: {$status}" . PHP_EOL;

Output (first request of a new session):

View count: 1
Status: first visit

session_start() must run before any output is sent and before $_SESSION is touched. It looks for a session-id cookie (named PHPSESSID by default); if none is found, it creates a new session and a matching cookie in the response. Unlike GET, POST, or SERVER data, $_SESSION persists across multiple requests because PHP stores it server-side (by default, in a file) keyed by that session id.

Under the Hood: $GLOBALS and Scope

Every other superglobal is about the request; $GLOBALS is about scope. Normally, a variable declared at the top level of a script is invisible inside a function unless you pass it as a parameter or declare it with global $var;. $GLOBALS gives you a second way to reach it – as an array where each key is a global variable’s name:

<?php
$counter = 0;

function increment(): void {
    $GLOBALS['counter']++;
}

increment();
increment();
echo $GLOBALS['counter'];

Output:

2

Internally, $GLOBALS is not a snapshot copy – it is a live view onto the global symbol table, so reading or writing through it has exactly the same effect as reading or writing the variable directly in the global scope. Because it makes data flow implicit and harder to trace, most style guides (including this one) recommend passing values as function parameters and return values instead of reaching for $GLOBALS except in legacy code or very small scripts.

Common Mistakes

Mistake 1: Echoing user input directly (XSS risk)

Printing a superglobal value straight into HTML lets an attacker inject a <script> tag through the URL or a form field.

<?php
echo "Welcome, " . $_GET['username'];

If username contains markup, it renders as live HTML in the visitor’s browser – a classic cross-site scripting (XSS) hole. Always escape output that originated from the client:

<?php
echo "Welcome, " . htmlspecialchars($_GET['username'] ?? 'Guest', ENT_QUOTES);

Mistake 2: Accessing a key without checking it exists

Assuming a GET or POST field is always present causes an “Undefined array key” warning (and a silently missing value) the moment a request omits it.

<?php
$id = $_GET['id'];
echo "Product ID: " . $id;

Guard every optional key with ?? or isset(), and handle the missing case explicitly:

<?php
$id = $_GET['id'] ?? null;

if ($id === null) {
    echo "No product ID supplied.";
} else {
    echo "Product ID: " . htmlspecialchars($id, ENT_QUOTES);
}

Mistake 3: Relying on $_REQUEST for security-sensitive logic

$_REQUEST merges GET, POST, and COOKIE data, so a value you expect to come only from a submitted form could actually be smuggled in through the URL’s query string or an attacker-controlled cookie. For anything that changes state – deleting a record, transferring funds, changing a password – always read explicitly from $_POST (or $_GET for idempotent reads), never from the ambiguous $_REQUEST.

Best Practices

  • Never trust superglobal data – validate types with filter_input() or explicit checks, and escape with htmlspecialchars() before echoing into HTML.
  • Use ?? or isset() for every key that might be absent instead of assuming it exists.
  • Avoid $_REQUEST for anything meaningful; read from $_GET or $_POST explicitly so the data source is unambiguous.
  • Call session_start() as the very first statement of the request (before any output) when using $_SESSION.
  • Prefer passing values as function parameters over reaching into $GLOBALS – it keeps data flow explicit and testable.
  • Store secrets (API keys, database passwords) in $_ENV or a `.env` loader rather than hard-coding them in source files.
  • When processing $_FILES, always check the error key first and validate the real MIME type – never trust the client-supplied type field.
  • Use $_SERVER['REQUEST_METHOD'] to branch behavior (for example, showing a form on GET and processing it on POST) rather than checking for the presence of POST fields.

Practice Exercises

  • Write a script that reads a page parameter from $_GET, defaults it to 1 if missing, validates it is a positive integer, and prints “Showing page N”.
  • Write a script that checks $_SERVER['REQUEST_METHOD']: if it is POST, print “Form submitted”; otherwise print “Please submit the form”.
  • Write a script using $_SESSION that stores a list of “recently viewed” product IDs (an array), appending a new ID on each run while avoiding duplicates, and print the current list.

Summary

  • Superglobals are built-in arrays available in every scope, without global or parameters.
  • $_GET, $_POST, and $_FILES carry client-submitted request data; $_SERVER describes the request and server environment.
  • $_SESSION persists data across requests server-side and requires session_start(); $_COOKIE only reads cookies already sent by the client.
  • $_REQUEST merges GET, POST, and COOKIE – useful for convenience, risky for security-sensitive logic.
  • $_ENV exposes process environment variables; $GLOBALS is a live reference to the global scope, not request data.
  • Always validate and escape superglobal values – they represent the boundary between your trusted code and the untrusted outside world.