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:
$_SERVERis filled from CGI/SAPI variables and HTTP headers (things likeREQUEST_METHODandHTTP_HOST).$_GETis filled by parsing the query string portion of the URL.$_POSTand$_FILESare filled only when the request method is POST and the body isapplication/x-www-form-urlencodedormultipart/form-data.$_COOKIEis filled by parsing theCookieheader sent by the browser.$_ENVis filled from the process environment, subject to thevariables_orderini directive.$_SESSIONis the odd one out: it does not exist until you explicitly callsession_start(), which either creates a new session or resumes one identified by a session-id cookie.$_REQUESTis a merge of GET, POST, and COOKIE data, in an order controlled by therequest_orderini setting (by default, GET then POST).$GLOBALSis 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 withhtmlspecialchars()before echoing into HTML. - Use
??orisset()for every key that might be absent instead of assuming it exists. - Avoid
$_REQUESTfor anything meaningful; read from$_GETor$_POSTexplicitly 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
$_ENVor a `.env` loader rather than hard-coding them in source files. - When processing
$_FILES, always check theerrorkey first and validate the real MIME type – never trust the client-suppliedtypefield. - 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
pageparameter from$_GET, defaults it to1if missing, validates it is a positive integer, and prints “Showing page N”. - Write a script that checks
$_SERVER['REQUEST_METHOD']: if it isPOST, print “Form submitted”; otherwise print “Please submit the form”. - Write a script using
$_SESSIONthat 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
globalor parameters. $_GET,$_POST, and$_FILEScarry client-submitted request data;$_SERVERdescribes the request and server environment.$_SESSIONpersists data across requests server-side and requiressession_start();$_COOKIEonly reads cookies already sent by the client.$_REQUESTmerges GET, POST, and COOKIE – useful for convenience, risky for security-sensitive logic.$_ENVexposes process environment variables;$GLOBALSis 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.
