HTTP Content Negotiation
Content Negotiation is the mechanism used to serve different representations of a resource for the same URI (e.g., language, format, or encoding).
When a client requests a resource, it does so using a URL. Based on this URL, the server selects one of the available variants—called representations—and returns the appropriate representation to the client. Both the resource itself and each of its representations have their own URLs. Content negotiation defines how the server chooses which representation to return when the resource is requested.
The HTTP/1.1 specification defines a set of standard request headers that initiate server-driven content negotiation, such as Accept, Accept-Encoding, and Accept-Language.
Constants
| Constant | Description |
|---|---|
Negotiation::ALL |
Get all values from a accept header (without q-factor) |
Negotiation::LOW |
Sort values in the header low to high by q-factors |
Negotiation::HIGH |
Sort values in the header high to low by q-factors |
API
| Method | Equivalent usage | Description |
|---|---|---|
contentTypes(int $sort = self::HIGH): array |
...->entries('accept', ...) |
Returns all values from the Accept header, ordered by the second parameter |
encodings(int $sort = self::HIGH): array |
...->entries('accept-encoding', ...) |
Returns all values from the Accept-Encoding header, ordered by the second parameter |
languages(int $sort = self::HIGH): array |
...->entries('accept-language', ...) |
Returns all values from the Accept-Language header, ordered by the second parameter |
topContentType(): string|mixed |
...->top('accept-encondig') |
Returns the priority document type in the Accept header |
topEncondig(): string|mixed |
...->top('accept-encondig') |
Returns the priority encoding in the Accept-Encondig header |
topLanguage(): string|mixed |
...->top('accept-language') |
Returns the priority language in the Accept-Language header |
fromString(string $str): Negotiation |
Create a Negotiation instance based on a string |
|
qFactor($value, $sort = self::HIGH): array |
Parse and retrieves the sorted items from a single value |
Accept header
If you have a HTTP request like:
GET /foo/bar HTTP/1.1
Accept: image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5
The following example will return image/avif, which is the value with the highest q-value:
use Inphinit\Http\Negotiation;
$negotiation = new Negotiation();
echo $negotiation->getContentType();
Returns all values in Accept sorted from largest to smallest q-value as array:
use Inphinit\Http\Negotiation;
$negotiation = new Negotiation();
print_r($negotiation->contentTypes(Negotiation::HIGH));
Output:
Array
(
[image/avif] => 1
[image/webp] => 1
[image/png] => 1
[image/svg+xml] => 1
[image/*] => 0.8
[*/*] => 0.5
)
Returns all values in Accept sorted from smallest to largest q-value as array:
use Inphinit\Http\Negotiation;
$negotiation = new Negotiation();
print_r($negotiation->contentTypes(Negotiation::LOW));
Output:
Array
(
[*/*] => 0.5
[image/*] => 0.8
[image/svg+xml] => 1
[image/png] => 1
[image/webp] => 1
[image/avif] => 1
)
Accept-Encoding header
If you have a HTTP request like:
GET /foo/bar HTTP/1.1
Accept-Encoding: br;q=1.0, gzip;q=0.8, *;q=0.1
The following example will return br, which is the value with the highest q-value:
use Inphinit\Http\Negotiation;
$negotiation = new Negotiation();
echo $negotiation->getEncoding();
Returns all values in Accept-Encoding sorted from largest to smallest q-value as array:
use Inphinit\Http\Negotiation;
$negotiation = new Negotiation();
print_r($negotiation->encodings(Negotiation::HIGH));
Output:
Array
(
[br] => 1
[gzip] => 0.8
[*] => 0.1
)
Returns all values in Accept-Encoding sorted from smallest to largest q-value as array:
use Inphinit\Http\Negotiation;
$negotiation = new Negotiation();
print_r($negotiation->encodings(Negotiation::LOW));
Output:
Array
(
[*] => 0.1
[gzip] => 0.8
[br] => 1
)
Accept-Language header
If you have a HTTP request like:
GET /foo/bar HTTP/1.1
Accept-Language: fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5
The following example will return fr-CH, which is the value with the highest q-value:
use Inphinit\Http\Negotiation;
$negotiation = new Negotiation();
echo $negotiation->getLanguage();
Returns all values in Accept-Language sorted from largest to smallest q-value as array:
use Inphinit\Http\Negotiation;
$negotiation = new Negotiation();
print_r($negotiation->languages(Negotiation::HIGH));
Output:
Array
(
[fr-CH] => 1
[fr] => 0.9
[en] => 0.8
[de] => 0.7
[*] => 0.5
)
Returns all values in Accept-Language sorted from smallest to largest q-value as array:
use Inphinit\Http\Negotiation;
$negotiation = new Negotiation();
print_r($negotiation->languages(Negotiation::LOW));
Output:
Array
(
[*] => 0.5
[de] => 0.7
[en] => 0.8
[fr] => 0.9
[fr-CH] => 1
)
Other headers with quality values
Request example:
GET /foo/bar HTTP/1.1
TE: gzip; q=1.0, deflate; q=0.8
Custom: foo, bar;q=0.9, baz;q=0.8, quux;q=0.7, waldo;q=0.5
Usage:
use Inphinit\Http\Negotiation;
$negotiation = new Negotiation();
$te = $negotiation->top('te', Negotiation::HIGH);
var_dump($te);
$te = $negotiation->entries('te', Negotiation::HIGH);
print_r($te);
$te = $negotiation->top('custom', Negotiation::HIGH);
var_dump($te);
$custom = $negotiation->entries('custom', Negotiation::HIGH);
print_r($custom);
Output:
string(4) "gzip"
Array
(
[gzip] => 1
[deflate] => 0.8
)
string(3) "foo"
Array
(
[foo] => 1
[bar] => 0.9
[baz] => 0.8
[quux] => 0.7
[waldo] => 0.5
)
Parsing strings
Parsing headers
The internal parser can be used independently of HTTP requests, allowing it to be reused in other contexts or even in custom client–server implementations. Example:
$str = <<<EOT
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate, br, zstd
EOT;
$negotiation = Negotiation::fromString($str);
...
Parsing quality values
It is possible to parse quality values (q-values or q-factors) independently of the header context, making their use quite flexible:
$input = 'mesh/capsule;q=0.2,mesh/cube;q=0.9,mesh/cylinder;q=0.5,mesh/plane;q=0.4,mesh/quad;q=0.3,mesh/sphere;q=0.8';
$entries = Negotiation::qFactor($input, Negotiation::HIGH);
print_r($entries);
Output:
Array
(
[mesh/cube] => 0.9
[mesh/sphere] => 0.8
[mesh/cylinder] => 0.5
[mesh/plane] => 0.4
[mesh/quad] => 0.3
[mesh/capsule] => 0.2
)