Source of file UserAgent.php
Size: 25,863 Bytes - Last Modified: 2021-12-23T10:46:40+00:00
/var/www/docs.ssmods.com/process/src/thirdparty/Zend/Http/UserAgent.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854 | <?php /** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@zend.com so we can send you a copy immediately. * * @category Zend * @package Zend_Http_UserAgent * @subpackage UserAgent * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ /** * Lists of User Agent chains for testing : * * - http://www.useragentstring.com/layout/useragentstring.php * - http://user-agent-string.info/list-of-ua * - http://www.user-agents.org/allagents.xml * - http://en.wikipedia.org/wiki/List_of_user_agents_for_mobile_phones * - http://www.mobilemultimedia.be/fr/ * * @category Zend * @package Zend_Http_UserAgent * @subpackage UserAgent * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Http_UserAgent implements Serializable { /** * 'desktop' by default if the sequence return false for each item or is empty */ const DEFAULT_IDENTIFICATION_SEQUENCE = 'mobile,desktop'; /** * Default persitent storage adapter : Session or NonPersitent */ const DEFAULT_PERSISTENT_STORAGE_ADAPTER = 'Session'; /** * 'desktop' by default if the sequence return false for each item */ const DEFAULT_BROWSER_TYPE = 'desktop'; /** * Default User Agent chain to prevent empty value */ const DEFAULT_HTTP_USER_AGENT = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'; /** * Default Http Accept param to prevent empty value */ const DEFAULT_HTTP_ACCEPT = "application/xhtml+xml"; /** * Default markup language */ const DEFAULT_MARKUP_LANGUAGE = "xhtml"; /** * Browser type * * @var string */ protected $_browserType; /** * Browser type class * * Map of browser types to classes. * * @var array */ protected $_browserTypeClass = array(); /** * Array to store config * * Default values are provided to ensure specific keys are present at * instantiation. * * @var array */ protected $_config = array( 'identification_sequence' => self::DEFAULT_IDENTIFICATION_SEQUENCE, 'storage' => array( 'adapter' => self::DEFAULT_PERSISTENT_STORAGE_ADAPTER, ), ); /** * Identified device * * @var Zend_Http_UserAgent_Device */ protected $_device; /** * Whether or not this instance is immutable. * * If true, none of the following may be modified: * - $_server * - $_browserType * - User-Agent (defined in $_server) * - HTTP Accept value (defined in $_server) * - $_storage * * @var bool */ protected $_immutable = false; /** * Plugin loaders * @var array */ protected $_loaders = array(); /** * Valid plugin loader types * @var array */ protected $_loaderTypes = array('storage', 'device'); /** * Trace of items matched to identify the browser type * * @var array */ protected $_matchLog = array(); /** * Server variable * * @var array */ protected $_server; /** * Persistent storage handler * * @var Zend_Http_UserAgent_Storage */ protected $_storage; /** * Constructor * * @param null|array|Zend_Config|ArrayAccess $options * @return void */ public function __construct($options = null) { if (null !== $options) { $this->setOptions($options); } } /** * Serialized representation of the object * * @return string */ public function serialize() { $device = $this->getDevice(); $spec = array( 'browser_type' => $this->_browserType, 'config' => $this->_config, 'device_class' => get_class($device), 'device' => $device->serialize(), 'user_agent' => $this->getServerValue('http_user_agent'), 'http_accept' => $this->getServerValue('http_accept'), ); return serialize($spec); } /** * Unserialize a previous representation of the object * * @param string $serialized * @return void */ public function unserialize($serialized) { $spec = unserialize($serialized); $this->setOptions($spec); // Determine device class and ensure the class is loaded $deviceClass = $spec['device_class']; if (!class_exists($deviceClass)) { $this->_getUserAgentDevice($this->getBrowserType()); } // Get device specification and instantiate $deviceSpec = unserialize($spec['device']); $deviceSpec['_config'] = $this->getConfig(); $deviceSpec['_server'] = $this->getServer(); $this->_device = new $deviceClass($deviceSpec); } /** * Configure instance * * @param array|Zend_Config|ArrayAccess $options * @return Zend_Http_UserAgent */ public function setOptions($options) { if ($options instanceof Zend_Config) { $options = $options->toArray(); } if (!is_array($options) && !$options instanceof ArrayAccess && !$options instanceof Traversable ) { require_once 'Zend/Http/UserAgent/Exception.php'; throw new Zend_Http_UserAgent_Exception(sprintf( 'Invalid argument; expected array, Zend_Config object, or object implementing ArrayAccess and Traversable; received %s', (is_object($options) ? get_class($options) : gettype($options)) )); } // Set $_SERVER first if (isset($options['server'])) { $this->setServer($options['server']); unset($options['server']); } // Get plugin loaders sorted if (isset($options['plugin_loader'])) { $plConfig = $options['plugin_loader']; if (is_array($plConfig) || $plConfig instanceof Traversable) { foreach ($plConfig as $type => $class) { $this->setPluginLoader($type, $class); } } unset($plConfig, $options['plugin_loader']); } // And then loop through the remaining options $config = array(); foreach ($options as $key => $value) { switch (strtolower($key)) { case 'browser_type': $this->setBrowserType($value); break; case 'http_accept': $this->setHttpAccept($value); break; case 'user_agent': $this->setUserAgent($value); break; default: // Cache remaining options for $_config $config[$key] = $value; break; } } $this->setConfig($config); return $this; } /** * Comparison of the UserAgent chain and browser signatures. * * The comparison is case-insensitive : the browser signatures must be in lower * case * * @param string $deviceClass Name of class against which a match will be attempted * @return bool */ protected function _match($deviceClass) { // Validate device class $r = new ReflectionClass($deviceClass); if (!$r->implementsInterface('Zend_Http_UserAgent_Device')) { throw new Zend_Http_UserAgent_Exception(sprintf( 'Invalid device class provided ("%s"); must implement Zend_Http_UserAgent_Device', $deviceClass )); } $userAgent = $this->getUserAgent(); // Call match method on device class return call_user_func( array($deviceClass, 'match'), $userAgent, $this->getServer() ); } /** * Loads class for a user agent device * * @param string $browserType Browser type * @return string * @throws Zend_Loader_PluginLoader_Exception if unable to load UA device */ protected function _getUserAgentDevice($browserType) { $browserType = strtolower($browserType); if (isset($this->_browserTypeClass[$browserType])) { return $this->_browserTypeClass[$browserType]; } if (isset($this->_config[$browserType]) && isset($this->_config[$browserType]['device']) ) { $deviceConfig = $this->_config[$browserType]['device']; if (is_array($deviceConfig) && isset($deviceConfig['classname'])) { $device = (string) $deviceConfig['classname']; if (!class_exists($device)) { require_once 'Zend/Http/UserAgent/Exception.php'; throw new Zend_Http_UserAgent_Exception(sprintf( 'Invalid classname "%s" provided in device configuration for browser type "%s"', $device, $browserType )); } } elseif (is_array($deviceConfig) && isset($deviceConfig['path'])) { $loader = $this->getPluginLoader('device'); $path = $deviceConfig['path']; $prefix = isset($deviceConfig['prefix']) ? $deviceConfig['prefix'] : 'Zend_Http_UserAgent'; $loader->addPrefixPath($prefix, $path); $device = $loader->load($browserType); } else { $loader = $this->getPluginLoader('device'); $device = $loader->load($browserType); } } else { $loader = $this->getPluginLoader('device'); $device = $loader->load($browserType); } $this->_browserTypeClass[$browserType] = $device; return $device; } /** * Returns the User Agent value * * If $userAgent param is null, the value of $_server['HTTP_USER_AGENT'] is * returned. * * @return string */ public function getUserAgent() { if (null === ($ua = $this->getServerValue('http_user_agent'))) { $ua = self::DEFAULT_HTTP_USER_AGENT; $this->setUserAgent($ua); } return $ua; } /** * Force or replace the UA chain in $_server variable * * @param string $userAgent Forced UserAgent chain * @return Zend_Http_UserAgent */ public function setUserAgent($userAgent) { $this->setServerValue('http_user_agent', $userAgent); return $this; } /** * Returns the HTTP Accept server param * * @param string $httpAccept (option) forced HTTP Accept chain * @return string */ public function getHttpAccept($httpAccept = null) { if (null === ($accept = $this->getServerValue('http_accept'))) { $accept = self::DEFAULT_HTTP_ACCEPT; $this->setHttpAccept($accept); } return $accept; } /** * Force or replace the HTTP_ACCEPT chain in self::$_server variable * * @param string $httpAccept Forced HTTP Accept chain * @return Zend_Http_UserAgent */ public function setHttpAccept($httpAccept) { $this->setServerValue('http_accept', $httpAccept); return $this; } /** * Returns the persistent storage handler * * Session storage is used by default unless a different storage adapter * has been set via the "persistent_storage_adapter" key. That key should * contain either a fully qualified class name, or a short name that * resolves via the plugin loader. * * @param string $browser Browser identifier (User Agent chain) * @return Zend_Http_UserAgent_Storage */ public function getStorage($browser = null) { if (null === $browser) { $browser = $this->getUserAgent(); } if (null === $this->_storage) { $config = $this->_config['storage']; $adapter = $config['adapter']; if (!class_exists($adapter)) { $loader = $this->getPluginLoader('storage'); $adapter = $loader->load($adapter); $loader = $this->getPluginLoader('storage'); } $options = array('browser_type' => $browser); if (isset($config['options'])) { $options = array_merge($options, $config['options']); } $this->setStorage(new $adapter($options)); } return $this->_storage; } /** * Sets the persistent storage handler * * @param Zend_Http_UserAgent_Storage $storage * @return Zend_Http_UserAgent */ public function setStorage(Zend_Http_UserAgent_Storage $storage) { if ($this->_immutable) { require_once 'Zend/Http/UserAgent/Exception.php'; throw new Zend_Http_UserAgent_Exception( 'The User-Agent device object has already been retrieved; the storage object is now immutable' ); } $this->_storage = $storage; return $this; } /** * Clean the persistent storage * * @param string $browser Browser identifier (User Agent chain) * @return void */ public function clearStorage($browser = null) { $this->getStorage($browser)->clear(); } /** * Get user configuration * * @return array */ public function getConfig() { return $this->_config; } /** * Config parameters is an Array or a Zend_Config object * * The allowed parameters are : * - the identification sequence (can be empty) => desktop browser type is the * default browser type returned * $config['identification_sequence'] : ',' separated browser types * - the persistent storage adapter * $config['persistent_storage_adapter'] = "Session" or "NonPersistent" * - to add or replace a browser type device * $config[(type)]['device']['path'] * $config[(type)]['device']['classname'] * - to add or replace a browser type features adapter * $config[(type)]['features']['path'] * $config[(type)]['features']['classname'] * * @param mixed $config (option) Config array * @return Zend_Http_UserAgent */ public function setConfig($config = array()) { if ($config instanceof Zend_Config) { $config = $config->toArray(); } // Verify that Config parameters are in an array. if (!is_array($config) && !$config instanceof Traversable) { require_once 'Zend/Http/UserAgent/Exception.php'; throw new Zend_Http_UserAgent_Exception(sprintf( 'Config parameters must be in an array or a Traversable object; received "%s"', (is_object($config) ? get_class($config) : gettype($config)) )); } if ($config instanceof Traversable) { $tmp = array(); foreach ($config as $key => $value) { $tmp[$key] = $value; } $config = $tmp; unset($tmp); } $this->_config = array_merge($this->_config, $config); return $this; } /** * Returns the device object * * This is the object that will contain the various discovered device * capabilities. * * @return Zend_Http_UserAgent_Device $device */ public function getDevice() { if (null !== $this->_device) { return $this->_device; } $userAgent = $this->getUserAgent(); // search an existing identification in the session $storage = $this->getStorage($userAgent); if (!$storage->isEmpty()) { // If the user agent and features are already existing, the // Zend_Http_UserAgent object is serialized in the session $object = $storage->read(); $this->unserialize($object); } else { // Otherwise, the identification is made and stored in the session. // Find the browser type: $this->setBrowserType($this->_matchUserAgent()); $this->_createDevice(); // put the result in storage: $this->getStorage($userAgent) ->write($this->serialize()); } // Mark the object as immutable $this->_immutable = true; // Return the device instance return $this->_device; } /** * Retrieve the browser type * * @return string $browserType */ public function getBrowserType() { return $this->_browserType; } /** * Set the browser "type" * * @param string $browserType * @return Zend_Http_UserAgent */ public function setBrowserType($browserType) { if ($this->_immutable) { require_once 'Zend/Http/UserAgent/Exception.php'; throw new Zend_Http_UserAgent_Exception( 'The User-Agent device object has already been retrieved; the browser type is now immutable' ); } $this->_browserType = $browserType; return $this; } /** * Retrieve the "$_SERVER" array * * Basically, the $_SERVER array or an equivalent container storing the * data that will be introspected. * * If the value has not been previously set, it sets itself from the * $_SERVER superglobal. * * @return array */ public function getServer() { if (null === $this->_server) { $this->setServer($_SERVER); } return $this->_server; } /** * Set the "$_SERVER" array * * Basically, the $_SERVER array or an equivalent container storing the * data that will be introspected. * * @param array|ArrayAccess $server * @return void * @throws Zend_Http_UserAgent_Exception on invalid parameter */ public function setServer($server) { if ($this->_immutable) { require_once 'Zend/Http/UserAgent/Exception.php'; throw new Zend_Http_UserAgent_Exception( 'The User-Agent device object has already been retrieved; the server array is now immutable' ); } if (!is_array($server) && !$server instanceof Traversable) { require_once 'Zend/Http/UserAgent/Exception.php'; throw new Zend_Http_UserAgent_Exception(sprintf( 'Expected an array or object implementing Traversable; received %s', (is_object($server) ? get_class($server) : gettype($server)) )); } // Get an array if we don't have one if ($server instanceof ArrayObject) { $server = $server->getArrayCopy(); } elseif ($server instanceof Traversable) { $tmp = array(); foreach ($server as $key => $value) { $tmp[$key] = $value; } $server = $tmp; unset($tmp); } // Normalize key case $server = array_change_key_case($server, CASE_LOWER); $this->_server = $server; return $this; } /** * Retrieve a server value * * @param string $key * @return mixed */ public function getServerValue($key) { $key = strtolower($key); $server = $this->getServer(); $return = null; if (isset($server[$key])) { $return = $server[$key]; } unset($server); return $return; } /** * Set a server value * * @param string|int|float $key * @param mixed $value * @return void */ public function setServerValue($key, $value) { if ($this->_immutable) { require_once 'Zend/Http/UserAgent/Exception.php'; throw new Zend_Http_UserAgent_Exception( 'The User-Agent device object has already been retrieved; the server array is now immutable' ); } $server = $this->getServer(); // ensure it's been initialized $key = strtolower($key); $this->_server[$key] = $value; return $this; } /** * Set plugin loader * * @param string $type Type of plugin loader; one of 'storage', (?) * @param string|Zend_Loader_PluginLoader $loader * @return Zend_Http_UserAgent */ public function setPluginLoader($type, $loader) { $type = $this->_validateLoaderType($type); if (is_string($loader)) { if (!class_exists($loader)) { require_once 'Zend/Loader.php'; Zend_Loader::loadClass($loader); } $loader = new $loader(); } elseif (!is_object($loader)) { require_once 'Zend/Http/UserAgent/Exception.php'; throw new Zend_Http_UserAgent_Exception(sprintf( 'Expected a plugin loader class or object; received %s', gettype($loader) )); } if (!$loader instanceof Zend_Loader_PluginLoader) { require_once 'Zend/Http/UserAgent/Exception.php'; throw new Zend_Http_UserAgent_Exception(sprintf( 'Expected an object extending Zend_Loader_PluginLoader; received %s', get_class($loader) )); } $basePrefix = 'Zend_Http_UserAgent_'; $basePath = 'Zend/Http/UserAgent/'; switch ($type) { case 'storage': $prefix = $basePrefix . 'Storage'; $path = $basePath . 'Storage'; break; case 'device': $prefix = $basePrefix; $path = $basePath; break; } $loader->addPrefixPath($prefix, $path); $this->_loaders[$type] = $loader; return $this; } /** * Get a plugin loader * * @param string $type A valid plugin loader type; see {@link $_loaderTypes} * @return Zend_Loader_PluginLoader */ public function getPluginLoader($type) { $type = $this->_validateLoaderType($type); if (!isset($this->_loaders[$type])) { require_once 'Zend/Loader/PluginLoader.php'; $this->setPluginLoader($type, new Zend_Loader_PluginLoader()); } return $this->_loaders[$type]; } /** * Validate a plugin loader type * * Verifies that it is in {@link $_loaderTypes}, and returns a normalized * version of the type. * * @param string $type * @return string * @throws Zend_Http_UserAgent_Exception on invalid type */ protected function _validateLoaderType($type) { $type = strtolower($type); if (!in_array($type, $this->_loaderTypes)) { $types = implode(', ', $this->_loaderTypes); require_once 'Zend/Http/UserAgent/Exception.php'; throw new Zend_Http_UserAgent_Exception(sprintf( 'Expected one of "%s" for plugin loader type; received "%s"', $types, (string) $type )); } return $type; } /** * Run the identification sequence to match the right browser type according to the * user agent * * @return Zend_Http_UserAgent_Result */ protected function _matchUserAgent() { $type = self::DEFAULT_BROWSER_TYPE; // If we have no identification sequence, just return the default type if (empty($this->_config['identification_sequence'])) { return $type; } // Get sequence against which to match $sequence = explode(',', $this->_config['identification_sequence']); // If a browser type is already configured, push that to the front of the list if (null !== ($browserType = $this->getBrowserType())) { array_unshift($sequence, $browserType); } // Append the default browser type to the list if not alread in the list if (!in_array($type, $sequence)) { $sequence[] = $type; } // Test each type until we find a match foreach ($sequence as $browserType) { $browserType = trim($browserType); $className = $this->_getUserAgentDevice($browserType); // Attempt to match this device class if ($this->_match($className)) { $type = $browserType; $this->_browserTypeClass[$type] = $className; break; } } return $type; } /** * Creates device object instance * * @return void */ protected function _createDevice() { $browserType = $this->getBrowserType(); $classname = $this->_getUserAgentDevice($browserType); $this->_device = new $classname($this->getUserAgent(), $this->getServer(), $this->getConfig()); } } |