$_GET & $_POST
$_GET and $_POST are the two superglobals you will use most often when a PHP page needs to react to input from a visitor. Both are associative arrays keyed by field name, but they draw their data from different parts of an HTTP request, and that difference is not just technical trivia — it should guide which one you reach for.
Where each one gets its data
$_GETreads name/value pairs from the URL query string, the part after?, such as?category=books&page=2.$_POSTreads name/value pairs from the body of the HTTP request, which is only present when the request method is POST.A GET request has no body at all - everything the server sees arrives in the URL and headers.
A POST request keeps its data out of the URL, so it does not show up in browser history, bookmarks, or server access logs.
Reading a GET parameter
<?php
// Visiting /products.php?category=books&page=2
$category = $_GET['category'] ?? 'all';
$pageNum = (int) ($_GET['page'] ?? 1);
echo "Category: {$category}, page: {$pageNum}";Category: books, page: 2
GET is for retrieval, POST is for mutation
HTTP defines GET as a "safe" and idempotent method: a GET request should only retrieve data and should be repeatable without side effects. That is why browsers freely re-fetch, cache, and prefetch GET URLs. POST carries no such guarantee — it is the method you use when the request changes something on the server, such as creating an account, submitting a comment, or placing an order. Following this convention matters beyond style: browsers, proxies, and search engine crawlers can and do re-issue GET requests automatically, so a "delete this item" link built on GET can be triggered accidentally.
A form that mutates data should use POST
<form method="post" action="/comments/create.php"> <label for="body">Comment</label> <textarea id="body" name="body"></textarea> <button type="submit">Post comment</button> </form>
Size and visibility limits
Query strings are limited in practice by the web server and browser, commonly somewhere around 2,000 to 8,000 characters depending on the stack, which makes $_GET unsuitable for large payloads such as file contents. $_POST bodies are governed instead by PHP's own post_max_size directive in php.ini, which defaults to a much more generous size and is the right place to look when a large form submission arrives empty.
Detecting a form that exceeded post_max_size
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty($_POST) && empty($_FILES)) {
echo 'The submitted data was larger than this server allows.';
}Always validate and escape
Regardless of which superglobal a value came from, it originated on the visitor's machine and must be treated as untrusted. Validate the shape and type you expect (an integer ID, a non-empty string, a valid email), and escape anything you echo back into HTML with htmlspecialchars() to prevent cross-site scripting.
Validating and escaping a POST field
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
if ($name === '') {
echo 'Name is required.';
} else {
$safeName = htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
echo "Thanks, {$safeName}!";
}
}Quick comparison
Aspect | $_GET | $_POST |
|---|---|---|
Data location | URL query string | Request body |
Visible in URL/history | Yes | No |
Typical use | Search, filters, pagination | Login, forms that change data |
Practical size limit | A few thousand characters | Governed by post_max_size |
Cacheable/idempotent | Yes, by convention | No, by convention |