web php
URL Parsing And Building
PHP applications often need to read URLs, preserve query parameters, build pagination links, validate redirect targets, and generate links safely.
Do not build URLs by casually concatenating untrusted strings. Use the standard parsing and encoding functions so spaces, ampersands, and special characters are represented correctly.
Parse URL parts
<?php
declare(strict_types=1);
$url = 'https://example.com/products?page=2&search=php';
$parts = parse_url($url);
echo $parts['scheme'] . PHP_EOL;
echo $parts['host'] . PHP_EOL;
echo $parts['path'] . PHP_EOL;
echo $parts['query'] . PHP_EOL;
// Prints:
// https
// example.com
// /products
// page=2&search=php
parse_url() does not validate that a URL is safe to use. It only breaks the string into parts.
Parse query strings
Use parse_str() to turn a query string into an array.
<?php
declare(strict_types=1);
parse_str('page=2&search=php+arrays', $query);
echo $query['page'] . PHP_EOL;
echo $query['search'] . PHP_EOL;
// Prints:
// 2
// php arrays
Treat parsed query values as untrusted input. Validate expected types and allowed values before using them.
Build query strings
Use http_build_query() when generating links.
<?php
declare(strict_types=1);
$query = [
'page' => 3,
'search' => 'php arrays',
'sort' => 'newest',
];
$url = '/products?' . http_build_query($query);
echo $url . PHP_EOL;
// Prints:
// /products?page=3&search=php+arrays&sort=newest
This is safer than writing '/products?page=' . $page . '&search=' . $search by hand.
Preserve filters while changing one value
Pagination often needs to keep the current filters while changing the page number.
<?php
declare(strict_types=1);
/**
* @param array<string, scalar|null> $currentQuery
*/
function pageUrl(string $path, array $currentQuery, int $page): string
{
$query = array_merge($currentQuery, ['page' => $page]);
return $path . '?' . http_build_query($query);
}
echo pageUrl('/products', ['search' => 'php', 'sort' => 'newest'], 4) . PHP_EOL;
// Prints:
// /products?search=php&sort=newest&page=4
Safe local redirects
Redirect targets are a common URL security issue. If you accept a return_to value from the request, do not blindly redirect to it. That creates an open redirect.
For local redirects, allow only paths that start with one / and do not start with //.
<?php
declare(strict_types=1);
function safeLocalPath(string $target): string
{
if (str_starts_with($target, '/') && !str_starts_with($target, '//')) {
return $target;
}
return '/';
}
echo safeLocalPath('/dashboard') . PHP_EOL;
echo safeLocalPath('https://evil.example') . PHP_EOL;
// Prints:
// /dashboard
// /
Escape URLs in HTML
After building a URL, escape it before placing it in HTML.
<?php
declare(strict_types=1);
$url = '/products?' . http_build_query(['search' => 'PHP & web']);
$safeUrl = htmlspecialchars($url, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
echo '<a href="' . $safeUrl . '">Search</a>' . PHP_EOL;
// Prints:
// <a href="/products?search=PHP+%26+web">Search</a>
What to check in a project
Check that query strings are built with http_build_query() or framework URL helpers.
Check that redirect targets are constrained to local paths unless external redirects are explicitly allowed.
Check that URL parameters are validated after parsing. page=abc should not become a broken database query.
Check that generated URLs are escaped when rendered into HTML.
What you should be able to do
After this lesson, you should be able to parse URL parts, parse and build query strings, preserve filters while changing pagination, escape URLs in HTML, and avoid open redirects.
Practice
Task: Build Pagination URLs
Write a small PHP script that builds pagination URLs while preserving existing filters.
Requirements
- Use
declare(strict_types=1);. - Create a function that accepts a path, current query array, and target page.
- Preserve existing query values.
- Replace or add the
pagevalue. - Use
http_build_query(). - Include a normal filtered URL.
- Include an edge case where the query is empty.
- Print both URLs.
Check Your Work
Run the script and confirm spaces and ampersands are encoded correctly.
Show solution
This solution lets PHP handle URL encoding instead of concatenating query strings by hand.
<?php
declare(strict_types=1);
/**
* @param array<string, scalar|null> $currentQuery
*/
function paginationUrl(string $path, array $currentQuery, int $page): string
{
$query = array_merge($currentQuery, ['page' => $page]);
$queryString = http_build_query($query);
return $queryString === '' ? $path : $path . '?' . $queryString;
}
echo paginationUrl('/products', ['search' => 'PHP & web', 'sort' => 'newest'], 2) . PHP_EOL;
echo paginationUrl('/products', [], 1) . PHP_EOL;
// Prints:
// /products?search=PHP+%26+web&sort=newest&page=2
// /products?page=1
When rendering this URL into an href, escape it with htmlspecialchars() as part of HTML output.
Why This Works
The filtered case proves existing values are preserved and encoded. The empty case proves the function still builds a valid page link.