RFC3986 URI

The League\Uri\Uri class implements:

The class handles all URI schemes and default to RFC3986 rules if the scheme is not present and not recognized as special.

Instantiation

The default constructor is private and can not be accessed to instantiate a new object.

The League\Uri\Uri class comes with the following named constructors to ease instantiation.

All named constructors supports parameter widening. When a string is expected, scalar values and objects implementing the __toString method can be used.

Using a string

<?php

use League\Uri\Uri;

$uri = Uri::createFromString(
	'http://example.com/path/to?q=foo%20bar#section-42'
);

If no input is provided a instance representing the empty string is returned.

Using Uri components

use League\Uri\Uri;
use League\Uri\UriString;

$uri = Uri::createFromComponents(
	UriString::parse("http://uri.thephpleague/5.0/uri/api")
);

If you supply your own hash to createFromComponents, you are responsible for providing well parsed components without their URI delimiters.

Using environment variables

//don't forget to provide the $_SERVER array
$uri = Uri::createFromServer($_SERVER);

The method only relies on the server's safe parameters to determine the current URI. If you are using the library behind a proxy the result may differ from your expectation as no $_SERVER['HTTP_X_*'] header is taken into account for security reasons.

Using a base URI

Resolves an URI as a browser would for a relative URI.

$uri = Uri::createFromBaseUri(
	"./p#~toto",
	"http://www.example.com/path/to/the/sky/"
);

echo $uri; //displays "http://www.example.com/path/to/the/sky/p#~toto"

This method expect at most two variables. The URL to resolve and the base URL to use for resolution. If not base URL is provided, the URL to resolve must be absolute. On the other hand, if a base URL is provided it must be absolute.

Using an URI object

use Zend\Diactoros\Uri as ZendUri;
use League\Uri\Uri;

$zendUri = new ZendUri("http://www.example.com/path/to/the/sky");
$zendUri->getQuery();   //return '';

$leagueUri = Uri::createFromUri($zendUri);
$leagueUri->getQuery(); //return null;

This named constructor accepts PSR-7 or League UriInterface implementing objects as its sole argument.

Using the content of a file

Returns a new URI object with the data scheme and using the content of the file located at the provided path. Because the function uses internally PHP’s file streaming capabilities an optional context resource can be used to beller access the file content.

$uri = Uri::createFromDataPath('path/to/my/png/image.png');
echo $uri; //returns 'data:image/png;charset=binary;base64,...'
//where '...' represent the base64 representation of the file

Using a Windows file path

Returns a new URI object using the file scheme for a Windows file path.

$uri = Uri::createFromWidowsPath('c:\windows\My Documents\my word.docx');
echo $uri; //returns 'file://localhost/c:My%20Documents/my%20word.docx'

Using a Unix file path

Returns a new URI object using the file scheme for a Unix file path.

$uri = Uri::createFromUnixPath('/path/to/my/file.xml');
echo $uri; //returns 'file://localhost/path/to/my/file.xml'

URI validation

A League\Uri\Contracts\UriException exception is triggered if an invalid URI is given.

$uri = Uri::createFromString(':');
// throws a League\Uri\Exceptions\SyntaxError
// because the URI string is invalid

Because the League\Uri\Exceptions\SyntaxError exception extends League\Uri\Contracts\UriException you should catch any exception triggered by the package using the following code.

use League\Uri\Uri;
use League\Uri\Contracts\UriException;

try {
	$uri = Uri::createFromString(':');
} catch (UriException $e) {
}

Basic validations

By default, if the URI scheme is not recognized, the URI object wil only validate RFC3986 rules. This means that depending on the URI scheme the returned URI may not be valid.

$mailto_uri = 'mailto://thephpleague.com/path/to?here#content';

$uri = Uri::createFromString($mailto_uri);
//this will not throw an error because this URI satified RFC3986 rules

For the following special schemes (order alphabetically) extra validation are take into account.

These extra validation rules are triggerd only when the URI is absolute and the scheme is detected. Otherwise only basic RFC3986 rules are taken into account.

http(s) scheme validation

Authority presence

If a scheme is present and the scheme specific part of a Http URI is not empty the URI can not contain an empty authority. Thus, some Http URI modifications must be applied in a specific order to preserve the URI validation.

$uri = Uri::createFromString('http://uri.thephpleague.com/');
echo $uri->withHost(null)->withScheme(null);
// will throw an League\Uri\Exceptions\SyntaxError
// you can not remove the Host if a scheme is present

Instead you are required to proceed as below

$uri = Uri::createFromString('http://uri.thephpleague.com/');
echo $uri->withScheme(null)->withHost(null); //displays "/"

When an invalid URI object is created an SyntaxError exception is thrown

Path validity

According to RFC3986, if an HTTP URI contains a non empty authority part, the URI path must be the empty string or absolute. Thus, some modification may trigger an SyntaxError.

$uri = Uri::createFromString('http://uri.thephpleague.com/');
echo $uri->withPath('uri/schemes/http');
// will throw an League\Uri\Exceptions\SyntaxError

Instead you are required to submit a absolute path

$uri = Uri::createFromString('http://uri.thephpleague.com/');
echo $uri->withPath('/uri/schemes/http');
// displays 'http://uri.thephpleague.com/uri/schemes/http'

Of note this does not mean that rootless path are forbidden, the following code is fine.

$uri = Uri::createFromString('?foo=bar');
echo $uri->withPath('uri/schemes/http'); // displays 'uri/schemes/http?foo=bar'

ftp scheme validation

It can not contains a query and or a fragment component.

Adding contents to the fragment or query components throws an UriException exception

$uri = Uri::createFromString('ftp://thephpleague.com/path/to/image.png;type=i');
$uri->withQuery('p=1'); // will throw an League\Uri\Exceptions\SyntaxError

Apart from the fragment requirements, FTP URIs share the same [validation rules](/5.0/uri/schemes/http/#validation) as Http URIs.

ws(s) scheme validation

It can not contain a fragment component as per RFC6455.

Adding contents to the fragment component throws an UriException exception

$uri = Uri::createFromString('wss://thephpleague.com/path/to?here#content');
// will throw an League\Uri\Exceptions\SyntaxError

Apart from the fragment requirements, FTP URIs share the same [validation rules](/5.0/uri/schemes/http/#validation) as Http URIs.

data scheme validation

Even though all URI properties are defined and accessible attempt to set any component other than the path will result in the object throwing a SyntaxError exception. As adding data to theses URI parts will generate an invalid Data URI.

$uri = Uri::createFromPath('path/to/my/png/image.png');
$uri->getHost(); //returns null
$uri->withHost('example.com'); // will throw an League\Uri\Exceptions\SyntaxError

Accessing URI properties

The RFC3986 URI object exposes the following methods.

public function Uri::__toString(): string
public function Uri::getScheme(void): ?string
public function Uri::getUserInfo(void): ?string
public function Uri::getHost(void): ?string
public function Uri::getPort(void): ?int
public function Uri::getAuthority(void): ?string
public function Uri::getPath(void): string
public function Uri::getQuery(void): ?string
public function Uri::getFragment(void): ?string
public function Uri::jsonSerialize(void): string

Apart from the path component, which is always a string, all the other URI components can be null

You can access the URI string, its individual parts and components using their respective getter methods. This lead to the following result for a simple HTTP URI:

$uri = Uri::createFromString("http://foo:bar@www.example.com:81/how/are/you?foo=baz#title");
echo $uri->getScheme();    //displays "http"
echo $uri->getUserInfo();  //displays "foo:bar"
echo $uri->getHost();      //displays "www.example.com"
echo $uri->getPort();      //displays 81 as an integer
echo $uri->getAuthority(); //displays "foo:bar@www.example.com:81"
echo $uri->getPath();      //displays "/how/are/you"
echo $uri->getQuery();     //displays "foo=baz"
echo $uri->getFragment();  //displays "title"
echo $uri;
//displays "http://foo:bar@www.example.com:81/how/are/you?foo=baz#title"
echo json_encode($uri);
//displays "http:\/\/foo:bar@www.example.com:81\/how\/are\/you?foo=baz#title"

Modifying URI properties

To replace one of the URI component you can use the modifying methods exposed by all URI object. If the modifications do not alter the current object, it is returned as is, otherwise, a new modified object is returned.

Any modification method can trigger a League\Uri\Contracts\UriException exception if the resulting URI is not valid. Just like with the instantiation methods, validition is scheme dependant.

<?php

public function Uri::withScheme(?string $scheme): self
public function Uri::withUserInfo(?string $user [, ?string $password = null]): self
public function Uri::withHost(?string $host): self
public function Uri::withPort(?int $port): self
public function Uri::withPath(string $path): self
public function Uri::withQuery(?string $query): self
public function Uri::withFragment(?string $fragment): self

Apart from the path component, which is always a string, to delete a URI component you need to specify its content as being null

Since All URI object are immutable you can chain each modifying methods to simplify URI creation and/or modification.

$uri = Uri::createFromString("ws://thephpleague.com/fr/")
    ->withScheme("wss")
    ->withUserInfo("foo", "bar")
    ->withHost("www.example.com")
    ->withPort(81)
    ->withPath("/how/are/you")
    ->withQuery("foo=baz");

echo $uri; //displays wss://foo:bar@www.example.com:81/how/are/you?foo=baz

URI normalization

Out of the box the package normalizes any given URI according to the non destructive rules of RFC3986.

These non destructives rules are:

$uri = Uri::createFromString(
    "hTTp://www.ExAmPLE.com:80/hello/./wor ld?who=f 3#title"
);
echo $uri; //displays http://www.example.com/hello/./wor%20ld?who=f%203#title

$uri = Uri::createFromComponent(parse_url("hTTp://www.bébé.be?#"));
echo $uri; //displays http://xn--bb-bjab.be?#

The last example depends on the presence of the ext-intl extension. Otherwise the code will trigger a IdnSupportMissing exception