PHP · PRACTICAL TUTORIAL
How to Get the Current Page URL with PHP
Separate the requested address from the canonical address and avoid making your public hostname depend on untrusted request headers.

There is more than one “current URL”
A PHP page may need a sharing link, a canonical link, a breadcrumb or a return address. These look similar, but they do not always need the same URL. A visitor might request an article with tracking parameters, while the canonical URL should identify the clean article. Decide which meaning you need before joining server variables into a string.
For a site with one public hostname, a dependable approach is to keep the public origin in configuration and combine it with the request target. On this site that origin is https://www.knut-edvart.com. It is an application setting, rather than a value copied from whichever Host header a request happens to contain.
Know what PHP can see
$_SERVER['REQUEST_URI'] usually contains the requested path and query string, such as /programming/php/?page=2. Availability and details depend on the server environment, so provide a fallback. The fragment after a hash, such as #example, is handled by the browser and is not sent as part of the HTTP request target.
PHP_SELF and SCRIPT_NAME describe script-related paths. They may differ from a friendly public URL when rewriting is involved. __FILE__ is a filesystem location, which belongs to a different namespace entirely. A path on disk cannot reliably tell you the public URL that a visitor used.
HTTP_HOST originates in request information. Unless the web server or framework has already validated it against allowed hosts, do not use it as the authority for canonical links or password-reset links. On a single-domain site, a configured origin avoids that dependency.
Build a requested URL from a trusted origin
The following teaching example accepts an ordinary path beginning with one slash, optionally followed by a query string. It falls back to the homepage for unexpected absolute request targets, leading double slashes, raw control characters, spaces, backslashes or fragments. It also rejects percent-encoded ASCII control characters.
<?php
// PHP 7.4+ teaching example. Use your configured public origin.
function pageUrls(string $requestTarget, string $origin): array
{
// Accept ordinary origin-form requests only. Fail closed to the homepage.
if ($requestTarget === '' || $requestTarget[0] !== '/'
|| substr($requestTarget, 0, 2) === '//'
|| preg_match('/[\x00-\x20\x7F#]/', $requestTarget) || strpos($requestTarget, chr(92)) !== false
|| preg_match('/%(?:0[0-9a-f]|1[0-9a-f]|7f)/i', $requestTarget)) {
$requestTarget = '/';
}
$path = explode('?', $requestTarget, 2)[0];
return [
'requested' => $origin . $requestTarget,
'without_query' => $origin . $path,
];
}
$urls = pageUrls(
$_SERVER['REQUEST_URI'] ?? '/',
'https://www.knut-edvart.com'
);
// Output encoding is separate from URL construction.
echo htmlspecialchars($urls['requested'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
Download the PHP example. The origin argument is trusted configuration and must have no trailing slash. Do not populate it from a form field or request header. For a multi-domain application, select an origin from an explicit allowlist or use a framework’s trusted-host configuration.
This function is a small construction policy, not a general-purpose URL validator. It preserves existing percent encoding and query order. It does not authorize a redirect destination, normalize every unusual path or verify that the requested resource exists. Those jobs require separate rules appropriate to the application.
Choose whether to keep the query string
For /programming/php/?page=2&utm_source=newsletter, the requested result retains both parameters. The result without a query ends at /programming/php/. That may be useful for an article’s clean sharing link, but it could be wrong for a paginated listing where page two contains different content.
Do not remove all parameters by habit. Decide which ones change the resource and which merely record navigation or tracking. A search page’s query defines the result; a newsletter tag generally does not define an article. When rebuilding a selected query, use an explicit parameter allowlist and a query encoder rather than concatenating raw input.
A canonical link also expresses editorial intent. For a directory-based article site, the strongest option is often an explicit page path stored with its metadata. That handles aliases, old filenames and preferred trailing slashes more predictably than inferring the canonical address from every incoming request.
$canonical = 'https://www.knut-edvart.com' . $page['path'];
// $page['path'] is trusted site metadata, not arbitrary visitor input.
Escape the result where you output it
A URL may include characters that are meaningful in HTML, especially quotes and ampersands. Use htmlspecialchars() when placing it in text or a quoted attribute. URL construction and HTML escaping solve different problems: one decides the address, while the other prevents its characters from being interpreted as markup.
Avoid decoding a request target and inserting the decoded result into a page. An encoded space or slash can change meaning during unnecessary decoding and re-encoding. Keep URL components in their intended form, then apply the output encoding required by the destination context. JavaScript strings and HTTP headers need their own handling.
Account for proxies and local development
A reverse proxy can accept HTTPS publicly while forwarding HTTP to PHP. Checking only the backend connection may then describe the wrong scheme. Conversely, trusting any incoming forwarded header lets untrusted clients influence URL construction. Configure trusted proxy handling at the server or framework boundary.
For this small example, the configured public origin makes that scheme inference unnecessary. Use a separate configured origin for a development installation, such as an approved localhost address. Avoid changing the production canonical hostname merely because a development request arrived through a different host or port.
Keep navigation separate from redirects
A current-page helper does not make a visitor-supplied return URL safe. If a login form accepts a return destination, prefer a known route or a validated local path and reject external origins. Apply the same checks at the point where the application actually redirects. Do not assume that an address is approved because it appeared on your page earlier.
Similarly, avoid including private query parameters in public sharing links. An account page or one-time token should not become a canonical URL simply because the request contained it. Choose the public identifier deliberately.
Check a small set of requests
Try the homepage, a nested article, an encoded path and a request containing multiple query parameters. Confirm that the requested result retains the intended parameters and that the clean article URL uses the preferred hostname and slash policy. Check the generated HTML source as well as the browser address bar.
Also try malformed request targets in an isolated test, confirm the fallback and verify behavior behind your actual hosting setup. The downloadable example requires PHP 7.4 or later and still needs execution on a PHP-enabled server. Related articles explain filesystem paths and relative versus absolute URLs.