summaryrefslogtreecommitdiff
path: root/src/ext/HTTP_Accept.class.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/HTTP_Accept.class.php')
-rw-r--r--src/ext/HTTP_Accept.class.php659
1 files changed, 0 insertions, 659 deletions
diff --git a/src/ext/HTTP_Accept.class.php b/src/ext/HTTP_Accept.class.php
deleted file mode 100644
index 5efaa5d..0000000
--- a/src/ext/HTTP_Accept.class.php
+++ /dev/null
@@ -1,659 +0,0 @@
-<?php
-
-/**
- * HTTP_Accept class for dealing with the HTTP 'Accept' header
- *
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to the MIT License.
- * The full text of this license is available at the following URL:
- * http://www.opensource.org/licenses/mit-license.php
- *
- * @category HTTP
- * @package HTTP_Accept
- * @author Kevin Locke <kwl7@cornell.edu>
- * @copyright 2007 Kevin Locke
- * @license http://www.opensource.org/licenses/mit-license.php MIT License
- * @version SVN: $Id: HTTP_Accept.php 22 2007-10-06 18:46:45Z kevin $
- * @link http://pear.php.net/package/HTTP_Accept
- */
-
-/**
- * HTTP_Accept class for dealing with the HTTP 'Accept' header
- *
- * This class is intended to be used to parse the HTTP Accept header into
- * usable information and provide a simple API for dealing with that
- * information.
- *
- * The parsing of this class is designed to follow RFC 2616 to the letter,
- * any deviations from that standard are bugs and should be reported to the
- * maintainer.
- *
- * Often the class will be used very simply as
- * <code>
- * <?php
- * $accept = new HTTP_Accept($_SERVER['HTTP_ACCEPT']);
- * if ($accept->getQuality("image/png") > $accept->getQuality("image/jpeg"))
- * // Send PNG image
- * else
- * // Send JPEG image
- * ?>
- * </code>
- *
- * However, for browsers which do not accurately describe their preferences,
- * it may be necessary to check if a MIME Type is explicitly listed in their
- * Accept header, in addition to being preferred to another type
- *
- * <code>
- * <?php
- * if ($accept->isMatchExact("application/xhtml+xml"))
- * // Client specifically asked for this type at some quality level
- * ?>
- * </code>
- *
- *
- * @category HTTP
- * @package HTTP_Accept
- * @access public
- * @link http://pear.php.net/package/HTTP_Accept
- */
-class HTTP_Accept
-{
- /**
- * Array of types and their associated parameters, extensions, and quality
- * factors, as represented in the Accept: header.
- * Indexed by [type][subtype][index],
- * and contains 'PARAMS', 'QUALITY', and 'EXTENSIONS' keys for the
- * parameter set, quality factor, and extensions set respectively.
- * Note: Since type, subtype, and parameters are case-insensitive
- * (RFC 2045 5.1) they are stored as lower-case.
- *
- * @var array
- * @access private
- */
- var $acceptedtypes = array();
-
- /**
- * Regular expression to match a token, as defined in RFC 2045
- *
- * @var string
- * @access private
- */
- var $_matchtoken = '(?:[^[:cntrl:]()<>@,;:\\\\"\/\[\]?={} \t]+)';
-
- /**
- * Regular expression to match a quoted string, as defined in RFC 2045
- *
- * @var string
- * @access private
- */
- var $_matchqstring = '(?:"[^\\\\"]*(?:\\\\.[^\\\\"]*)*")';
-
- /**
- * Constructs a new HTTP_Accept object
- *
- * Initializes the HTTP_Accept class with a given accept string
- * or creates a new (empty) HTTP_Accept object if no string is given
- *
- * Note: The behavior is a little strange here to accomodate
- * missing headers (to be interpreted as accept all) as well as
- * new empty objects which should accept nothing. This means that
- * HTTP_Accept("") will be different than HTTP_Accept()
- *
- * @access public
- * @return object HTTP_Accept
- * @param string $acceptstring The value of an Accept: header
- * Will often be $_SERVER['HTTP_ACCEPT']
- * Note: If get_magic_quotes_gpc is on,
- * run stripslashes() on the string first
- */
- function HTTP_Accept()
- {
- if (func_num_args() == 0) {
- // User wishes to create empty HTTP_Accept object
- $this->acceptedtypes = array(
- '*' => array(
- '*' => array (
- 0 => array(
- 'PARAMS' => array(),
- 'QUALITY' => 0,
- 'EXTENSIONS' => array()
- )
- )
- )
- );
- return;
- }
-
- $acceptstring = trim(func_get_arg(0));
- if (empty($acceptstring)) {
- // Accept header empty or not sent, interpret as "*/*"
- $this->acceptedtypes = array(
- '*' => array(
- '*' => array (
- 0 => array(
- 'PARAMS' => array(),
- 'QUALITY' => 1,
- 'EXTENSIONS' => array()
- )
- )
- )
- );
- return;
- }
-
- $matches = preg_match_all(
- '/\s*('.$this->_matchtoken.')\/' . // typegroup/
- '('.$this->_matchtoken.')' . // subtype
- '((?:\s*;\s*'.$this->_matchtoken.'\s*' . // parameter
- '(?:=\s*' . // optional =value
- '(?:'.$this->_matchqstring.'|'.$this->_matchtoken.'))?)*)/', // value
- $acceptstring, $acceptedtypes,
- PREG_SET_ORDER);
-
- if ($matches == 0) {
- // Malformed Accept header
- $this->acceptedtypes = array(
- '*' => array(
- '*' => array (
- 0 => array(
- 'PARAMS' => array(),
- 'QUALITY' => 1,
- 'EXTENSIONS' => array()
- )
- )
- )
- );
- return;
- }
-
- foreach ($acceptedtypes as $accepted) {
- $typefamily = strtolower($accepted[1]);
- $subtype = strtolower($accepted[2]);
-
- // */subtype is invalid according to grammar in section 14.1
- // so we ignore it
- if ($typefamily == '*' && $subtype != '*')
- continue;
-
- // Parse all arguments of the form "key=value"
- $matches = preg_match_all('/;\s*('.$this->_matchtoken.')\s*' .
- '(?:=\s*' .
- '('.$this->_matchqstring.'|'.
- $this->_matchtoken.'))?/',
- $accepted[3], $args,
- PREG_SET_ORDER);
-
- $params = array();
- $quality = -1;
- $extensions = array();
- foreach ($args as $arg) {
- array_shift($arg);
- if (!empty($arg[1])) {
- // Strip quotes (Note: Can't use trim() in case "text\"")
- $len = strlen($arg[1]);
- if ($arg[1][0] == '"' && $arg[1][$len-1] == '"'
- && $len > 1) {
- $arg[1] = substr($arg[1], 1, $len-2);
- $arg[1] = stripslashes($arg[1]);
- }
- } else if (!isset($arg[1])) {
- $arg[1] = null;
- }
-
- // Everything before q=# is a parameter, after is an extension
- if ($quality >= 0) {
- $extensions[$arg[0]] = $arg[1];
- } else if ($arg[0] == 'q') {
- $quality = (float)$arg[1];
-
- if ($quality < 0)
- $quality = 0;
- else if ($quality > 1)
- $quality = 1;
- } else {
- $arg[0] = strtolower($arg[0]);
- // Values required for parameters,
- // assume empty-string for missing values
- if (isset($arg[1]))
- $params[$arg[0]] = $arg[1];
- else
- $params[$arg[0]] = "";
- }
- }
-
- if ($quality < 0)
- $quality = 1;
- else if ($quality == 0)
- continue;
-
- if (!isset($this->acceptedtypes[$typefamily]))
- $this->acceptedtypes[$typefamily] = array();
- if (!isset($this->acceptedtypes[$typefamily][$subtype]))
- $this->acceptedtypes[$typefamily][$subtype] = array();
-
- $this->acceptedtypes[$typefamily][$subtype][] =
- array('PARAMS' => $params,
- 'QUALITY' => $quality,
- 'EXTENSIONS' => $extensions);
- }
-
- if (!isset($this->acceptedtypes['*']))
- $this->acceptedtypes['*'] = array();
- if (!isset($this->acceptedtypes['*']['*']))
- $this->acceptedtypes['*']['*'] = array(
- 0 => array(
- 'PARAMS' => array(),
- 'QUALITY' => 0,
- 'EXTENSIONS' => array()
- )
- );
- }
-
- /**
- * Gets the accepted quality factor for a given MIME Type
- *
- * Note: If there are multiple best matches
- * (e.g. "text/html;level=4;charset=utf-8" matching both "text/html;level=4"
- * and "text/html;charset=utf-8"), it returns the lowest quality factor as
- * a conservative estimate. Further, if the ambiguity is between parameters
- * and extensions (e.g. "text/html;level=4;q=1;ext=foo" matching both
- * "text/html;level=4" and "text/html;q=1;ext=foo") the parameters take
- * precidence.
- *
- * Usage Note: If the quality factor for all supported media types is 0,
- * RFC 2616 specifies that applications SHOULD send an HTTP 406 (not
- * acceptable) response.
- *
- * @access public
- * @return double the quality value for the given MIME Type
- * Quality values are in the range [0,1] where 0 means
- * "not accepted" and 1 is "perfect quality".
- * @param string $mimetype The MIME Type to query ("text/html")
- * @param array $params Parameters of Type to query ([level => 4])
- * @param array $extensions Extension parameters to query
- */
- function getQuality($mimetype, $params = array(), $extensions = array())
- {
- $type = explode("/", $mimetype);
- $supertype = strtolower($type[0]);
- $subtype = strtolower($type[1]);
-
- if ($params == null)
- $params = array();
- if ($extensions == null)
- $extensions = array();
-
- if (empty($this->acceptedtypes[$supertype])) {
- if ($supertype == '*')
- return 0;
- else
- return $this->getQuality("*/*", $params, $extensions);
- }
-
- if (empty($this->acceptedtypes[$supertype][$subtype])) {
- if ($subtype == '*')
- return $this->getQuality("*/*", $params, $extensions);
- else
- return $this->getQuality("$supertype/*", $params, $extensions);
- }
-
- $params = array_change_key_case($params, CASE_LOWER);
-
- $matches = $this->_findBestMatchIndices($supertype, $subtype,
- $params, $extensions);
-
- if (count($matches) == 0) {
- if ($subtype != '*')
- return $this->getQuality("$supertype/*", $params, $extensions);
- else if ($supertype != '*')
- return $this->getQuality("*/*", $params, $extensions);
- else
- return 0;
- }
-
- $minquality = 1;
- foreach ($matches as $match)
- if ($this->acceptedtypes[$supertype][$subtype][$match]['QUALITY'] < $minquality)
- $minquality = $this->acceptedtypes[$supertype][$subtype][$match]['QUALITY'];
-
- return $minquality;
- }
-
- /**
- * Determines if there is an exact match for the specified MIME Type
- *
- * @access public
- * @return boolean true if there is an exact match to the given
- * values, false otherwise.
- * @param string $mimetype The MIME Type to query (e.g. "text/html")
- * @param array $params Parameters of Type to query (e.g. [level => 4])
- * @param array $extensions Extension parameters to query
- */
- function isMatchExact($mimetype, $params = array(), $extensions = array())
- {
- $type = explode("/", $mimetype);
- $supertype = strtolower($type[0]);
- $subtype = strtolower($type[1]);
-
- if ($params == null)
- $params = array();
- if ($extensions == null)
- $extensions = array();
-
- return $this->_findExactMatchIndex($supertype, $subtype,
- $params, $extensions) >= 0;
- }
-
- /**
- * Gets a list of all MIME Types explicitly accepted, sorted by quality
- *
- * @access public
- * @return array list of MIME Types explicitly accepted, sorted
- * in decreasing order of quality factor
- */
- function getTypes()
- {
- $qvalues = array();
- $types = array();
- foreach ($this->acceptedtypes as $typefamily => $subtypes) {
- if ($typefamily == '*')
- continue;
-
- foreach ($subtypes as $subtype => $variants) {
- if ($subtype == '*')
- continue;
-
- $maxquality = 0;
- foreach ($variants as $variant)
- if ($variant['QUALITY'] > $maxquality)
- $maxquality = $variant['QUALITY'];
-
- if ($maxquality > 0) {
- $qvalues[] = $maxquality;
- $types[] = $typefamily.'/'.$subtype;
- }
- }
- }
-
- array_multisort($qvalues, SORT_DESC, SORT_NUMERIC,
- $types, SORT_DESC, SORT_STRING);
-
- return $types;
- }
-
- /**
- * Gets the parameter sets for a given mime type, sorted by quality.
- * Only parameter sets where the extensions set is empty will be returned.
- *
- * @access public
- * @return array list of sets of name=>value parameter pairs
- * in decreasing order of quality factor
- * @param string $mimetype The MIME Type to query ("text/html")
- */
- function getParameterSets($mimetype)
- {
- $type = explode("/", $mimetype);
- $supertype = strtolower($type[0]);
- $subtype = strtolower($type[1]);
-
- if (!isset($this->acceptedtypes[$supertype])
- || !isset($this->acceptedtypes[$supertype][$subtype]))
- return array();
-
- $qvalues = array();
- $paramsets = array();
- foreach ($this->acceptedtypes[$supertype][$subtype] as $acceptedtype) {
- if (count($acceptedtype['EXTENSIONS']) == 0) {
- $qvalues[] = $acceptedtype['QUALITY'];
- $paramsets[] = $acceptedtype['PARAMS'];
- }
- }
-
- array_multisort($qvalues, SORT_DESC, SORT_NUMERIC,
- $paramsets, SORT_DESC, SORT_STRING);
-
- return $paramsets;
- }
-
- /**
- * Gets the extension sets for a given mime type, sorted by quality.
- * Only extension sets where the parameter set is empty will be returned.
- *
- * @access public
- * @return array list of sets of name=>value extension pairs
- * in decreasing order of quality factor
- * @param string $mimetype The MIME Type to query ("text/html")
- */
- function getExtensionSets($mimetype)
- {
- $type = explode("/", $mimetype);
- $supertype = strtolower($type[0]);
- $subtype = strtolower($type[1]);
-
- if (!isset($this->acceptedtypes[$supertype])
- || !isset($this->acceptedtypes[$supertype][$subtype]))
- return array();
-
- $qvalues = array();
- $extensionsets = array();
- foreach ($this->acceptedtypes[$supertype][$subtype] as $acceptedtype) {
- if (count($acceptedtype['PARAMS']) == 0) {
- $qvalues[] = $acceptedtype['QUALITY'];
- $extensionsets[] = $acceptedtype['EXTENSIONS'];
- }
- }
-
- array_multisort($qvalues, SORT_DESC, SORT_NUMERIC,
- $extensionsets, SORT_DESC, SORT_STRING);
-
- return $extensionsets;
- }
-
- /**
- * Adds a type to the set of accepted types
- *
- * @access public
- * @param string $mimetype The MIME Type to add (e.g. "text/html")
- * @param double $quality The quality value for the given MIME Type
- * Quality values are in the range [0,1] where
- * 0 means "not accepted" and 1 is
- * "perfect quality".
- * @param array $params Parameters of the type to add (e.g. [level => 4])
- * @param array $extensions Extension parameters of the type to add
- */
- function addType($mimetype, $quality = 1,
- $params = array(), $extensions = array())
- {
- $type = explode("/", $mimetype);
- $supertype = strtolower($type[0]);
- $subtype = strtolower($type[1]);
-
- if ($params == null)
- $params = array();
- if ($extensions == null)
- $extensions = array();
-
- $index = $this->_findExactMatchIndex($supertype, $subtype, $params, $extensions);
-
- if ($index >= 0) {
- $this->acceptedtypes[$supertype][$subtype][$index]['QUALITY'] = $quality;
- } else {
- if (!isset($this->acceptedtypes[$supertype]))
- $this->acceptedtypes[$supertype] = array();
- if (!isset($this->acceptedtypes[$supertype][$subtype]))
- $this->acceptedtypes[$supertype][$subtype] = array();
-
- $this->acceptedtypes[$supertype][$subtype][] =
- array('PARAMS' => $params,
- 'QUALITY' => $quality,
- 'EXTENSIONS' => $extensions);
- }
- }
-
- /**
- * Removes a type from the set of accepted types
- *
- * @access public
- * @param string $mimetype The MIME Type to remove (e.g. "text/html")
- * @param array $params Parameters of the type to remove (e.g. [level => 4])
- * @param array $extensions Extension parameters of the type to remove
- */
- function removeType($mimetype, $params = array(), $extensions = array())
- {
- $type = explode("/", $mimetype);
- $supertype = strtolower($type[0]);
- $subtype = strtolower($type[1]);
-
- if ($params == null)
- $params = array();
- if ($extensions == null)
- $extensions = array();
-
- $index = $this->_findExactMatchIndex($supertype, $subtype, $params, $extensions);
-
- if ($index >= 0) {
- $this->acceptedtypes[$supertype][$subtype] =
- array_merge(array_slice($this->acceptedtypes[$supertype][$subtype],
- 0, $index),
- array_slice($this->acceptedtypes[$supertype][$subtype],
- $index+1));
- }
- }
-
- /**
- * Gets a string representation suitable for use in an HTTP Accept header
- *
- * @access public
- * @return string a string representation of this object
- */
- function __toString()
- {
- $accepted = array();
- $qvalues = array();
- foreach ($this->acceptedtypes as $supertype => $subtypes) {
- foreach ($subtypes as $subtype => $entries) {
- foreach ($entries as $entry) {
- $accepted[] = array('TYPE' => "$supertype/$subtype",
- 'QUALITY' => $entry['QUALITY'],
- 'PARAMS' => $entry['PARAMS'],
- 'EXTENSIONS' => $entry['EXTENSIONS']);
- $qvalues[] = $entry['QUALITY'];
- }
- }
- }
-
- array_multisort($qvalues, SORT_DESC, SORT_NUMERIC,
- $accepted);
-
- $str = "";
- foreach ($accepted as $accept) {
- // Skip the catchall value if it is 0, since this is implied
- if ($accept['TYPE'] == '*/*' &&
- $accept['QUALITY'] == 0 &&
- count($accept['PARAMS']) == 0 &&
- count($accept['EXTENSIONS'] == 0))
- continue;
-
- $str = $str.$accept['TYPE'].';';
-
- foreach ($accept['PARAMS'] as $param => $value) {
- if (preg_match('/^'.$this->_matchtoken.'$/', $value))
- $str = $str.$param.'='.$value.';';
- else
- $str = $str.$param.'="'.addcslashes($value,'"\\').'";';
- }
-
- if ($accept['QUALITY'] < 1 || !empty($accept['EXTENSIONS']))
- $str = $str.'q='.$accept['QUALITY'].';';
-
- foreach ($accept['EXTENSIONS'] as $extension => $value) {
- if (preg_match('/^'.$this->_matchtoken.'$/', $value))
- $str = $str.$extension.'='.$value.';';
- else
- $str = $str.$extension.'="'.addcslashes($value,'"\\').'";';
- }
-
- $str[strlen($str)-1] = ',';
- }
-
- return rtrim($str, ',');
- }
-
- /**
- * Finds the index of an exact match for the specified MIME Type
- *
- * @access private
- * @return int the index of an exact match if found,
- * -1 otherwise
- * @param string $supertype The general MIME Type to find (e.g. "text")
- * @param string $subtype The MIME subtype to find (e.g. "html")
- * @param array $params Parameters of Type to find ([level => 4])
- * @param array $extensions Extension parameters to find
- */
- function _findExactMatchIndex($supertype, $subtype, $params, $extensions)
- {
- if (empty($this->acceptedtypes[$supertype])
- || empty($this->acceptedtypes[$supertype][$subtype]))
- return -1;
-
- $params = array_change_key_case($params, CASE_LOWER);
-
- $parammatches = array();
- foreach ($this->acceptedtypes[$supertype][$subtype] as $index => $typematch)
- if ($typematch['PARAMS'] == $params
- && $typematch['EXTENSIONS'] == $extensions)
- return $index;
-
- return -1;
- }
-
- /**
- * Finds the indices of the best matches for the specified MIME Type
- *
- * A "match" in this context is an exact type match and no extraneous
- * matches for parameters or extensions (so the best match for
- * "text/html;level=4" may be "text/html" but not the other way around).
- *
- * "Best" is interpreted as the entries that match the most
- * parameters and extensions (the sum of the number of matches)
- *
- * @access private
- * @return array an array of the indices of the best matches
- * (empty if no matches)
- * @param string $supertype The general MIME Type to find (e.g. "text")
- * @param string $subtype The MIME subtype to find (e.g. "html")
- * @param array $params Parameters of Type to find ([level => 4])
- * @param array $extensions Extension parameters to find
- */
- function _findBestMatchIndices($supertype, $subtype, $params, $extensions)
- {
- $bestmatches = array();
- $bestlength = 0;
-
- if (empty($this->acceptedtypes[$supertype])
- || empty($this->acceptedtypes[$supertype][$subtype]))
- return $bestmatches;
-
- foreach ($this->acceptedtypes[$supertype][$subtype] as $index => $typematch) {
- if (count(array_diff_assoc($typematch['PARAMS'], $params)) == 0
- && count(array_diff_assoc($typematch['EXTENSIONS'],
- $extensions)) == 0) {
- $length = count($typematch['PARAMS'])
- + count($typematch['EXTENSIONS']);
-
- if ($length > $bestlength) {
- $bestmatches = array($index);
- $bestlength = $length;
- } else if ($length == $bestlength) {
- $bestmatches[] = $index;
- }
- }
- }
-
- return $bestmatches;
- }
-}
-
-// vim: set ts=4 sts=4 sw=4 et:
-?>