PHP Content Negotiation

Table of Contents:

About this Source:

Purpose:

The library described in this document was developed with the goal of facilitating the development of 'smart' web applications that take advantage of the information most user agents provide with each HTTP request to serve the most appropriate resource to the user agent (language, compression, character-set and mime-type).

Current Release:

The version number of the current release is 1.2.0, this code is mature and there are no known issues.

Licence:

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

Function Prototypes:

The content_negotiation class contains a set of 8 public functions. Two each for the four header fields it can parse (Accept, Accept-Charset, Accept-Encoding & Accept-Language); One that returns the preferred type for it and another that returns the array with the q_value elements completed.

string content_negotiation::mime_best_negotiation ( array $content_match )

Given an array of types and application preferences in the format specified below, the function will return the preferred type based upon the q value sent by the user agent and the application preference value specified in the array. If no parameter is passed then it will simply parse the types specified by the Accept header and return the preferred type. (note: if there is more than one type sharing the highest q value then only one type is arbitrarily returned)

Returns a string that contains the mime-type preferred by the user-agent (& when looking for specific types the application's preference).

array content_negotiation::mime_all_negotiation ( array $content_match )

Given an array of types and application preferences in the format specified below, the function will return an array of types, in descending order, based upon the q value sent by the user agent and the application preference value specified in the array. If no parameter is passed then it will simply parse the types specified by the Accept header and return the preferred type.

Returns an array of mime-types preferred, in descending order, by the user-agent (& when looking for specific types the application's preference).

string content_negotiation::charset_best_negotiation ( array $content_match )

Given an array of character sets and application preferences in the format specified below, the function will return an the preferred character set based upon the q value sent by the user agent and the application preference value specified in the array. If no parameter is passed then it will simply parse the character sets specified by the Accept-Charset header and return the preferred character set. (note: if there is more than one character set sharing the highest q value then only one character set is arbitrarily returned)

Returns a string that contains the character set preferred by the user-agent (& when looking for specific character sets the application's preference).

array content_negotiation::charset_all_negotiation ( array $content_match )

Given an array of character sets and application preferences in the format specified below, the function will return an array of character sets, in descending order, based upon the q value sent by the user agent and the application preference value specified in the array. If no parameter is passed then it will simply parse the character sets specified by the Accept-Charset header and return the preferred character set.

Returns a array that contains the character sets preferred, in descending order, by the user-agent (& when looking for specific character sets the application's preference).

string content_negotiation::encoding_best_negotiation ( array $content_match )

Given an array of encodings and application preferences in the format specified below, the function will return an the preferred encoding based upon the q value sent by the user agent and the application preference value specified in the array. If no parameter is passed then it will simply parse the encodings specified by the Accept-Encoding header and return the preferred encoding. (note: if there is more than one encoding sharing the highest q value then only one encoding is arbitrarily returned)

Returns a string that contains the encoding preferred by the user-agent (& when looking for specific encodings the application's preference).

array content_negotiation::encoding_all_negotiation ( array $content_match )

Given an array of encodings and application preferences in the format specified below, the function will return an array of encodings, in descending order, based upon the q value sent by the user agent and the application preference value specified in the array. If no parameter is passed then it will simply parse the encodings specified by the Accept-Encoding header and return the preferred encoding.

Returns a array that contains the encodings preferred, in descending order, by the user-agent (& when looking for specific encodings the application's preference).

string content_negotiation::language_best_negotiation ( array $content_match )

Given an array of languages and application preferences in the format specified below, the function will return an the preferred language based upon the q value sent by the user agent and the application preference value specified in the array. If no parameter is passed then it will simply parse the languages specified by the Accept-Language header and return the preferred language. (note: if there is more than one language sharing the highest q value then only one language is arbitrarily returned)

Returns a string that contains the language preferred by the user-agent (& when looking for specific languages the application's preference).

array content_negotiation::language_all_negotiation ( array $content_match )

Given an array of languages and application preferences in the format specified below, the function will return an array of languages, in descending order, based upon the q value sent by the user agent and the application preference value specified in the array. If no parameter is passed then it will simply parse the languages specified by the Accept-Encoding header and return the preferred language.

Returns a array that contains the languages preferred, in descending order, by the user-agent (& when looking for specific languages the application's preference).

string xhtml_html::xhtml_or_html ( void )

Returns either text/html or application/xhtml+xml depending upon which the user agent prefers and, in situations where both types have equal preference in the user agent, prefers text/html for compatibility reasons; a user agent too old to support XHTML should not have application/xthml+xml in it's Accept list and modern user agents that do include it should give it a suitably low q value in relation to text/html. (note: requires including the 'xhtml_html.inc.php' file)

Usage:

To use the base class in your applications you must fist include the content negotiation file. With that file included you may use the functionality provided in one of two ways; if you're only interested in certain types then construct a multi-dimensional associative array with the format that can be seen in the example below (which is tailored to be used to determine what charset to send) and pass it as a parameter to the appropriate function:

include 'content_negotiation.inc.php'; $charset_array = array('type' => array('UTF-8', 'iso-8859-1', 'UTF-16'), 'app_preference' => array(1, 0.9, 0.5));

The array in the 'type' element is an array of character sets that your application supports, and the 'app_preference' element is an array of preferences that your application has for that type; these values MUST be different from each other and range from 0-1 and are only used if the user-agent supports two types with equal preference and a choice must be made between the two.

The second method is to simply call the appropriate function with no parameters, this simply calculates what the user-agent prefers and orders the types by the elements q values.

In the above example, given the charset field 'Accept-Charset: iso-8859-1,*,utf-8' and the above applicaiton preferences, the best charset would evaluate to UTF-8. The application would then alter it's output as appropriate and send it's Content-Type field in the reply appropriately, as well as the Vary field to indicate to caching mechanisms that the page changes dependant on that field:

// First perform negotiation $charset_best = content_negotiation::charset_best_negotiation($charset_array); // Indicate that content negotiation took place for benefit of caching agents header('Vary: Accept-Charset'); // send the correct Content-Type in the header header('Content-Type: text/html; charset=' . $charset_best);

Download:

Version: Release Date: ptlis.net
1.2.0 (current, stable) 2007-12-25 zip (13KB)
1.1.0 2006-12-25 zip (14KB)
1.0.2 2006-02-07 zip (11KB)
1.0.1 2006-01-23 zip (11KB)
1.0.0 2006-01-19 zip (11KB)

Notes:

As the HTTP specification does not specify how invalid headers should be handled i've simply done what to me seems to be the most logical method of error handling; the media-range must be identical to the one in the application-propegated array, the accept-params value however has intentionally more leeway. For example "q=0.9c" will be taken as 0.9, because otherwise it's value would either have to be inflated to 1 or dropped down all the way to 0. Quality factor values containing non-numeric or malformed values (negative numbers, values greater than one, etc) are also evaluated to 1.

Changelog:

2006-01-19 - Version 1.0.0
     - Initial public release.

2006-01-23 - Version 1.0.1
     - Added strtolower into parsing so that comparisons of media-types can be
       done with the '===' php identical operator without worrying about case.

2006-02-07 - Version 1.0.2
     - Replaced the inner for loop and conditional with the use of the
       array_search function - my thanks go to NeoThermic for telling me about
       this function.

2006-12-25 - Version 1.1.0
     - Significant re-write to encapsulate functionality within a class.
     - There are now two versions, a version targetted at the PHP 4.x releases
       and a version targetted at the 5.x releases that takes advantage of the
       improved support for OOP techniques.
     - There is now a seperate include file that can be used to determine if a
       browser can handle XHTML, and if it can whether it has a preferance
       towards it or HTML.

2007-12-05 - Version 1.2.0
     - Support for php 4.x dropped being as the php developers will no longer
       be supporting php 4 as of the 31st December.
     - Support for wildcard rules implemented.
     - No longer requires a list of types to look for, if there is no parameter
       passed to the negotiation functions then they generate a list internally
       from the browser's headers.
     - Fixed the XHTML & HTML negotiation class so that it works as intended.