Skip to content
Extraits de code Groupes Projets
UserAgentParserEnhanced.php 29,8 ko
Newer Older
  • Learn to ignore specific revisions
  • mattab's avatar
    mattab a validé
    <?php
    /**
     * Piwik - Open source web analytics
     *
     * @link http://piwik.org
     * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
     *
     */
    //yml parser
    
    require_once(PIWIK_INCLUDE_PATH . '/libs/spyc.php');
    
    mattab's avatar
    mattab a validé
    
    class UserAgentParserEnhanced
    {
    
        public static $deviceTypes = array(
    
            'desktop',          // 0
            'smartphone',       // 1
            'tablet',           // 2
            'feature phone',    // 3
            'console',          // 4
            'tv',               // 5
            'car browser',      // 6
    
            'smart display',    // 7
            'camera'            // 8
    
    mattab's avatar
    mattab a validé
    
        public static $deviceBrands = array(
            'AC' => 'Acer',
            'AI' => 'Airness',
            'AL' => 'Alcatel',
    
            'AN' => 'Arnova',
    
    mattab's avatar
    mattab a validé
            'AO' => 'Amoi',
            'AP' => 'Apple',
    
            'AR' => 'Archos',
    
    mattab's avatar
    mattab a validé
            'AU' => 'Asus',
            'AV' => 'Avvio',
            'AX' => 'Audiovox',
    
    mattab's avatar
    mattab a validé
            'BE' => 'Becker',
            'BI' => 'Bird',
            'BL' => 'Beetel',
    
            'BO' => 'BangOlufsen',
    
    mattab's avatar
    mattab a validé
            'BQ' => 'BenQ',
            'BS' => 'BenQ-Siemens',
    
    sgiehl's avatar
    sgiehl a validé
            'CA' => 'Cat',
    
    mattab's avatar
    mattab a validé
            'CK' => 'Cricket',
            'CL' => 'Compal',
    
    sgiehl's avatar
    sgiehl a validé
            'CN' => 'CnM',
    
    sgiehl's avatar
    sgiehl a validé
            'CR' => 'CreNova',
    
    mattab's avatar
    mattab a validé
            'CT' => 'Capitel',
    
            'CO' => 'Coolpad',
    
            'CU' => 'Cube',
    
            'DE' => 'Denver',
    
    mattab's avatar
    mattab a validé
            'DB' => 'Dbtel',
            'DC' => 'DoCoMo',
            'DI' => 'Dicam',
            'DL' => 'Dell',
    
    mattab's avatar
    mattab a validé
            'DP' => 'Dopod',
            'EC' => 'Ericsson',
            'EI' => 'Ezio',
            'ER' => 'Ericy',
            'ET' => 'eTouch',
            'EZ' => 'Ezze',
            'FL' => 'Fly',
    
            'GD' => 'Gemini',
    
    mattab's avatar
    mattab a validé
            'GI' => 'Gionee',
    
            'GG' => 'Gigabyte',
    
    mattab's avatar
    mattab a validé
            'GO' => 'Google',
            'GR' => 'Gradiente',
            'GU' => 'Grundig',
            'HA' => 'Haier',
            'HP' => 'HP',
            'HT' => 'HTC',
            'HU' => 'Huawei',
    
            'HX' => 'Humax',
            'IA' => 'Ikea',
    
    mattab's avatar
    mattab a validé
            'IK' => 'iKoMo',
            'IM' => 'i-mate',
            'IN' => 'Innostream',
            'IO' => 'i-mobile',
            'IQ' => 'INQ',
    
            'IT' => 'Intek',
            'IV' => 'Inverto',
    
            'JI' => 'Jiayu',
    
    mattab's avatar
    mattab a validé
            'KA' => 'Karbonn',
            'KD' => 'KDDI',
            'KN' => 'Kindle',
            'KO' => 'Konka',
    
            'KT' => 'K-Touch',
    
            'KH' => 'KT-Tech',
    
    mattab's avatar
    mattab a validé
            'KY' => 'Kyocera',
            'LA' => 'Lanix',
            'LC' => 'LCT',
            'LE' => 'Lenovo',
            'LG' => 'LG',
    
    mattab's avatar
    mattab a validé
            'LU' => 'LGUPlus',
    
            'MA' => 'Manta Multimedia',
    
            'MD' => 'Medion',
            'ME' => 'Metz',
    
    mattab's avatar
    mattab a validé
            'MI' => 'MicroMax',
    
            'MK' => 'MediaTek',
    
    mattab's avatar
    mattab a validé
            'MO' => 'Mio',
            'MR' => 'Motorola',
            'MS' => 'Microsoft',
            'MT' => 'Mitsubishi',
            'MY' => 'MyPhone',
            'NE' => 'NEC',
            'NG' => 'NGM',
            'NI' => 'Nintendo',
            'NK' => 'Nokia',
    
    mattab's avatar
    mattab a validé
            'NW' => 'Newgen',
            'NX' => 'Nexian',
            'OD' => 'Onda',
            'OP' => 'OPPO',
            'OR' => 'Orange',
            'OT' => 'O2',
    
    mattab's avatar
    mattab a validé
            'PA' => 'Panasonic',
    
    mattab's avatar
    mattab a validé
            'PH' => 'Philips',
    
            'PL' => 'Polaroid',
    
    mattab's avatar
    mattab a validé
            'PM' => 'Palm',
            'PO' => 'phoneOne',
            'PT' => 'Pantech',
    
            'PP' => 'PolyPad',
    
            'PR' => 'Prestigio',
    
    mattab's avatar
    mattab a validé
            'QT' => 'Qtek',
            'RM' => 'RIM',
            'RO' => 'Rover',
            'SA' => 'Samsung',
            'SD' => 'Sega',
            'SE' => 'Sony Ericsson',
            'SF' => 'Softbank',
            'SG' => 'Sagem',
            'SH' => 'Sharp',
            'SI' => 'Siemens',
            'SN' => 'Sendo',
            'SO' => 'Sony',
            'SP' => 'Spice',
    
            'SU' => 'SuperSonic',
    
            'SV' => 'Selevision',
    
    mattab's avatar
    mattab a validé
            'SY' => 'Sanyo',
    
            'SM' => 'Symphony',
    
    mattab's avatar
    mattab a validé
            'TA' => 'Tesla',
            'TC' => 'TCL',
            'TE' => 'Telit',
            'TH' => 'TiPhone',
            'TI' => 'TIANYU',
    
            'TL' => 'Telefunken',
    
    mattab's avatar
    mattab a validé
            'TM' => 'T-Mobile',
    
    mattab's avatar
    mattab a validé
            'TO' => 'Toplux',
            'TS' => 'Toshiba',
    
            'TT' => 'TechnoTrend',
    
            'TX' => 'TechniSat',
    
            'TZ' => 'teXet',
    
    mattab's avatar
    mattab a validé
            'UT' => 'UTStarcom',
            'VD' => 'Videocon',
            'VE' => 'Vertu',
            'VI' => 'Vitelcom',
            'VK' => 'VK Mobile',
    
    mattab's avatar
    mattab a validé
            'VO' => 'Voxtel',
    
            'VW' => 'Videoweb',
    
    mattab's avatar
    mattab a validé
            'WB' => 'Web TV',
            'WE' => 'WellcoM',
            'WO' => 'Wonu',
    
            'WX' => 'Woxter',
    
            'XI' => 'Xiaomi',
    
    mattab's avatar
    mattab a validé
            'XX' => 'Unknown',
    
            'YU' => 'Yuandao',
    
    mattab's avatar
    mattab a validé
            'ZO' => 'Zonda',
            'ZT' => 'ZTE',
        );
        public static $osShorts = array(
    
            'AIX'                  => 'AIX',
            'Android'              => 'AND',
    
    sgiehl's avatar
    sgiehl a validé
            'AmigaOS'              => 'AMG',
    
            'Apple TV'             => 'ATV',
            'Arch Linux'           => 'ARL',
            'BackTrack'            => 'BTR',
            'Bada'                 => 'SBA',
    
            'BlackBerry OS'        => 'BLB',
    
    mattab's avatar
    mattab a validé
            'BlackBerry Tablet OS' => 'QNX',
    
            'Bot'                  => 'BOT',
            'Brew'                 => 'BMP',
            'CentOS'               => 'CES',
            'Chrome OS'            => 'COS',
            'Debian'               => 'DEB',
            'DragonFly'            => 'DFB',
            'Fedora'               => 'FED',
            'Firefox OS'           => 'FOS',
            'FreeBSD'              => 'BSD',
            'Gentoo'               => 'GNT',
            'Google TV'            => 'GTV',
            'HP-UX'                => 'HPX',
    
            'IRIX'                 => 'IRI',
    
            'Inferno'              => 'INF',
    
            'Knoppix'              => 'KNO',
            'Kubuntu'              => 'KBT',
            'Linux'                => 'LIN',
            'Lubuntu'              => 'LBT',
            'Mac'                  => 'MAC',
            'Mandriva'             => 'MDR',
            'MeeGo'                => 'SMG',
            'Mint'                 => 'MIN',
            'NetBSD'               => 'NBS',
            'Nintendo'             => 'WII',
            'Nintendo Mobile'      => 'NDS',
            'OS/2'                 => 'OS2',
            'OSF1'                 => 'T64',
            'OpenBSD'              => 'OBS',
    
            'PlayStation Portable' => 'PSP',
            'PlayStation'          => 'PS3',
    
            'Presto'               => 'PRS',
            'Puppy'                => 'PPY',
            'Red Hat'              => 'RHT',
    
            'RISC OS'              => 'ROS',
    
            'SUSE'                 => 'SSE',
    
            'Sailfish OS'          => 'SAF',
    
            'Slackware'            => 'SLW',
            'Solaris'              => 'SOS',
            'Syllable'             => 'SYL',
            'Symbian'              => 'SYM',
            'Symbian OS'           => 'SYS',
    
    mattab's avatar
    mattab a validé
            'Symbian OS Series 40' => 'S40',
            'Symbian OS Series 60' => 'S60',
    
            'Symbian^3'            => 'SY3',
            'Talkatone'            => 'TKT',
            'Tizen'                => 'TIZ',
            'Ubuntu'               => 'UBT',
            'WebTV'                => 'WTV',
            'WinWAP'               => 'WWP',
            'Windows'              => 'WIN',
            'Windows 2000'         => 'W2K',
            'Windows 3.1'          => 'W31',
            'Windows 7'            => 'WI7',
            'Windows 8'            => 'WI8',
            'Windows 95'           => 'W95',
            'Windows 98'           => 'W98',
            'Windows CE'           => 'WCE',
            'Windows ME'           => 'WME',
            'Windows Mobile'       => 'WMO',
            'Windows NT'           => 'WNT',
            'Windows Phone'        => 'WPH',
            'Windows RT'           => 'WRT',
            'Windows Server 2003'  => 'WS3',
            'Windows Vista'        => 'WVI',
            'Windows XP'           => 'WXP',
            'Xbox'                 => 'XBX',
            'Xubuntu'              => 'XBT',
            'YunOs'                => 'YNS',
            'iOS'                  => 'IOS',
            'palmOS'               => 'POS',
            'webOS'                => 'WOS'
    
    mattab's avatar
    mattab a validé
        );
    
        protected static $desktopOsArray = array('AmigaOS', 'IBM', 'Linux', 'Mac', 'Unix', 'Windows', 'BeOS');
    
    mattab's avatar
    mattab a validé
        public static $osFamilies = array(
    
            'Android'               => array('AND'),
    
    sgiehl's avatar
    sgiehl a validé
            'AmigaOS'               => array('AMG'),
    
            'Apple TV'              => array('ATV'),
            'BlackBerry'            => array('BLB'),
            'Bot'                   => array('BOT'),
            'Brew'                  => array('BMP'),
    
            'Chrome OS'             => array('COS'),
            'Firefox OS'            => array('FOS'),
            'Gaming Console'        => array('WII', 'PS3'),
            'Google TV'             => array('GTV'),
            'IBM'                   => array('OS2'),
            'iOS'                   => array('IOS'),
    
            'RISC OS'               => array('ROS'),
    
            'Linux'                 => array('LIN', 'ARL', 'DEB', 'KNO', 'MIN', 'UBT', 'KBT', 'XBT', 'LBT', 'FED', 'RHT', 'MDR', 'GNT', 'SAB', 'SLW', 'SSE', 'PPY', 'CES', 'BTR', 'YNS', 'PRS', 'SAF'),
    
            'Mac'                   => array('MAC'),
    
    mattab's avatar
    mattab a validé
            'Mobile Gaming Console' => array('PSP', 'NDS', 'XBX'),
    
            'Other Mobile'          => array('WOS', 'POS', 'QNX', 'SBA', 'TIZ', 'SMG'),
    
            'Simulator'             => array('TKT', 'WWP'),
    
            'Symbian'               => array('SYM', 'SYS', 'SY3', 'S60', 'S40'),
    
            'Unix'                  => array('SOS', 'AIX', 'HPX', 'BSD', 'NBS', 'OBS', 'DFB', 'SYL', 'IRI', 'T64', 'INF'),
    
            'WebTV'                 => array('WTV'),
    
    sgiehl's avatar
    sgiehl a validé
            'Windows'               => array('WI7', 'WI8', 'WVI', 'WS3', 'WXP', 'W2K', 'WNT', 'WME', 'W98', 'W95', 'WRT', 'W31', 'WIN'),
    
            'Windows Mobile'        => array('WPH', 'WMO', 'WCE')
    
    mattab's avatar
    mattab a validé
        );
        public static $browserFamilies = array(
    
            'Android Browser'    => array('AN'),
    
    mattab's avatar
    mattab a validé
            'BlackBerry Browser' => array('BB'),
    
            'Chrome'             => array('CH', 'CD', 'CM', 'CI', 'CF', 'CN', 'CR', 'CP', 'RM'),
    
            'Firefox'            => array('FF', 'FE', 'SX', 'FB', 'PX', 'MB'),
            'Internet Explorer'  => array('IE', 'IM'),
            'Konqueror'          => array('KO'),
            'NetFront'           => array('NF'),
    
            'Nokia Browser'      => array('NB', 'NO', 'NV'),
    
            'Opera'              => array('OP', 'OM', 'OI', 'ON'),
    
            'Safari'             => array('SF', 'MF'),
            'Sailfish Browser'   => array('SA')
    
    mattab's avatar
    mattab a validé
        );
        public static $browsers = array(
    
    mattab's avatar
    mattab a validé
            'AB' => 'ABrowse',
    
            'AG' => 'ANTGalio',
    
    mattab's avatar
    mattab a validé
            'AM' => 'Amaya',
            'AN' => 'Android Browser',
            'AR' => 'Arora',
            'AV' => 'Amiga Voyager',
            'AW' => 'Amiga Aweb',
            'BB' => 'BlackBerry Browser',
            'BD' => 'Baidu Browser',
            'BE' => 'Beonex',
    
            'BJ' => 'Bunjalloo',
    
    mattab's avatar
    mattab a validé
            'BX' => 'BrowseX',
            'CA' => 'Camino',
    
            'CD' => 'Comodo Dragon',
    
            'CX' => 'Charon',
    
    mattab's avatar
    mattab a validé
            'CF' => 'Chrome Frame',
            'CH' => 'Chrome',
            'CI' => 'Chrome Mobile iOS',
            'CK' => 'Conkeror',
            'CM' => 'Chrome Mobile',
    
            'CN' => 'CoolNovo',
    
    mattab's avatar
    mattab a validé
            'CO' => 'CometBird',
    
            'CP' => 'ChromePlus',
    
    mattab's avatar
    mattab a validé
            'CR' => 'Chromium',
            'CS' => 'Cheshire',
            'DF' => 'Dolphin',
            'DI' => 'Dillo',
            'EL' => 'Elinks',
            'EP' => 'Epiphany',
    
            'ES' => 'Espial TV Browser',
    
    mattab's avatar
    mattab a validé
            'FB' => 'Firebird',
            'FD' => 'Fluid',
            'FE' => 'Fennec',
            'FF' => 'Firefox',
            'FL' => 'Flock',
            'FN' => 'Fireweb Navigator',
            'GA' => 'Galeon',
            'GE' => 'Google Earth',
            'HJ' => 'HotJava',
    
            'IA' => 'Iceape',
    
    mattab's avatar
    mattab a validé
            'IB' => 'IBrowse',
            'IC' => 'iCab',
    
            'ID' => 'IceDragon',
    
    mattab's avatar
    mattab a validé
            'IE' => 'Internet Explorer',
            'IM' => 'IE Mobile',
            'IR' => 'Iron',
            'JS' => 'Jasmine',
            'KI' => 'Kindle Browser',
            'KM' => 'K-meleon',
            'KO' => 'Konqueror',
            'KP' => 'Kapiko',
            'KZ' => 'Kazehakase',
            'LG' => 'Lightning',
            'LI' => 'Links',
    
            'LS' => 'Lunascape',
    
    mattab's avatar
    mattab a validé
            'LX' => 'Lynx',
            'MB' => 'MicroB',
            'MC' => 'NCSA Mosaic',
    
    mattab's avatar
    mattab a validé
            'MF' => 'Mobile Safari',
            'MI' => 'Midori',
            'MS' => 'Mobile Silk',
            'MX' => 'Maxthon',
            'NB' => 'Nokia Browser',
    
            'NO' => 'Nokia OSS Browser',
            'NV' => 'Nokia Ovi Browser',
    
    mattab's avatar
    mattab a validé
            'NF' => 'NetFront',
            'NL' => 'NetFront Life',
    
    mattab's avatar
    mattab a validé
            'NS' => 'Netscape',
            'OB' => 'Obigo',
            'OI' => 'Opera Mini',
            'OM' => 'Opera Mobile',
            'OP' => 'Opera',
    
            'ON' => 'Opera Next',
    
            'OR' => 'Oregano',
    
    mattab's avatar
    mattab a validé
            'OV' => 'Openwave Mobile Browser',
            'OW' => 'OmniWeb',
            'PL' => 'Palm Blazer',
    
    mattab's avatar
    mattab a validé
            'PR' => 'Palm Pre',
    
            'PU' => 'Puffin',
    
    mattab's avatar
    mattab a validé
            'PX' => 'Phoenix',
    
            'PO' => 'Polaris',
    
    mattab's avatar
    mattab a validé
            'RK' => 'Rekonq',
            'RM' => 'RockMelt',
    
            'SA' => 'Sailfish Browser',
    
    mattab's avatar
    mattab a validé
            'SF' => 'Safari',
    
            'SL' => 'Sleipnir',
    
    mattab's avatar
    mattab a validé
            'SM' => 'SeaMonkey',
            'SN' => 'Snowshoe',
            'SX' => 'Swiftfox',
    
    sgiehl's avatar
    sgiehl a validé
            'TB' => 'Thunderbird',
    
    mattab's avatar
    mattab a validé
            'TZ' => 'Tizen Browser',
            'UC' => 'UC Browser',
    
    mattab's avatar
    mattab a validé
            'WO' => 'wOSBrowser',
    
    mattab's avatar
    mattab a validé
        );
    
        const UNKNOWN = "UNK";
        protected static $regexesDir = '/regexes/';
        protected static $osRegexesFile = 'oss.yml';
        protected static $browserRegexesFile = 'browsers.yml';
        protected static $mobileRegexesFile = 'mobiles.yml';
    
        protected static $televisionRegexesFile = 'televisions.yml';
    
    mattab's avatar
    mattab a validé
        protected $userAgent;
    
        protected $os = '';
        protected $browser = '';
        protected $device = '';
        protected $brand = '';
        protected $model = '';
    
    mattab's avatar
    mattab a validé
        protected $debug = false;
    
    
        /**
         * @var \Piwik\CacheFile
         */
    
        protected $cache = null;
    
    mattab's avatar
    mattab a validé
    
        public function __construct($userAgent)
        {
            $this->userAgent = $userAgent;
        }
    
        protected function getOsRegexes()
        {
    
            static $regexOs;
    
            if(empty($regexOs)) {
                $regexOs = $this->getRegexList('os', self::$osRegexesFile);
    
    mattab's avatar
    mattab a validé
        }
    
        protected function getBrowserRegexes()
        {
    
            static $regexBrowser;
            if (empty($regexBrowser)) {
    
                $regexBrowser = $this->getRegexList('browser', self::$browserRegexesFile);
    
            }
            return $regexBrowser;
    
    mattab's avatar
    mattab a validé
        }
    
        protected function getMobileRegexes()
        {
    
            static $regexMobile;
            if (empty($regexMobile)) {
    
                $regexMobile = $this->getRegexList('mobile', self::$mobileRegexesFile);
    
            }
            return $regexMobile;
    
    mattab's avatar
    mattab a validé
        }
    
    
        protected function getTelevisionRegexes()
        {
    
            static $regexTvs;
            if (empty($regexTvs)) {
    
                $regexTvs = $this->getRegexList('tv', self::$televisionRegexesFile);
    
    sgiehl's avatar
    sgiehl a validé
            }
            return $regexTvs;
    
        public function setCache($cache)
        {
            $this->cache = $cache;
        }
    
        protected function saveParsedYmlInCache($type, $data)
        {
            if (!empty($this->cache) && method_exists($this->cache, 'set')) {
                $this->cache->set($type, serialize($data));
            }
        }
    
        protected function getParsedYmlFromCache($type)
        {
            $data = null;
            if (!empty($this->cache) && method_exists($this->cache, 'get')) {
                $data = $this->cache->get($type);
                if (!empty($data)) {
                    $data = unserialize($data);
                }
            }
            return $data;
        }
    
    
    
    mattab's avatar
    mattab a validé
        public function parse()
        {
            $this->parseOs();
            if ($this->isBot() || $this->isSimulator())
                return;
    
            $this->parseBrowser();
    
    
            if($this->isHbbTv()) {
                $this->parseTelevision();
            } else {
                $this->parseMobile();
            }
    
            if (empty($this->device) && $this->isHbbTv()) {
                $this->device = array_search('tv', self::$deviceTypes);
            } else if (empty($this->device) && $this->isDesktop()) {
    
    mattab's avatar
    mattab a validé
                $this->device = array_search('desktop', self::$deviceTypes);
            }
    
    
            /**
             * Android up to 3.0 was designed for smartphones only. But as 3.0, which was tablet only, was published
             * too late, there were a bunch of tablets running with 2.x
             * With 4.0 the two trees were merged and it is for smartphones and tablets
             *
             * So were are expecting that all devices running Android < 2 are smartphones
             * Devices running Android 3.X are tablets. Device type of Android 2.X and 4.X+ are unknown
             */
            if (empty($this->device) && $this->getOs('short_name') == 'AND' && $this->getOs('version') != '') {
                if (version_compare($this->getOs('version'), '2.0') == -1) {
                    $this->device = array_search('smartphone', self::$deviceTypes);
                } else if (version_compare($this->getOs('version'), '3.0') >= 0 AND version_compare($this->getOs('version'), '4.0') == -1) {
                    $this->device = array_search('tablet', self::$deviceTypes);
                }
            }
    
    
    mattab's avatar
    mattab a validé
            if ($this->debug) {
    
                var_export($this->brand, $this->model, $this->device);
    
    mattab's avatar
    mattab a validé
            }
        }
    
        protected function parseOs()
        {
            foreach ($this->getOsRegexes() as $osRegex) {
                $matches = $this->matchUserAgent($osRegex['regex']);
                if ($matches)
                    break;
            }
    
            if (!$matches)
                return;
    
    
            $name  = $this->buildOsName($osRegex['name'], $matches);
            $short = 'UNK';
    
            foreach (self::$osShorts AS $osName => $osShort) {
                if (strtolower($name) == strtolower($osName)) {
                    $name  = $osName;
                    $short = $osShort;
                }
    
    mattab's avatar
    mattab a validé
            }
    
            $this->os = array(
    
    sgiehl's avatar
    sgiehl a validé
                'name'       => $name,
    
    mattab's avatar
    mattab a validé
                'short_name' => $short,
    
                'version'    => $this->buildOsVersion($osRegex['version'], $matches)
    
    mattab's avatar
    mattab a validé
            );
    
            if (array_key_exists($this->os['name'], self::$osShorts)) {
                $this->os['short_name'] = self::$osShorts[$this->os['name']];
            }
        }
    
        protected function parseBrowser()
        {
            foreach ($this->getBrowserRegexes() as $browserRegex) {
                $matches = $this->matchUserAgent($browserRegex['regex']);
                if ($matches)
                    break;
            }
    
            if (!$matches)
                return;
    
    
            $name  = $this->buildBrowserName($browserRegex['name'], $matches);
            $short = 'XX';
    
            foreach (self::$browsers AS $browserShort => $browserName) {
                if (strtolower($name) == strtolower($browserName)) {
                    $name  = $browserName;
                    $short = $browserShort;
                }
    
    mattab's avatar
    mattab a validé
            }
    
            $this->browser = array(
    
                'name'       => $name,
    
    mattab's avatar
    mattab a validé
                'short_name' => $short,
    
                'version'    => $this->buildBrowserVersion($browserRegex['version'], $matches)
    
    mattab's avatar
    mattab a validé
            );
        }
    
    
        protected function parseMobile()
        {
            $mobileRegexes = $this->getMobileRegexes();
            $this->parseBrand($mobileRegexes);
            $this->parseModel($mobileRegexes);
        }
    
        protected function parseTelevision()
        {
            $televisionRegexes = $this->getTelevisionRegexes();
            $this->parseBrand($televisionRegexes);
            $this->parseModel($televisionRegexes);
        }
    
        protected function parseBrand($deviceRegexes)
    
    mattab's avatar
    mattab a validé
        {
    
            foreach ($deviceRegexes as $brand => $mobileRegex) {
    
    mattab's avatar
    mattab a validé
                $matches = $this->matchUserAgent($mobileRegex['regex']);
                if ($matches)
                    break;
            }
    
            if (!$matches)
                return;
    
    mattab's avatar
    mattab a validé
    
            $brandId = array_search($brand, self::$deviceBrands);
            if($brandId === false) {
                throw new Exception("The brand with name '$brand' should be listed in the deviceBrands array.");
            }
            $this->brand = $brandId;
    
    mattab's avatar
    mattab a validé
            $this->fullName = $brand;
    
            if (isset($mobileRegex['device'])) {
    
                $this->device = array_search($mobileRegex['device'], self::$deviceTypes);
    
    mattab's avatar
    mattab a validé
            }
    
            if (isset($mobileRegex['model'])) {
                $this->model = $this->buildModel($mobileRegex['model'], $matches);
            }
        }
    
    
        protected function parseModel($deviceRegexes)
    
    mattab's avatar
    mattab a validé
        {
    
            if (empty($this->brand) || !empty($this->model) || empty($deviceRegexes[$this->fullName]['models']))
    
    mattab's avatar
    mattab a validé
                return;
    
    
            foreach ($deviceRegexes[$this->fullName]['models'] as $modelRegex) {
    
    mattab's avatar
    mattab a validé
                $matches = $this->matchUserAgent($modelRegex['regex']);
                if ($matches)
                    break;
            }
    
            if (!$matches) {
                return;
            }
    
            $this->model = $this->buildModel($modelRegex['model'], $matches);
    
            if (isset($modelRegex['device'])) {
                $this->device = array_search($modelRegex['device'], self::$deviceTypes);
            }
        }
    
        protected function matchUserAgent($regex)
        {
    
            $regex = '/(?:^|[^A-Z_-])(?:' . str_replace('/', '\/', $regex) . ')/i';
    
    mattab's avatar
    mattab a validé
    
            if (preg_match($regex, $this->userAgent, $matches)) {
                return $matches;
            }
    
            return false;
        }
    
        protected function buildOsName($osName, $matches)
        {
            return $this->buildByMatch($osName, $matches);
        }
    
        protected function buildOsVersion($osVersion, $matches)
        {
            $osVersion = $this->buildByMatch($osVersion, $matches);
    
            $osVersion = $this->buildByMatch($osVersion, $matches, '2');
    
            $osVersion = str_replace('_', '.', $osVersion);
    
            return $osVersion;
        }
    
        protected function buildBrowserName($browserName, $matches)
        {
            return $this->buildByMatch($browserName, $matches);
        }
    
        protected function buildBrowserVersion($browserVersion, $matches)
        {
            $browserVersion = $this->buildByMatch($browserVersion, $matches);
    
            $browserVersion = $this->buildByMatch($browserVersion, $matches, '2');
    
            $browserVersion = str_replace('_', '.', $browserVersion);
    
            return $browserVersion;
        }
    
        protected function buildModel($model, $matches)
        {
            $model = $this->buildByMatch($model, $matches);
    
            $model = $this->buildByMatch($model, $matches, '2');
    
            $model = $this->buildModelExceptions($model);
    
            $model = str_replace('_', ' ', $model);
    
            return $model;
        }
    
        protected function buildModelExceptions($model)
        {
            if ($this->brand == 'O2') {
                $model = preg_replace('/([a-z])([A-Z])/', '$1 $2', $model);
                $model = ucwords(str_replace('_', ' ', $model));
            }
    
            return $model;
        }
    
        /**
    
    sgiehl's avatar
    sgiehl a validé
         * This method is used in this class for processing results of pregmatch
    
    mattab's avatar
    mattab a validé
         * results into string containing recognized information.
    
    sgiehl's avatar
    sgiehl a validé
         *
    
    mattab's avatar
    mattab a validé
         * General algorithm:
         * Parsing UserAgent string consists of trying to match it against list of
    
    sgiehl's avatar
    sgiehl a validé
         * regular expressions for three different information:
    
    mattab's avatar
    mattab a validé
         * browser + version,
    
    sgiehl's avatar
    sgiehl a validé
         * OS + version,
         * device manufacturer + model.
         *
         * After match has been found iteration stops, and results are processed
    
    mattab's avatar
    mattab a validé
         * by buildByMatch.
         * As $item we get decoded name (name of browser, name of OS, name of manufacturer).
         * In array $match we recieve preg_match results containing whole string matched at index 0
         * and following matches in further indexes. Desired action now is to concatenate
         * decoded name ($item) with matches found. First step is to append first found match,
         * which is located in index=1 (that's why $nb is 1 by default).
         * In other cases, where whe know that preg_match may return more than 1 result,
         * we call buildByMatch with $nb = 2 or more, depending on what will be returned from
         * regular expression.
    
    sgiehl's avatar
    sgiehl a validé
         *
    
    mattab's avatar
    mattab a validé
         * Example:
    
    sgiehl's avatar
    sgiehl a validé
         * We are parsing UserAgent of Firefox 20.0 browser.
    
    mattab's avatar
    mattab a validé
         * UserAgentParserEnhanced calls buildBrowserName() and buildBrowserVersion() in order
         * to retrieve those information.
         * In buildBrowserName() we only have one call of buildByMatch, where passed argument
         * is regular expression testing given string for browser name. In this case, we are only
         * interrested in first hit, so no $nb parameter will be set to 1. After finding match, and calling
         * buildByMatch - we will receive just the name of browser.
    
    sgiehl's avatar
    sgiehl a validé
         *
    
    mattab's avatar
    mattab a validé
         * Also after decoding browser we will get list of regular expressions for this browser name
         * testing UserAgent string for version number. Again we iterate over this list, and after finding first
         * occurence - we break loop and proceed to build by match. Since browser regular expressions can
         * contain two hits (major version and minor version) in function buildBrowserVersion() we have
         * two calls to buildByMatch, one without 3rd parameter, and second with $nb set to 2.
         * This way we can retrieve version number, and assign it to object property.
    
    sgiehl's avatar
    sgiehl a validé
         *
    
    mattab's avatar
    mattab a validé
         * In case of mobiles.yml this schema slightly varies, but general idea is the same.
    
    sgiehl's avatar
    sgiehl a validé
         *
    
    mattab's avatar
    mattab a validé
         * @param string $item
         * @param array $matches
    
    sgiehl's avatar
    sgiehl a validé
         * @param int|string $nb
         * @return string type
    
    mattab's avatar
    mattab a validé
         */
        protected function buildByMatch($item, $matches, $nb = '1')
        {
            if (strpos($item, '$' . $nb) === false)
                return $item;
    
            $replace = isset($matches[$nb]) ? $matches[$nb] : '';
            return trim(str_replace('$' . $nb, $replace, $item));
        }
    
        public function isBot()
        {
    
    sgiehl's avatar
    sgiehl a validé
            return $this->getOsFamily($this->getOs('short_name')) == 'Bot';
    
    mattab's avatar
    mattab a validé
        }
    
        public function isSimulator()
        {
    
    sgiehl's avatar
    sgiehl a validé
            return $this->getOsFamily($this->getOs('short_name')) == 'Simulator';
    
    mattab's avatar
    mattab a validé
        }
    
    
        public function isHbbTv()
        {
            $regex = 'HbbTV/([1-9]{1}(\.[0-9]{1}){1,2})';
            return $this->matchUserAgent($regex);
        }
    
    
    mattab's avatar
    mattab a validé
        public function isMobile()
        {
            return !$this->isDesktop();
        }
    
        public function isDesktop()
        {
            $osName = $this->getOs('name');
            if (empty($osName) || empty(self::$osShorts[$osName])) {
                return false;
            }
    
            $osShort = self::$osShorts[$osName];
            foreach (self::$osFamilies as $family => $familyOs) {
                if (in_array($osShort, $familyOs)) {
                    $decodedFamily = $family;
                    break;
                }
            }
            return in_array($decodedFamily, self::$desktopOsArray);
        }
    
        public function getOs($attr = '')
        {
            if ($attr == '') {
                return $this->os;
            }
    
            if (!isset($this->os[$attr])) {
                return self::UNKNOWN;
            }
    
    sgiehl's avatar
    sgiehl a validé
    
    
    mattab's avatar
    mattab a validé
            return $this->os[$attr];
        }
    
        public function getBrowser($attr = '')
        {
            if ($attr == '') {
                return $this->browser;
            }
    
            if (!isset($this->browser[$attr])) {
                return self::UNKNOWN;
            }
    
            return $this->browser[$attr];
        }
    
        public function getDevice()
        {
            return $this->device;
        }
    
        public function getBrand()
        {
            return $this->brand;
        }
    
        public function getModel()
        {
            return $this->model;
        }
    
        public function getUserAgent()
        {
            return $this->userAgent;
        }
    
    
    mattab's avatar
    mattab a validé
        /**
         * @param $osLabel
         * @return bool|string If false, "Unknown"
         */
    
    mattab's avatar
    mattab a validé
        public static function getOsFamily($osLabel)
        {
    
    mattab's avatar
    mattab a validé
            foreach (self::$osFamilies as $family => $labels) {
                if (in_array($osLabel, $labels)) {
                    return $family;
    
    mattab's avatar
    mattab a validé
                }
            }
    
    mattab's avatar
    mattab a validé
            return false;
    
    mattab's avatar
    mattab a validé
        }
    
    
    mattab's avatar
    mattab a validé
        /**
         * @param $browserLabel
         * @return bool|string If false, "Unknown"
         */
    
    mattab's avatar
    mattab a validé
        public static function getBrowserFamily($browserLabel)
        {
    
    mattab's avatar
    mattab a validé
            foreach (self::$browserFamilies as $browserFamily => $browserLabels) {
                if (in_array($browserLabel, $browserLabels)) {
    
    mattab's avatar
    mattab a validé
                    return $browserFamily;
                }
            }
    
    mattab's avatar
    mattab a validé
            return false;
    
    mattab's avatar
    mattab a validé
        }
    
        public static function getOsNameFromId($os, $ver = false)
        {
            $osFullName = array_search($os, self::$osShorts);
            if ($osFullName) {
                if (in_array($os, self::$osFamilies['Windows'])) {
                    return $osFullName;
                } else {
                    return trim($osFullName . " " . $ver);
                }
            }
            return false;
        }
    
    
        static public function getInfoFromUserAgent($ua)
        {
            $userAgentParserEnhanced = new UserAgentParserEnhanced($ua);
            $userAgentParserEnhanced->parse();
    
    
            $osFamily = $userAgentParserEnhanced->getOsFamily($userAgentParserEnhanced->getOs('short_name'));
            $browserFamily = $userAgentParserEnhanced->getBrowserFamily($userAgentParserEnhanced->getBrowser('short_name'));
    
            $device = $userAgentParserEnhanced->getDevice();
    
            $deviceName = $device === '' ? '' : UserAgentParserEnhanced::$deviceTypes[$device];
            $processed = array(
                'user_agent'     => $userAgentParserEnhanced->getUserAgent(),
                'os'             => array(
                    'name'       => $userAgentParserEnhanced->getOs('name'),
                    'short_name' => $userAgentParserEnhanced->getOs('short_name'),
                    'version'    => $userAgentParserEnhanced->getOs('version'),
                ),
                'browser'        => array(
                    'name'       => $userAgentParserEnhanced->getBrowser('name'),
                    'short_name' => $userAgentParserEnhanced->getBrowser('short_name'),
                    'version'    => $userAgentParserEnhanced->getBrowser('version'),
                ),
                'device'         => array(
                    'type'       => $deviceName,
                    'brand'      => $userAgentParserEnhanced->getBrand(),
                    'model'      => $userAgentParserEnhanced->getModel(),
                ),
                'os_family'      => $osFamily !== false ? $osFamily : 'Unknown',
                'browser_family' => $browserFamily !== false ? $browserFamily : 'Unknown',
            );
            return $processed;
        }
    
    
        protected function getRegexList($type, $regexesFile)
        {
            $regexList = $this->getParsedYmlFromCache($type);
            if (empty($regexList)) {
                $regexList = Spyc::YAMLLoad(dirname(__FILE__) . self::$regexesDir . $regexesFile);
                $this->saveParsedYmlInCache($type, $regexList);
            }
            return $regexList;
        }