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 )
Go to homepage
Star us on Github