From Kromonos, 8 Months ago, written in PHP.
Embed
  1. <?php
  2.  
  3. namespace kromonos\browser;
  4.  
  5. class Browser
  6. {
  7.     const     PLATFORM        = 'platform';
  8.     const     BROWSER         = 'browser';
  9.     const     BROWSER_VERSION = 'version';
  10.  
  11.     private $u_agent          = 'Mozilla/5.0 (compatible; Unknown;)';
  12.  
  13.     protected $useragent      = [];
  14.     protected $browserVersion = [
  15.         'chrome'         => 80,
  16.         'firefox'        => 75,
  17.         'opera'          => 65,
  18.         'yandex'         => 13,
  19.         'safari'         => 11,
  20.         'samsungbrowser' => 10,
  21.         'uc browser'     => 10,
  22.         'msie'           => 10,
  23.         'vivaldi'        => 2,
  24.         'miuibrowser'    => 10
  25.     ];
  26.     protected $bots = [
  27.         'bot',
  28.         'crawl',
  29.         'guzzlehttp',
  30.         'zapier',
  31.         'curl',
  32.         'node\-red',
  33.         'twingly',
  34.         'ahc',
  35.         'proxy',
  36.         'python\-requests',
  37.         'ubermetrics\-technologies\.com',
  38.         'dapper\-security',
  39.         'nuzzel',
  40.         'scoop\.it',
  41.         'trendsmap',
  42.         'mastodon',
  43.         'pleroma',
  44.         'go-http-client',
  45.         'embarcadero',
  46.         'aiohttp',
  47.         'imgsizer',
  48.         'wpif',
  49.         'CFNetwork',
  50.         'BrightEdge'
  51.     ];
  52.  
  53.     /**
  54.      * Browser constructor.
  55.      */
  56.     public function __construct()
  57.     {
  58.         if (isset($_SERVER['HTTP_USER_AGENT'])) {
  59.             $this->u_agent = (string)$_SERVER['HTTP_USER_AGENT'];
  60.         }
  61.  
  62.         try {
  63.             $this->useragent = $this->parseUserAgent();
  64.         } catch (\InvalidArgumentException $e) {
  65.             $this->useragent = $this->parseUserAgent($this->u_agent);
  66.         }
  67.     }
  68.  
  69.     public function getUserAgent(): string
  70.     {
  71.         return $this->u_agent;
  72.     }
  73.  
  74.     /**
  75.      * Parses a user agent string into its important parts
  76.      *
  77.      * @param string|false $u_agent User agent string to parse or null. Uses $_SERVER['HTTP_USER_AGENT'] on NULL
  78.      * @return string[] an array with 'browser', 'version' and 'platform' keys
  79.      * @throws \InvalidArgumentException on not having a proper user agent to parse.
  80.      */
  81.     public function parseUserAgent($u_agent = false)
  82.     {
  83.         if ($u_agent) {
  84.             $this->u_agent = (string)$u_agent;
  85.         }
  86.  
  87.         $platform = '-';
  88.         $browser  = '-';
  89.         $version  = '0.0.0';
  90.  
  91.         $empty = [
  92.             static::PLATFORM => $platform,
  93.             static::BROWSER => $browser,
  94.             static::BROWSER_VERSION => $version
  95.         ];
  96.  
  97.         if (!$this->u_agent) {
  98.             return $empty;
  99.         }
  100.  
  101.         if (preg_match('/\((.*?)\)/m', $this->u_agent, $parent_matches)) {
  102.             preg_match_all(<<<'REGEX'
  103. /(?P<platform>BB\d+;|Android|CrOS|Tizen|iPhone|iPad|iPod|
  104. Linux|(Open|Net|Free)BSD|Macintosh|Windows(\ Phone)?|Silk|linux-gnu|
  105. BlackBerry|PlayBook|X11|(New\ )?Nintendo\ (WiiU?|3?DS|Switch)|Xbox(\ One)?)
  106. (?:\ [^;]*)?
  107. (?:;|$)/imx
  108. REGEX
  109.                 , $parent_matches[1], $result);
  110.  
  111.             $priority = [
  112.                 'Xbox One',
  113.                 'Xbox',
  114.                 'Windows Phone',
  115.                 'Tizen',
  116.                 'Android',
  117.                 'FreeBSD',
  118.                 'NetBSD',
  119.                 'OpenBSD',
  120.                 'CrOS',
  121.                 'X11'
  122.             ];
  123.  
  124.             $result[static::PLATFORM] = array_unique($result[static::PLATFORM]);
  125.             if (count($result[static::PLATFORM]) > 1) {
  126.                 if ($keys = array_intersect($priority, $result[static::PLATFORM])) {
  127.                     $platform = reset($keys);
  128.                 } else {
  129.                     $platform = $result[static::PLATFORM][0];
  130.                 }
  131.             } elseif (isset($result[static::PLATFORM][0])) {
  132.                 $platform = $result[static::PLATFORM][0];
  133.             }
  134.         }
  135.  
  136.         if ($platform == 'linux-gnu' || $platform == 'X11') {
  137.             $platform = 'Linux';
  138.         } elseif ($platform == 'CrOS') {
  139.             $platform = 'Chrome OS';
  140.         }
  141.  
  142.         preg_match_all(<<<'REGEX'
  143. %(?P<browser>Camino|Kindle(\ Fire)?|Firefox|Iceweasel|IceCat|Safari|MSIE|Trident|AppleWebKit|
  144. TizenBrowser|FBAV|(?:Headless)?Chrome|YaBrowser|Vivaldi|IEMobile|Opera|OPR|Silk|Midori|Edge|Edg|CriOS|PaperLiBot|
  145. MiuiBrowser|UCBrowser|Puffin|OculusBrowser|SamsungBrowser|Baiduspider|Applebot|Googlebot|YandexBot|bingbot|Twitterbot|
  146. Lynx|Mastodon|Pleroma|Version|Wget|curl|Valve\ Steam\ Tenfoot|NintendoBrowser|PLAYSTATION\ (\d|Vita)+)
  147. (?:\)?;?)
  148. (?:(?:[:/ ])(?P<version>[0-9A-Z.]+)|/(?:[A-Z]*))%ix
  149. REGEX
  150.             , $this->u_agent, $result);
  151.  
  152.  
  153.         // If nothing matched, return null (to avoid undefined index errors)
  154.         if (!isset($result[static::BROWSER][0]) || !isset($result[static::BROWSER_VERSION][0])) {
  155.             if (preg_match(
  156.                 '%^(?!Mozilla)(?P<browser>[A-Z0-9\-]+)(/(?P<version>[0-9A-Z.]+))?%ix',
  157.                 $this->u_agent,
  158.                 $result
  159.             )) {
  160.                 return [
  161.                     static::PLATFORM => $platform ?: '',
  162.                     static::BROWSER => $result[static::BROWSER],
  163.                     static::BROWSER_VERSION => empty($result[static::BROWSER_VERSION])
  164.                         ? ''
  165.                         : $result[static::BROWSER_VERSION]
  166.                 ];
  167.             }
  168.  
  169.             return $empty;
  170.         }
  171.  
  172.         if (preg_match('/rv:(?P<version>[0-9A-Z.]+)/i', $this->u_agent, $rv_result)) {
  173.             $rv_result = $rv_result[static::BROWSER_VERSION];
  174.         }
  175.  
  176.         $browser = $result[static::BROWSER][0];
  177.         $version = $result[static::BROWSER_VERSION][0];
  178.  
  179.         $lowerBrowser = array_map('strtolower', $result[static::BROWSER]);
  180.  
  181.         $find = function ($search, &$key = null, &$value = null) use ($lowerBrowser) {
  182.             $search = (array)$search;
  183.  
  184.             foreach ($search as $val) {
  185.                 $xkey = array_search(strtolower($val), $lowerBrowser);
  186.                 if ($xkey !== false) {
  187.                     $value = $val;
  188.                     $key   = $xkey;
  189.  
  190.                     return true;
  191.                 }
  192.             }
  193.  
  194.             return false;
  195.         };
  196.  
  197.         $findT = function (array $search, &$key = null, &$value = null) use ($find) {
  198.             $value2 = null;
  199.             if ($find(array_keys($search), $key, $value2)) {
  200.                 $value = $search[$value2];
  201.  
  202.                 return true;
  203.             }
  204.  
  205.             return false;
  206.         };
  207.  
  208.         $key = 0;
  209.         $val = '';
  210.         if ($findT([
  211.             'OPR'       => 'Opera',
  212.             'UCBrowser' => 'UC Browser',
  213.             'YaBrowser' => 'Yandex',
  214.             'Iceweasel' => 'Firefox',
  215.             'Icecat'    => 'Firefox',
  216.             'CriOS'     => 'Chrome',
  217.             'Edg'       => 'Edge',
  218.             'FBAV'      => 'Facebook App'
  219.         ], $key, $browser)) {
  220.             $version = $result[static::BROWSER_VERSION][$key];
  221.         } elseif ($find('Playstation Vita', $key, $platform)) {
  222.             $platform = 'PlayStation Vita';
  223.             $browser  = 'Browser';
  224.         } elseif ($find(array( 'Kindle Fire', 'Silk'), $key, $val)) {
  225.             $browser  = $val == 'Silk' ? 'Silk' : 'Kindle';
  226.             $platform = 'Kindle Fire';
  227.             if (!($version = $result[static::BROWSER_VERSION][$key]) || !is_numeric($version[0])) {
  228.                 $version = $result[static::BROWSER_VERSION][array_search('Version', $result[static::BROWSER])];
  229.             }
  230.         } elseif ($find('NintendoBrowser', $key) || $platform == 'Nintendo 3DS') {
  231.             $browser = 'NintendoBrowser';
  232.             $version = $result[static::BROWSER_VERSION][$key];
  233.         } elseif ($find('Kindle', $key, $platform)) {
  234.             $browser = $result[static::BROWSER][$key];
  235.             $version = $result[static::BROWSER_VERSION][$key];
  236.         } elseif ($find('Opera', $key, $browser)) {
  237.             $find('Version', $key);
  238.             $version = $result[static::BROWSER_VERSION][$key];
  239.         } elseif ($find('Puffin', $key, $browser)) {
  240.             $version = $result[static::BROWSER_VERSION][$key];
  241.             if (strlen($version) > 3) {
  242.                 $part = substr($version, -2);
  243.                 if (ctype_upper($part)) {
  244.                     $version = substr($version, 0, -2);
  245.  
  246.                     $flags = [
  247.                         'IP' => 'iPhone',
  248.                         'IT' => 'iPad',
  249.                         'AP' => 'Android',
  250.                         'AT' => 'Android',
  251.                         'WP' => 'Windows Phone',
  252.                         'WT' => 'Windows'
  253.                     ];
  254.  
  255.                     if (isset($flags[$part])) {
  256.                         $platform = $flags[$part];
  257.                     }
  258.                 }
  259.             }
  260.         } elseif ($find([
  261.             'Applebot',
  262.             'IEMobile',
  263.             'Edge',
  264.             'Midori',
  265.             'Vivaldi',
  266.             'OculusBrowser',
  267.             'SamsungBrowser',
  268.             'Valve Steam Tenfoot',
  269.             'Twitterbot',
  270.             'PaperLiBot',
  271.             'Mastodon',
  272.             'Pleroma',
  273.             'MiuiBrowser',
  274.             'HeadlessChrome',
  275.             'Chrome'
  276.         ], $key, $browser)) {
  277.             $version = $result[static::BROWSER_VERSION][$key];
  278.         } elseif ($rv_result && $find('Trident')) {
  279.             $browser = 'MSIE';
  280.             $version = $rv_result;
  281.         } elseif ($browser == 'AppleWebKit') {
  282.             if ($platform == 'Android') {
  283.                 $browser = 'Android Browser';
  284.             } elseif (strpos($platform, 'BB') === 0) {
  285.                 $browser  = 'BlackBerry Browser';
  286.                 $platform = 'BlackBerry';
  287.             } elseif ($platform == 'BlackBerry' || $platform == 'PlayBook') {
  288.                 $browser = 'BlackBerry Browser';
  289.             } else {
  290.                 $find('Safari', $key, $browser) || $find('TizenBrowser', $key, $browser);
  291.             }
  292.  
  293.             $find('Version', $key);
  294.             $version = $result[static::BROWSER_VERSION][$key];
  295.         } elseif ($pKey = preg_grep('/playstation \d/i', $result[static::BROWSER])) {
  296.             $pKey = reset($pKey);
  297.  
  298.             $platform = 'PlayStation ' . preg_replace('/\D/', '', $pKey);
  299.             $browser  = 'NetFront';
  300.         }
  301.  
  302.         return [
  303.             static::PLATFORM        => $platform ?: '',
  304.             static::BROWSER         => $browser  ?: '',
  305.             static::BROWSER_VERSION => $version  ?: ''
  306.         ];
  307.     }
  308.  
  309.     /**
  310.      * Get the current browser identifier
  311.      *
  312.      * Currently detected browsers:
  313.      *
  314.      * Android Browser
  315.      * BlackBerry Browser
  316.      * Camino
  317.      * Kindle / Silk
  318.      * Firefox / Iceweasel
  319.      * Safari
  320.      * Internet Explorer
  321.      * IEMobile
  322.      * Chrome
  323.      * Opera
  324.      * Midori
  325.      * Vivaldi
  326.      * TizenBrowser
  327.      * Lynx
  328.      * Wget
  329.      * Curl
  330.      *
  331.      * @param  bool   return lowercased?
  332.      * @return string the browser name
  333.      */
  334.     public function getBrowser($lower = false): string
  335.     {
  336.         return strlen($this->useragent['browser']) > 0
  337.             ? ($lower === true ? strtolower($this->useragent['browser']) : $this->useragent['browser'])
  338.             : '-';
  339.     }
  340.  
  341.     /**
  342.      * Get the current platform identifier
  343.      *
  344.      * Currently detected platforms:
  345.      *
  346.      * Desktop
  347.      *   -> Windows
  348.      *   -> Linux
  349.      *   -> Macintosh
  350.      *   -> Chrome OS
  351.      * Mobile
  352.      *   -> Android
  353.      *   -> iPhone
  354.      *   -> iPad / iPod Touch
  355.      *   -> Windows Phone OS
  356.      *   -> Kindle
  357.      *   -> Kindle Fire
  358.      *   -> BlackBerry
  359.      *   -> Playbook
  360.      *   -> Tizen
  361.      * Console
  362.      *   -> Nintendo 3DS
  363.      *   -> New Nintendo 3DS
  364.      *   -> Nintendo Wii
  365.      *   -> Nintendo WiiU
  366.      *   -> PlayStation 3
  367.      *   -> PlayStation 4
  368.      *   -> PlayStation Vita
  369.      *   -> Xbox 360
  370.      *   -> Xbox One
  371.      *
  372.      * @param  bool   return lowercased?
  373.      * @return string the lowercase platform name
  374.      */
  375.     public function getPlatform($lower = false): string
  376.     {
  377.         return isset($this->useragent['platform']) && $this->useragent['platform'] != null
  378.             ? ($lower ? strtolower($this->useragent['platform']) : $this->useragent['platform'])
  379.             : '-';
  380.     }
  381.  
  382.     /**
  383.      * Get the current full version identifier
  384.      *
  385.      * @return string the browser full version identifier
  386.      */
  387.     public function getLongVersion(): string
  388.     {
  389.         return strlen($this->useragent['version']) > 0 ? $this->useragent['version'] : '0.0.0';
  390.     }
  391.  
  392.     /**
  393.      * Get the current major version identifier
  394.      *
  395.      * @return string the browser major version identifier
  396.      */
  397.     public function getVersion(): int
  398.     {
  399.         $version = explode('.', $this->getLongVersion());
  400.  
  401.         return (int)$version[0];
  402.     }
  403.  
  404.     /**
  405.      * Add new bots. Regex allowed
  406.      *
  407.      * @param array $newBots
  408.      */
  409.     public function addBots(array $newBots)
  410.     {
  411.         $this->bots = array_unique(array_merge($this->bots, $newBots));
  412.     }
  413.  
  414.     /**
  415.      * Determine if the request comes from a human, or from a bot/crawler
  416.      *
  417.      * @return bool
  418.      */
  419.     public function isHuman(): bool
  420.     {
  421.         $browser = $this->getBrowser(true);
  422.         if (empty($browser) || $browser === '-') {
  423.             return false;
  424.         }
  425.  
  426.         if (isset($this->browserVersion[$browser])
  427.             && $this->getVersion() <= $this->browserVersion[$browser]
  428.         ) {
  429.             return false;
  430.         }
  431.  
  432.         if (preg_match('~(' . implode('|', $this->bots) . ')~i', $this->u_agent)) {
  433.             return false;
  434.         }
  435.  
  436.         return true;
  437.     }
  438.  
  439.     /**
  440.      * Merge given array with browserVersion
  441.      *
  442.      * Commit array like:
  443.      * [
  444.      *     'chrome'         => 80,
  445.      *     'firefox'        => 75,
  446.      *     'opera'          => 65,
  447.      *     'safari'         => 11
  448.      * ];
  449.      *
  450.      * @param array $browsers
  451.      *
  452.      * @return array
  453.      */
  454.     public function mergeLatestBrowser(array $browsers): array
  455.     {
  456.         return $this->browserVersion = array_unique(
  457.             array_merge(
  458.                 $this->browserVersion,
  459.                 $browsers
  460.             )
  461.         );
  462.     }
  463.  
  464.     /**
  465.      * Return latest browser versions
  466.      *
  467.      * @return array
  468.      */
  469.     public function getLatestBrowser(): array
  470.     {
  471.         return $this->browserVersion;
  472.     }
  473.  
  474.     /**
  475.      * Determine if "Do Not Track" is set by browser
  476.      * @see https://www.w3.org/TR/tracking-dnt/
  477.      *
  478.      * @return bool
  479.      */
  480.     public function isTrackable(): bool
  481.     {
  482.         return !(isset($_SERVER['HTTP_DNT']) && $_SERVER['HTTP_DNT'] === '1');
  483.     }
  484. }
  485.  

A PHP Error was encountered

Severity: Core Warning

Message: Module 'zip' already loaded

Filename: Unknown

Line Number: 0

Backtrace: