UrlUtilities
in package
URL handling utilities.
Provides methods for parsing and manipulating URLs, including dictionary URL parsing.
Tags
Table of Contents
Properties
- $appUrl : string|null|false
- Cached app URL value.
- $basePath : string|null
- Cached base path value.
- $trustProxy : bool|null
- Cached `TRUST_PROXY` resolution. null = not yet resolved.
Methods
- buildUrl() : string
- Build a URL with query parameters.
- getAppOrigin() : string
- Get the application origin (scheme + host), preferring APP_URL env var.
- getAppUrl() : string|null
- Get the configured application URL (scheme + host).
- getBasePath() : string
- Get the configured application base path.
- getRequestHost() : string
- Get the host of the current request, honouring `X-Forwarded-Host` when the proxy is trusted.
- isSecureRequest() : bool
- Whether the current request reached LWT over a secure transport.
- langFromDict() : string
- Get a two-letter language code from dictionary source language.
- resetBasePath() : void
- Reset the cached base path.
- safeHttpGet() : string|null
- Safely fetch an HTTP/HTTPS URL with SSRF protection.
- stripBasePath() : string
- Strip the base path from a request URI for route matching.
- targetLangFromDict() : string
- Get a two-letter language code from dictionary target language
- trustsProxy() : bool
- Whether to honour `X-Forwarded-*` headers from the front-end proxy.
- url() : string
- Generate a URL with the application base path prepended.
- urlBase() : string
- Get the base URL of the application
- validateUrlForFetch() : array{valid: bool, error?: string, resolved_ip?: string}
- Validate that a URL is safe to fetch (not pointing to internal/private IPs).
- isPublicIp() : bool
- Check if an IP address is a public (non-private, non-reserved) address.
- resolveHostToIps() : array<string|int, string>
- Resolve a hostname to its IP addresses.
- resolveRelativeUrl() : string
- Resolve a (possibly relative) URL against a base URL.
Properties
$appUrl
Cached app URL value.
private
static string|null|false
$appUrl
= null
null = not yet resolved, false = no env var set
$basePath
Cached base path value.
private
static string|null
$basePath
= null
$trustProxy
Cached `TRUST_PROXY` resolution. null = not yet resolved.
private
static bool|null
$trustProxy
= null
Methods
buildUrl()
Build a URL with query parameters.
public
static buildUrl(string $path[, array<string, mixed> $params = [] ]) : string
Constructs a URL by combining a path with query parameters. Empty/null parameter values are filtered out.
Parameters
- $path : string
-
The URL path (will have base path prepended)
- $params : array<string, mixed> = []
-
Query parameters to append
Tags
Return values
string —The complete URL with query string
getAppOrigin()
Get the application origin (scheme + host), preferring APP_URL env var.
public
static getAppOrigin() : string
Falls back to detecting from $_SERVER if APP_URL is not configured.
The fallback honors X-Forwarded-Proto and X-Forwarded-Host so
the app generates correct https URLs when deployed behind a TLS-
terminating reverse proxy (Traefik, Caddy, nginx, Cloudflare, ...).
Set TRUST_PROXY=false to suppress this for direct-internet-facing
deployments that aren't shielded by a trusted proxy.
Return values
string —The application origin (e.g., 'https://example.com')
getAppUrl()
Get the configured application URL (scheme + host).
public
static getAppUrl() : string|null
Returns the APP_URL environment variable if set (e.g., 'https://example.com'). This should be used instead of $_SERVER['HTTP_HOST'] to prevent Host Header Injection attacks.
Return values
string|null —The app URL, or null if not configured
getBasePath()
Get the configured application base path.
public
static getBasePath() : string
Returns the APP_BASE_PATH environment variable value, normalized to ensure it starts with / and has no trailing slash.
Return values
string —The base path (e.g., '/lwt') or empty string for root
getRequestHost()
Get the host of the current request, honouring `X-Forwarded-Host` when the proxy is trusted.
public
static getRequestHost() : string
Validates against alphanumeric / dot / hyphen / colon / bracket
to mitigate Host-Header-Injection; falls back to localhost on
unparseable input.
Return values
string —The validated host (may include :port)
isSecureRequest()
Whether the current request reached LWT over a secure transport.
public
static isSecureRequest() : bool
Recognises four signals: direct HTTPS ($_SERVER['HTTPS'] set and
not 'off'), the standard HTTPS port, and — when the proxy is
trusted — X-Forwarded-Proto: https or X-Forwarded-Ssl: on.
The X-Forwarded-* headers can be spoofed by anyone able to talk
directly to LWT, so the install must opt out via TRUST_PROXY=false
if it isn't shielded by a proxy that strips them.
Return values
bool —True if the request is HTTPS (directly or via a trusted proxy that terminated TLS).
langFromDict()
Get a two-letter language code from dictionary source language.
public
static langFromDict(string $url) : string
Parameters
- $url : string
-
Input URL, usually Google Translate or LibreTranslate
Return values
string —The source language code or empty string
resetBasePath()
Reset the cached base path.
public
static resetBasePath() : void
Useful for testing or when environment changes dynamically.
safeHttpGet()
Safely fetch an HTTP/HTTPS URL with SSRF protection.
public
static safeHttpGet(string $url[, array{timeout?: int, maxBytes?: int, maxRedirects?: int, accept?: string, userAgent?: string} $opts = [] ]) : string|null
Unlike file_get_contents with follow_location => true, this
routes every redirect hop through validateUrlForFetch() — so
an attacker-controlled public host cannot 302 the request into
127.0.0.1:8080, 169.254.169.254, or any private range. The
response body is capped at maxBytes, the wall-clock at
timeout, and the redirect chain at maxRedirects.
Residual: validation does its own DNS resolve, then the fetch does another — a TTL-0 rebinding attacker who wins the race could still hit a private IP. Mitigating that fully needs connecting by IP literal with an explicit Host header, which is more invasive than this helper provides; the per-hop revalidation here narrows the window to a single resolve per hop instead of an open-ended redirect chain.
Parameters
- $url : string
-
The URL to fetch
- $opts : array{timeout?: int, maxBytes?: int, maxRedirects?: int, accept?: string, userAgent?: string} = []
-
Override defaults (timeout=15s, maxBytes=2MB, maxRedirects=5, accept='/', UA='LWT/3.0').
Return values
string|null —Response body, or null on any failure (invalid URL, network error, non-2xx, size/redirect cap exceeded, or a redirect into a blocked range).
stripBasePath()
Strip the base path from a request URI for route matching.
public
static stripBasePath(string $requestUri) : string
This is used by the Router to normalize incoming requests so that routes like '/' work regardless of the configured APP_BASE_PATH.
Parameters
- $requestUri : string
-
The full request URI
Tags
Return values
string —The path with base path stripped
targetLangFromDict()
Get a two-letter language code from dictionary target language
public
static targetLangFromDict(string $url) : string
Parameters
- $url : string
-
Input URL, usually Google Translate or LibreTranslate
Return values
string —The target language code or empty string
trustsProxy()
Whether to honour `X-Forwarded-*` headers from the front-end proxy.
public
static trustsProxy() : bool
Default: true (matches the historical behaviour of LWT's cookie
and HSTS code, which has always trusted X-Forwarded-Proto).
Operators running LWT directly on the public internet should set
TRUST_PROXY=false to prevent header-spoofing attacks.
Return values
bool —True to trust forwarded headers, false to ignore them
url()
Generate a URL with the application base path prepended.
public
static url(string $path) : string
Use this for all internal links to ensure they work correctly when the application is installed in a subdirectory.
Parameters
- $path : string
-
The path to generate URL for (must start with /)
Tags
Return values
string —The full URL path with base path prepended
urlBase()
Get the base URL of the application
public
static urlBase() : string
Honours X-Forwarded-Proto / X-Forwarded-Host when the proxy
is trusted (see isSecureRequest() / getRequestHost()).
Return values
string —base URL
validateUrlForFetch()
Validate that a URL is safe to fetch (not pointing to internal/private IPs).
public
static validateUrlForFetch(string $url) : array{valid: bool, error?: string, resolved_ip?: string}
Prevents SSRF attacks by blocking requests to:
- Private IP ranges (10.x, 172.16-31.x, 192.168.x)
- Loopback addresses (127.x, ::1)
- Link-local addresses (169.254.x, fe80::)
- Reserved/special addresses
- Non-HTTP(S) schemes
Parameters
- $url : string
-
URL to validate
Return values
array{valid: bool, error?: string, resolved_ip?: string}isPublicIp()
Check if an IP address is a public (non-private, non-reserved) address.
private
static isPublicIp(string $ip) : bool
Parameters
- $ip : string
-
IP address to check
Return values
bool —True if the IP is public and safe to access
resolveHostToIps()
Resolve a hostname to its IP addresses.
private
static resolveHostToIps(string $host) : array<string|int, string>
Parameters
- $host : string
-
Hostname to resolve
Return values
array<string|int, string> —List of IP addresses
resolveRelativeUrl()
Resolve a (possibly relative) URL against a base URL.
private
static resolveRelativeUrl(string $base, string $relative) : string
Handles three Location header shapes that real servers emit:
absolute (https://other.com/x), protocol-relative (//cdn/x),
and absolute-path (/x). Anything else is treated as a path
fragment relative to the base URL's directory.
Parameters
- $base : string
-
Base URL (the URL of the page that returned the redirect).
- $relative : string
-
The Location header value.
Return values
string —Fully qualified URL.