Uri-Interop is based on research including the following URI projects:
- amphp/url (amphp)
- aura/uri (aura)
- codeigniter4 (ci4)
- codezero/php-url-builder (codezero)
- joomla/uri (joomla)
- josantonius/url (josan)
- juststeveking/uri-builder (justking)
- laminas/laminas-uri (laminas)
- league/uri (league)
- nette/http (nette)
- opis/uri (opis)
- pear/net_url2 (pear)
- psr/http-message (psr)
- xp-forge/uri (xpforge)
- zenstruck/uri (zenstr)
These IRI and WHATWG-URL projects are included as well, for their overlap with URI projects:
- ml/iri (mliri)
- rmccue/requests (rmccue)
- rowbot/url (rowbot)
Many other projects were considered but did not have an obviously relevant implementation.
The projects offer varying levels of mutability:
| Readonly | Immutable | Mutable | |
|---|---|---|---|
| amphp | X | ||
| aura | X | ||
| ci4 | X | ||
| codezero | X | ||
| joomla | X | X | |
| josan | X | ||
| justking | X | ||
| laminas | X | ||
| league | X | ||
| mliri | X | ||
| nette | X | X | |
| opis | X | ||
| pear | X | ||
| psr | X | ||
| rmccue | X | ||
| rowbot | X | ||
| xpforge | X | ||
| zenstr | X |
Note that Joomla and Nette offer both mutable and immutable implementations.
All of the projects provide a means to retrieve these URI components, either via a getter method or a property:
schemehostportpathquery(as a string)fragment
Most projects provide access to a useror username component, either via a getter method or a property, but some do not provide it at all:
user |
username |
none | |
|---|---|---|---|
| amphp | X | ||
| aura | X | ||
| ci4 | X | ||
| codezero | X | ||
| joomla | X | ||
| josan | X | ||
| justking | X | ||
| laminas | X | ||
| league | X | ||
| mliri | X | ||
| nette | X | ||
| opis | X | ||
| pear | X | ||
| psr | X | ||
| rmccue | X | ||
| rowbot | X | ||
| xpforge | X | ||
| zenstr | X |
Most projects provide acccess to a pass or password component, either via a getter method or a property, but some do not provide it at all:
pass |
password |
none | |
|---|---|---|---|
| amphp | X | ||
| aura | X | ||
| ci4 | X | ||
| codezero | X | ||
| joomla | X | ||
| josan | X | ||
| justking | X | ||
| laminas | X | ||
| league | X | ||
| mliri | X | ||
| nette | X | ||
| opis | X | ||
| pear | X | ||
| psr | X | ||
| rmccue | X | ||
| rowbot | X | ||
| xpforge | X | ||
| zenstr | X |
The port value is always an integer, while the other components are always strings.
These projects allow the following components to be nullable:
| Scheme | User | Password | Host | Port | Path | Query | Fragment | |
|---|---|---|---|---|---|---|---|---|
| amphp | X | |||||||
| aura | X | |||||||
| ci4 | X | |||||||
| codezero | X | |||||||
| joomla | X | |||||||
| josan | X | |||||||
| justking | X | |||||||
| laminas | X | X | X | X | X | X | X | X |
| league | X | X | X | X | X | X | X | |
| mliri | X | X | X | X | X | X | X | |
| nette | X | |||||||
| opis | X | X | X | X | X | X | X | X |
| pear (1) | X | X | X | X | X | X | X | |
| psr | X | X | ||||||
| rmccue | X | X | X | X | X | X | X | |
| rowbot | X | |||||||
| xpforge | X | X | X | X | ||||
| zenstr | X | X | X | X |
(1) Pear uses false instead of null to the same effect.
Almost all projects retain all basic URI component values in their encoded form. Only these projects retain some components in their decoded form:
| Decoded | |
|---|---|
| aura | all |
| nette | host, username, password, fragment |
| zenstr | fragment |
The projects sometimes offer additional or computed URI components.
These projects offer the query string decoded into arrays of strings, either via a getter method or a property:
| Query (as array) | |
|---|---|
| amphp | X |
| aura | X |
| ci4 | |
| codezero | X |
| joomla | X |
| josan | X |
| justking | X |
| laminas | X |
| league | |
| mliri | |
| nette | X |
| opis | |
| pear | X |
| psr | |
| rmccue | |
| rowbot | |
| xpforge | X |
| zenstr | X |
When the query is offered as an array, it is under various terms, with variations on "params" and "parameters" being the most common:
| Method/Property | query | array | params | parameters | variables | |
|---|---|---|---|---|---|---|
| amphp | getAllQueryParameters() | X | ||||
| aura | $query | X | ||||
| codezero | getQuery() | X | ||||
| joomla | getQuery() | X | ||||
| josan | $parameters | X | ||||
| justking | queryParams() | X | ||||
| laminas | getQueryAsArray() | X | ||||
| nette | getQueryParameters() | X | ||||
| pear | getQueryVariables() | X | ||||
| xpforge | params() | X | ||||
| zenstr | $parameters, withQueryParams() | X | X |
These projects offer the path string decoded into an array (or equivalent) of segment strings, either via a getter method or a property:
| Path (as array) | |
|---|---|
| amphp | |
| aura | Path extends ArrayObject |
| ci4 | URI::getSegments() |
| codezero | UrlBuilder::getSlugs() |
| joomla | |
| josan | Url::$segments |
| justking | |
| laminas | |
| league | |
| mliri | |
| nette | |
| opis | |
| pear | |
| psr | |
| rmccue | |
| rowbot | |
| xpforge | |
| zenstr | Path::segments() |
These projects offer a string of the combined username and password portions of the URI, per RFC 3986, either via a getter method or a property:
| User Information | |
|---|---|
| amphp | |
| aura | |
| ci4 | X |
| codezero | |
| joomla | |
| josan | |
| justking | |
| laminas | X |
| league | X |
| mliri | X |
| nette | |
| opis | X |
| pear | X |
| psr | X |
| rmccue | X |
| rowbot | |
| xpforge | |
| zenstr | X |
When the user information component is offered, the "info" portion of the term is capitalized differently in different projects:
| Info | info | |
|---|---|---|
| ci4 | X | |
| laminas | X | |
| league | X | |
| mliri | X | |
| opis | X | |
| pear | X | |
| psr | X | |
| zenstr | X |
The ability to modify user information per se is present in few of the projects; the method signature usually separates the user name from the password. (It is more common to modify the user name and password independently.)
| Method | |
|---|---|
| laminas | setUserInfo($userinfo) |
| league | withUserInfo(?string $user, ?string $password = null) |
| pear | setUserinfo($userinfo, $password = false) |
| psr | withUserInfo(string $user, ?string $password = null) |
| rmccue | set_userinfo(string $userinfo) |
The following projects offer a combined string of the username, password, host, and port portions of the URI, per the RFC, either via a getter method or a property.
| Authority | |
|---|---|
| amphp | X |
| aura | |
| ci4 | X |
| codezero | |
| joomla | |
| josan | X |
| justking | |
| laminas | |
| league | X |
| mliri | X |
| nette | |
| opis | X |
| pear | X |
| psr | X |
| rmccue | X |
| rowbot | |
| xpforge | X |
| zenstr | X |
When the authority component is offered, the term "authority" is always used.
The ability to modify the authority value per se is present in only one project (rmccue). The other projects all opt to modify the sub-components of the authority independently.
These projects use these approaches to parsing URL component values.
| parse_url() | RFC 3986 | RFC 3987 | None | |
|---|---|---|---|---|
| amphp | X | |||
| aura | X | |||
| ci4 | X | |||
| codezero | X | |||
| joomla | X (1) | |||
| josan | X | |||
| justking | X | |||
| laminas | X | |||
| league | X | X | ||
| mliri | X | X | ||
| nette | X (2) | |||
| opis | X | |||
| pear | X | |||
| psr | X | |||
| rmccue | X | X | ||
| xpforge | X | |||
| zenstr | X |
- Joomla handles UTF-8 characters while parsing.
- Nette applies rawurldecode() to the host, user, password, and fragment.
These projects offer a public method to parse URI strings to their component values (often just a constructor):
| Parse into component values | |
|---|---|
| amphp | Uri::__construct(string $uri) |
| aura | UrlFactory::newInstance(string $spec) : Url |
| ci4 | Uri::__construct(?string $uri = null) |
| codezero | Uri::setURI(?string $uri = null) : void |
| joomla | Uri::__construct(?string $uri = null) |
| josan | Url::__construct(?string $url = null) |
| justking | Uri::fromString(string $uri) : Uri |
| laminas | Uri::parse(string $uri) : Uri |
| league | Uri::new(Stringable|string $uri = '') : Uri |
| mliri | IRI::__construct(null|string|IRI $iri = null) |
| nette | Url::__construct(string|Url|UrlImmutable|null $url = null) |
| opis | Uri::create(string $uri, bool $normalize = false) : ?Uri |
| pear | Net_URL2::__construct(string $url, array $options = array()) |
| psr | UriFactoryInterface::createUri(string $uri = '') : UriInterface |
| rowbot | BasicURLParser::parse(USVStringInterface $input) : UrlRecord|false |
| xpforge | Uri::__construct(string|Creation $base, ?string $relative = null) |
| zenstr | ParsedUri::new(ParsedUri|string|null $what = null) : ParsedUri |
These projects offer a public method to normalize URI components (cf. https://datatracker.ietf.org/doc/html/rfc3986/#section-6.2.2):
| Signature | Notes | |
|---|---|---|
| amphp | Uri::normalize() : string |
|
| laminas | Uri::normalize() : Uri |
Mutates $this, returns $this |
| opis | Uri::normalizeComponents(array $components) : array |
|
| pear | Net_URL2::normalize() : void |
Mutates $this |
| zenstr | ParsedUri::normalize() |
Clones $this without modification |
These projects offer a public method to resolve a relative URI reference (cf. https://datatracker.ietf.org/doc/html/rfc3986/#section-5) -- though the base URI is sometime the instance being called, and sometimes the argument being passed:
| Signature | Base URI | Notes | |
|---|---|---|---|
| amphp | Uri::resolve(string $toResolve) : Uri |
$this |
Returns a new instance |
| ci4 | URI::resolveRelativeURI(string $uri) : URI |
$this |
Returns a new instance |
| laminas | Uri::resolve(Uri|string $baseUri) : Uri |
$baseUri |
Mutates $this, returns $this |
| league | BaseUri::resolve(Stringable|string $uri) : static |
$this |
Returns a new instance |
| mliri | IRI::resolve(self|string $relativeReference) : self |
$this |
Returns a new instance |
| nette | UrlImmutable::resolve(string $reference) : self |
$this |
Returns a new instance |
| opis | Uri::resolve($base, bool $normalize = false) : self |
$base |
Returns $this or a new instance |
| pear | Net_URL2::resolve(Net_URL2|string $reference) : self |
$this |
Returns a new instance |
| rmccue | Iri::absolutize(IRI|string $base, IRI|string $relative) : false|Iri |
$base |
Returns a new instance |
| xp-forge | URI::resolve(string|self $arg) : self |
$this |
Returns $this or a new instance |
The projects throw these PHP Exception types when parsing a URI or validating its components:
| Failure to parse | Failure to validate | Custom Exception classes | |
|---|---|---|---|
| amphp | Exception | Exception | Amp\Uri\InvalidUriException |
| aura | |||
| ci4 | RuntimeException | RuntimeException | CodeIgniter\HTTP\Exceptions\HTTPException |
| codezero | |||
| joomla | RuntimeException | ||
| josan | |||
| justking | InvalidArgumentException | InvalidArgumentException | |
| laminas | InvalidArgumentException | InvalidArgumentException | Laminas\Uri\Exception\{InvalidArgumentException, InvalidUriPartException} |
| league | InvalidArgumentException | League\Uri\Exceptions\SyntaxError | |
| mliri | InvalidArgumentException | ||
| nette | InvalidArgumentException | ||
| opis | |||
| pear | |||
| psr | InvalidArgumentException | ||
| rmccue | InvalidArgumentException | ||
| rowbot | |||
| xpforge | Exception | Exception | lang\{FormatException, IllegalStateException} |
| zenstr | InvalidArgumentException | InvalidArgumentException |