$_GET

Yo Yogesh.M Updated 01 Nov 2026
7 min read ·Lesson 217 of 219

What Is $_GET?

In simple terms: $_GET is an array containing the parameters in the URL after the ? — the query string. For the address products.php?category=books&page=2, $_GET contains ['category' => 'books', 'page' => '2']. Technically: $_GET is a superglobal that PHP fills by parsing the query string of the requested URL, regardless of the request method. Parameters arrive from links, from forms submitted with method="get", and from any URL typed or generated by a client.

When GET Parameters Are the Right Choice

GET parameters describe what to show, not what to change:

Good UsesAvoid For
Search termsPasswords, tokens, personal data
Filters and sortingCreating, updating, or deleting data
PaginationLarge amounts of data
Selecting an item to view (?id=42)Anything that must not be repeated by reloading
Tracking the source of a visit (?ref=newsletter)

Because the parameters are part of the URL, the resulting page can be bookmarked, shared, and reloaded — which is exactly what users expect from search results and product listings. The same property makes GET unsuitable for sensitive data: URLs are stored in browser history, server logs, analytics tools, and Referer headers.


Reading Query Parameters

<?php
// Request: GET /products.php?category=books&page=2&sort=price_asc
$category = $_GET['category'] ?? 'all';
$page = $_GET['page'] ?? '1';
$sort = $_GET['sort'] ?? 'newest';
$search = $_GET['q'] ?? '';
var_dump($category, $page, $sort, $search);

Output

string(5) "books"
string(1) "2"
string(9) "price_asc"
string(0) ""

Key Points

  • Every value is a string — even page, which looks like a number. Validate and convert before using it as an integer.
  • Parameters that are not in the URL (q) are missing from $_GET; ?? provides a default without a warning.
  • Parameter names are case-sensitive: ?Page=2 does not set $_GET['page'].

How the Query String Is Parsed

PHP decodes the query string with the same rules as parse_str(), which lets you see the result directly:

<?php
$queryString = 'q=php+%26+mysql&tags[]=new&tags[]=sale&price[min]=100&price[max]=500&empty=&flag';
parse_str($queryString, $params);
var_dump($params);

Output

array(6) {
  ["q"]=>
  string(11) "php & mysql"
  ["tags"]=>
  array(2) {
    [0]=>
    string(3) "new"
    [1]=>
    string(4) "sale"
  }
  ["price"]=>
  array(2) {
    ["min"]=>
    string(3) "100"
    ["max"]=>
    string(3) "500"
  }
  ["empty"]=>
  string(0) ""
  ["flag"]=>
  string(0) ""
}

What This Shows

In the URLIn $_GET
+A space
%26& (URL-encoded characters are decoded)
tags[]=new&tags[]=saleA list: ['new', 'sale']
price[min]=100A nested array: ['min' => '100']
empty= and flag (no =)Empty strings

Validating GET Parameters

Since users can type any URL, every parameter needs validation.

Integers

<?php
// Request: GET /products.php?page=abc
$page = filter_var($_GET['page'] ?? 1, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
if ($page === false) {
    $page = 1;
}
var_dump($page);

Output

int(1)

FILTER_VALIDATE_INT returns an int for valid input and false otherwise. min_range rejects zero and negative pages.

Allow-Lists for Fixed Choices

<?php
// Request: GET /products.php?sort=price;DROP
$allowedSorts = ['newest', 'price_asc', 'price_desc', 'rating'];
$sort = $_GET['sort'] ?? 'newest';
if (!in_array($sort, $allowedSorts, true)) {
    $sort = 'newest';
}
echo $sort . "\n";

Output

newest

Values such as sort orders often end up in SQL (ORDER BY), where placeholders cannot be used for column names. An allow-list is the safe way to handle them: only known values are ever used.

filter_input()

filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT) reads and validates in one step. It returns null if the parameter is missing and false if it is invalid. Note that it reads the original request data (changes to $_GET do not affect it) and returns null in command-line scripts, which can make testing harder. Validation is covered in detail in PHP Filters.


The "String or Array" Problem

The client controls the shape of every parameter. Adding [] to a name turns a string into an array:

/search.php?q=php        → $_GET['q'] is "php"
/search.php?q[]=php      → $_GET['q'] is ["php"]

Code that passes the value to a string function then fails:

<?php
// Request: GET /search.php?q[]=php
try {
    $term = trim($_GET['q'] ?? '');
} catch (TypeError $e) {
    echo get_class($e) . ": " . $e->getMessage() . "\n";
}

Output

TypeError: trim(): Argument #1 ($string) must be of type string, array given

An uncaught TypeError produces a server error (500) — easy for anyone to trigger. Check the type when reading parameters:

<?php
function queryString(string $key, string $default = ''): string
{
    $value = $_GET[$key] ?? $default;
    return is_string($value) ? trim($value) : $default;
}

Escaping GET Values in Output

Displaying a search term back to the user is a classic cross-site scripting (XSS) vulnerability:

<!-- Vulnerable -->
<p>Results for: <?= $_GET['q'] ?></p>

A link such as /search.php?q=<script>stealCookies()</script> would execute the script in the victim's browser. Always escape:

<p>Results for: <?= htmlspecialchars($_GET['q'] ?? '') ?></p>

The same applies when inserting values into HTML attributes, JavaScript, or URLs. See Escaping Output (htmlspecialchars) and XSS Prevention.


Building URLs With Query Parameters

Never build query strings by concatenating raw values — special characters such as &, =, #, and spaces break the URL. Use http_build_query():

<?php
$params = ['q' => 'php & mysql', 'category' => 'books', 'page' => 2];
echo '/search.php?' . http_build_query($params) . "\n";
echo '/search.php?q=' . urlencode('C# basics') . "\n";

Output

/search.php?q=php+%26+mysql&category=books&page=2
/search.php?q=C%23+basics
  • http_build_query() encodes keys and values and joins them with &.
  • urlencode() encodes a single value; without it, # would start a URL fragment and the rest of the search term would be lost.
  • When printing a URL into an HTML attribute, also escape it with htmlspecialchars(), because & must be written as & in HTML.

Practical Example: Product Listing With Filters and Pagination

<?php
function readFilters(array $query): array
{
    $allowedSorts = ['newest', 'price_asc', 'price_desc'];
    $sort = is_string($query['sort'] ?? null) && in_array($query['sort'], $allowedSorts, true)
        ? $query['sort']
        : 'newest';
    $category = is_string($query['category'] ?? null) && preg_match('/^[a-z-]{1,30}$/', $query['category'])
        ? $query['category']
        : null;
    $page = filter_var($query['page'] ?? 1, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
    return ['category' => $category, 'sort' => $sort, 'page' => $page === false ? 1 : $page];
}
function listingUrl(array $filters, array $changes = []): string
{
    $params = array_filter(
        array_replace($filters, $changes),
        fn($value) => $value !== null && $value !== '' && $value !== 1
    );
    return '/products.php' . ($params === [] ? '' : '?' . http_build_query($params));
}
// Simulates: GET /products.php?category=books&sort=price_desc&page=2&utm=promo
$filters = readFilters(['category' => 'books', 'sort' => 'price_desc', 'page' => '2', 'utm' => 'promo']);
print_r($filters);
echo listingUrl($filters, ['page' => 3]) . "\n";
echo listingUrl($filters, ['sort' => 'newest', 'page' => 1]) . "\n";
echo listingUrl($filters, ['category' => null, 'page' => 1]) . "\n";
// In the real page: $filters = readFilters($_GET);

Output

Array
(
    [category] => books
    [sort] => price_desc
    [page] => 2
)
/products.php?category=books&sort=price_desc&page=3
/products.php?category=books&sort=newest
/products.php?sort=price_desc

Step-by-Step Explanation

  1. readFilters() receives the query array as a parameter ($_GET in real use), which makes it testable with any input.
    • sort must be in the allow-list.
    • category must be a short lowercase slug; anything else means "no category filter" (null).
    • page must be a positive integer.
    • Unknown parameters (such as utm) are ignored.
  2. listingUrl() builds links that keep the current filters while changing some of them:
    • array_replace() applies the changes.
    • array_filter() removes empty values and page=1, so URLs stay short and canonical.
    • http_build_query() encodes everything safely.
  3. The three links show typical uses: "next page", "change sorting and go back to page 1", and "remove the category filter". Changing a filter resets the page to 1, because page 3 of the old results may not exist in the new results. Keeping URLs canonical (no redundant parameters) also helps search engines treat equivalent pages as one.

Common Mistakes

Using GET for Actions That Change Data

Effect: Links, prefetching browsers, and search engine crawlers can trigger deletions or orders; CSRF attacks become trivial. Fix: Use POST for changes.

Putting Sensitive Data in URLs

Effect: Passwords or tokens leak through history, logs, and Referer headers. Fix: Send sensitive data in POST bodies or headers.

Treating Parameters as Numbers Without Validation

Effect: "2abc", "-5", or "99999999999" cause wrong results or errors. Fix: Validate with filter_var() and range options.

Assuming Parameters Are Strings

Effect: ?q[]=x triggers a TypeError and a 500 error. Fix: Check with is_string() before using string functions.

Printing Parameters Unescaped

Effect: Reflected XSS. Fix: htmlspecialchars() for HTML output.

Concatenating Raw Values Into URLs

Effect: Broken links and injected parameters. Fix: http_build_query() or rawurlencode()/urlencode().


Best Practices

  • Use GET for safe, repeatable requests: viewing, searching, filtering, and paginating.
  • Read parameters with defaults, check their types, and validate them against allow-lists or patterns.
  • Escape parameters whenever they are printed.
  • Build links with http_build_query(), preserving current filters where appropriate.
  • Pass the query array into functions instead of reading $_GET deep inside your code. Official reference: https://www.php.net/manual/en/reserved.variables.get.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else User-defined Functions Slicing Strings Function Arguments PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators AJAX PHP AJAX Database AJAX XML AJAX Live Search AJAX Poll AJAX with JSON Security Introduction Password Hashing SQL Injection Prevention XSS Prevention Garbage Collection Project: Simple Blog PHP What is OOP PHP Classes/Objects The $this Keyword Access Array Items Update Array Items Add Array Items Remove Array Items Sorting Arrays Multidimensional Arrays Array Destructuring Array Spread Operator Search in Arrays Merge Arrays PHP Abstract Classes PHP Interfaces Polymorphism PHP Traits PHP Static Methods PHP Static Properties Late Static Binding Magic Methods Object Cloning MySQL Database MySQL Connect MySQL Create DB MySQL Create Table MySQL Insert Data MySQL Get Last ID MySQL Insert Multiple MySQL Prepared MySQL Select Data MySQL Where Debugging PHP Project: Image Upload Gallery $_SESSION $_ENV PHP RegEx RegEx Patterns Heredoc and Nowdoc RegEx Modifiers preg_match preg_replace preg_split PHP RegEx Functions Nullable Types Mixed and Never Types Nullsafe Operator PHP Attributes PHP Fibers Readonly Classes Property Hooks (PHP 8.4) Asymmetric Visibility (PHP 8.4) Reflection API SPL Data Structures Composer PHP Form Handling PHP XML Parsers PDO Transactions PDO Error Handling PHP XML Parsers PHP SimpleXML Parser PHP SimpleXML - Get PHP XML Expat Parser PHP DOM Parser PHP XMLReader PHP XMLWriter AJAX Intro PHP Class Constants Encryption with Sodium Recursive Functions Variable Functions Anonymous Functions Closures Arrow Functions First-class Callable Syntax PHP Arrays Indexed Arrays Associative Arrays Create Arrays Variables Scope Static Variables Variable Variables PHP Echo / Print PHP printf / sprintf PHP Data Types PHP Booleans PHP NULL PHP Strings String Functions array_map / array_filter / array_reduce Array Functions What Are Superglobals? $GLOBALS What Is `$_SERVER` ? $_REQUEST $_POST $_GET $_FILES $_COOKIE
Ask about this post
AI Ask about this post

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

Signed-in readers only.