In PHP, what does $_REQUEST contain, how does request_order control it, and why do most codebases avoid it?
answer
- a merge of GET, POST, maybe cookies
- request_order = "GP" in the shipped ini
- a later source overwrites an earlier one
- unset request_order: variables_order
- it erases where a value came from
basics
~20 s$_REQUEST merges $_GET, $_POST and possibly $_COOKIE in the order request_order lists them. The shipped php.ini files set "GP", so POST overrides GET and cookies are left out. Codebases avoid it because it hides where a value came from.
solid answer
~50 s`$_REQUEST` is built by merging the input arrays in the order the `request_order` directive lists them — `G` for `$_GET`, `P` for `$_POST`, `C` for `$_COOKIE` — and a later source overwrites an earlier one for the same key. Both php.ini-development and php.ini-production set `request_order = "GP"`, so POST values win over query-string values and cookies are not included. If `request_order` is not set at all, PHP falls back to the letters in `variables_order`, whose built-in default `"EGPCS"` does bring cookies in — which is why the manual describes `$_REQUEST` as containing cookies by default. The array is avoided because it erases provenance: an action meant to accept a POST body also accepts the same field from a link's query string or a cookie, and its behaviour changes with server configuration. Read `$_GET` or `$_POST` explicitly, chosen by `$_SERVER['REQUEST_METHOD']`.
code
php · 7 lines<?php
// php.ini: request_order = "GP"
// POST /bookings?nights=1 with body: nights=3
var_dump($_GET['nights']); // string(1) "1"
var_dump($_POST['nights']); // string(1) "3"
var_dump($_REQUEST['nights']); // string(1) "3" - P comes after G, so POST winsgo deeper
Recall that $_REQUEST merges $_GET and $_POST (and sometimes cookies) and that reading the specific array is preferred.
Explain how request_order decides the sources and the precedence, why the shipped "GP" excludes cookies, and what happens when request_order is unset.
Remove $_REQUEST from state-changing handlers, choose the input source by method, and avoid behaviour that changes with server configuration.
Adopt a request abstraction that keeps query, body and cookie input separate, so provenance survives through the whole application.
## How PHP builds $_REQUEST `$_REQUEST` is not a separate input source; it is a **merged copy** of other superglobals. PHP builds it like this: 1. Take the value of `request_order`. If it is not set, use `variables_order` instead. 2. Walk its letters from left to right. `G` merges `$_GET`, `P` merges `$_POST`, `C` merges `$_COOKIE`; other letters are ignored, and each source is merged at most once. 3. Each merge writes its keys into the result. When a key already exists, the **later** source overwrites it (nested arrays are merged recursively). So the order is also a precedence rule: with `"GP"`, a field present in both the query string and the POST body takes the POST value. ## Configuration values | Setting | `$_REQUEST` contains | Precedence | |---|---|---| | `request_order = "GP"` (both shipped php.ini files) | `$_GET`, then `$_POST` | POST wins | | `request_order = "PG"` | `$_POST`, then `$_GET` | GET wins | | `request_order = "GPC"` | Query, body and cookies | Cookies win | | `request_order` unset, built-in `variables_order = "EGPCS"` | Query, body and cookies | Cookies win | The last row is why the manual says `$_REQUEST` contains `$_GET`, `$_POST` and `$_COOKIE` "by default": the engine's own defaults include cookies, while the recommended ini files exclude them. The same code can therefore see different data on a server that ships no php.ini. ## Why codebases avoid it - **It erases provenance.** A handler that reads `$_REQUEST['cancel_booking']` cannot tell whether the value came from a submitted form, a URL someone was tricked into clicking, or a cookie. - **It weakens the GET/POST split.** An action intended only for POST also runs for `GET /bookings/cancel?cancel_booking=1`, which can be embedded in an image tag or a link on another site. CSRF defences such as tokens still matter, but accepting GET for a state change makes attacks easier. - **It depends on configuration.** Changing `request_order` or running without a php.ini changes which value wins, without any code change. - **Cookies can shadow form fields** when cookies are included: a cookie named like a form field silently overrides it. - **It hides intent from readers.** `$_POST['nights']` documents where the value is expected; `$_REQUEST['nights']` does not. ## What to use instead Read the source you expect, chosen by the method: ```php $input = match ($_SERVER['REQUEST_METHOD'] ?? 'GET') { 'POST' => $_POST, default => $_GET, }; ``` Frameworks go one step further and wrap the superglobals in a request object with separate accessors for query parameters, body parameters and cookies, which keeps the distinction explicit throughout the application. ## Removing $_REQUEST from an existing codebase A mechanical migration works in small, safe steps: 1. Search for `$_REQUEST` and list each handler that reads it. 2. For each handler, decide which method it serves; a form handler reads `$_POST`, a listing or search reads `$_GET`. 3. Where one handler serves both (a search form that also accepts links), read both explicitly and document the precedence you want. 4. Reject the unexpected method with a 405 response instead of silently accepting it. 5. Check whether any code relied on cookie values arriving through `$_REQUEST`; read those from `$_COOKIE` deliberately. To see what a given server actually does, `ini_get('request_order')` returns the effective value; an empty result means the directive is unset and `variables_order` is in charge. ## When $_REQUEST is harmless A read-only search endpoint that deliberately accepts a term either from a link or from a form can use `$_REQUEST` without risk, as long as the server's `request_order` is known and cookies are excluded. Even there, reading `$_GET` and `$_POST` explicitly is only one line longer and states the intent.
- Does $_REQUEST include cookies?It depends on configuration. With `request_order = "GP"`, the value both shipped php.ini files use, it does not. If `request_order` is unset, PHP uses `variables_order`, whose built-in default `"EGPCS"` includes `C`, so cookies are merged in and override GET and POST values of the same name.
- With request_order = "GP", which value does $_REQUEST['id'] hold when both the query string and the POST body set id?The POST value. PHP merges the sources in the order the letters appear, and a later source overwrites an earlier one for the same key; `P` comes after `G`, so the body wins.
saying these in an interview costs you the question
- $_REQUEST always includes cookies, whatever the configuration
- In $_REQUEST, the first source listed wins a key conflict
- request_order has no effect on which value $_REQUEST returns
- Reading $_REQUEST is safer because it checks every source
- $_REQUEST is a separate input source, not a merge of others