$_SERVER

Yo Yogesh.M Updated 29 Oct 2026
8 min read

What Is $_SERVER?

In simple terms: $_SERVER is an array with information about the current request and the environment the script runs in: which URL was requested, which HTTP method was used, the visitor's IP address, request headers, the script's file path, and more. Technically: $_SERVER is a superglobal array populated by PHP from the web server (through the server API, such as PHP-FPM or Apache's module) and from the process environment. Its exact contents depend on the web server and its configuration; PHP does not guarantee that every key exists.

Why It Is Needed

Many decisions depend on details of the request itself rather than on submitted data:

  • Was the form submitted (POST) or just displayed (GET)?
  • Which path was requested (for routing)?
  • Is the connection secure (HTTPS)?
  • What language does the browser prefer?
  • From which IP address did the request come (for rate limiting or logging)?

Common Keys

Request Information

KeyExample ValueMeaning
REQUEST_METHODGET, POST, PUT, DELETEHTTP method
REQUEST_URI/products.php?category=books&page=2Path and query string as requested
QUERY_STRINGcategory=books&page=2Only the query string
REQUEST_TIME1791541200Unix timestamp of the request start
REQUEST_TIME_FLOAT1791541200.2531Same, with microseconds
SERVER_PROTOCOLHTTP/1.1Protocol version
HTTPSonNon-empty when the request used HTTPS (may be missing or off otherwise)
CONTENT_TYPEapplication/jsonType of the request body
CONTENT_LENGTH57Size of the request body in bytes

Script and Server Information

KeyExample ValueMeaning
SCRIPT_NAME/products.phpURL path of the running script
SCRIPT_FILENAME/var/www/shop/public/products.phpAbsolute file path of the script
DOCUMENT_ROOT/var/www/shop/publicWeb server document root
PHP_SELF/products.phpScript path plus any extra path info (see Security)
SERVER_NAMEgocourse.inServer name from the web server configuration
SERVER_PORT443Port the server received the request on
SERVER_SOFTWAREnginx/1.26.0Web server name and version

Client and Header Information

KeyExample ValueMeaning
REMOTE_ADDR203.0.113.7IP address of the client (or of the last proxy)
HTTP_HOSTgocourse.inHost header sent by the client
HTTP_USER_AGENTMozilla/5.0 (...)Browser identification
HTTP_ACCEPT_LANGUAGEta-IN,ta;q=0.9,en;q=0.8Preferred languages
HTTP_REFERERhttps://google.com/Page that linked here (often absent)

How Request Headers Become Keys

Every request header is available with the prefix HTTP_, in uppercase, with hyphens replaced by underscores:

Header$_SERVER Key
Accept-LanguageHTTP_ACCEPT_LANGUAGE
X-Requested-WithHTTP_X_REQUESTED_WITH
AuthorizationHTTP_AUTHORIZATION (some servers need extra configuration to pass it)

Content-Type and Content-Length are exceptions: they appear as CONTENT_TYPE and CONTENT_LENGTH, without the prefix.


Reading $_SERVER Safely

Keys may be missing depending on the server, the request, and whether the script runs in the command line. Always provide defaults:

<?php
// Example request: GET https://gocourse.in/products.php?category=books&page=2
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$uri = $_SERVER['REQUEST_URI'] ?? '/';
$path = parse_url($uri, PHP_URL_PATH);
$query = $_SERVER['QUERY_STRING'] ?? '';
$isHttps = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
$referrer = $_SERVER['HTTP_REFERER'] ?? 'none';
echo "Method: $method\n";
echo "Path: $path\n";
echo "Query: $query\n";
echo "HTTPS: " . ($isHttps ? 'yes' : 'no') . "\n";
echo "Referrer: $referrer\n";

Output (for the example request, visited directly)

Method: GET
Path: /products.php
Query: category=books&page=2
HTTPS: yes
Referrer: none
  • parse_url(..., PHP_URL_PATH) extracts the path from REQUEST_URI, dropping the query string.
  • The HTTPS check accepts any non-empty value except off, which some servers (such as IIS) use for plain HTTP.
  • HTTP_REFERER is missing when the visitor typed the address, used a bookmark, or the browser's privacy settings removed it.

Detecting the Request Method

The most common use of $_SERVER is distinguishing "show the form" from "process the form":

<?php
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
    // validate and process $_POST, then redirect
} else {
    // display the empty form
}

Checking the method is more reliable than checking whether $_POST is empty: a POST request can have an empty body, and a request whose body exceeds post_max_size arrives with an empty $_POST even though it was submitted. See $_POST.


Practical Example: A Small Router

A router maps the method and path of each request to the code that handles it. Keeping the logic in a function makes it testable without a web server:

<?php
function route(string $method, string $uri): array
{
    $path = rtrim(parse_url($uri, PHP_URL_PATH) ?? '/', '/') ?: '/';
    $routes = [
        'GET /' => 'Home page',
        'GET /products' => 'Product list',
        'POST /products' => 'Product created',
    ];
    if (isset($routes["$method $path"])) {
        return [200, $routes["$method $path"]];
    }
    $pathExists = array_filter(
        array_keys($routes),
        fn(string $route): bool => explode(' ', $route, 2)[1] === $path
    );
    return $pathExists ? [405, 'Method not allowed'] : [404, 'Page not found'];
}
$requests = [
    ['GET', '/'],
    ['GET', '/products?page=2'],
    ['POST', '/products/'],
    ['DELETE', '/products'],
    ['GET', '/about'],
];
foreach ($requests as [$method, $uri]) {
    [$status, $body] = route($method, $uri);
    printf("%-6s %-18s → %d %s\n", $method, $uri, $status, $body);
}
// In a real front controller:
// [$status, $body] = route($_SERVER['REQUEST_METHOD'] ?? 'GET', $_SERVER['REQUEST_URI'] ?? '/');
// http_response_code($status);
// echo $body;

Output

GET    /                  → 200 Home page
GET    /products?page=2   → 200 Product list
POST   /products/         → 200 Product created
DELETE /products          → 405 Method not allowed
GET    /about             → 404 Page not found

Step-by-Step Explanation

  1. parse_url() removes the query string, and rtrim(..., '/') removes a trailing slash, so /products/ and /products match the same route. The root path / would become an empty string, so ?: '/' restores it.
  2. Routes are stored as "METHOD /path" keys for fast lookup.
  3. If the path exists but not for this method, the correct HTTP status is 405 Method Not Allowed; if the path does not exist at all, it is 404 Not Found.
  4. The commented lines show how a front controller (public/index.php) feeds $_SERVER values into the function and sends the response. Frameworks use the same principle with far more features: route parameters (/products/{id}), middleware, and controllers.

Security Considerations

Many $_SERVER values come directly from the client and can be manipulated.

PHP_SELF and Cross-Site Scripting

<!-- Vulnerable -->
<form action="<?= $_SERVER['PHP_SELF'] ?>" method="post">

PHP_SELF includes any extra path information after the script name. A request to /contact.php/"><script>alert(1)</script> can make PHP_SELF contain HTML, which is then printed into the page. Safer options:

<form action="" method="post">                                        <!-- submit to the current URL -->
<form action="<?= htmlspecialchars($_SERVER['SCRIPT_NAME']) ?>" method="post">

HTTP_HOST Can Be Spoofed

The Host header is chosen by the client. Using it to build absolute URLs — for example, in password reset emails — allows host header injection: an attacker requests a reset for a victim with a forged Host, and the email contains a link to the attacker's domain. Fix: Build absolute URLs from a configured base URL (for example, APP_URL=https://gocourse.in in your configuration), not from HTTP_HOST. Also configure the web server to accept only your real domain names.

REMOTE_ADDR and Proxies

REMOTE_ADDR is the IP address of whoever connected to the server. Behind a load balancer, CDN, or reverse proxy, that is the proxy's address, and the real client address is passed in a header such as X-Forwarded-For. That header can be forged by anyone, so it may only be trusted when the request actually came from your own proxy:

<?php
function clientIp(array $server, array $trustedProxies): string
{
    $remote = $server['REMOTE_ADDR'] ?? '0.0.0.0';
    if (!in_array($remote, $trustedProxies, true) || empty($server['HTTP_X_FORWARDED_FOR'])) {
        return $remote;
    }
    $chain = array_map('trim', explode(',', $server['HTTP_X_FORWARDED_FOR']));
    foreach (array_reverse($chain) as $ip) {
        if (!in_array($ip, $trustedProxies, true) && filter_var($ip, FILTER_VALIDATE_IP)) {
            return $ip;
        }
    }
    return $remote;
}
$trusted = ['10.0.0.2'];
echo clientIp(['REMOTE_ADDR' => '203.0.113.7'], $trusted) . "\n";
echo clientIp(['REMOTE_ADDR' => '10.0.0.2', 'HTTP_X_FORWARDED_FOR' => '198.51.100.23'], $trusted) . "\n";
echo clientIp(['REMOTE_ADDR' => '203.0.113.7', 'HTTP_X_FORWARDED_FOR' => '1.2.3.4'], $trusted) . "\n";
echo clientIp(['REMOTE_ADDR' => '10.0.0.2', 'HTTP_X_FORWARDED_FOR' => '1.2.3.4, 198.51.100.23'], $trusted) . "\n";

Output

203.0.113.7
198.51.100.23
203.0.113.7
198.51.100.23

How It Works

  1. A direct connection (not from a trusted proxy) returns REMOTE_ADDR; any X-Forwarded-For header sent by the client is ignored (third case).
  2. When the request comes from the trusted proxy, the function reads the forwarded chain from right to left. Each proxy appends the address it received the request from, so the rightmost address not belonging to your proxies is the real client.
  3. In the fourth case, the client tried to fake its address by sending 1.2.3.4 itself; the proxy appended the real address 198.51.100.23, which is the one returned. The function receives the server array as a parameter (clientIp($_SERVER, $trusted) in real code), which makes it easy to test with different inputs.

$_SERVER in the Command Line

When running a script with php script.php, there are no HTTP keys (REQUEST_METHOD, HTTP_HOST, and so on are missing). Instead, $_SERVER['argv'] and $_SERVER['argc'] contain the command-line arguments, and the environment variables of the shell are included. Code that may run in both contexts should use ?? defaults for every HTTP-related key (see PHP Command Line (CLI)).


Common Mistakes

Assuming a Key Always Exists

Effect: Warnings, especially for HTTP_REFERER, HTTPS, and in CLI scripts. Fix: Use ?? with sensible defaults.

Printing PHP_SELF Unescaped

Effect: Cross-site scripting. Fix: Use action="", or escape SCRIPT_NAME with htmlspecialchars().

Effect: Host header injection in emails and redirects. Fix: Use a configured application URL.

Trusting X-Forwarded-For Unconditionally

Effect: Attackers bypass IP-based rate limits or appear to come from any address. Fix: Trust forwarded headers only when REMOTE_ADDR is your own proxy.

Using HTTP_REFERER for Security

Effect: The header is optional and easily forged. Fix: Use CSRF tokens to verify form submissions (see CSRF Protection).


Best Practices

  • Read $_SERVER values with defaults and validate them.
  • Use REQUEST_METHOD to decide between displaying and processing forms.
  • Parse REQUEST_URI with parse_url() for routing.
  • Treat all client-controlled values (HTTP_*, PHP_SELF, REQUEST_URI) as untrusted input.
  • Wrap request-dependent logic in functions that accept values as parameters, so it can be tested without a web server. Official reference: https://www.php.net/manual/en/reserved.variables.server.php

0 Comments

Reviewed before they appear

No comments yet.

Data Mining
Introduction to Data Mining Data Mining Implementation Process Data Mining Architecture Data Mining Techniques KDD: Knowledge Discovery in Databases History of Data Mining Data Mining Tools Data Mining vs Machine Learning Facebook Data Mining Social Media Data Mining Methods Clustering in Data Mining Text Data Mining Bagging vs Boosting Data Mining vs Data Warehousing Social Media Data Mining Data Mining: Bayesian Classifiers Data Mining: World Wide Web Different Types of Clustering Bitcoin Mining and Blockchain Data Mining Orange Data Mining Data Mining vs Big Data Decision Tree Induction Educational Data Mining Data Mining in Healthcare Apriori Algorithm Data Integration in Data Mining Difference Between Data Mining and Text Mining Discretization in Data Mining Redundancy and Correlation in Data Mining Classification of Data Mining Systems Classification Algorithms in Data Mining Data Generalization in Data Mining Classification and Prediction in Data Mining Regression in Data Mining What Is an Outlier in Data Mining Data Cleaning in Data Mining Data Processing in Data Mining Data Mining Task Primitives Web Content Mining, Web Structure Mining, and Web Usage Mini Binning in Data Mining KDD vs. Data Mining Noise in Data Mining BIRCH in Data Mining Stemming in Data Mining Feature Transformation in Data Mining Visual and Audio Data Mining Class Comparison Methods in Data Mining Data Selection in Data Mining Tasks and Functionalities of Data Mining Ubiquitous and Invisible Data Mining Importance of Data Mining Data Quality in Data Mining Mining Frequent Patterns in Data Mining Data Warehouse and OLAP Technology for Data Mining Need for Data Mining Pattern Evaluation Methods in Data Mining Logarithms and Exponents in Complexity Analysis Time Series Clustering What is the C4.5 Algorithm and How Does It Work? Expanding Contractions in Text Mining Cosine Similarity in Data Mining Lazy Learning in Data Mining Neural Networks in Data Mining Building a Text Normalizer Shallow Parsing Data Pipeline Orchestration Big Data vs Small Data Myths of Data Mining Data Reduction in Data Mining Data Mining Models Difference Between Data Mining and Data Science Difference Between Data Mining and Statistics Difference Between Data Mining and Web Mining Difference Between Data Mining and Data Analysis Difference Between Business Intelligence and Data Mining Difference Between Data Mining and Data Visualization Data Mining vs Data Analytics Types of Data Mining Difference Between Data Profiling and Data Mining Predictive Analytics vs Data Mining Difference Between Data Mining and OLAP Descriptive and Predictive Data Mining Difference Between Spatial and Temporal Data Mining Difference Between Classification and Clustering in Data Min Hierarchical Clustering in Data Mining Density-Based Clustering in Data Mining What Is Aggregation in Data Mining?
Ask about this post
AI Ask about this post

Ask questions about $_SERVER and get answers drawn from it.

Signed-in readers only.