diff --git a/inc/user_agent_parser.inc.php b/inc/user_agent_parser.inc.php new file mode 100644 index 00000000..9a831f84 --- /dev/null +++ b/inc/user_agent_parser.inc.php @@ -0,0 +1,165 @@ + + * @link https://github.com/donatj/PhpUserAgent + * @link http://donatstudios.com/PHP-Parser-HTTP_USER_AGENT + * @param string|null $u_agent User agent string to parse or null. Uses $_SERVER['HTTP_USER_AGENT'] on NULL + * @throws InvalidArgumentException on not having a proper user agent to parse. + * @return string[] an array with browser, version and platform keys + */ +function parse_user_agent( $u_agent = null ) { + if( is_null($u_agent) ) { + if( isset($_SERVER['HTTP_USER_AGENT']) ) { + $u_agent = $_SERVER['HTTP_USER_AGENT']; + } else { + throw new \InvalidArgumentException('parse_user_agent requires a user agent'); + } + } + + $platform = null; + $browser = null; + $version = null; + + $empty = array( 'platform' => $platform, 'browser' => $browser, 'version' => $version ); + + if( !$u_agent ) return $empty; + + if( preg_match('/\((.*?)\)/im', $u_agent, $parent_matches) ) { + + preg_match_all('/(?PBB\d+;|Android|CrOS|Tizen|iPhone|iPad|Linux|Macintosh|Windows(\ Phone)?|Silk|linux-gnu|BlackBerry|PlayBook|(New\ )?Nintendo\ (WiiU?|3?DS)|Xbox(\ One)?) + (?:\ [^;]*)? + (?:;|$)/imx', $parent_matches[1], $result, PREG_PATTERN_ORDER); + + $priority = array( 'Xbox One', 'Xbox', 'Windows Phone', 'Tizen', 'Android' ); + $result['platform'] = array_unique($result['platform']); + if( count($result['platform']) > 1 ) { + if( $keys = array_intersect($priority, $result['platform']) ) { + $platform = reset($keys); + } else { + $platform = $result['platform'][0]; + } + } elseif( isset($result['platform'][0]) ) { + $platform = $result['platform'][0]; + } + } + + if( $platform == 'linux-gnu' ) { + $platform = 'Linux'; + } elseif( $platform == 'CrOS' ) { + $platform = 'Chrome OS'; + } + + preg_match_all('%(?PCamino|Kindle(\ Fire\ Build)?|Firefox|Iceweasel|Safari|MSIE|Trident|AppleWebKit|TizenBrowser|Chrome| + Vivaldi|IEMobile|Opera|OPR|Silk|Midori|Edge|CriOS| + Baiduspider|Googlebot|YandexBot|bingbot|Lynx|Version|Wget|curl| + NintendoBrowser|PLAYSTATION\ (\d|Vita)+) + (?:\)?;?) + (?:(?:[:/ ])(?P[0-9A-Z.]+)|/(?:[A-Z]*))%ix', + $u_agent, $result, PREG_PATTERN_ORDER); + + // If nothing matched, return null (to avoid undefined index errors) + if( !isset($result['browser'][0]) || !isset($result['version'][0]) ) { + if( preg_match('%^(?!Mozilla)(?P[A-Z0-9\-]+)(/(?P[0-9A-Z.]+))?%ix', $u_agent, $result) ) { + return array( 'platform' => $platform ?: null, 'browser' => $result['browser'], 'version' => isset($result['version']) ? $result['version'] ?: null : null ); + } + + return $empty; + } + + if( preg_match('/rv:(?P[0-9A-Z.]+)/si', $u_agent, $rv_result) ) { + $rv_result = $rv_result['version']; + } + + $browser = $result['browser'][0]; + $version = $result['version'][0]; + + $find = function ( $search, &$key ) use ( $result ) { + $xkey = array_search(strtolower($search), array_map('strtolower', $result['browser'])); + if( $xkey !== false ) { + $key = $xkey; + + return true; + } + + return false; + }; + + $key = 0; + $ekey = 0; + if( $browser == 'Iceweasel' ) { + $browser = 'Firefox'; + } elseif( $find('Playstation Vita', $key) ) { + $platform = 'PlayStation Vita'; + $browser = 'Browser'; + } elseif( $find('Kindle Fire Build', $key) || $find('Silk', $key) ) { + $browser = $result['browser'][$key] == 'Silk' ? 'Silk' : 'Kindle'; + $platform = 'Kindle Fire'; + if( !($version = $result['version'][$key]) || !is_numeric($version[0]) ) { + $version = $result['version'][array_search('Version', $result['browser'])]; + } + } elseif( $find('NintendoBrowser', $key) || $platform == 'Nintendo 3DS' ) { + $browser = 'NintendoBrowser'; + $version = $result['version'][$key]; + } elseif( $find('Kindle', $key) ) { + $browser = $result['browser'][$key]; + $platform = 'Kindle'; + $version = $result['version'][$key]; + } elseif( $find('OPR', $key) ) { + $browser = 'Opera Next'; + $version = $result['version'][$key]; + } elseif( $find('Opera', $key) ) { + $browser = 'Opera'; + $find('Version', $key); + $version = $result['version'][$key]; + } elseif( $find('Midori', $key) ) { + $browser = 'Midori'; + $version = $result['version'][$key]; + } elseif( $browser == 'MSIE' || ($rv_result && $find('Trident', $key)) || $find('Edge', $ekey) ) { + $browser = 'MSIE'; + if( $find('IEMobile', $key) ) { + $browser = 'IEMobile'; + $version = $result['version'][$key]; + } elseif( $ekey ) { + $version = $result['version'][$ekey]; + } else { + $version = $rv_result ?: $result['version'][$key]; + } + + if( version_compare($version, '12', '>=') ) { + $browser = 'Edge'; + } + } elseif( $find('Vivaldi', $key) ) { + $browser = 'Vivaldi'; + $version = $result['version'][$key]; + } elseif( $find('Chrome', $key) || $find('CriOS', $key) ) { + $browser = 'Chrome'; + $version = $result['version'][$key]; + } elseif( $browser == 'AppleWebKit' ) { + if( ($platform == 'Android' && !($key = 0)) ) { + $browser = 'Android Browser'; + } elseif( strpos($platform, 'BB') === 0 ) { + $browser = 'BlackBerry Browser'; + $platform = 'BlackBerry'; + } elseif( $platform == 'BlackBerry' || $platform == 'PlayBook' ) { + $browser = 'BlackBerry Browser'; + } elseif( $find('Safari', $key) ) { + $browser = 'Safari'; + } elseif( $find('TizenBrowser', $key) ) { + $browser = 'TizenBrowser'; + } + + $find('Version', $key); + + $version = $result['version'][$key]; + } elseif( $key = preg_grep('/playstation \d/i', array_map('strtolower', $result['browser'])) ) { + $key = reset($key); + + $platform = 'PlayStation ' . preg_replace('/[^\d]/i', '', $key); + $browser = 'NetFront'; + } + + return array( 'platform' => $platform ?: null, 'browser' => $browser ?: null, 'version' => $version ?: null ); +}