web/lib/Zend/Http/UserAgent/AbstractDevice.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Http
       
    17  * @subpackage UserAgent
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    20  */
       
    21 
       
    22 require_once 'Zend/Http/UserAgent/Device.php';
       
    23 
       
    24 /**
       
    25  * Abstract Class to define a browser device.
       
    26  *
       
    27  * @category   Zend
       
    28  * @package    Zend_Http
       
    29  * @subpackage UserAgent
       
    30  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    31  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    32  */
       
    33 abstract class Zend_Http_UserAgent_AbstractDevice
       
    34     implements Zend_Http_UserAgent_Device
       
    35 {
       
    36     /**
       
    37      * Browser signature
       
    38      *
       
    39      * @var string
       
    40      */
       
    41     protected $_browser = '';
       
    42 
       
    43     /**
       
    44      * Browser version
       
    45      *
       
    46      * @var string
       
    47      */
       
    48     protected $_browserVersion = '';
       
    49 
       
    50     /**
       
    51      * Configuration
       
    52      * 
       
    53      * @var array
       
    54      */
       
    55     protected $_config;
       
    56 
       
    57     /**
       
    58      * User Agent chain
       
    59      *
       
    60      * @var string
       
    61      */
       
    62     protected $_userAgent;
       
    63 
       
    64     /**
       
    65      * Server variable
       
    66      * 
       
    67      * @var array
       
    68      */
       
    69     protected $_server;
       
    70 
       
    71     /**
       
    72      * Image types
       
    73      * 
       
    74      * @var array
       
    75      */
       
    76     protected $_images = array(
       
    77         'jpeg', 
       
    78         'gif', 
       
    79         'png', 
       
    80         'pjpeg', 
       
    81         'x-png', 
       
    82         'bmp',
       
    83     );
       
    84 
       
    85     /**
       
    86      * Browser/Device features
       
    87      *
       
    88      * @var array
       
    89      */
       
    90     protected $_aFeatures = array();
       
    91 
       
    92     /**
       
    93      * Browser/Device features groups
       
    94      *
       
    95      * @var array
       
    96      */
       
    97     protected $_aGroup = array();
       
    98 
       
    99     /**
       
   100      * Constructor
       
   101      *
       
   102      * @param  null|string|array $userAgent If array, restores from serialized version
       
   103      * @param  array $server 
       
   104      * @param  array $config 
       
   105      * @return void
       
   106      */
       
   107     public function __construct($userAgent = null, array $server = array(), array $config = array())
       
   108     {
       
   109         if (is_array($userAgent)) {
       
   110             // Restoring from serialized array
       
   111             $this->_restoreFromArray($userAgent);
       
   112         } else {
       
   113             // Constructing new object
       
   114             $this->setUserAgent($userAgent);
       
   115             $this->_server    = $server;
       
   116             $this->_config    = $config;
       
   117             $this->_getDefaultFeatures();
       
   118             $this->_defineFeatures();
       
   119         }
       
   120     }
       
   121 
       
   122     /**
       
   123      * Serialize object
       
   124      * 
       
   125      * @return string
       
   126      */
       
   127     public function serialize()
       
   128     {
       
   129         $spec = array(
       
   130             '_aFeatures'      => $this->_aFeatures,
       
   131             '_aGroup'         => $this->_aGroup,
       
   132             '_browser'        => $this->_browser,
       
   133             '_browserVersion' => $this->_browserVersion,
       
   134             '_userAgent'      => $this->_userAgent,
       
   135             '_images'         => $this->_images,
       
   136         );
       
   137         return serialize($spec);
       
   138     }
       
   139 
       
   140     /**
       
   141      * Unserialize
       
   142      * 
       
   143      * @param  string $serialized 
       
   144      * @return void
       
   145      */
       
   146     public function unserialize($serialized)
       
   147     {
       
   148         $spec = unserialize($serialized);
       
   149         $this->_restoreFromArray($spec);
       
   150     }
       
   151 
       
   152     /**
       
   153      * Restore object state from array
       
   154      * 
       
   155      * @param  array $spec 
       
   156      * @return void
       
   157      */
       
   158     protected function _restoreFromArray(array $spec)
       
   159     {
       
   160         foreach ($spec as $key => $value) {
       
   161             if (property_exists($this, $key)) {
       
   162                 $this->{$key} = $value;
       
   163             }
       
   164         }
       
   165     }
       
   166 
       
   167     /**
       
   168      * Look for features
       
   169      *
       
   170      * @return array|null
       
   171      */
       
   172     protected function _defineFeatures()
       
   173     {
       
   174         $features = $this->_loadFeaturesAdapter();
       
   175 
       
   176         if (is_array($features)) {
       
   177             $this->_aFeatures = array_merge($this->_aFeatures, $features);
       
   178         }
       
   179         
       
   180         return $this->_aFeatures;
       
   181     }
       
   182 
       
   183     /**
       
   184      * Gets the browser type identifier
       
   185      *
       
   186      * @return string
       
   187      */
       
   188     abstract public function getType();
       
   189 
       
   190     /**
       
   191      * Check a feature for the current browser/device.
       
   192      *
       
   193      * @param  string $feature The feature to check.
       
   194      * @return bool
       
   195      */
       
   196     public function hasFeature($feature)
       
   197     {
       
   198         return (!empty($this->_aFeatures[$feature]));
       
   199     }
       
   200 
       
   201     /**
       
   202      * Gets the value of the current browser/device feature
       
   203      *
       
   204      * @param  string $feature Feature to search
       
   205      * @return string|null
       
   206      */
       
   207     public function getFeature($feature)
       
   208     {
       
   209         if ($this->hasFeature($feature)) {
       
   210             return $this->_aFeatures[$feature];
       
   211         }
       
   212     }
       
   213 
       
   214     /**
       
   215      * Set a feature for the current browser/device.
       
   216      *
       
   217      * @param  string $feature The feature to set.
       
   218      * @param  string $value (option) feature value.
       
   219      * @param  string $group (option) Group to associate with the feature
       
   220      * @return Zend_Http_UserAgent_AbstractDevice
       
   221      */
       
   222     public function setFeature($feature, $value = false, $group = '')
       
   223     {
       
   224         $this->_aFeatures[$feature] = $value;
       
   225         if (!empty($group)) {
       
   226             $this->setGroup($group, $feature);
       
   227         }
       
   228         return $this;
       
   229     }
       
   230 
       
   231     /**
       
   232      * Affects a feature to a group
       
   233      *
       
   234      * @param  string $group Group name
       
   235      * @param  string $feature Feature name
       
   236      * @return Zend_Http_UserAgent_AbstractDevice
       
   237      */
       
   238     public function setGroup($group, $feature)
       
   239     {
       
   240         if (!isset($this->_aGroup[$group])) {
       
   241             $this->_aGroup[$group] = array();
       
   242         }
       
   243         if (!in_array($feature, $this->_aGroup[$group])) {
       
   244             $this->_aGroup[$group][] = $feature;
       
   245         }
       
   246         return $this;
       
   247     }
       
   248 
       
   249     /**
       
   250      * Gets an array of features associated to a group
       
   251      *
       
   252      * @param  string $group Group param
       
   253      * @return array
       
   254      */
       
   255     public function getGroup($group)
       
   256     {
       
   257         return $this->_aGroup[$group];
       
   258     }
       
   259 
       
   260     /**
       
   261      * Gets all the browser/device features
       
   262      *
       
   263      * @return array
       
   264      */
       
   265     public function getAllFeatures()
       
   266     {
       
   267         return $this->_aFeatures;
       
   268     }
       
   269 
       
   270     /**
       
   271      * Gets all the browser/device features' groups
       
   272      *
       
   273      * @return array
       
   274      */
       
   275     public function getAllGroups()
       
   276     {
       
   277         return $this->_aGroup;
       
   278     }
       
   279 
       
   280     /**
       
   281      * Sets all the standard features extracted from the User Agent chain and $this->_server
       
   282      * vars
       
   283      *
       
   284      * @return void
       
   285      */
       
   286     protected function _getDefaultFeatures()
       
   287     {
       
   288         $server = array();
       
   289         
       
   290         // gets info from user agent chain 
       
   291         $uaExtract = $this->extractFromUserAgent($this->getUserAgent());
       
   292         
       
   293         if (is_array($uaExtract)) {
       
   294             foreach ($uaExtract as $key => $info) {
       
   295                 $this->setFeature($key, $info, 'product_info');
       
   296             }
       
   297         }
       
   298         
       
   299         if (isset($uaExtract['browser_name'])) {
       
   300             $this->_browser = $uaExtract['browser_name'];
       
   301         }
       
   302         if (isset($uaExtract['browser_version'])) {
       
   303             $this->_browserVersion = $uaExtract['browser_version'];
       
   304         }
       
   305         if (isset($uaExtract['device_os'])) {
       
   306             $this->device_os = $uaExtract['device_os_name'];
       
   307         }
       
   308         
       
   309         /* browser & device info */
       
   310         $this->setFeature('is_wireless_device', false, 'product_info');
       
   311         $this->setFeature('is_mobile', false, 'product_info');
       
   312         $this->setFeature('is_desktop', false, 'product_info');
       
   313         $this->setFeature('is_tablet', false, 'product_info');
       
   314         $this->setFeature('is_bot', false, 'product_info');
       
   315         $this->setFeature('is_email', false, 'product_info');
       
   316         $this->setFeature('is_text', false, 'product_info');
       
   317         $this->setFeature('device_claims_web_support', false, 'product_info');
       
   318         
       
   319         $this->setFeature('is_' . strtolower($this->getType()), true, 'product_info');
       
   320         
       
   321         /* sets the browser name */
       
   322         if (isset($this->list) && empty($this->_browser)) {
       
   323             $lowerUserAgent = strtolower($this->getUserAgent());
       
   324             foreach ($this->list as $browser_signature) {
       
   325                 if (strpos($lowerUserAgent, $browser_signature) !== false) {
       
   326                     $this->_browser = strtolower($browser_signature);
       
   327                     $this->setFeature('browser_name', $this->_browser, 'product_info');
       
   328                 }
       
   329             }
       
   330         }
       
   331         
       
   332         /* sets the client IP */
       
   333         if (isset($this->_server['remote_addr'])) {
       
   334             $this->setFeature('client_ip', $this->_server['remote_addr'], 'product_info');
       
   335         } elseif (isset($this->_server['http_x_forwarded_for'])) {
       
   336             $this->setFeature('client_ip', $this->_server['http_x_forwarded_for'], 'product_info');
       
   337         } elseif (isset($this->_server['http_client_ip'])) {
       
   338             $this->setFeature('client_ip', $this->_server['http_client_ip'], 'product_info');
       
   339         }
       
   340         
       
   341         /* sets the server infos */
       
   342         if (isset($this->_server['server_software'])) {
       
   343             if (strpos($this->_server['server_software'], 'Apache') !== false || strpos($this->_server['server_software'], 'LiteSpeed') !== false) {
       
   344                 $server['version'] = 1;
       
   345                 if (strpos($this->_server['server_software'], 'Apache/2') !== false) {
       
   346                     $server['version'] = 2;
       
   347                 }
       
   348                 $server['server'] = 'apache';
       
   349             }
       
   350             
       
   351             if (strpos($this->_server['server_software'], 'Microsoft-IIS') !== false) {
       
   352                 $server['server'] = 'iis';
       
   353             }
       
   354             
       
   355             if (strpos($this->_server['server_software'], 'Unix') !== false) {
       
   356                 $server['os'] = 'unix';
       
   357                 if (isset($_ENV['MACHTYPE'])) {
       
   358                     if (strpos($_ENV['MACHTYPE'], 'linux') !== false) {
       
   359                         $server['os'] = 'linux';
       
   360                     }
       
   361                 }
       
   362             } elseif (strpos($this->_server['server_software'], 'Win') !== false) {
       
   363                 $server['os'] = 'windows';
       
   364             }
       
   365             
       
   366             if (preg_match('/Apache\/([0-9\.]*)/', $this->_server['server_software'], $arr)) {
       
   367                 if ($arr[1]) {
       
   368                     $server['version'] = $arr[1];
       
   369                     $server['server']  = 'apache';
       
   370                 }
       
   371             }
       
   372         }
       
   373         
       
   374         $this->setFeature('php_version', phpversion(), 'server_info');
       
   375         if (isset($server['server'])) {
       
   376             $this->setFeature('server_os', $server['server'], 'server_info');
       
   377         }
       
   378         if (isset($server['version'])) {
       
   379             $this->setFeature('server_os_version', $server['version'], 'server_info');
       
   380         }
       
   381         if (isset($this->_server['http_accept'])) {
       
   382             $this->setFeature('server_http_accept', $this->_server['http_accept'], 'server_info');
       
   383         }
       
   384         if (isset($this->_server['http_accept_language'])) {
       
   385             $this->setFeature('server_http_accept_language', $this->_server['http_accept_language'], 'server_info');
       
   386         }
       
   387         if (isset($this->_server['server_addr'])) {
       
   388             $this->setFeature('server_ip', $this->_server['server_addr'], 'server_info');
       
   389         }
       
   390         if (isset($this->_server['server_name'])) {
       
   391             $this->setFeature('server_name', $this->_server['server_name'], 'server_info');
       
   392         }
       
   393     }
       
   394 
       
   395     /**
       
   396      * Extract and sets informations from the User Agent chain
       
   397      *
       
   398      * @param  string $userAgent User Agent chain
       
   399      * @return array
       
   400      */
       
   401     public static function extractFromUserAgent($userAgent)
       
   402     {
       
   403         $userAgent = trim($userAgent);
       
   404         
       
   405         /**
       
   406          * @see http://www.texsoft.it/index.php?c=software&m=sw.php.useragent&l=it
       
   407          */
       
   408         $pattern =  "(([^/\s]*)(/(\S*))?)(\s*\[[a-zA-Z][a-zA-Z]\])?\s*(\\((([^()]|(\\([^()]*\\)))*)\\))?\s*";
       
   409         preg_match("#^$pattern#", $userAgent, $match);
       
   410 
       
   411         $comment = array();
       
   412         if (isset($match[7])) {
       
   413             $comment = explode(';', $match[7]);
       
   414         }
       
   415         
       
   416         // second part if exists
       
   417         $end = substr($userAgent, strlen($match[0]));
       
   418         if (!empty($end)) {
       
   419             $result['others']['full'] = $end;
       
   420         }
       
   421         
       
   422         $match2 = array();
       
   423         if (isset($result['others'])) {
       
   424             preg_match_all('/(([^\/\s]*)(\/)?([^\/\(\)\s]*)?)(\s\((([^\)]*)*)\))?/i', $result['others']['full'], $match2);
       
   425         }
       
   426         $result['user_agent']   = trim($match[1]);
       
   427         $result['product_name'] = isset($match[2]) ? trim($match[2]) : '';
       
   428         $result['browser_name'] = $result['product_name'];
       
   429         if (isset($match[4]) && trim($match[4])) {
       
   430             $result['product_version'] = trim($match[4]);
       
   431             $result['browser_version'] = trim($match[4]);
       
   432         }
       
   433         if (count($comment) && !empty($comment[0])) {
       
   434             $result['comment']['full']     = trim($match[7]);
       
   435             $result['comment']['detail']   = $comment;
       
   436             $result['compatibility_flag']  = trim($comment[0]);
       
   437             if (isset($comment[1])) {
       
   438                 $result['browser_token']   = trim($comment[1]);
       
   439             }
       
   440             if (isset($comment[2])) {
       
   441                 $result['device_os_token'] = trim($comment[2]);
       
   442             }
       
   443         }
       
   444         if (empty($result['device_os_token']) && !empty($result['compatibility_flag'])) {
       
   445             // some browsers do not have a platform token
       
   446             $result['device_os_token'] = $result['compatibility_flag'];
       
   447         }
       
   448         if ($match2) {
       
   449             $i = 0;
       
   450             $max = count($match2[0]);
       
   451             for ($i = 0; $i < $max; $i ++) {
       
   452                 if (!empty($match2[0][$i])) {
       
   453                     $result['others']['detail'][] = array(
       
   454                         $match2[0][$i], 
       
   455                         $match2[2][$i], 
       
   456                         $match2[4][$i],
       
   457                     );
       
   458                 }
       
   459             }
       
   460         }
       
   461         
       
   462         /** Security level */
       
   463         $security = array(
       
   464             'N' => 'no security', 
       
   465             'U' => 'strong security', 
       
   466             'I' => 'weak security',
       
   467         );
       
   468         if (!empty($result['browser_token'])) {
       
   469             if (isset($security[$result['browser_token']])) {
       
   470                 $result['security_level'] = $security[$result['browser_token']];
       
   471                 unset($result['browser_token']);
       
   472             }
       
   473         }
       
   474         
       
   475         $product = strtolower($result['browser_name']);
       
   476         
       
   477         // Mozilla : true && false
       
   478         $compatibleOrIe = false;
       
   479         if (isset($result['compatibility_flag']) && isset($result['comment'])) {
       
   480             $compatibleOrIe = ($result['compatibility_flag'] == 'compatible' || strpos($result['comment']['full'], "MSIE") !== false);
       
   481         }
       
   482         if ($product == 'mozilla' && $compatibleOrIe) {
       
   483             if (!empty($result['browser_token'])) {
       
   484                 // Classic Mozilla chain
       
   485                 preg_match_all('/([^\/\s].*)(\/|\s)(.*)/i', $result['browser_token'], $real);
       
   486             } else {
       
   487                 // MSIE specific chain with 'Windows' compatibility flag
       
   488                 foreach ($result['comment']['detail'] as $v) {
       
   489                     if (strpos($v, 'MSIE') !== false) {
       
   490                         $real[0][1]               = trim($v);
       
   491                         $result['browser_engine'] = "MSIE";
       
   492                         $real[1][0]               = "Internet Explorer";
       
   493                         $temp                     = explode(' ', trim($v));
       
   494                         $real[3][0]               = $temp[1];
       
   495                     
       
   496                     }
       
   497                     if (strpos($v, 'Win') !== false) {
       
   498                         $result['device_os_token'] = trim($v);
       
   499                     }
       
   500                 }
       
   501             }
       
   502             
       
   503             if (!empty($real[0])) {
       
   504                 $result['browser_name']    = $real[1][0];
       
   505                 $result['browser_version'] = $real[3][0];
       
   506             } else {
       
   507                 $result['browser_name']    = $result['browser_token'];
       
   508                 $result['browser_version'] = '??';
       
   509             }
       
   510         } elseif ($product == 'mozilla' && $result['browser_version'] < 5.0) {
       
   511             // handles the real Mozilla (or old Netscape if version < 5.0)
       
   512             $result['browser_name'] = 'Netscape';
       
   513         }
       
   514         
       
   515         /** windows */
       
   516         if ($result['browser_name'] == 'MSIE') {
       
   517             $result['browser_engine'] = 'MSIE';
       
   518             $result['browser_name']   = 'Internet Explorer';
       
   519         }
       
   520         if (isset($result['device_os_token'])) {
       
   521             if (strpos($result['device_os_token'], 'Win') !== false) {
       
   522                 
       
   523                 $windows = array(
       
   524                     'Windows NT 6.1'          => 'Windows 7', 
       
   525                     'Windows NT 6.0'          => 'Windows Vista', 
       
   526                     'Windows NT 5.2'          => 'Windows Server 2003', 
       
   527                     'Windows NT 5.1'          => 'Windows XP', 
       
   528                     'Windows NT 5.01'         => 'Windows 2000 SP1', 
       
   529                     'Windows NT 5.0'          => 'Windows 2000', 
       
   530                     'Windows NT 4.0'          => 'Microsoft Windows NT 4.0', 
       
   531                     'WinNT'                   => 'Microsoft Windows NT 4.0', 
       
   532                     'Windows 98; Win 9x 4.90' => 'Windows Me', 
       
   533                     'Windows 98'              => 'Windows 98', 
       
   534                     'Win98'                   => 'Windows 98', 
       
   535                     'Windows 95'              => 'Windows 95', 
       
   536                     'Win95'                   => 'Windows 95', 
       
   537                     'Windows CE'              => 'Windows CE',
       
   538                 );
       
   539                 if (isset($windows[$result['device_os_token']])) {
       
   540                     $result['device_os_name'] = $windows[$result['device_os_token']];
       
   541                 } else {
       
   542                     $result['device_os_name'] = $result['device_os_token'];
       
   543                 }
       
   544             }
       
   545         }
       
   546         
       
   547         // iphone 
       
   548         $apple_device = array(
       
   549             'iPhone', 
       
   550             'iPod', 
       
   551             'iPad',
       
   552         );
       
   553         if (isset($result['compatibility_flag'])) {
       
   554             if (in_array($result['compatibility_flag'], $apple_device)) {
       
   555                 $result['device']           = strtolower($result['compatibility_flag']);
       
   556                 $result['device_os_token']  = 'iPhone OS';
       
   557                 $result['browser_language'] = trim($comment[3]);
       
   558                 $result['browser_version']  = $result['others']['detail'][1][2];
       
   559                 if (!empty($result['others']['detail'][2])) {
       
   560                     $result['firmware'] = $result['others']['detail'][2][2];
       
   561                 }
       
   562                 if (!empty($result['others']['detail'][3])) {
       
   563                     $result['browser_name']  = $result['others']['detail'][3][1];
       
   564                     $result['browser_build'] = $result['others']['detail'][3][2];
       
   565                 }
       
   566             }
       
   567         }
       
   568         
       
   569         // Safari
       
   570         if (isset($result['others'])) {
       
   571             if ($result['others']['detail'][0][1] == 'AppleWebKit') {
       
   572                 $result['browser_engine'] = 'AppleWebKit';
       
   573                 if ($result['others']['detail'][1][1] == 'Version') {
       
   574                     $result['browser_version'] = $result['others']['detail'][1][2];
       
   575                 } else {
       
   576                     $result['browser_version'] = $result['others']['detail'][count($result['others']['detail']) - 1][2];
       
   577                 }
       
   578                 if (isset($comment[3])) {
       
   579                      $result['browser_language'] = trim($comment[3]);
       
   580                 }
       
   581                 
       
   582                 $last = $result['others']['detail'][count($result['others']['detail']) - 1][1];
       
   583                 
       
   584                 if (empty($result['others']['detail'][2][1]) || $result['others']['detail'][2][1] == 'Safari') {
       
   585                     $result['browser_name']    = ($result['others']['detail'][1][1] && $result['others']['detail'][1][1] != 'Version' ? $result['others']['detail'][1][1] : 'Safari');
       
   586                     $result['browser_version'] = ($result['others']['detail'][1][2] ? $result['others']['detail'][1][2] : $result['others']['detail'][0][2]);
       
   587                 } else {
       
   588                     $result['browser_name']    = $result['others']['detail'][2][1];
       
   589                     $result['browser_version'] = $result['others']['detail'][2][2];
       
   590                     
       
   591                     // mobile version
       
   592                     if ($result['browser_name'] == 'Mobile') {
       
   593                         $result['browser_name'] = 'Safari ' . $result['browser_name'];
       
   594                         if ($result['others']['detail'][1][1] == 'Version') {
       
   595                             $result['browser_version'] = $result['others']['detail'][1][2];
       
   596                         }
       
   597                     }
       
   598                 }
       
   599                 
       
   600                 // For Safari < 2.2, AppleWebKit version gives the Safari version
       
   601                 if (strpos($result['browser_version'], '.') > 2 || (int) $result['browser_version'] > 20) {
       
   602                     $temp = explode('.', $result['browser_version']);
       
   603                     $build = (int) $temp[0];
       
   604                     $awkVersion = array(
       
   605                         48  => '0.8', 
       
   606                         73  => '0.9', 
       
   607                         85  => '1.0', 
       
   608                         103 => '1.1', 
       
   609                         124 => '1.2', 
       
   610                         300 => '1.3', 
       
   611                         400 => '2.0',
       
   612                     );
       
   613                     foreach ($awkVersion as $k => $v) {
       
   614                         if ($build >= $k) {
       
   615                             $result['browser_version'] = $v;
       
   616                         }
       
   617                     }
       
   618                 }
       
   619             }
       
   620             
       
   621             // Gecko (Firefox or compatible)
       
   622             if ($result['others']['detail'][0][1] == 'Gecko') {
       
   623                 $searchRV = true;
       
   624                 if (!empty($result['others']['detail'][1][1]) && !empty($result['others']['detail'][count($result['others']['detail']) - 1][2]) || strpos(strtolower($result['others']['full']), 'opera') !== false) {
       
   625                     $searchRV = false;
       
   626                     $result['browser_engine'] = $result['others']['detail'][0][1];
       
   627                     
       
   628                     // the name of the application is at the end indepenently 
       
   629                     // of quantity of information in $result['others']['detail']
       
   630                     $last = count($result['others']['detail']) - 1;
       
   631                     
       
   632                     // exception : if the version of the last information is 
       
   633                     // empty we take the previous one
       
   634                     if (empty($result['others']['detail'][$last][2])) {
       
   635                         $last --;
       
   636                     }
       
   637                     
       
   638                     // exception : if the last one is 'Red Hat' or 'Debian' => 
       
   639                     // use rv: to find browser_version */
       
   640                     if (in_array($result['others']['detail'][$last][1], array(
       
   641                         'Debian', 
       
   642                         'Hat',
       
   643                     ))) {
       
   644                         $searchRV = true;
       
   645                     }
       
   646                     $result['browser_name']    = $result['others']['detail'][$last][1];
       
   647                     $result['browser_version'] = $result['others']['detail'][$last][2];
       
   648                     if (isset($comment[4])) {
       
   649                         $result['browser_build'] = trim($comment[4]);
       
   650                     }
       
   651                     $result['browser_language'] = trim($comment[3]);
       
   652                     
       
   653                     // Netscape
       
   654                     if ($result['browser_name'] == 'Navigator' || $result['browser_name'] == 'Netscape6') {
       
   655                         $result['browser_name'] = 'Netscape';
       
   656                     }
       
   657                 }
       
   658                 if ($searchRV) {
       
   659                     // Mozilla alone : the version is identified by rv:
       
   660                     $result['browser_name'] = 'Mozilla';
       
   661                     if (isset($result['comment']['detail'])) {
       
   662                         foreach ($result['comment']['detail'] as $rv) {
       
   663                             if (strpos($rv, 'rv:') !== false) {
       
   664                                 $result['browser_version'] = trim(str_replace('rv:', '', $rv));
       
   665                             }
       
   666                         }
       
   667                     }
       
   668                 }
       
   669             }
       
   670             
       
   671             // Netscape
       
   672             if ($result['others']['detail'][0][1] == 'Netscape') {
       
   673                 $result['browser_name']    = 'Netscape';
       
   674                 $result['browser_version'] = $result['others']['detail'][0][2];
       
   675             }
       
   676             
       
   677             // Opera 
       
   678             // Opera: engine Presto
       
   679             if ($result['others']['detail'][0][1] == 'Presto') {
       
   680                 $result['browser_engine'] = 'Presto';
       
   681                 if (!empty($result['others']['detail'][1][2])) {
       
   682                     $result['browser_version'] = $result['others']['detail'][1][2];
       
   683                 }
       
   684             }
       
   685             
       
   686             // UA ends with 'Opera X.XX'
       
   687             if ($result['others']['detail'][0][1] == 'Opera') {
       
   688                 $result['browser_name']    = $result['others']['detail'][0][1];
       
   689                 $result['browser_version'] = $result['others']['detail'][1][1];
       
   690             }
       
   691             
       
   692             // Opera Mini
       
   693             if (isset($result["browser_token"])) {
       
   694                 if (strpos($result["browser_token"], 'Opera Mini') !== false) {
       
   695                     $result['browser_name'] = 'Opera Mini';
       
   696                 }
       
   697             }
       
   698             
       
   699             // Symbian
       
   700             if ($result['others']['detail'][0][1] == 'SymbianOS') {
       
   701                 $result['device_os_token'] = 'SymbianOS';
       
   702             }
       
   703         }
       
   704         
       
   705         // UA ends with 'Opera X.XX'
       
   706         if (isset($result['browser_name']) && isset($result['browser_engine'])) {
       
   707             if ($result['browser_name'] == 'Opera' && $result['browser_engine'] == 'Gecko' && empty($result['browser_version'])) {
       
   708                 $result['browser_version'] = $result['others']['detail'][count($result['others']['detail']) - 1][1];
       
   709             }
       
   710         }
       
   711         
       
   712         // cleanup
       
   713         if (isset($result['browser_version']) && isset($result['browser_build'])) {
       
   714             if ($result['browser_version'] == $result['browser_build']) {
       
   715                 unset($result['browser_build']);
       
   716             }
       
   717         }
       
   718         
       
   719         // compatibility
       
   720         $compatibility['AppleWebKit'] = 'Safari';
       
   721         $compatibility['Gecko']       = 'Firefox';
       
   722         $compatibility['MSIE']        = 'Internet Explorer';
       
   723         $compatibility['Presto']      = 'Opera';
       
   724         if (!empty($result['browser_engine'])) {
       
   725             if (isset($compatibility[$result['browser_engine']])) {
       
   726                 $result['browser_compatibility'] = $compatibility[$result['browser_engine']];
       
   727             }
       
   728         }
       
   729         
       
   730         ksort($result);
       
   731         return $result;
       
   732     }
       
   733 
       
   734     /**
       
   735      * Loads the Features Adapter if it's defined in the $config array
       
   736      * Otherwise, nothing is done
       
   737      *
       
   738      * @param  string $browserType Browser type
       
   739      * @return array
       
   740      */
       
   741     protected function _loadFeaturesAdapter()
       
   742     {
       
   743         $config      = $this->_config;
       
   744         $browserType = $this->getType();
       
   745         if (!isset($config[$browserType]) || !isset($config[$browserType]['features'])) {
       
   746             return array();
       
   747         }
       
   748         $config = $config[$browserType]['features'];
       
   749 
       
   750         if (empty($config['classname'])) {
       
   751             require_once 'Zend/Http/UserAgent/Exception.php';
       
   752             throw new Zend_Http_UserAgent_Exception('The ' . $this->getType() . ' features adapter must have a "classname" config parameter defined');
       
   753         }
       
   754 
       
   755         $className = $config['classname'];
       
   756         if (!class_exists($className)) {
       
   757             if (isset($config['path'])) {
       
   758                 $path = $config['path'];
       
   759             } else {
       
   760                 require_once 'Zend/Http/UserAgent/Exception.php';
       
   761                 throw new Zend_Http_UserAgent_Exception('The ' . $this->getType() . ' features adapter must have a "path" config parameter defined');
       
   762             }
       
   763             
       
   764             if (false === include_once ($path)) {
       
   765                 require_once 'Zend/Http/UserAgent/Exception.php';
       
   766                 throw new Zend_Http_UserAgent_Exception('The ' . $this->getType() . ' features adapter path that does not exist');
       
   767             }
       
   768         }
       
   769         
       
   770         return call_user_func(array($className, 'getFromRequest'), $this->_server, $this->_config);
       
   771     }
       
   772 
       
   773     /**
       
   774      * Retrieve image format support
       
   775      *
       
   776      * @return array
       
   777      */
       
   778     public function getImageFormatSupport()
       
   779     {
       
   780         return $this->_images;
       
   781     }
       
   782 
       
   783     /**
       
   784      * Get maximum image height supported by this device
       
   785      *
       
   786      * @return int
       
   787      */
       
   788     public function getMaxImageHeight()
       
   789     {
       
   790         return null;
       
   791     }
       
   792 
       
   793     /**
       
   794      * Get maximum image width supported by this device
       
   795      *
       
   796      * @return int
       
   797      */
       
   798     public function getMaxImageWidth()
       
   799     {
       
   800         return null;
       
   801     }
       
   802 
       
   803     /**
       
   804      * Get physical screen height of this device
       
   805      *
       
   806      * @return int
       
   807      */
       
   808     public function getPhysicalScreenHeight()
       
   809     {
       
   810         return null;
       
   811     }
       
   812 
       
   813     /**
       
   814      * Get physical screen width of this device
       
   815      *
       
   816      * @return int
       
   817      */
       
   818     public function getPhysicalScreenWidth()
       
   819     {
       
   820         return null;
       
   821     }
       
   822 
       
   823     /**
       
   824      * Get preferred markup type
       
   825      *
       
   826      * @return string
       
   827      */
       
   828     public function getPreferredMarkup()
       
   829     {
       
   830         return 'xhtml';
       
   831     }
       
   832 
       
   833     /**
       
   834      * Get supported X/HTML version
       
   835      *
       
   836      * @return int
       
   837      */
       
   838     public function getXhtmlSupportLevel()
       
   839     {
       
   840         return 4;
       
   841     }
       
   842 
       
   843     /**
       
   844      * Does the device support Flash?
       
   845      *
       
   846      * @return bool
       
   847      */
       
   848     public function hasFlashSupport()
       
   849     {
       
   850         return true;
       
   851     }
       
   852 
       
   853     /**
       
   854      * Does the device support PDF?
       
   855      *
       
   856      * @return bool
       
   857      */
       
   858     public function hasPdfSupport()
       
   859     {
       
   860         return true;
       
   861     }
       
   862 
       
   863     /**
       
   864      * Does the device have a phone number associated with it?
       
   865      *
       
   866      * @return bool
       
   867      */
       
   868     public function hasPhoneNumber()
       
   869     {
       
   870         return false;
       
   871     }
       
   872 
       
   873     /**
       
   874      * Does the device support HTTPS?
       
   875      *
       
   876      * @return bool
       
   877      */
       
   878     public function httpsSupport()
       
   879     {
       
   880         return true;
       
   881     }
       
   882 
       
   883     /**
       
   884      * Get the browser type
       
   885      *
       
   886      * @return string
       
   887      */
       
   888     public function getBrowser()
       
   889     {
       
   890         return $this->_browser;
       
   891     }
       
   892 
       
   893     /**
       
   894      * Get the browser version
       
   895      *
       
   896      * @return string
       
   897      */
       
   898     public function getBrowserVersion()
       
   899     {
       
   900         return $this->_browserVersion;
       
   901     }
       
   902 
       
   903     /**
       
   904      * Get the user agent string
       
   905      *
       
   906      * @return string
       
   907      */
       
   908     public function getUserAgent()
       
   909     {
       
   910         return $this->_userAgent;
       
   911     }
       
   912 
       
   913     /**
       
   914      * @return the $_images
       
   915      */
       
   916     public function getImages()
       
   917     {
       
   918         return $this->_images;
       
   919     }
       
   920 
       
   921     /**
       
   922      * @param string $browser
       
   923      */
       
   924     public function setBrowser($browser)
       
   925     {
       
   926         $this->_browser = $browser;
       
   927     }
       
   928 
       
   929     /**
       
   930      * @param string $browserVersion
       
   931      */
       
   932     public function setBrowserVersion($browserVersion)
       
   933     {
       
   934         $this->_browserVersion = $browserVersion;
       
   935     }
       
   936 
       
   937     /**
       
   938      * @param string $userAgent
       
   939      */
       
   940     public function setUserAgent($userAgent)
       
   941     {
       
   942         $this->_userAgent = $userAgent;
       
   943         return $this;
       
   944     }
       
   945 
       
   946     /**
       
   947      * @param array $_images
       
   948      */
       
   949     public function setImages($_images)
       
   950     {
       
   951         $this->_images = $_images;
       
   952     }
       
   953 
       
   954     /**
       
   955      * Match a user agent string against a list of signatures
       
   956      * 
       
   957      * @param  string $userAgent 
       
   958      * @param  array $signatures 
       
   959      * @return bool
       
   960      */
       
   961     protected static function _matchAgentAgainstSignatures($userAgent, $signatures)
       
   962     {
       
   963         $userAgent = strtolower($userAgent);
       
   964         foreach ($signatures as $signature) {
       
   965             if (!empty($signature)) {
       
   966                 if (strpos($userAgent, $signature) !== false) {
       
   967                     // Browser signature was found in user agent string
       
   968                     return true;
       
   969                 }
       
   970             }
       
   971         }
       
   972         return false;
       
   973     }
       
   974 }