File indexing completed on 2024-05-26 06:03:07

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Http
0017  * @subpackage UserAgent
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  */
0021 
0022 // require_once 'Zend/Http/UserAgent/Device.php';
0023 
0024 /**
0025  * Abstract Class to define a browser device.
0026  *
0027  * @category   Zend
0028  * @package    Zend_Http
0029  * @subpackage UserAgent
0030  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0031  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0032  */
0033 abstract class Zend_Http_UserAgent_AbstractDevice
0034     implements Zend_Http_UserAgent_Device
0035 {
0036     /**
0037      * Browser signature
0038      *
0039      * @var string
0040      */
0041     protected $_browser = '';
0042 
0043     /**
0044      * Browser version
0045      *
0046      * @var string
0047      */
0048     protected $_browserVersion = '';
0049 
0050     /**
0051      * Configuration
0052      *
0053      * @var array
0054      */
0055     protected $_config;
0056 
0057     /**
0058      * User Agent chain
0059      *
0060      * @var string
0061      */
0062     protected $_userAgent;
0063 
0064     /**
0065      * Server variable
0066      *
0067      * @var array
0068      */
0069     protected $_server;
0070 
0071     /**
0072      * Image types
0073      *
0074      * @var array
0075      */
0076     protected $_images = array(
0077         'jpeg',
0078         'gif',
0079         'png',
0080         'pjpeg',
0081         'x-png',
0082         'bmp',
0083     );
0084 
0085     /**
0086      * Browser/Device features
0087      *
0088      * @var array
0089      */
0090     protected $_aFeatures = array();
0091 
0092     /**
0093      * Browser/Device features groups
0094      *
0095      * @var array
0096      */
0097     protected $_aGroup = array();
0098 
0099     /**
0100      * Constructor
0101      *
0102      * @param  null|string|array $userAgent If array, restores from serialized version
0103      * @param  array $server
0104      * @param  array $config
0105      * @return void
0106      */
0107     public function __construct($userAgent = null, array $server = array(), array $config = array())
0108     {
0109         if (is_array($userAgent)) {
0110             // Restoring from serialized array
0111             $this->_restoreFromArray($userAgent);
0112         } else {
0113             // Constructing new object
0114             $this->setUserAgent($userAgent);
0115             $this->_server    = $server;
0116             $this->_config    = $config;
0117             $this->_getDefaultFeatures();
0118             $this->_defineFeatures();
0119         }
0120     }
0121 
0122     /**
0123      * Serialize object
0124      *
0125      * @return string
0126      */
0127     public function serialize()
0128     {
0129         $spec = array(
0130             '_aFeatures'      => $this->_aFeatures,
0131             '_aGroup'         => $this->_aGroup,
0132             '_browser'        => $this->_browser,
0133             '_browserVersion' => $this->_browserVersion,
0134             '_userAgent'      => $this->_userAgent,
0135             '_images'         => $this->_images,
0136         );
0137         return serialize($spec);
0138     }
0139 
0140     /**
0141      * Unserialize
0142      *
0143      * @param  string $serialized
0144      * @return void
0145      */
0146     public function unserialize($serialized)
0147     {
0148         $spec = unserialize($serialized);
0149         $this->_restoreFromArray($spec);
0150     }
0151 
0152     /**
0153      * Restore object state from array
0154      *
0155      * @param  array $spec
0156      * @return void
0157      */
0158     protected function _restoreFromArray(array $spec)
0159     {
0160         foreach ($spec as $key => $value) {
0161             if (property_exists($this, $key)) {
0162                 $this->{$key} = $value;
0163             }
0164         }
0165     }
0166 
0167     /**
0168      * Look for features
0169      *
0170      * @return array|null
0171      */
0172     protected function _defineFeatures()
0173     {
0174         $features = $this->_loadFeaturesAdapter();
0175 
0176         if (is_array($features)) {
0177             $this->_aFeatures = array_merge($this->_aFeatures, $features);
0178         }
0179 
0180         return $this->_aFeatures;
0181     }
0182 
0183     /**
0184      * Gets the browser type identifier
0185      *
0186      * @return string
0187      */
0188     abstract public function getType();
0189 
0190     /**
0191      * Check a feature for the current browser/device.
0192      *
0193      * @param  string $feature The feature to check.
0194      * @return bool
0195      */
0196     public function hasFeature($feature)
0197     {
0198         return (isset($this->_aFeatures[$feature]) && !is_null($this->_aFeatures[$feature]));
0199     }
0200 
0201     /**
0202      * Gets the value of the current browser/device feature
0203      *
0204      * @param  string $feature Feature to search
0205      * @return string|null
0206      */
0207     public function getFeature($feature)
0208     {
0209         if ($this->hasFeature($feature)) {
0210             return $this->_aFeatures[$feature];
0211         }
0212     }
0213 
0214     /**
0215      * Set a feature for the current browser/device.
0216      *
0217      * @param  string $feature The feature to set.
0218      * @param  string $value (option) feature value.
0219      * @param  string $group (option) Group to associate with the feature
0220      * @return Zend_Http_UserAgent_AbstractDevice
0221      */
0222     public function setFeature($feature, $value = false, $group = '')
0223     {
0224         $this->_aFeatures[$feature] = $value;
0225         if (!empty($group)) {
0226             $this->setGroup($group, $feature);
0227         }
0228         return $this;
0229     }
0230 
0231     /**
0232      * Affects a feature to a group
0233      *
0234      * @param  string $group Group name
0235      * @param  string $feature Feature name
0236      * @return Zend_Http_UserAgent_AbstractDevice
0237      */
0238     public function setGroup($group, $feature)
0239     {
0240         if (!isset($this->_aGroup[$group])) {
0241             $this->_aGroup[$group] = array();
0242         }
0243         if (!in_array($feature, $this->_aGroup[$group])) {
0244             $this->_aGroup[$group][] = $feature;
0245         }
0246         return $this;
0247     }
0248 
0249     /**
0250      * Gets an array of features associated to a group
0251      *
0252      * @param  string $group Group param
0253      * @return array
0254      */
0255     public function getGroup($group)
0256     {
0257         return $this->_aGroup[$group];
0258     }
0259 
0260     /**
0261      * Gets all the browser/device features
0262      *
0263      * @return array
0264      */
0265     public function getAllFeatures()
0266     {
0267         return $this->_aFeatures;
0268     }
0269 
0270     /**
0271      * Gets all the browser/device features' groups
0272      *
0273      * @return array
0274      */
0275     public function getAllGroups()
0276     {
0277         return $this->_aGroup;
0278     }
0279 
0280     /**
0281      * Sets all the standard features extracted from the User Agent chain and $this->_server
0282      * vars
0283      *
0284      * @return void
0285      */
0286     protected function _getDefaultFeatures()
0287     {
0288         $server = array();
0289 
0290         // gets info from user agent chain
0291         $uaExtract = $this->extractFromUserAgent($this->getUserAgent());
0292 
0293         if (is_array($uaExtract)) {
0294             foreach ($uaExtract as $key => $info) {
0295                 $this->setFeature($key, $info, 'product_info');
0296             }
0297         }
0298 
0299         if (isset($uaExtract['browser_name'])) {
0300             $this->_browser = $uaExtract['browser_name'];
0301         }
0302         if (isset($uaExtract['browser_version'])) {
0303             $this->_browserVersion = $uaExtract['browser_version'];
0304         }
0305         if (isset($uaExtract['device_os'])) {
0306             $this->device_os = $uaExtract['device_os_name'];
0307         }
0308 
0309         /* browser & device info */
0310         $this->setFeature('is_wireless_device', false, 'product_info');
0311         $this->setFeature('is_mobile', false, 'product_info');
0312         $this->setFeature('is_desktop', false, 'product_info');
0313         $this->setFeature('is_tablet', false, 'product_info');
0314         $this->setFeature('is_bot', false, 'product_info');
0315         $this->setFeature('is_email', false, 'product_info');
0316         $this->setFeature('is_text', false, 'product_info');
0317         $this->setFeature('device_claims_web_support', false, 'product_info');
0318 
0319         $this->setFeature('is_' . strtolower($this->getType()), true, 'product_info');
0320 
0321         /* sets the browser name */
0322         if (isset($this->list) && empty($this->_browser)) {
0323             $lowerUserAgent = strtolower($this->getUserAgent());
0324             foreach ($this->list as $browser_signature) {
0325                 if (strpos($lowerUserAgent, $browser_signature) !== false) {
0326                     $this->_browser = strtolower($browser_signature);
0327                     $this->setFeature('browser_name', $this->_browser, 'product_info');
0328                 }
0329             }
0330         }
0331 
0332         /* sets the client IP */
0333         if (isset($this->_server['remote_addr'])) {
0334             $this->setFeature('client_ip', $this->_server['remote_addr'], 'product_info');
0335         } elseif (isset($this->_server['http_x_forwarded_for'])) {
0336             $this->setFeature('client_ip', $this->_server['http_x_forwarded_for'], 'product_info');
0337         } elseif (isset($this->_server['http_client_ip'])) {
0338             $this->setFeature('client_ip', $this->_server['http_client_ip'], 'product_info');
0339         }
0340 
0341         /* sets the server infos */
0342         if (isset($this->_server['server_software'])) {
0343             if (strpos($this->_server['server_software'], 'Apache') !== false || strpos($this->_server['server_software'], 'LiteSpeed') !== false) {
0344                 $server['version'] = 1;
0345                 if (strpos($this->_server['server_software'], 'Apache/2') !== false) {
0346                     $server['version'] = 2;
0347                 }
0348                 $server['server'] = 'apache';
0349             }
0350 
0351             if (strpos($this->_server['server_software'], 'Microsoft-IIS') !== false) {
0352                 $server['server'] = 'iis';
0353             }
0354 
0355             if (strpos($this->_server['server_software'], 'Unix') !== false) {
0356                 $server['os'] = 'unix';
0357                 if (isset($_ENV['MACHTYPE'])) {
0358                     if (strpos($_ENV['MACHTYPE'], 'linux') !== false) {
0359                         $server['os'] = 'linux';
0360                     }
0361                 }
0362             } elseif (strpos($this->_server['server_software'], 'Win') !== false) {
0363                 $server['os'] = 'windows';
0364             }
0365 
0366             if (preg_match('/Apache\/([0-9\.]*)/', $this->_server['server_software'], $arr)) {
0367                 if ($arr[1]) {
0368                     $server['version'] = $arr[1];
0369                     $server['server']  = 'apache';
0370                 }
0371             }
0372         }
0373 
0374         $this->setFeature('php_version', phpversion(), 'server_info');
0375         if (isset($server['server'])) {
0376             $this->setFeature('server_os', $server['server'], 'server_info');
0377         }
0378         if (isset($server['version'])) {
0379             $this->setFeature('server_os_version', $server['version'], 'server_info');
0380         }
0381         if (isset($this->_server['http_accept'])) {
0382             $this->setFeature('server_http_accept', $this->_server['http_accept'], 'server_info');
0383         }
0384         if (isset($this->_server['http_accept_language'])) {
0385             $this->setFeature('server_http_accept_language', $this->_server['http_accept_language'], 'server_info');
0386         }
0387         if (isset($this->_server['server_addr'])) {
0388             $this->setFeature('server_ip', $this->_server['server_addr'], 'server_info');
0389         }
0390         if (isset($this->_server['server_name'])) {
0391             $this->setFeature('server_name', $this->_server['server_name'], 'server_info');
0392         }
0393     }
0394 
0395     /**
0396      * Extract and sets informations from the User Agent chain
0397      *
0398      * @param  string $userAgent User Agent chain
0399      * @return array
0400      */
0401     public static function extractFromUserAgent($userAgent)
0402     {
0403         $userAgent = trim($userAgent);
0404 
0405         /**
0406          * @see http://www.texsoft.it/index.php?c=software&m=sw.php.useragent&l=it
0407          */
0408         $pattern =  "(([^/\s]*)(/(\S*))?)(\s*\[[a-zA-Z][a-zA-Z]\])?\s*(\\((([^()]|(\\([^()]*\\)))*)\\))?\s*";
0409         preg_match("#^$pattern#", $userAgent, $match);
0410 
0411         $comment = array();
0412         if (isset($match[7])) {
0413             $comment = explode(';', $match[7]);
0414         }
0415 
0416         // second part if exists
0417         $end = substr($userAgent, strlen($match[0]));
0418         if (!empty($end)) {
0419             $result['others']['full'] = $end;
0420         }
0421 
0422         $match2 = array();
0423         if (isset($result['others'])) {
0424             preg_match_all('/(([^\/\s]*)(\/)?([^\/\(\)\s]*)?)(\s\((([^\)]*)*)\))?/i', $result['others']['full'], $match2);
0425         }
0426         $result['user_agent']   = trim($match[1]);
0427         $result['product_name'] = isset($match[2]) ? trim($match[2]) : '';
0428         $result['browser_name'] = $result['product_name'];
0429         if (isset($match[4]) && trim($match[4])) {
0430             $result['product_version'] = trim($match[4]);
0431             $result['browser_version'] = trim($match[4]);
0432         }
0433         if (count($comment) && !empty($comment[0])) {
0434             $result['comment']['full']     = trim($match[7]);
0435             $result['comment']['detail']   = $comment;
0436             $result['compatibility_flag']  = trim($comment[0]);
0437             if (isset($comment[1])) {
0438                 $result['browser_token']   = trim($comment[1]);
0439             }
0440             if (isset($comment[2])) {
0441                 $result['device_os_token'] = trim($comment[2]);
0442             }
0443         }
0444         if (empty($result['device_os_token']) && !empty($result['compatibility_flag'])) {
0445             // some browsers do not have a platform token
0446             $result['device_os_token'] = $result['compatibility_flag'];
0447         }
0448         if ($match2) {
0449             $i = 0;
0450             $max = count($match2[0]);
0451             for ($i = 0; $i < $max; $i ++) {
0452                 if (!empty($match2[0][$i])) {
0453                     $result['others']['detail'][] = array(
0454                         $match2[0][$i],
0455                         $match2[2][$i],
0456                         $match2[4][$i],
0457                     );
0458                 }
0459             }
0460         }
0461 
0462         /** Security level */
0463         $security = array(
0464             'N' => 'no security',
0465             'U' => 'strong security',
0466             'I' => 'weak security',
0467         );
0468         if (!empty($result['browser_token'])) {
0469             if (isset($security[$result['browser_token']])) {
0470                 $result['security_level'] = $security[$result['browser_token']];
0471                 unset($result['browser_token']);
0472             }
0473         }
0474 
0475         $product = strtolower($result['browser_name']);
0476 
0477         // Mozilla : true && false
0478         $compatibleOrIe = false;
0479         if (isset($result['compatibility_flag']) && isset($result['comment'])) {
0480             $compatibleOrIe = ($result['compatibility_flag'] == 'compatible' || strpos($result['comment']['full'], "MSIE") !== false);
0481         }
0482         if ($product == 'mozilla' && $compatibleOrIe) {
0483             if (!empty($result['browser_token'])) {
0484                 // Classic Mozilla chain
0485                 preg_match_all('/([^\/\s].*)(\/|\s)(.*)/i', $result['browser_token'], $real);
0486             } else {
0487                 // MSIE specific chain with 'Windows' compatibility flag
0488                 foreach ($result['comment']['detail'] as $v) {
0489                     if (strpos($v, 'MSIE') !== false) {
0490                         $real[0][1]               = trim($v);
0491                         $result['browser_engine'] = "MSIE";
0492                         $real[1][0]               = "Internet Explorer";
0493                         $temp                     = explode(' ', trim($v));
0494                         $real[3][0]               = $temp[1];
0495 
0496                     }
0497                     if (strpos($v, 'Win') !== false) {
0498                         $result['device_os_token'] = trim($v);
0499                     }
0500                 }
0501             }
0502 
0503             if (!empty($real[0])) {
0504                 $result['browser_name']    = $real[1][0];
0505                 $result['browser_version'] = $real[3][0];
0506             } else {
0507                 if(isset($result['browser_token'])) {
0508                     $result['browser_name']    = $result['browser_token'];
0509                 }
0510                 $result['browser_version'] = '??';
0511             }
0512         } elseif ($product == 'mozilla' && isset($result['browser_version'])
0513                   && $result['browser_version'] < 5.0
0514         ) {
0515             // handles the real Mozilla (or old Netscape if version < 5.0)
0516             $result['browser_name'] = 'Netscape';
0517         }
0518 
0519         /** windows */
0520         if ($result['browser_name'] == 'MSIE') {
0521             $result['browser_engine'] = 'MSIE';
0522             $result['browser_name']   = 'Internet Explorer';
0523         }
0524         if (isset($result['device_os_token'])) {
0525             if (strpos($result['device_os_token'], 'Win') !== false) {
0526 
0527                 $windows = array(
0528                     'Windows NT 6.1'          => 'Windows 7',
0529                     'Windows NT 6.0'          => 'Windows Vista',
0530                     'Windows NT 5.2'          => 'Windows Server 2003',
0531                     'Windows NT 5.1'          => 'Windows XP',
0532                     'Windows NT 5.01'         => 'Windows 2000 SP1',
0533                     'Windows NT 5.0'          => 'Windows 2000',
0534                     'Windows NT 4.0'          => 'Microsoft Windows NT 4.0',
0535                     'WinNT'                   => 'Microsoft Windows NT 4.0',
0536                     'Windows 98; Win 9x 4.90' => 'Windows Me',
0537                     'Windows 98'              => 'Windows 98',
0538                     'Win98'                   => 'Windows 98',
0539                     'Windows 95'              => 'Windows 95',
0540                     'Win95'                   => 'Windows 95',
0541                     'Windows CE'              => 'Windows CE',
0542                 );
0543                 if (isset($windows[$result['device_os_token']])) {
0544                     $result['device_os_name'] = $windows[$result['device_os_token']];
0545                 } else {
0546                     $result['device_os_name'] = $result['device_os_token'];
0547                 }
0548             }
0549         }
0550 
0551         // iphone
0552         $apple_device = array(
0553             'iPhone',
0554             'iPod',
0555             'iPad',
0556         );
0557         if (isset($result['compatibility_flag'])) {
0558             if (in_array($result['compatibility_flag'], $apple_device)) {
0559                 $result['device']           = strtolower($result['compatibility_flag']);
0560                 $result['device_os_token']  = 'iPhone OS';
0561                 if (isset($comment[3])) {
0562                     $result['browser_language'] = trim($comment[3]);
0563                 }
0564                 if (isset($result['others']['detail'][1])) {
0565                     $result['browser_version']  = $result['others']['detail'][1][2];
0566                 } elseif (isset($result['others']['detail']) && count($result['others']['detail'])) {
0567                     $result['browser_version']  = $result['others']['detail'][0][2];
0568                 }
0569                 if (!empty($result['others']['detail'][2])) {
0570                     $result['firmware'] = $result['others']['detail'][2][2];
0571                 }
0572                 if (!empty($result['others']['detail'][3])) {
0573                     $result['browser_name']  = $result['others']['detail'][3][1];
0574                     $result['browser_build'] = $result['others']['detail'][3][2];
0575                 }
0576             }
0577         }
0578 
0579         // Safari
0580         if (isset($result['others'])) {
0581             if ($result['others']['detail'][0][1] == 'AppleWebKit') {
0582                 $result['browser_engine'] = 'AppleWebKit';
0583                 if (isset($result['others']['detail'][1]) && $result['others']['detail'][1][1] == 'Version') {
0584                     $result['browser_version'] = $result['others']['detail'][1][2];
0585                 } else {
0586                     $result['browser_version'] = $result['others']['detail'][count($result['others']['detail']) - 1][2];
0587                 }
0588                 if (isset($comment[3])) {
0589                      $result['browser_language'] = trim($comment[3]);
0590                 }
0591 
0592                 $last = $result['others']['detail'][count($result['others']['detail']) - 1][1];
0593 
0594                 if (empty($result['others']['detail'][2][1]) || $result['others']['detail'][2][1] == 'Safari') {
0595                     if (isset($result['others']['detail'][1])) {
0596                         $result['browser_name']    = ($result['others']['detail'][1][1] && $result['others']['detail'][1][1] != 'Version' ? $result['others']['detail'][1][1] : 'Safari');
0597                         $result['browser_version'] = ($result['others']['detail'][1][2] ? $result['others']['detail'][1][2] : $result['others']['detail'][0][2]);
0598                     } else {
0599                         $result['browser_name']    = ($result['others']['detail'][0][1] && $result['others']['detail'][0][1] != 'Version' ? $result['others']['detail'][0][1] : 'Safari');
0600                         $result['browser_version'] = $result['others']['detail'][0][2];
0601                     }
0602                 } else {
0603                     $result['browser_name']    = $result['others']['detail'][2][1];
0604                     $result['browser_version'] = $result['others']['detail'][2][2];
0605 
0606                     // mobile version
0607                     if ($result['browser_name'] == 'Mobile') {
0608                         $result['browser_name'] = 'Safari ' . $result['browser_name'];
0609                         if ($result['others']['detail'][1][1] == 'Version') {
0610                             $result['browser_version'] = $result['others']['detail'][1][2];
0611                         }
0612                     }
0613                 }
0614 
0615                 // For Safari < 2.2, AppleWebKit version gives the Safari version
0616                 if (strpos($result['browser_version'], '.') > 2 || (int) $result['browser_version'] > 20) {
0617                     $temp = explode('.', $result['browser_version']);
0618                     $build = (int) $temp[0];
0619                     $awkVersion = array(
0620                         48  => '0.8',
0621                         73  => '0.9',
0622                         85  => '1.0',
0623                         103 => '1.1',
0624                         124 => '1.2',
0625                         300 => '1.3',
0626                         400 => '2.0',
0627                     );
0628                     foreach ($awkVersion as $k => $v) {
0629                         if ($build >= $k) {
0630                             $result['browser_version'] = $v;
0631                         }
0632                     }
0633                 }
0634             }
0635 
0636             // Gecko (Firefox or compatible)
0637             if ($result['others']['detail'][0][1] == 'Gecko') {
0638                 $searchRV = true;
0639                 if (!empty($result['others']['detail'][1][1]) && !empty($result['others']['detail'][count($result['others']['detail']) - 1][2]) || strpos(strtolower($result['others']['full']), 'opera') !== false) {
0640                     $searchRV = false;
0641                     $result['browser_engine'] = $result['others']['detail'][0][1];
0642 
0643                     // the name of the application is at the end indepenently
0644                     // of quantity of information in $result['others']['detail']
0645                     $last = count($result['others']['detail']) - 1;
0646 
0647                     // exception : if the version of the last information is
0648                     // empty we take the previous one
0649                     if (empty($result['others']['detail'][$last][2])) {
0650                         $last --;
0651                     }
0652 
0653                     // exception : if the last one is 'Red Hat' or 'Debian' =>
0654                     // use rv: to find browser_version */
0655                     if (in_array($result['others']['detail'][$last][1], array(
0656                         'Debian',
0657                         'Hat',
0658                     ))) {
0659                         $searchRV = true;
0660                     }
0661                     $result['browser_name']    = $result['others']['detail'][$last][1];
0662                     $result['browser_version'] = $result['others']['detail'][$last][2];
0663                     if (isset($comment[4])) {
0664                         $result['browser_build'] = trim($comment[4]);
0665                     }
0666                     if (isset($comment[3])) {
0667                         $result['browser_language'] = trim($comment[3]);
0668                     }
0669 
0670                     // Netscape
0671                     if ($result['browser_name'] == 'Navigator' || $result['browser_name'] == 'Netscape6') {
0672                         $result['browser_name'] = 'Netscape';
0673                     }
0674                 }
0675                 if ($searchRV) {
0676                     // Mozilla alone : the version is identified by rv:
0677                     $result['browser_name'] = 'Mozilla';
0678                     if (isset($result['comment']['detail'])) {
0679                         foreach ($result['comment']['detail'] as $rv) {
0680                             if (strpos($rv, 'rv:') !== false) {
0681                                 $result['browser_version'] = trim(str_replace('rv:', '', $rv));
0682                             }
0683                         }
0684                     }
0685                 }
0686             }
0687 
0688             // Netscape
0689             if ($result['others']['detail'][0][1] == 'Netscape') {
0690                 $result['browser_name']    = 'Netscape';
0691                 $result['browser_version'] = $result['others']['detail'][0][2];
0692             }
0693 
0694             // Opera
0695             // Opera: engine Presto
0696             if ($result['others']['detail'][0][1] == 'Presto') {
0697                 $result['browser_engine'] = 'Presto';
0698                 if (!empty($result['others']['detail'][1][2])) {
0699                     $result['browser_version'] = $result['others']['detail'][1][2];
0700                 }
0701             }
0702 
0703             // UA ends with 'Opera X.XX' or 'Opera/X.XX'
0704             if ($result['others']['detail'][0][1] == 'Opera') {
0705                 $result['browser_name']    = $result['others']['detail'][0][1];
0706                 // Opera X.XX
0707                 if (isset($result['others']['detail'][1][1])) {
0708                     $result['browser_version'] = $result['others']['detail'][1][1];
0709                 // Opera/X.XX
0710                 } elseif (isset($result['others']['detail'][0][2])) {
0711                     $result['browser_version'] = $result['others']['detail'][0][2];
0712                 }
0713             }
0714 
0715             // Opera Mini
0716             if (isset($result["browser_token"])) {
0717                 if (strpos($result["browser_token"], 'Opera Mini') !== false) {
0718                     $result['browser_name'] = 'Opera Mini';
0719                 }
0720             }
0721 
0722             // Symbian
0723             if ($result['others']['detail'][0][1] == 'SymbianOS') {
0724                 $result['device_os_token'] = 'SymbianOS';
0725             }
0726         }
0727 
0728         // UA ends with 'Opera X.XX'
0729         if (isset($result['browser_name']) && isset($result['browser_engine'])) {
0730             if ($result['browser_name'] == 'Opera' && $result['browser_engine'] == 'Gecko' && empty($result['browser_version'])) {
0731                 $result['browser_version'] = $result['others']['detail'][count($result['others']['detail']) - 1][1];
0732             }
0733         }
0734 
0735         // cleanup
0736         if (isset($result['browser_version']) && isset($result['browser_build'])) {
0737             if ($result['browser_version'] == $result['browser_build']) {
0738                 unset($result['browser_build']);
0739             }
0740         }
0741 
0742         // compatibility
0743         $compatibility['AppleWebKit'] = 'Safari';
0744         $compatibility['Gecko']       = 'Firefox';
0745         $compatibility['MSIE']        = 'Internet Explorer';
0746         $compatibility['Presto']      = 'Opera';
0747         if (!empty($result['browser_engine'])) {
0748             if (isset($compatibility[$result['browser_engine']])) {
0749                 $result['browser_compatibility'] = $compatibility[$result['browser_engine']];
0750             }
0751         }
0752 
0753         ksort($result);
0754         return $result;
0755     }
0756 
0757     /**
0758      * Loads the Features Adapter if it's defined in the $config array
0759      * Otherwise, nothing is done
0760      *
0761      * @param  string $browserType Browser type
0762      * @return array
0763      */
0764     protected function _loadFeaturesAdapter()
0765     {
0766         $config      = $this->_config;
0767         $browserType = $this->getType();
0768         if (!isset($config[$browserType]) || !isset($config[$browserType]['features'])) {
0769             return array();
0770         }
0771         $config = $config[$browserType]['features'];
0772 
0773         if (empty($config['classname'])) {
0774             // require_once 'Zend/Http/UserAgent/Exception.php';
0775             throw new Zend_Http_UserAgent_Exception('The ' . $this->getType() . ' features adapter must have a "classname" config parameter defined');
0776         }
0777 
0778         $className = $config['classname'];
0779         if (!class_exists($className)) {
0780             if (isset($config['path'])) {
0781                 $path = $config['path'];
0782             } else {
0783                 // require_once 'Zend/Http/UserAgent/Exception.php';
0784                 throw new Zend_Http_UserAgent_Exception('The ' . $this->getType() . ' features adapter must have a "path" config parameter defined');
0785             }
0786 
0787             if (false === include_once ($path)) {
0788                 // require_once 'Zend/Http/UserAgent/Exception.php';
0789                 throw new Zend_Http_UserAgent_Exception('The ' . $this->getType() . ' features adapter path that does not exist');
0790             }
0791         }
0792 
0793         return call_user_func(array($className, 'getFromRequest'), $this->_server, $this->_config);
0794     }
0795 
0796     /**
0797      * Retrieve image format support
0798      *
0799      * @return array
0800      */
0801     public function getImageFormatSupport()
0802     {
0803         return $this->_images;
0804     }
0805 
0806     /**
0807      * Get maximum image height supported by this device
0808      *
0809      * @return int
0810      */
0811     public function getMaxImageHeight()
0812     {
0813         return null;
0814     }
0815 
0816     /**
0817      * Get maximum image width supported by this device
0818      *
0819      * @return int
0820      */
0821     public function getMaxImageWidth()
0822     {
0823         return null;
0824     }
0825 
0826     /**
0827      * Get physical screen height of this device
0828      *
0829      * @return int
0830      */
0831     public function getPhysicalScreenHeight()
0832     {
0833         return null;
0834     }
0835 
0836     /**
0837      * Get physical screen width of this device
0838      *
0839      * @return int
0840      */
0841     public function getPhysicalScreenWidth()
0842     {
0843         return null;
0844     }
0845 
0846     /**
0847      * Get preferred markup type
0848      *
0849      * @return string
0850      */
0851     public function getPreferredMarkup()
0852     {
0853         return 'xhtml';
0854     }
0855 
0856     /**
0857      * Get supported X/HTML version
0858      *
0859      * @return int
0860      */
0861     public function getXhtmlSupportLevel()
0862     {
0863         return 4;
0864     }
0865 
0866     /**
0867      * Does the device support Flash?
0868      *
0869      * @return bool
0870      */
0871     public function hasFlashSupport()
0872     {
0873         return true;
0874     }
0875 
0876     /**
0877      * Does the device support PDF?
0878      *
0879      * @return bool
0880      */
0881     public function hasPdfSupport()
0882     {
0883         return true;
0884     }
0885 
0886     /**
0887      * Does the device have a phone number associated with it?
0888      *
0889      * @return bool
0890      */
0891     public function hasPhoneNumber()
0892     {
0893         return false;
0894     }
0895 
0896     /**
0897      * Does the device support HTTPS?
0898      *
0899      * @return bool
0900      */
0901     public function httpsSupport()
0902     {
0903         return true;
0904     }
0905 
0906     /**
0907      * Get the browser type
0908      *
0909      * @return string
0910      */
0911     public function getBrowser()
0912     {
0913         return $this->_browser;
0914     }
0915 
0916     /**
0917      * Get the browser version
0918      *
0919      * @return string
0920      */
0921     public function getBrowserVersion()
0922     {
0923         return $this->_browserVersion;
0924     }
0925 
0926     /**
0927      * Get the user agent string
0928      *
0929      * @return string
0930      */
0931     public function getUserAgent()
0932     {
0933         return $this->_userAgent;
0934     }
0935 
0936     /**
0937      * @return the $_images
0938      */
0939     public function getImages()
0940     {
0941         return $this->_images;
0942     }
0943 
0944     /**
0945      * @param string $browser
0946      */
0947     public function setBrowser($browser)
0948     {
0949         $this->_browser = $browser;
0950     }
0951 
0952     /**
0953      * @param string $browserVersion
0954      */
0955     public function setBrowserVersion($browserVersion)
0956     {
0957         $this->_browserVersion = $browserVersion;
0958     }
0959 
0960     /**
0961      * @param string $userAgent
0962      */
0963     public function setUserAgent($userAgent)
0964     {
0965         $this->_userAgent = $userAgent;
0966         return $this;
0967     }
0968 
0969     /**
0970      * @param array $_images
0971      */
0972     public function setImages($_images)
0973     {
0974         $this->_images = $_images;
0975     }
0976 
0977     /**
0978      * Match a user agent string against a list of signatures
0979      *
0980      * @param  string $userAgent
0981      * @param  array $signatures
0982      * @return bool
0983      */
0984     protected static function _matchAgentAgainstSignatures($userAgent, $signatures)
0985     {
0986         $userAgent = strtolower($userAgent);
0987         foreach ($signatures as $signature) {
0988             if (!empty($signature)) {
0989                 if (strpos($userAgent, $signature) !== false) {
0990                     // Browser signature was found in user agent string
0991                     return true;
0992                 }
0993             }
0994         }
0995         return false;
0996     }
0997 }