URI modifiers
Sometimes you do not wish to change the full component of a URI, but you are interested in updating part of one of its component. In order to do so in PHP the code can quickly become a headache with a lot of edge case. For instance here’s how you would update the query string from a given URI object:
<?php
use GuzzleHttp\Psr7\Uri;
$uriString = "http://www.example.com?fo.o=toto#~typo";
$queryToMerge = 'fo.o=bar&taz=';
$uri = new Uri($uriString);
parse_str($uri->getQuery(), $params);
parse_str($queryToMerge, $paramsToMerge);
$query = http_build_query(
array_merge($params, $paramsToMerge),
'',
'&',
PHP_QUERY_RFC3986
);
$newUri = $uri->withQuery($query);
echo $newUri; // display http://www.example.com?fo_o=bar&taz=#~typo
In contrast, using the provided League\Uri\Modifier::mergeQuery
modifier the code becomes
<?php
use League\Uri\Modifier;
$uriString = "http://www.example.com?fo.o=toto#~typo";
$queryToMerge = 'fo.o=bar&taz=';
echo Modifier::from($uriString)->mergeQuery($queryToMerge);
// display http://www.example.com?fo.o=bar&taz=#~typo
In addition to merging the query to the URI, mergeQuery
has:
- enforced
RFC3986
encoding throughout the modifications; - not mangle your data during merging;
- returned a valid URI object;
Because the Modifier
is immutable and the modifying methods return a new instance of the class,
out of the box, piping multiple methods to improve your code is supported.
<?php
use League\Uri\Modifier;
use GuzzleHttp\Psr7\Uri as GuzzleUri;
$uri = Modifier::from(new GuzzleUri('http://bébé.be'))
->appendSegment('toto')
->addRootLabel()
->prependLabel('shop')
->hostToUnicode()
->appendQuery('foo=toto&foo=tata')
->getUri();
echo $uri::class; // returns GuzzleHttp\Psr7\Uri
echo $uri, PHP_EOL; // returns http://shop.bébé.be./toto?foo=toto&foo=tata
Returned URI object and string representations
The Modifier
can return different URI results depending on the context and your usage.
The Modifier::getUri
method returns a League URI UriInterface
unless you instantiated the modifier
with a PSR-7
Uri object in which case a PSR-7
Uri object of the same type is returned. If you
are not interested in the returned URI but only on its underlying string representation, you can instead use
the Modifier::getUriString
which is a shortcut to Modifier::getUri->__toString()
.
the Modifier::toString
method returns the strict RFC3986 string representation of the URI regardless of the underlying URI object string representation.
This is the representation used by the Stringable
and the JsonSerializable
interface to improve interoperability.
The Modifier::toDisplayString
method returns a RFC3987 like string representation which is more suited for
displaying the URI and should not be used to interact with an API as the produced URI may not be RFC3986 compliant
at all.
use GuzzleHttp\Psr7\Utils;
$uri = Modifier::from(Utils::uriFor('https://bébé.be?foo[]=bar'))->prepend('shop');
$uri->getUri()::class; // returns 'GuzzleHttp\Psr7\Uri'
$uri->getUri()->__toString(); // returns 'https://shop.bébé.be?foo%5B%5D=bar'
$uri->getUriString(); // returns 'https://shop.bébé.be?foo%5B%5D=bar'
$uri->toString(); // returns 'https://shop.xn--bb-bjab.be?foo%5B%5D=bar'
$uri->toDisplayString(); // returns 'https://shop.bébé.be?foo[]=bar'
Available modifiers
Under the hood the Modifier
class intensively uses the URI components objects
to apply the following changes to the submitted URI.
- removeDotSegments
- removeEmptySegments
- removeTrailingSlash
- addTrailingSlash
- removeLeadingSlash
- addLeadingSlash
- replaceDirname
- replaceBasename
- replaceExtension
- addBasePath
- removeBasePath
- appendSegment
- prependSegment
- replaceSegment
- removeSegments
- sliceSegments
- replaceDataUriParameters
- dataPathToBinary
- dataPathToAscii
Query modifiers
The following modifiers update and normalize the URI query component.
Modifier::encodeQuery
Change the encoding of the query string. You can either specify one of PHP’s constant between PHP_QUERY_RFC1738
and
PHP_QUERY_RFC3986
use League\Uri\Modifier;
echo Modifier::from("https://example.com/?kingkong=toto&foo=bar%20baz&kingkong=ape")
->encodeQuery(PHP_QUERY_RFC1738)
->getUri()
->getQuery();
//display "kingkong=toto&kingkong=ape&foo=bar+baz"
or for more specific conversions you can provide a League\Uri\KeyValuePair\Converter
class.
use League\Uri\KeyValuePair\Converter as KeyValuePairConverter;
use League\Uri\Modifier;
use Nyholm\Psr7\Uri;
$converter = KeyValuePairConverter::new(';')
->withEncodingMap([
'%3F' => '?',
'%2F' => '/',
'%40' => '@',
'%3A' => ':',
]);
Modifier::from(new Uri('https://example.com?foo[2]=bar#fragment'))
->appendQuery('url=https://example.com?foo[2]=bar#fragment')
->encodeQuery($converter)
->getUri()
->getQuery();
//display "foo%5B2%5D=bar;url=https://example.com?foo%5B2%5D%3Dbar%23fragment"
Modifier::sortQuery
Sorts the query according to its key values. The sorting rules are the same uses by WHATWG URLSearchParams::sort
method.
use League\Uri\Modifier;
echo Modifier::from("http://example.com/?kingkong=toto&foo=bar%20baz&kingkong=ape")
->sortQuery()
->getUri()
->getQuery();
//display "kingkong=toto&kingkong=ape&foo=bar%20baz"
Modifier::mergeQuery
Merges a submitted query string to the URI object to be modified. When merging two query strings with the same key value the submitted query string value takes precedence over the URI query string value.
$uri = Http::new("http://example.com/test.php?kingkong=toto&foo=bar+baz#doc3");
echo Modifier::from($uri)
->mergeQuery('kingkong=godzilla&toto')
->getUri()
->getQuery();
//display "kingkong=godzilla&foo=bar%20baz&toto"
Modifier::appendQuery
Appends a submitted query string to the URI object to be modified. When appending two query strings with the same key value the submitted query string value is added to the return query string without modifying the URI query string value.
Http::new("http://example.com/test.php?kingkong=toto&foo=bar+baz#doc3")
echo Modifier::from($uri)
->appendQuery('kingkong=godzilla&toto')
->getUri()
->getQuery();
//display "kingkong=toto&kingkong=godzilla&foo=bar%20baz&toto"
Modifier::appendQueryPairs
Appends a query pairs to the URI object to be modified. When appending two query strings with the same key value the submitted query string value is added to the return query string without modifying the URI query string value.
Http::new("http://example.com/test.php?kingkong=toto&foo=bar+baz#doc3")
echo Modifier::from($uri)
->appendQueryPairs([['kingkong', 'godzilla'], ['toto', null]])
->getUri()
->getQuery();
//display "kingkong=toto&kingkong=godzilla&foo=bar%20baz&toto"
Modifier::appendQueryParameters
Appends a query PHP parameters to the URI object to be modified. When appending two query strings with the same key value the submitted query string value is added to the return query string without modifying the URI query string value.
Http::new("http://example.com/test.php?kingkong=toto&foo=bar+baz#doc3")
echo Modifier::from($uri)
->appendQueryParameters(['kingkong' => 'godzilla', 'toto' => ''])
->getUri()
->getQuery();
//display "kingkong=toto&kingkong=godzilla&foo=bar%20baz&toto="
Modifier::removeQueryPairs
Removes query pairs from the current URI query string by providing the pairs key.
$uri = "http://example.com/test.php?kingkong=toto&foo=bar+baz&bar=baz#doc3";
$modifier = Modifier::from($uri);
$newUri = $modifier->removeQueryPairs('foo', 'bar')->getUri();
echo $modifier->getUri()->getQuery(); //display "kingkong=toto&foo=bar+baz&bar=baz"
echo $newUri->getUri()->getQuery(); //display "kingkong=toto"
Modifier::removeQueryParameters
Removes query params from the current URI query string by providing the param name. The removal preserves mangled key params.
$uri = "http://example.com/test.php?kingkong=toto&fo.o=bar&fo_o=bar";
$modifier = Modifier::from($uri);
$newUri = $modifier->removeQueryParameters('fo.o');
echo $modifier->getUri()->getQuery(); //display "kingkong=toto&fo.o=bar&fo_o=bar
echo $newUri->getUri()->getQuery(); //display "kingkong=toto&fo_o=bar"
Modifier::removeQueryParameterIndices
Removes query params numeric indices from the current URI query string. The removal preserves mangled key params.
$uri = "http://example.com/test.php?kingkong[1]=toto&fkingkong[2]=toto";
$modifier = Modifier::from($uri);
$newUri = $modifier->removeQueryParameterIndices();
echo $modifier->getUri()->getQuery(); //display "kingkong%5B1%5D=toto&fkingkong%5B2%5D=toto"
echo $newUri->getUri()->getQuery(); //display "kingkong%5B%5D=toto&fkingkong%5B%5D=toto"
Modifier::mergeQueryParameters
Merge PHP query parameters with the current URI query string by providing the parameters. The addition preserves mangled key params.
$uri = "http://example.com/test.php?kingkong=toto&fo.o=bar&fo_o=bar";
$newUri = Modifier::from($uri)->:mergeQueryParameters(['toto' => 'baz']);
echo $newUri->getUri()->getQuery(); //display "kingkong=tot&fo.o=bar&fo_o=bar&toto=baz"
Modifier::mergeQueryPairs
Merge query paurs with the current URI query string by providing the pairs.
$uri = "http://example.com/test.php?kingkong=toto&fo.o=bar&fo_o=bar";
$newUri = Modifier::from($uri)->:mergeQueryPairs([['fo.o', 'champion']]);
echo $newUri->getUri()->getQuery(); //display "kingkong=toto&fo.o=champion&fo_o=bar"
Host modifiers
The following modifiers update and normalize the URI host component according to RFC3986 or RFC3987.
Modifier::hostToAscii
Converts the host into its ascii representation according to RFC3986:
<?php
use GuzzleHttp\Psr7\Uri;
use League\Uri\Modifier;
$uri = new Uri("http://스타벅스코리아.com/to/the/sky/");
$newUri = Modifier::from($uri)->hostToAscii()->getUri();
echo get_class($newUri); //display \GuzzleHttp\Psr7\Uri
echo $newUri; //display "http://xn--oy2b35ckwhba574atvuzkc.com/to/the/sky/"
Modifier::hostToUnicode
Converts the host into its idn representation according to RFC3986:
<?php
use GuzzleHttp\Psr7\Uri;
use League\Uri\Modifiers\HostToUnicode;
$uriString = "http://xn--oy2b35ckwhba574atvuzkc.com/to/the/./sky/";
$uri = new Uri($uriString);
$newUri = Modifier::from($uri)->hostToUnicode();
echo get_class($newUri); //display \GuzzleHttp\Psr7\Uri
echo $newUri; //display "http://스타벅스코리아.com/to/the/sky/"
Modifier::hostToDecimal
Normalizes the URI host content to a IPv4 dot-decimal notation if possible otherwise returns the uri instance unchanged. See the IPv4 Converter documentation page for more information.
<?php
use League\Uri\Modifier;
$uri = 'http://0300.0250.0000.0001/path/to/the/sky.php';
echo Modifier::from($uri)->hostToDecimal()->getUri();
//display 'http://192.168.0.1/path/to/the/sky.php'
Modifier::hostToOctal
Normalizes the URI host content to a IPv4 dot-octal notation if possible otherwise returns the uri instance unchanged. See the IPv4 Converter documentation page for more information.
<?php
use League\Uri\Modifier;
$uri = 'http://192.168.0.1/path/to/the/sky.php';
echo Modifier::from($uri)->hostToOctal()->getUri();
//display 'http://0300.0250.0000.0001/path/to/the/sky.php'
Modifier::hostToHexadecimal
Normalizes the URI host content to a IPv4 hexadecimal notation if possible otherwise returns the uri instance unchanged. See the IPv4 Converter documentation page for more information.
<?php
use League\Uri\Modifier;
$uri = 'http://192.168.257/path/to/the/sky.php';
echo Modifier::from($uri)->hostToOctal()->getUri();
//display 'http://0xc0a811/path/to/the/sky.php'
Modifier::hostToIpv6Compressed
Normalizes the URI host content to a compressed IPv6 notation if possible. See the IPv6 Converter documentation page for more information.
<?php
use League\Uri\Modifier;
$uri = 'http://[1050:0000:0000:0000:0005:0000:300c:326b]/path/to/the/sky.php';
echo Modifier::from($uri)->hostToIpv6Compressed()->getUriString();
//display 'http://[1050::5:0:300c:326b]/path/to/the/sky.php'
Modifier::hostToIpv6Expanded
Normalizes the URI host content to a expanded IPv6 notation if possible. See the IPv6 Converter documentation page for more information.
<?php
use League\Uri\Modifier;
$uri = 'http://[0000:0000:0000:0000:0000:0000:0000:0001]/path/to/the/sky.php';
echo Modifier::from($uri)->hostToIpv6Compressed()->getUriString();
//display 'http://[::1]/path/to/the/sky.php'
Modifier::removeZoneIdentifier
Removes the host zone identifier if present
<?php
use Zend\Diactoros\Uri;
use League\Uri\Modifier;
$uri = new Uri('http://[fe80::1234%25eth0-1]/path/to/the/sky.php');
$newUri = Modifier::from($uri)->removeZoneIdentifier()->getUri();
echo get_class($newUri); //display \Zend\Diactoros\Uri
echo $newUri; //display 'http://[fe80::1234]/path/to/the/sky.php'
Modifier::normalizeHostIp
Returns the host as formatted following WHATWG host formatting
$uri = "https://0:0@0:0";
echo Modifier::from($uri)->normalizeHostIp()->getUriString();
//display "https://0:0@0.0.0.0:0"
In case of IPv4 and/or IPv6 some extra normalization are applied.
Modifier::addRootLabel
Adds the root label if not present
use League\Uri\Modifier;
echo Modifier::from('http://example.com:83')->addRootLabel(); //display 'http://example.com.:83'
Modifier::removeRootLabel
Removes the root label if present
use League\Uri\Modifier;
echo Modifier::from('http://example.com.#yes')->removeRootLabel(); //display 'http://example.com#yes'
Modifier::appendLabel
Appends a host to the current URI host.
use League\Uri\Modifier;
echo Modifier::from("http://www.example.com/path/to/the/sky/")->appendLabel('fr');
//display "http://www.example.com.fr/path/to/the/sky/"
Modifier::prependLabel
Prepends a host to the current URI path.
use League\Uri\Modifier;
echo Modifier::from("http://www.example.com/path/to/the/sky/")->prependLabel('shop'); //display "http://shop.www.example.com/path/to/the/sky/and/above"
Modifier::replaceLabel
Replaces a label from the current URI host with a host.
use League\Uri\Modifier;
$uri = "http://www.example.com/path/to/the/sky/";
echo Modifier::from($uri)->replaceLabel(2, 'admin.shop');
//display"http://admin.shop.example.com/path/to/the/sky"
The previous example can be rewritten using negative offset:
use League\Uri\Modifier;
$uri = "http://www.example.com/path/to/the/sky/";
echo Modifier::from($uri)->replaceLabel(-1, 'admin.shop');
//display"http://admin.shop.example.com/path/to/the/sky"
Modifier::removeLabels
Removes selected labels from the current URI host. Labels are indicated string variadic labels offsets.
$uri = "http://www.localhost.com/path/to/the/sky/";
echo Modifier::from($uri)->removeLabels(2, 0);
//display "http://localhost/path/the/sky/"
The previous example can be rewritten using negative offset:
$uri = "http://www.example.com/path/to/the/sky/";
Modifier::from($uri)->removeLabels(-1, -3)->getUriString();
//return "http://localhost/path/the/sky/"
Modifier::sliceLabels
Slice the host from the current URI host. Negative offset are also supported.
$uri = "http://www.localhost.com/path/to/the/sky/";
echo Modifier::from($uri)->sliceLabels(1, 1)->getUriString();
//display "http://localhost/path/the/sky/"
Path modifiers
Modifier::removeDotSegments
Removes dot segments according to RFC3986:
$uri = "http://www.example.com/path/../to/the/./sky/";
echo Modifier::from($uri)->removeDotSegments();
//display "http://www.example.com/to/the/sky/"
Modifier::removeEmptySegments
Removes adjacent separators with empty segment.
$uri = "http://www.example.com/path//to/the//sky/";
echo Modifier::from($uri)->removeEmptySegments();
//display "http://www.example.com/path/to/the/sky/"
Modifier::removeTrailingSlash
Removes the path trailing slash if present
$uri = Uri::new("http://www.example.com/path/?foo=bar");
echo Modifier::from($uri)->removeTrailingSlash();
//display "http://www.example.com/path?foo=bar"
Modifier::addTrailingSlash
Adds the path trailing slash if not present
$uri = "http://www.example.com/sky#top";
echo Modifier::from($uri)->addTrailingSlash();
//display "http://www.example.com/sky/#top"
Modifier::removeLeadingSlash
Removes the path leading slash if present.
$uri = "/path/to/the/sky/";
echo Modifier::from($uri)->removeLeadingSlash();
//display "path/to/the/sky"
Modifier::addLeadingSlash
Adds the path leading slash if not present.
echo Modifier::from("path/to/the/sky/")->addLeadingSlash();
//display "/path/to/the/sky"
Modifier::replaceDirname
Adds, updates and or removes the path dirname from the current URI path.
echo Modifier::from("http://www.example.com/path/to/the/sky")
->replaceDirname('/road/to')
->getUri()
->getPath(); //display "/road/to/sky"
Modifier::replaceBasename
Adds, updates and or removes the path basename from the current URI path.
$uri = Http::new("http://www.example.com/path/to/the/sky");
echo Modifier::from($uri)
->replaceBasename("paradise.xml")
->getUri()
->getPath();
//display "/path/to/the/paradise.xml"
Modifier::replaceExtension
Adds, updates and or removes the path extension from the current URI path.
$uri = Http::new("http://www.example.com/export.html");
echo Modifier::from($uri)->replaceExtension('csv')->getUri()->getPath();
//display "/export.csv"
Modifier::addBasePath
Adds the basepath to the current URI path.
$uri = Http::new("http://www.example.com/path/to/the/sky");
echo Modifier::from($uri)
->addBasePath('/the/real')
->getUri()
->getPath();
//display "/the/real/path/to/the/sky"
Modifier::removeBasePath
Removes the basepath from the current URI path.
$uri = Http::new("http://www.example.com/path/to/the/sky");
echo Modifier::from($uri)
->removeBasePath("/path/to/the")
->getUri()
->getPath();
//display "/sky"
Modifier::appendSegment
Appends a path to the current URI path.
$uri = Http::new("http://www.example.com/path/to/the/sky/");
echo Modifier::from($uri)
->appendSegment("and/above")
->getUri()
->getPath();
//display "/path/to/the/sky/and/above"
Modifier::prependSegment
Prepends a path to the current URI path.
$uri = Http::new("http://www.example.com/path/to/the/sky/");
echo Modifier::from($uri)
->prependSegment("and/above")
->getUri()
->getPath();
//display "/and/above/path/to/the/sky/"
Modifier::replaceSegment
Replaces a segment from the current URI path with a new path.
$uri = Http::new("http://www.example.com/path/to/the/sky/");
echo Modifier::from($uri)
->replaceSegment(3, "sea")
->getUri()
->getPath();
//display "/path/to/the/sea/"
The previous example can be rewritten using negative offset:
echo Modifier::from("http://www.example.com/path/to/the/sky/")
->replaceSegment(-1, "sea")
->getPath();
//display "/path/to/the/sea/"
Modifier::removeSegments
Removes selected segments from the current URI path by providing the segments offset.
echo Modifier::from("http://www.example.com/path/to/the/sky/")
->removeSegments(1, 3)
->getUri()
->getPath();
//display "/path/the/"
echo Modifier::from("http://www.example.com/path/to/the/sky/")
->removeSegments(-1, -2])
->getUri()
->getPath();
//display "/path/the/"
Modifier::sliceSegments
Slice the path from the current URI path. Negative offset are also supported.
$uri = "http://www.localhost.com/path/to/the/sky/";
echo Modifier::from($uri)->sliceSegments(2, 2)->getUriString();
//display "http://www.localhost.com/the/sky/"
Modifier::replaceDataUriParameters
Update Data URI parameters
$uri = Uri::new("data:text/plain;charset=US-ASCII,Hello%20World!");
echo Modifier::from($uri)
->replaceDataUriParameters("charset=utf-8")
->getUri()
->getPath();
//display "text/plain;charset=utf-8,Hello%20World!"
Modifier::dataPathToBinary
Converts a data URI path from text to its base64 encoded version
$uri = Uri::new("data:text/plain;charset=US-ASCII,Hello%20World!");
echo Modifier::from($uri)
->dataPathToBinary()
->getUri()
->getPath();
//display "text/plain;charset=US-ASCII;base64,SGVsbG8gV29ybGQh"
Modifier::dataPathToAscii
Converts a data URI path from text to its base64 encoded version
$uri = Uri::new("data:text/plain;charset=US-ASCII;base64,SGVsbG8gV29ybGQh");
echo Modifier::from($uri)
->dataPathToAscii()
->getUri()
->getPath();
//display "text/plain;charset=US-ASCII,Hello%20World!"
General modification
To ease modifying URI since version 7.6.0 you can directly access the modifier methods from the underlying URI object.
use League\Uri\Modifier;
$foo = '';
echo Modifier::from('http://bébé.be')
->when(
'' !== $foo,
fn (Modifier $uri) => $uri->withQuery('fname=jane&lname=Doe'), //on true
fn (Modifier $uri) => $uri->mergeQueryParameters(['fname' => 'john', 'lname' => 'Doe']), //on false
)
->appendSegment('toto')
->addRootLabel()
->prependLabel('shop')
->appendQuery('foo=toto&foo=tata')
->withFragment('chapter1')
->toDisplayString();
// returns 'http://shop.bébé.be./toto?fname=john&lname=Doe&foo=toto&foo=tata#chapter1';