$method)); return $method; } /** * Retrieves current user agent information * keys: browser, version, platform, mobile, robot * * @param string key * @return mixed NULL or the parsed value */ public static function user_agent($key = 'agent') { // Retrieve raw user agent without parsing if ($key === 'agent') { if (request::$user_agent === NULL) return request::$user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? trim($_SERVER['HTTP_USER_AGENT']) : ''; if (is_array(request::$user_agent)) return request::$user_agent['agent']; return request::$user_agent; } if ( ! is_array(request::$user_agent)) { request::$user_agent['agent'] = isset($_SERVER['HTTP_USER_AGENT']) ? trim($_SERVER['HTTP_USER_AGENT']) : ''; // Parse the user agent and extract basic information foreach (Kohana::config('user_agents') as $type => $data) { foreach ($data as $fragment => $name) { if (stripos(request::$user_agent['agent'], $fragment) !== FALSE) { if ($type === 'browser' AND preg_match('|'.preg_quote($fragment).'[^0-9.]*+([0-9.][0-9.a-z]*)|i', request::$user_agent['agent'], $match)) { // Set the browser version request::$user_agent['version'] = $match[1]; } // Set the agent name request::$user_agent[$type] = $name; break; } } } } return isset(request::$user_agent[$key]) ? request::$user_agent[$key] : NULL; } /** * Returns boolean of whether client accepts content type. * * @param string content type * @param boolean set to TRUE to disable wildcard checking * @return boolean */ public static function accepts($type = NULL, $explicit_check = FALSE) { request::parse_accept_content_header(); if ($type === NULL) return request::$accept_types; return (request::accepts_at_quality($type, $explicit_check) > 0); } /** * Returns boolean indicating if the client accepts a charset * * @param string * @return boolean */ public static function accepts_charset($charset = NULL) { request::parse_accept_charset_header(); if ($charset === NULL) return request::$accept_charsets; return (request::accepts_charset_at_quality($charset) > 0); } /** * Returns boolean indicating if the client accepts an encoding * * @param string * @param boolean set to TRUE to disable wildcard checking * @return boolean */ public static function accepts_encoding($encoding = NULL, $explicit_check = FALSE) { request::parse_accept_encoding_header(); if ($encoding === NULL) return request::$accept_encodings; return (request::accepts_encoding_at_quality($encoding, $explicit_check) > 0); } /** * Returns boolean indicating if the client accepts a language tag * * @param string language tag * @param boolean set to TRUE to disable prefix and wildcard checking * @return boolean */ public static function accepts_language($tag = NULL, $explicit_check = FALSE) { request::parse_accept_language_header(); if ($tag === NULL) return request::$accept_languages; return (request::accepts_language_at_quality($tag, $explicit_check) > 0); } /** * Compare the q values for given array of content types and return the one with the highest value. * If items are found to have the same q value, the first one encountered in the given array wins. * If all items in the given array have a q value of 0, FALSE is returned. * * @param array content types * @param boolean set to TRUE to disable wildcard checking * @return mixed string mime type with highest q value, FALSE if none of the given types are accepted */ public static function preferred_accept($types, $explicit_check = FALSE) { $max_q = 0; $preferred = FALSE; foreach ($types as $type) { $q = request::accepts_at_quality($type, $explicit_check); if ($q > $max_q) { $max_q = $q; $preferred = $type; } } return $preferred; } /** * Compare the q values for a given array of character sets and return the * one with the highest value. If items are found to have the same q value, * the first one encountered takes precedence. If all items in the given * array have a q value of 0, FALSE is returned. * * @param array character sets * @return mixed */ public static function preferred_charset($charsets) { $max_q = 0; $preferred = FALSE; foreach ($charsets as $charset) { $q = request::accepts_charset_at_quality($charset); if ($q > $max_q) { $max_q = $q; $preferred = $charset; } } return $preferred; } /** * Compare the q values for a given array of encodings and return the one with * the highest value. If items are found to have the same q value, the first * one encountered takes precedence. If all items in the given array have * a q value of 0, FALSE is returned. * * @param array encodings * @param boolean set to TRUE to disable wildcard checking * @return mixed */ public static function preferred_encoding($encodings, $explicit_check = FALSE) { $max_q = 0; $preferred = FALSE; foreach ($encodings as $encoding) { $q = request::accepts_encoding_at_quality($encoding, $explicit_check); if ($q > $max_q) { $max_q = $q; $preferred = $encoding; } } return $preferred; } /** * Compare the q values for a given array of language tags and return the * one with the highest value. If items are found to have the same q value, * the first one encountered takes precedence. If all items in the given * array have a q value of 0, FALSE is returned. * * @param array language tags * @param boolean set to TRUE to disable prefix and wildcard checking * @return mixed */ public static function preferred_language($tags, $explicit_check = FALSE) { $max_q = 0; $preferred = FALSE; foreach ($tags as $tag) { $q = request::accepts_language_at_quality($tag, $explicit_check); if ($q > $max_q) { $max_q = $q; $preferred = $tag; } } return $preferred; } /** * Returns quality factor at which the client accepts content type * * @param string content type (e.g. "image/jpg", "jpg") * @param boolean set to TRUE to disable wildcard checking * @return integer|float */ public static function accepts_at_quality($type, $explicit_check = FALSE) { request::parse_accept_content_header(); // Normalize type $type = strtolower($type); // General content type (e.g. "jpg") if (strpos($type, '/') === FALSE) { // Don't accept anything by default $q = 0; // Look up relevant mime types foreach ((array) Kohana::config('mimes.'.$type) as $type) { $q2 = request::accepts_at_quality($type, $explicit_check); $q = ($q2 > $q) ? $q2 : $q; } return $q; } // Content type with subtype given (e.g. "image/jpg") $type = explode('/', $type, 2); // Exact match if (isset(request::$accept_types[$type[0]][$type[1]])) return request::$accept_types[$type[0]][$type[1]]; if ($explicit_check === FALSE) { // Wildcard match if (isset(request::$accept_types[$type[0]]['*'])) return request::$accept_types[$type[0]]['*']; // Catch-all wildcard match if (isset(request::$accept_types['*']['*'])) return request::$accept_types['*']['*']; } // Content type not accepted return 0; } /** * Returns quality factor at which the client accepts a charset * * @param string charset (e.g., "ISO-8859-1", "utf-8") * @return integer|float */ public static function accepts_charset_at_quality($charset) { request::parse_accept_charset_header(); // Normalize charset $charset = strtolower($charset); // Exact match if (isset(request::$accept_charsets[$charset])) return request::$accept_charsets[$charset]; if (isset(request::$accept_charsets['*'])) return request::$accept_charsets['*']; if ($charset === 'iso-8859-1') return 1; return 0; } /** * Returns quality factor at which the client accepts an encoding * * @param string encoding (e.g., "gzip", "deflate") * @param boolean set to TRUE to disable wildcard checking * @return integer|float */ public static function accepts_encoding_at_quality($encoding, $explicit_check = FALSE) { request::parse_accept_encoding_header(); // Normalize encoding $encoding = strtolower($encoding); // Exact match if (isset(request::$accept_encodings[$encoding])) return request::$accept_encodings[$encoding]; if ($explicit_check === FALSE) { if (isset(request::$accept_encodings['*'])) return request::$accept_encodings['*']; if ($encoding === 'identity') return 1; } return 0; } /** * Returns quality factor at which the client accepts a language * * @param string tag (e.g., "en", "en-us", "fr-ca") * @param boolean set to TRUE to disable prefix and wildcard checking * @return integer|float */ public static function accepts_language_at_quality($tag, $explicit_check = FALSE) { request::parse_accept_language_header(); $tag = explode('-', strtolower($tag), 2); if (isset(request::$accept_languages[$tag[0]])) { if (isset($tag[1])) { // Exact match if (isset(request::$accept_languages[$tag[0]][$tag[1]])) return request::$accept_languages[$tag[0]][$tag[1]]; // A prefix matches if ($explicit_check === FALSE AND isset(request::$accept_languages[$tag[0]]['*'])) return request::$accept_languages[$tag[0]]['*']; } else { // No subtags if (isset(request::$accept_languages[$tag[0]]['*'])) return request::$accept_languages[$tag[0]]['*']; } } if ($explicit_check === FALSE AND isset(request::$accept_languages['*'])) return request::$accept_languages['*']; return 0; } /** * Parses a HTTP Accept or Accept-* header for q values * * @param string header data * @return array */ protected static function parse_accept_header($header) { $result = array(); // Remove linebreaks and parse the HTTP Accept header foreach (explode(',', str_replace(array("\r", "\n"), '', strtolower($header))) as $entry) { // Explode each entry in content type and possible quality factor $entry = explode(';', trim($entry), 2); $q = (isset($entry[1]) AND preg_match('~\bq\s*+=\s*+([.0-9]+)~', $entry[1], $match)) ? (float) $match[1] : 1; // Overwrite entries with a smaller q value if ( ! isset($result[$entry[0]]) OR $q > $result[$entry[0]]) { $result[$entry[0]] = $q; } } return $result; } /** * Parses a client's HTTP Accept-Charset header */ protected static function parse_accept_charset_header() { // Run this function just once if (request::$accept_charsets !== NULL) return; // No HTTP Accept-Charset header found if (empty($_SERVER['HTTP_ACCEPT_CHARSET'])) { // Accept everything request::$accept_charsets['*'] = 1; } else { request::$accept_charsets = request::parse_accept_header($_SERVER['HTTP_ACCEPT_CHARSET']); } } /** * Parses a client's HTTP Accept header */ protected static function parse_accept_content_header() { // Run this function just once if (request::$accept_types !== NULL) return; // No HTTP Accept header found if (empty($_SERVER['HTTP_ACCEPT'])) { // Accept everything request::$accept_types['*']['*'] = 1; } else { request::$accept_types = array(); foreach (request::parse_accept_header($_SERVER['HTTP_ACCEPT']) as $type => $q) { // Explode each content type (e.g. "text/html") $type = explode('/', $type, 2); // Skip invalid content types if ( ! isset($type[1])) continue; request::$accept_types[$type[0]][$type[1]] = $q; } } } /** * Parses a client's HTTP Accept-Encoding header */ protected static function parse_accept_encoding_header() { // Run this function just once if (request::$accept_encodings !== NULL) return; // No HTTP Accept-Encoding header found if ( ! isset($_SERVER['HTTP_ACCEPT_ENCODING'])) { // Accept everything request::$accept_encodings['*'] = 1; } elseif ($_SERVER['HTTP_ACCEPT_ENCODING'] === '') { // Accept only identity request::$accept_encodings['identity'] = 1; } else { request::$accept_encodings = request::parse_accept_header($_SERVER['HTTP_ACCEPT_ENCODING']); } } /** * Parses a client's HTTP Accept-Language header */ protected static function parse_accept_language_header() { // Run this function just once if (request::$accept_languages !== NULL) return; // No HTTP Accept-Language header found if (empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { // Accept everything request::$accept_languages['*'] = 1; } else { request::$accept_languages = array(); foreach (request::parse_accept_header($_SERVER['HTTP_ACCEPT_LANGUAGE']) as $tag => $q) { // Explode each language (e.g. "en-us") $tag = explode('-', $tag, 2); request::$accept_languages[$tag[0]][isset($tag[1]) ? $tag[1] : '*'] = $q; } } } } // End request