URI Value Object

The package provides an expressive and efficient API around building and manipulating URI. It allows the easy creation of URI in multiple contexts to increase your DX while working with URI.

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

Instantiation

While the default constructor is private and can not be accessed to instantiate a new object, the League\Uri\Uri class comes with the different named constructors to ease instantiation.

<?php

use League\Uri\Uri;
use League\Uri\UriString;
use Laminas\Diactoros\Uri as LaminasUri;

// using a string or an object which expose the `__toString` method

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

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

Uri::new($laminasUri)->getQuery(); //return null;

// using `parse_url` or the package `UriString::parse` static method.

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

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

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

The fromServer 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.

You can also return a URI based on standard specifications:

<?php

use League\Uri\Uri;

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

$template = 'https://example.com/hotels/{hotel}/bookings/{booking}';
$variables = ['booking' => '42', 'hotel' => 'Rest & Relax'];
echo Uri::fromTemplate($template, $variables)->toString();
//displays "https://example.com/hotels/Rest%20%26%20Relax/bookings/42"

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

$uri = Uri::fromData('Héllo World!', 'text/plain', 'charset=utf8');
echo $uri; // returns data:text/plain;charset=utf8,H%C3%A9llo%20World%21

The fromBaseUri method resolves URI using the same logic behind URL construction in a browser and is inline with how the Javascript URL object constructor works. If no base URI is provided, the URI to resolve MUST be absolute. Otherwise, the base URI MUST be absolute.

The fromTemplate method resolves a URI using the rules and variable from the URITemplate specification RFC6570: The method expects at most two parameters. The URI template to resolve and the variables use for resolution. You can get a more in-depth understanding of URI Template in its dedicated section of the documentation.

The fromFileContents named constructor generates a Data URI following its RFC specification. with the provided file location, the method will base64 encode the content of the file and return the generated URI.

The fromData named constructor generates a Data URI following its RFC specification. with the provided data and an optional mimetype and parameters.

Last but not least, you can easily translate RFC8089, Windows, Unix paths to URI using the three (3) following methods.

<?php

use League\Uri\Uri;

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

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

$uri = Uri::fromRfc8089('file:/etc/fstab');
echo $uri = //returns 'file:///etc/fstab'

fromRfc8089 is added since version 7.4.0

Accessing URI properties

Let’s examine the result of building a URI:

<?php

use League\Uri\Uri;

$uri = Uri::new("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->toString();
//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"
$uri->getComponents(); 
// returns array {
//   "scheme" => "http",
//   "user" => "foo",
//   "pass" => "bar",
//   "host" => "www.example.com",
//   "port" => 81,
//   "path" => "/how/are/you",
//   "query" => "foo=baz",
//   "fragment" => "title",
// }

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

Modifying URI properties

Use the modifying methods exposed by all URI instances to replace one of the URI component. 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, validation is scheme dependant.

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 objects are immutable you can chain each modifying methods to simplify URI creation and/or modification.

$uri = Uri::new("ftp://thephpleague.com/fr/")
    ->withScheme("yolo")
    ->withUserInfo("foo", "bar")
    ->withHost("www.example.com")
    ->withPort(81)
    ->withPath("")
    ->withQuery("foo=baz")
    ->withFragment('fine');

echo $uri; //displays yolo://foo:bar@www.example.com:81?foo=baz#fine

URI normalization

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

These non-destructive rules are:

$uri = Uri::new("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::fromComponent(parse_url("hTTp://www.bébé.be?#"));
echo $uri; //displays http://xn--bb-bjab.be?#

The last example depends on the presence of the idn_to_* functions, otherwise the code will trigger a MissingFeature exception