Browser_Detection
[ class tree: Browser_Detection ] [ index: Browser_Detection ] [ all elements ]

Source for file BrowserDetection.php

Documentation is available at BrowserDetection.php

  1. <?php
  2.  
  3. /**
  4.  * Browser detection class file.
  5.  * This file contains everything required to use the BrowserDetection class. Tested with PHP 5.3.29 - 7.4.0.
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify it under the terms of EITHER the MIT License
  8.  * (SPDX short identifier: MIT) OR the GNU Lesser General Public License Version 3 (SPDX short identifier:
  9.  * LGPL-3.0-only). License details can be found in the LICENSE-*.md files of this project or on the below URLs.
  10.  *
  11.  * @package Browser_Detection
  12.  * @version 2.9.7
  13.  * @last-modified September 20, 2022
  14.  * @author Alexandre Valiquette
  15.  * @copyright Copyright (c) 2022, Wolfcast
  16.  * @license https://spdx.org/licenses/GPL-3.0-only.html
  17.  * @license https://spdx.org/licenses/MIT.html
  18.  * @link https://wolfcast.com/
  19.  */
  20.  
  21.  
  22. namespace Wolfcast;
  23.  
  24.  
  25. /**
  26.  * The BrowserDetection class facilitates the identification of the user's environment such as Web browser, version,
  27.  * platform and device type.
  28.  *
  29.  * Typical usage:
  30.  *
  31.  * $browser = new Wolfcast\BrowserDetection();
  32.  * if ($browser->getName() == Wolfcast\BrowserDetection::BROWSER_FIREFOX &&
  33.  *     $browser->compareVersions($browser->getVersion(), '5.0') >= 0) {
  34.  *     echo 'You are using FireFox version 5 or greater.';
  35.  * }
  36.  *
  37.  * The class is a rewrite of Chris Schuld's Browser class version 1.9 which is mostly unmaintained since August 20th,
  38.  * 2010. Chris' class was based on the original work from Gary White.
  39.  *
  40.  * Updates:
  41.  *
  42.  * 2022-09-20: Version 2.9.7
  43.  *  + Changed licensing to dual licensing: MIT or LGPL-3.0-only. This has no impact on existing users. You can continue
  44.  *    under the previous license or switch to MIT.
  45.  *
  46.  * 2022-05-01: Version 2.9.6
  47.  *  + Added support for Chrome OS.
  48.  *  + Added support for macOS Monterey and macOS Big Sur.
  49.  *  + Now correctly detects AArch64 as 64-bit.
  50.  *  + Added support for PHP 8.
  51.  *  + Tested with latest Web Browsers and platforms.
  52.  *
  53.  * 2020-02-02: Version 2.9.5
  54.  *  + WARNING! Breaking change: complete rework of robots detection. Now robot name and version is detected in addition
  55.  *    of browser name and version. Use getRobotName() and getRobotVersion() when isRobot() is true.
  56.  *  + WARNING! Breaking change: due to robots detection rework the following methods signatures has changed (isRobot
  57.  *    parameter removed): addCustomBrowserDetection(), checkSimpleBrowserUA(), checkBrowserUAWithVersion().
  58.  *  + Added possibility to support new robots with addCustomRobotDetection().
  59.  *  + Added support for the new Microsoft Edge based on Chromium.
  60.  *  + Added version names for Android 10 and later (Google no longer use candy names for new versions).
  61.  *  + Added macOS Catalina detection.
  62.  *  + Added Windows Server 2019 detection (Windows Server 2016 can be no longer detected due to the fact that they both
  63.  *    use the same version number and that the build is not included in the user agent).
  64.  *
  65.  * 2019-03-27: Version 2.9.3
  66.  *  + Fixed Edge detection on Android.
  67.  *  + Added Android Q detection.
  68.  *  + Now filtering superglobals.
  69.  *
  70.  * 2019-02-28: Version 2.9.2
  71.  *  + Fixed Opera detection.
  72.  *
  73.  * 2018-08-23: Version 2.9.1
  74.  *  + Fixed Chrome detection under iOS.
  75.  *  + Added Android Pie detection.
  76.  *  + Added macOS Mojave detection.
  77.  *
  78.  * 2018-07-15: Version 2.9.0
  79.  *  + WARNING! Breaking change: new Wolfcast namespace. Use new Wolfcast\BrowserDetection().
  80.  *  + iPad, iPhone and iPod are all under iOS now.
  81.  *  + Added Android Oreo detection.
  82.  *  + Added macOS High Sierra detection.
  83.  *  + Added UC Browser detection.
  84.  *  + Improved regular expressions (even less false positives).
  85.  *  + Removed AOL detection.
  86.  *  + Removed the following Web browsers detection: Amaya, Galeon, NetPositive, OmniWeb, Vivaldi detection (use
  87.  *    addCustomBrowserDetection()).
  88.  *  + Removed the following legacy platforms detection: BeOS, OS/2, SunOS (use addCustomPlatformDetection()).
  89.  *
  90.  * 2016-11-28: Version 2.5.1
  91.  *  + Better detection of 64-bit platforms.
  92.  *
  93.  * 2016-08-19: Version 2.5.0
  94.  *  + Platform version and platform version name are now supported for Mac.
  95.  *  + Fixed platform version name for Android.
  96.  *
  97.  * 2016-08-02: Version 2.4.0
  98.  *  + Platform version and platform version name are now supported for Android.
  99.  *  + Added support for the Samsung Internet browser.
  100.  *  + Added support for the Vivaldi browser.
  101.  *  + Better support for legacy Windows versions.
  102.  *
  103.  * 2016-02-11: Version 2.3.0
  104.  *  + WARNING! Breaking change: public method getBrowser() is renamed to getName().
  105.  *  + WARNING! Breaking change: changed the compareVersions() return values to be more in line with other libraries.
  106.  *  + You can now get the exact platform version (name or version numbers) on which the browser is run on with
  107.  *    getPlatformVersion(). Only working with Windows operating systems at the moment.
  108.  *  + You can now determine if the browser is executed from a 64-bit platform with is64bitPlatform().
  109.  *  + Better detection of mobile platform for Googlebot.
  110.  *
  111.  * 2016-01-04: Version 2.2.0
  112.  *  + Added support for Microsoft Edge.
  113.  *
  114.  * 2014-12-30: Version 2.1.2
  115.  *  + Better detection of Opera.
  116.  *
  117.  * 2014-07-11: Version 2.1.1
  118.  *  + Better detection of mobile devices and platforms.
  119.  *
  120.  * 2014-06-04: Version 2.1.0
  121.  *  + Added support for IE 11+.
  122.  *
  123.  * 2013-05-27: Version 2.0.0 which is (almost) a complete rewrite based on Chris Schuld's Browser class version 1.9 plus
  124.  * changes below.
  125.  *  + Added support for Opera Mobile
  126.  *  + Added support for the Windows Phone (formerly Windows Mobile) platform
  127.  *  + Added support for BlackBerry Tablet OS and BlackBerry 10
  128.  *  + Added support for the Symbian platform
  129.  *  + Added support for Bingbot
  130.  *  + Added support for the Yahoo! Multimedia crawler
  131.  *  + Removed iPhone/iPad/iPod browsers since there are not browsers but platforms - test them with getPlatform()
  132.  *  + Removed support for Shiretoko (Firefox 3.5 alpha/beta) and MSN Browser
  133.  *  + Merged Nokia and Nokia S60
  134.  *  + Updated some deprecated browser names
  135.  *  + Many public methods are now protected
  136.  *  + Documentation updated
  137.  *
  138.  * 2010-07-04:
  139.  *  + Added detection of IE compatibility view - test with getIECompatibilityView()
  140.  *  + Added support for all (deprecated) Netscape versions
  141.  *  + Added support for Safari < 3.0
  142.  *  + Better Firefox version parsing
  143.  *  + Better Opera version parsing
  144.  *  + Better Mozilla detection
  145.  *
  146.  * @package Browser_Detection
  147.  * @version 2.9.7
  148.  * @last-modified September 20, 2022
  149.  * @author Alexandre Valiquette, Chris Schuld, Gary White
  150.  * @copyright Copyright (c) 2022, Wolfcast
  151.  * @license https://spdx.org/licenses/GPL-3.0-only.html
  152.  * @license https://spdx.org/licenses/MIT.html
  153.  * @link https://wolfcast.com/
  154.  * @link https://wolfcast.com/open-source/browser-detection/tutorial.php
  155.  * @link https://chrisschuld.com/
  156.  * @link https://www.apptools.com/phptools/browser/
  157.  */
  158. {
  159.  
  160.     /**#@+
  161.      * Constant for the name of the Web browser.
  162.      */
  163.     const BROWSER_ANDROID 'Android';
  164.     const BROWSER_BLACKBERRY 'BlackBerry';
  165.     const BROWSER_CHROME 'Chrome';
  166.     const BROWSER_EDGE 'Edge';
  167.     const BROWSER_FIREBIRD 'Firebird';
  168.     const BROWSER_FIREFOX 'Firefox';
  169.     const BROWSER_ICAB 'iCab';
  170.     const BROWSER_ICECAT 'GNU IceCat';
  171.     const BROWSER_ICEWEASEL 'GNU IceWeasel';
  172.     const BROWSER_IE 'Internet Explorer';
  173.     const BROWSER_IE_MOBILE 'Internet Explorer Mobile';
  174.     const BROWSER_KONQUEROR 'Konqueror';
  175.     const BROWSER_LYNX 'Lynx';
  176.     const BROWSER_MOZILLA 'Mozilla';
  177.     const BROWSER_MSNTV 'MSN TV';
  178.     const BROWSER_NETSCAPE 'Netscape';
  179.     const BROWSER_NOKIA 'Nokia Browser';
  180.     const BROWSER_OPERA 'Opera';
  181.     const BROWSER_OPERA_MINI 'Opera Mini';
  182.     const BROWSER_OPERA_MOBILE 'Opera Mobile';
  183.     const BROWSER_PHOENIX 'Phoenix';
  184.     const BROWSER_SAFARI 'Safari';
  185.     const BROWSER_SAMSUNG 'Samsung Internet';
  186.     const BROWSER_TABLET_OS 'BlackBerry Tablet OS';
  187.     const BROWSER_UC 'UC Browser';
  188.     const BROWSER_UNKNOWN 'unknown';
  189.     /**#@-*/
  190.  
  191.     /**#@+
  192.      * Constant for the name of the platform on which the Web browser runs.
  193.      */
  194.     const PLATFORM_ANDROID 'Android';
  195.     const PLATFORM_BLACKBERRY 'BlackBerry';
  196.     const PLATFORM_CHROME_OS 'Chrome OS';
  197.     const PLATFORM_FREEBSD 'FreeBSD';
  198.     const PLATFORM_IOS 'iOS';
  199.     const PLATFORM_LINUX 'Linux';
  200.     const PLATFORM_MACINTOSH 'Macintosh';
  201.     const PLATFORM_NETBSD 'NetBSD';
  202.     const PLATFORM_NOKIA 'Nokia';
  203.     const PLATFORM_OPENBSD 'OpenBSD';
  204.     const PLATFORM_OPENSOLARIS 'OpenSolaris';
  205.     const PLATFORM_SYMBIAN 'Symbian';
  206.     const PLATFORM_UNKNOWN 'unknown';
  207.     const PLATFORM_VERSION_UNKNOWN 'unknown';
  208.     const PLATFORM_WINDOWS 'Windows';
  209.     const PLATFORM_WINDOWS_CE 'Windows CE';
  210.     const PLATFORM_WINDOWS_PHONE 'Windows Phone';
  211.     /**#@-*/
  212.  
  213.     /**#@+
  214.      * Constant for the name of the robot.
  215.      */
  216.     const ROBOT_BINGBOT 'Bingbot';
  217.     const ROBOT_GOOGLEBOT 'Googlebot';
  218.     const ROBOT_MSNBOT 'MSNBot';
  219.     const ROBOT_SLURP 'Yahoo! Slurp';
  220.     const ROBOT_UNKNOWN '';
  221.     const ROBOT_VERSION_UNKNOWN '';
  222.     const ROBOT_W3CVALIDATOR 'W3C Validator';
  223.     const ROBOT_YAHOO_MM 'Yahoo! Multimedia';
  224.     /**#@-*/
  225.  
  226.     /**
  227.      * Version unknown constant.
  228.      */
  229.     const VERSION_UNKNOWN 'unknown';
  230.  
  231.  
  232.     /**
  233.      * @var string 
  234.      * @access private
  235.      */
  236.     private $_agent = '';
  237.  
  238.     /**
  239.      * @var string 
  240.      * @access private
  241.      */
  242.     private $_browserName = '';
  243.  
  244.     /**
  245.      * @var string 
  246.      * @access private
  247.      */
  248.     private $_compatibilityViewName = '';
  249.  
  250.     /**
  251.      * @var string 
  252.      * @access private
  253.      */
  254.     private $_compatibilityViewVer = '';
  255.  
  256.     /**
  257.      * @var array 
  258.      * @access private
  259.      */
  260.     private $_customBrowserDetection = array();
  261.  
  262.     /**
  263.      * @var array 
  264.      * @access private
  265.      */
  266.     private $_customPlatformDetection = array();
  267.  
  268.     /**
  269.      * @var array 
  270.      * @access private
  271.      */
  272.     private $_customRobotDetection = array();
  273.  
  274.     /**
  275.      * @var boolean 
  276.      * @access private
  277.      */
  278.     private $_is64bit = false;
  279.  
  280.     /**
  281.      * @var boolean 
  282.      * @access private
  283.      */
  284.     private $_isMobile = false;
  285.  
  286.     /**
  287.      * @var boolean 
  288.      * @access private
  289.      */
  290.     private $_isRobot = false;
  291.  
  292.     /**
  293.      * @var string 
  294.      * @access private
  295.      */
  296.     private $_platform = '';
  297.  
  298.     /**
  299.      * @var string 
  300.      * @access private
  301.      */
  302.     private $_platformVersion = '';
  303.  
  304.     /**
  305.      * @var string 
  306.      * @access private
  307.      */
  308.     private $_robotName = '';
  309.  
  310.     /**
  311.      * @var string 
  312.      * @access private
  313.      */
  314.     private $_robotVersion = '';
  315.  
  316.     /**
  317.      * @var string 
  318.      * @access private
  319.      */
  320.     private $_version = '';
  321.  
  322.  
  323.     //--- MAGIC METHODS ------------------------------------------------------------------------------------------------
  324.  
  325.  
  326.     /**
  327.      * BrowserDetection class constructor.
  328.      * @param string $useragent (optional) The user agent to work with. Leave empty for the current user agent
  329.      *  (contained in $_SERVER['HTTP_USER_AGENT']).
  330.      */
  331.     public function __construct($useragent '')
  332.     {
  333.         $this->setUserAgent($useragent);
  334.     }
  335.  
  336.     /**
  337.      * Determine how the class will react when it is treated like a string.
  338.      * @return string Returns an HTML formatted string with a summary of the browser informations.
  339.      */
  340.     public function __toString()
  341.     {
  342.         $result '';
  343.  
  344.         $values array();
  345.         $values[array('label' => 'User agent''value' => $this->getUserAgent());
  346.         $values[array('label' => 'Browser name''value' => $this->getName());
  347.         $values[array('label' => 'Browser version''value' => $this->getVersion());
  348.         $values[array('label' => 'Platform family''value' => $this->getPlatform());
  349.         $values[array('label' => 'Platform version''value' => $this->getPlatformVersion(true));
  350.         $values[array('label' => 'Platform version name''value' => $this->getPlatformVersion());
  351.         $values[array('label' => 'Platform is 64-bit''value' => $this->is64bitPlatform('true' 'false');
  352.         $values[array('label' => 'Is mobile''value' => $this->isMobile('true' 'false');
  353.         $values[array('label' => 'Is robot''value' => $this->isRobot('true' 'false');
  354.         $values[array('label' => 'Robot name''value' => $this->isRobot(($this->getRobotName(!= self::ROBOT_UNKNOWN $this->getRobotName('Unknown''Not applicable');
  355.         $values[array('label' => 'Robot version''value' => $this->isRobot(($this->getRobotVersion(!= self::ROBOT_VERSION_UNKNOWN $this->getRobotVersion('Unknown''Not applicable');
  356.         $values[array('label' => 'IE is in compatibility view''value' => $this->isInIECompatibilityView('true' 'false');
  357.         $values[array('label' => 'Emulated IE version''value' => $this->isInIECompatibilityView($this->getIECompatibilityView('Not applicable');
  358.         $values[array('label' => 'Is Chrome Frame''value' => $this->isChromeFrame('true' 'false');
  359.  
  360.         foreach ($values as $currVal{
  361.             $result .= '<strong>' htmlspecialchars($currVal['label']ENT_NOQUOTES':</strong> ' $currVal['value''<br />' PHP_EOL;
  362.         }
  363.  
  364.         return $result;
  365.     }
  366.  
  367.  
  368.     //--- PUBLIC MEMBERS -----------------------------------------------------------------------------------------------
  369.  
  370.  
  371.     /**
  372.      * Dynamically add support for a new Web browser.
  373.      * @param string $browserName The Web browser name (used for display).
  374.      * @param mixed $uaNameToLookFor (optional) The string (or array of strings) representing the browser name to find
  375.      *  in the user agent. If omitted, $browserName will be used.
  376.      * @param boolean $isMobile (optional) Determines if the browser is from a mobile device.
  377.      * @param string $separator (optional) The separator string used to split the browser name and the version number in
  378.      *  the user agent.
  379.      * @param boolean $uaNameFindWords (optional) Determines if the browser name to find should match a word instead of
  380.      *  a part of a word. For example "Bar" would not be found in "FooBar" when true but would be found in "Foo Bar".
  381.      *  When set to false, the browser name can be found anywhere in the user agent string.
  382.      * @see removeCustomBrowserDetection()
  383.      * @return boolean Returns true if the custom rule has been added, false otherwise.
  384.      */
  385.     public function addCustomBrowserDetection($browserName$uaNameToLookFor ''$isMobile false$separator '/'$uaNameFindWords true)
  386.     {
  387.         if ($browserName == ''{
  388.             return false;
  389.         }
  390.         if (array_key_exists($browserName$this->_customBrowserDetection)) {
  391.             unset($this->_customBrowserDetection[$browserName]);
  392.         }
  393.         if ($uaNameToLookFor == ''{
  394.             $uaNameToLookFor $browserName;
  395.         }
  396.         $this->_customBrowserDetection[$browserNamearray('uaNameToLookFor' => $uaNameToLookFor'isMobile' => $isMobile == true,
  397.                                                              'separator' => $separator'uaNameFindWords' => $uaNameFindWords == true);
  398.         return true;
  399.     }
  400.  
  401.     /**
  402.      * Dynamically add support for a new platform.
  403.      * @param string $platformName The platform name (used for display).
  404.      * @param mixed $platformNameToLookFor (optional) The string (or array of strings) representing the platform name to
  405.      *  find in the user agent. If omitted, $platformName will be used.
  406.      * @param boolean $isMobile (optional) Determines if the platform is from a mobile device.
  407.      * @param boolean $uaNameFindWords (optional) Determines if the platform name to find should match a word instead of
  408.      *  a part of a word. For example "Bar" would not be found in "FooBar" when true but would be found in "Foo Bar".
  409.      * @see removeCustomPlatformDetection()
  410.      * @return boolean Returns true if the custom rule has been added, false otherwise.
  411.      */
  412.     public function addCustomPlatformDetection($platformName$platformNameToLookFor ''$isMobile false$uaNameFindWords true)
  413.     {
  414.         if ($platformName == ''{
  415.             return false;
  416.         }
  417.         if (array_key_exists($platformName$this->_customPlatformDetection)) {
  418.             unset($this->_customPlatformDetection[$platformName]);
  419.         }
  420.         if ($platformNameToLookFor == ''{
  421.             $platformNameToLookFor $platformName;
  422.         }
  423.         $this->_customPlatformDetection[$platformNamearray('platformNameToLookFor' => $platformNameToLookFor,
  424.                                                                'isMobile' => $isMobile == true,
  425.                                                                'uaNameFindWords' => $uaNameFindWords == true);
  426.         return true;
  427.     }
  428.  
  429.     /**
  430.      * Dynamically add support for a new robot.
  431.      * @param string $robotName The robot name (used for display).
  432.      * @param mixed $uaNameToLookFor (optional) The string (or array of strings) representing the robot name to find
  433.      *  in the user agent. If omitted, $robotName will be used.
  434.      * @param boolean $isMobile (optional) Determines if the robot should be considered as mobile or not.
  435.      * @param string $separator (optional) The separator string used to split the robot name and the version number in
  436.      *  the user agent.
  437.      * @param boolean $uaNameFindWords (optional) Determines if the robot name to find should match a word instead of
  438.      *  a part of a word. For example "Bar" would not be found in "FooBar" when true but would be found in "Foo Bar".
  439.      *  When set to false, the robot name can be found anywhere in the user agent string.
  440.      * @see removeCustomRobotDetection()
  441.      * @return boolean Returns true if the custom rule has been added, false otherwise.
  442.      */
  443.     public function addCustomRobotDetection($robotName$uaNameToLookFor ''$isMobile false$separator '/'$uaNameFindWords true)
  444.     {
  445.         if ($robotName == ''{
  446.             return false;
  447.         }
  448.         if (array_key_exists($robotName$this->_customRobotDetection)) {
  449.             unset($this->_customRobotDetection[$robotName]);
  450.         }
  451.         if ($uaNameToLookFor == ''{
  452.             $uaNameToLookFor $robotName;
  453.         }
  454.         $this->_customRobotDetection[$robotNamearray('uaNameToLookFor' => $uaNameToLookFor'isMobile' => $isMobile == true,
  455.                                                          'separator' => $separator'uaNameFindWords' => $uaNameFindWords == true);
  456.         return true;
  457.     }
  458.  
  459.     /**
  460.      * Compare two version number strings.
  461.      * @param string $sourceVer The source version number.
  462.      * @param string $compareVer The version number to compare with the source version number.
  463.      * @return int Returns -1 if $sourceVer < $compareVer, 0 if $sourceVer == $compareVer or 1 if $sourceVer >
  464.      *  $compareVer.
  465.      */
  466.     public function compareVersions($sourceVer$compareVer)
  467.     {
  468.         $sourceVer explode('.'$sourceVer);
  469.         foreach ($sourceVer as $k => $v{
  470.             $sourceVer[$k$this->parseInt($v);
  471.         }
  472.  
  473.         $compareVer explode('.'$compareVer);
  474.         foreach ($compareVer as $k => $v{
  475.             $compareVer[$k$this->parseInt($v);
  476.         }
  477.  
  478.         if (count($sourceVer!= count($compareVer)) {
  479.             if (count($sourceVercount($compareVer)) {
  480.                 for ($i count($compareVer)$i count($sourceVer)$i++{
  481.                     $compareVer[$i0;
  482.                 }
  483.             else {
  484.                 for ($i count($sourceVer)$i count($compareVer)$i++{
  485.                     $sourceVer[$i0;
  486.                 }
  487.             }
  488.         }
  489.  
  490.         foreach ($sourceVer as $i => $srcVerPart{
  491.             if ($srcVerPart $compareVer[$i]{
  492.                 return 1;
  493.             else {
  494.                 if ($srcVerPart $compareVer[$i]{
  495.                     return -1;
  496.                 }
  497.             }
  498.         }
  499.  
  500.         return 0;
  501.     }
  502.  
  503.     /**
  504.      * Get the name and version of the browser emulated in the compatibility view mode (if any). Since Internet
  505.      * Explorer 8, IE can be put in compatibility mode to make websites that were created for older browsers, especially
  506.      * IE 6 and 7, look better in IE 8+ which renders web pages closer to the standards and thus differently from those
  507.      * older versions of IE.
  508.      * @param boolean $asArray (optional) Determines if the return value must be an array (true) or a string (false).
  509.      * @return mixed If a string was requested, the function returns the name and version of the browser emulated in
  510.      *  the compatibility view mode or an empty string if the browser is not in compatibility view mode. If an array was
  511.      *  requested, an array with the keys 'browser' and 'version' is returned.
  512.      */
  513.     public function getIECompatibilityView($asArray false)
  514.     {
  515.         if ($asArray{
  516.             return array('browser' => $this->_compatibilityViewName'version' => $this->_compatibilityViewVer);
  517.         else {
  518.             return trim($this->_compatibilityViewName . ' ' $this->_compatibilityViewVer);
  519.         }
  520.     }
  521.  
  522.     /**
  523.      * Return the BrowserDetection class version.
  524.      * @return string Returns the version as a sting with the #.#.# format.
  525.      */
  526.     public function getLibVersion()
  527.     {
  528.         return '2.9.7';
  529.     }
  530.  
  531.     /**
  532.      * Get the name of the browser. All of the return values are class constants. You can compare them like this:
  533.      * $myBrowserInstance->getName() == BrowserDetection::BROWSER_FIREFOX.
  534.      * @return string Returns the name of the browser or BrowserDetection::BROWSER_UNKNOWN if unknown.
  535.      */
  536.     public function getName()
  537.     {
  538.         return $this->_browserName;
  539.     }
  540.  
  541.     /**
  542.      * Get the name of the platform family on which the browser is run on (such as Windows, Apple, etc.). All of
  543.      * the return values are class constants. You can compare them like this:
  544.      * $myBrowserInstance->getPlatform() == BrowserDetection::PLATFORM_ANDROID.
  545.      * @return string Returns the name of the platform or BrowserDetection::PLATFORM_UNKNOWN if unknown.
  546.      */
  547.     public function getPlatform()
  548.     {
  549.         return $this->_platform;
  550.     }
  551.  
  552.     /**
  553.      * Get the platform version on which the browser is run on. It can be returned as a string number like 'NT 6.3' or
  554.      * as a name like 'Windows 8.1'. When returning version string numbers for Windows NT OS families the number is
  555.      * prefixed by 'NT ' to differentiate from older Windows 3.x & 9x release. At the moment only the Windows and
  556.      * Android operating systems are supported.
  557.      * @param boolean $returnVersionNumbers (optional) Determines if the return value must be versions numbers as a
  558.      *  string (true) or the version name (false).
  559.      * @param boolean $returnServerFlavor (optional) Since some Windows NT versions have the same values, this flag
  560.      *  determines if the Server flavor is returned or not. For instance Windows 8.1 and Windows Server 2012 R2 both use
  561.      *  version 6.3. This parameter is only useful when testing for Windows.
  562.      * @return string Returns the version name/version numbers of the platform or the constant PLATFORM_VERSION_UNKNOWN
  563.      *  if unknown.
  564.      */
  565.     public function getPlatformVersion($returnVersionNumbers false$returnServerFlavor false)
  566.     {
  567.         if ($this->_platformVersion == self::PLATFORM_VERSION_UNKNOWN || $this->_platformVersion == ''{
  568.             return self::PLATFORM_VERSION_UNKNOWN;
  569.         }
  570.  
  571.         if ($returnVersionNumbers{
  572.             return $this->_platformVersion;
  573.         else {
  574.             switch ($this->getPlatform()) {
  575.                 case self::PLATFORM_WINDOWS:
  576.                     if (substr($this->_platformVersion03== 'NT '{
  577.                         return $this->windowsNTVerToStr(substr($this->_platformVersion3)$returnServerFlavor);
  578.                     else {
  579.                         return $this->windowsVerToStr($this->_platformVersion);
  580.                     }
  581.                     break;
  582.  
  583.                 case self::PLATFORM_MACINTOSH:
  584.                     return $this->macVerToStr($this->_platformVersion);
  585.  
  586.                 case self::PLATFORM_ANDROID:
  587.                     return $this->androidVerToStr($this->_platformVersion);
  588.  
  589.                 case self::PLATFORM_IOS:
  590.                     return $this->iOSVerToStr($this->_platformVersion);
  591.  
  592.                 defaultreturn self::PLATFORM_VERSION_UNKNOWN;
  593.             }
  594.         }
  595.     }
  596.  
  597.     /**
  598.      * Get the name of the robot. All of the return values are class constants. You can compare them like this:
  599.      * $myBrowserInstance->getRobotName() == BrowserDetection::ROBOT_GOOGLEBOT.
  600.      * @return string Returns the name of the robot or BrowserDetection::ROBOT_UNKNOWN if unknown.
  601.      */
  602.     public function getRobotName()
  603.     {
  604.         return $this->_robotName;
  605.     }
  606.  
  607.     /**
  608.      * Get the version of the robot.
  609.      * @return string Returns the version of the robot or BrowserDetection::ROBOT_VERSION_UNKNOWN if unknown.
  610.      */
  611.     public function getRobotVersion()
  612.     {
  613.         return $this->_robotVersion;
  614.     }
  615.  
  616.     /**
  617.      * Get the user agent value used by the class to determine the browser details.
  618.      * @return string The user agent string.
  619.      */
  620.     public function getUserAgent()
  621.     {
  622.         return $this->_agent;
  623.     }
  624.  
  625.     /**
  626.      * Get the version of the browser.
  627.      * @return string Returns the version of the browser or BrowserDetection::VERSION_UNKNOWN if unknown.
  628.      */
  629.     public function getVersion()
  630.     {
  631.         return $this->_version;
  632.     }
  633.  
  634.     /**
  635.      * Determine if the browser is executed from a 64-bit platform. Keep in mind that not all platforms/browsers report
  636.      * this and the result may not always be accurate.
  637.      * @return boolean Returns true if the browser is executed from a 64-bit platform.
  638.      */
  639.     public function is64bitPlatform()
  640.     {
  641.         return $this->_is64bit;
  642.     }
  643.  
  644.     /**
  645.      * Determine if the browser runs Google Chrome Frame (it's a plug-in designed for Internet Explorer 6+ based on the
  646.      * open-source Chromium project - it's like a Chrome browser within IE).
  647.      * @return boolean Returns true if the browser is using Google Chrome Frame, false otherwise.
  648.      */
  649.     public function isChromeFrame()
  650.     {
  651.         return $this->containString($this->_agent'chromeframe');
  652.     }
  653.  
  654.     /**
  655.      * Determine if the browser is in compatibility view or not. Since Internet Explorer 8, IE can be put in
  656.      * compatibility mode to make websites that were created for older browsers, especially IE 6 and 7, look better in
  657.      * IE 8+ which renders web pages closer to the standards and thus differently from those older versions of IE.
  658.      * @return boolean Returns true if the browser is in compatibility view, false otherwise.
  659.      */
  660.     public function isInIECompatibilityView()
  661.     {
  662.         return ($this->_compatibilityViewName != ''|| ($this->_compatibilityViewVer != '');
  663.     }
  664.  
  665.     /**
  666.      * Determine if the browser is from a mobile device or not.
  667.      * @return boolean Returns true if the browser is from a mobile device, false otherwise.
  668.      */
  669.     public function isMobile()
  670.     {
  671.         return $this->_isMobile;
  672.     }
  673.  
  674.     /**
  675.      * Determine if the browser is a robot (Googlebot, Bingbot, Yahoo! Slurp...) or not.
  676.      * @return boolean Returns true if the browser is a robot, false otherwise.
  677.      */
  678.     public function isRobot()
  679.     {
  680.         return $this->_isRobot;
  681.     }
  682.  
  683.     /**
  684.      * Remove support for a previously added Web browser.
  685.      * @param string $browserName The Web browser name as used when added.
  686.      * @see addCustomBrowserDetection()
  687.      * @return boolean Returns true if the custom rule has been found and removed, false otherwise.
  688.      */
  689.     public function removeCustomBrowserDetection($browserName)
  690.     {
  691.         if (array_key_exists($browserName$this->_customBrowserDetection)) {
  692.             unset($this->_customBrowserDetection[$browserName]);
  693.             return true;
  694.         }
  695.  
  696.         return false;
  697.     }
  698.  
  699.     /**
  700.      * Remove support for a previously added platform.
  701.      * @param string $platformName The platform name as used when added.
  702.      * @see addCustomPlatformDetection()
  703.      * @return boolean Returns true if the custom rule has been found and removed, false otherwise.
  704.      */
  705.     public function removeCustomPlatformDetection($platformName)
  706.     {
  707.         if (array_key_exists($platformName$this->_customPlatformDetection)) {
  708.             unset($this->_customPlatformDetection[$platformName]);
  709.             return true;
  710.         }
  711.  
  712.         return false;
  713.     }
  714.  
  715.     /**
  716.      * Remove support for a previously added robot.
  717.      * @param string $robotName The robot name as used when added.
  718.      * @see addCustomRobotDetection()
  719.      * @return boolean Returns true if the custom rule has been found and removed, false otherwise.
  720.      */
  721.     public function removeCustomRobotDetection($robotName)
  722.     {
  723.         if (array_key_exists($robotName$this->_customRobotDetection)) {
  724.             unset($this->_customRobotDetection[$robotName]);
  725.             return true;
  726.         }
  727.  
  728.         return false;
  729.     }
  730.  
  731.     /**
  732.      * Set the user agent to use with the class.
  733.      * @param string $agentString (optional) The value of the user agent. If an empty string is sent (default),
  734.      *  $_SERVER['HTTP_USER_AGENT'] will be used.
  735.      */
  736.     public function setUserAgent($agentString '')
  737.     {
  738.         if (!is_string($agentString|| trim($agentString== ''{
  739.             //https://bugs.php.net/bug.php?id=49184
  740.             if (filter_has_var(INPUT_SERVER'HTTP_USER_AGENT')) {
  741.                 $agentString filter_input(INPUT_SERVER'HTTP_USER_AGENT'FILTER_UNSAFE_RAWFILTER_FLAG_STRIP_LOW);
  742.             else if (array_key_exists('HTTP_USER_AGENT'$_SERVER&& is_string($_SERVER['HTTP_USER_AGENT'])) {
  743.                 $agentString filter_var($_SERVER['HTTP_USER_AGENT']FILTER_UNSAFE_RAWFILTER_FLAG_STRIP_LOW);
  744.             else {
  745.                 $agentString '';
  746.             }
  747.  
  748.             if ($agentString === false || $agentString === NULL{
  749.                 //filter_input or filter_var failed
  750.                 $agentString '';
  751.             }
  752.         }
  753.  
  754.         $this->reset();
  755.         $this->_agent = $agentString;
  756.         $this->detect();
  757.     }
  758.  
  759.  
  760.     //--- PROTECTED MEMBERS --------------------------------------------------------------------------------------------
  761.  
  762.  
  763.     /**
  764.      * Convert the Android version numbers to the operating system name. For instance '1.6' returns 'Donut'.
  765.      * @access protected
  766.      * @param string $androidVer The Android version numbers as a string.
  767.      * @return string The operating system name or the constant PLATFORM_VERSION_UNKNOWN if nothing match the version
  768.      *  numbers.
  769.      */
  770.     protected function androidVerToStr($androidVer)
  771.     {
  772.         //https://en.wikipedia.org/wiki/Android_version_history
  773.  
  774.         if ($this->compareVersions($androidVer'10'>= 0{
  775.             $majorVer strstr($androidVer'.'true);
  776.             if ($majorVer == ''{
  777.                 $majorVer $androidVer;
  778.             }
  779.             return self::BROWSER_ANDROID ' ' $majorVer;
  780.         else if ($this->compareVersions($androidVer'9'>= && $this->compareVersions($androidVer'10'0{
  781.             return 'Pie';
  782.         else if ($this->compareVersions($androidVer'8'>= && $this->compareVersions($androidVer'9'0{
  783.             return 'Oreo';
  784.         else if ($this->compareVersions($androidVer'7'>= && $this->compareVersions($androidVer'8'0{
  785.             return 'Nougat';
  786.         else if ($this->compareVersions($androidVer'6'>= && $this->compareVersions($androidVer'7'0{
  787.             return 'Marshmallow';
  788.         else if ($this->compareVersions($androidVer'5'>= && $this->compareVersions($androidVer'5.2'0{
  789.             return 'Lollipop';
  790.         else if ($this->compareVersions($androidVer'4.4'>= && $this->compareVersions($androidVer'4.5'0{
  791.             return 'KitKat';
  792.         else if ($this->compareVersions($androidVer'4.1'>= && $this->compareVersions($androidVer'4.4'0{
  793.             return 'Jelly Bean';
  794.         else if ($this->compareVersions($androidVer'4'>= && $this->compareVersions($androidVer'4.1'0{
  795.             return 'Ice Cream Sandwich';
  796.         else if ($this->compareVersions($androidVer'3'>= && $this->compareVersions($androidVer'3.3'0{
  797.             return 'Honeycomb';
  798.         else if ($this->compareVersions($androidVer'2.3'>= && $this->compareVersions($androidVer'2.4'0{
  799.             return 'Gingerbread';
  800.         else if ($this->compareVersions($androidVer'2.2'>= && $this->compareVersions($androidVer'2.3'0{
  801.             return 'Froyo';
  802.         else if ($this->compareVersions($androidVer'2'>= && $this->compareVersions($androidVer'2.2'0{
  803.             return 'Eclair';
  804.         else if ($this->compareVersions($androidVer'1.6'== 0{
  805.             return 'Donut';
  806.         else if ($this->compareVersions($androidVer'1.5'== 0{
  807.             return 'Cupcake';
  808.         else {
  809.             return self::PLATFORM_VERSION_UNKNOWN//Unknown/unnamed Android version
  810.         }
  811.     }
  812.  
  813.     /**
  814.      * Determine if the browser is the Android browser (based on the WebKit layout engine and coupled with Chrome's
  815.      * JavaScript engine) or not.
  816.      * @access protected
  817.      * @return boolean Returns true if the browser is the Android browser, false otherwise.
  818.      */
  819.     protected function checkBrowserAndroid()
  820.     {
  821.         //Android don't use the standard "Android/1.0", it uses "Android 1.0;" instead
  822.         return $this->checkSimpleBrowserUA('Android'$this->_agentself::BROWSER_ANDROIDtrue);
  823.     }
  824.  
  825.     /**
  826.      * Determine if the browser is the BlackBerry browser or not.
  827.      * @access protected
  828.      * @link https://web.archive.org/web/20170328000854/http://supportforums.blackberry.com/t5/Web-and-WebWorks-Development/How-to-detect-the-BlackBerry-Browser/ta-p/559862
  829.      * @return boolean Returns true if the browser is the BlackBerry browser, false otherwise.
  830.      */
  831.     protected function checkBrowserBlackBerry()
  832.     {
  833.         $found false;
  834.  
  835.         //Tablet OS check
  836.         if ($this->checkSimpleBrowserUA('RIM Tablet OS'$this->_agentself::BROWSER_TABLET_OStrue)) {
  837.             return true;
  838.         }
  839.  
  840.         //Version 6, 7 & 10 check (versions 8 & 9 does not exists)
  841.         if ($this->checkBrowserUAWithVersion(array('BlackBerry''BB10')$this->_agentself::BROWSER_BLACKBERRYtrue)) {
  842.             if ($this->getVersion(== self::VERSION_UNKNOWN{
  843.                 $found true;
  844.             else {
  845.                 return true;
  846.             }
  847.         }
  848.  
  849.         //Version 4.2 to 5.0 check
  850.         if ($this->checkSimpleBrowserUA('BlackBerry'$this->_agentself::BROWSER_BLACKBERRYtrue'/'false)) {
  851.             if ($this->getVersion(== self::VERSION_UNKNOWN{
  852.                 $found true;
  853.             else {
  854.                 return true;
  855.             }
  856.         }
  857.  
  858.         return $found;
  859.     }
  860.  
  861.     /**
  862.      * Determine if the browser is Chrome or not.
  863.      * @access protected
  864.      * @link https://www.google.com/chrome/
  865.      * @return boolean Returns true if the browser is Chrome, false otherwise.
  866.      */
  867.     protected function checkBrowserChrome()
  868.     {
  869.         return $this->checkSimpleBrowserUA(array('Chrome''CriOS')$this->_agentself::BROWSER_CHROME);
  870.     }
  871.  
  872.     /**
  873.      * Determine if the browser is among the custom browser rules or not. Rules are checked in the order they were
  874.      * added.
  875.      * @access protected
  876.      * @return boolean Returns true if we found the browser we were looking for in the custom rules, false otherwise.
  877.      */
  878.     protected function checkBrowserCustom()
  879.     {
  880.         foreach ($this->_customBrowserDetection as $browserName => $customBrowser{
  881.             $uaNameToLookFor $customBrowser['uaNameToLookFor'];
  882.             $isMobile $customBrowser['isMobile'];
  883.             $separator $customBrowser['separator'];
  884.             $uaNameFindWords $customBrowser['uaNameFindWords'];
  885.             if ($this->checkSimpleBrowserUA($uaNameToLookFor$this->_agent$browserName$isMobile$separator$uaNameFindWords)) {
  886.                 return true;
  887.             }
  888.         }
  889.         return false;
  890.     }
  891.  
  892.     /**
  893.      * Determine if the browser is Edge or not.
  894.      * @access protected
  895.      * @return boolean Returns true if the browser is Edge, false otherwise.
  896.      */
  897.     protected function checkBrowserEdge()
  898.     {
  899.         return $this->checkSimpleBrowserUA(array('Edg''Edge''EdgA')$this->_agentself::BROWSER_EDGE);
  900.     }
  901.  
  902.     /**
  903.      * Determine if the browser is Firebird or not. Firebird was the name of Firefox from version 0.6 to 0.7.1.
  904.      * @access protected
  905.      * @return boolean Returns true if the browser is Firebird, false otherwise.
  906.      */
  907.     protected function checkBrowserFirebird()
  908.     {
  909.         return $this->checkSimpleBrowserUA('Firebird'$this->_agentself::BROWSER_FIREBIRD);
  910.     }
  911.  
  912.     /**
  913.      * Determine if the browser is Firefox or not.
  914.      * @access protected
  915.      * @link https://www.mozilla.org/en-US/firefox/new/
  916.      * @return boolean Returns true if the browser is Firefox, false otherwise.
  917.      */
  918.     protected function checkBrowserFirefox()
  919.     {
  920.         //Safari heavily matches with Firefox, ensure that Safari is filtered out...
  921.         if (preg_match('/.*Firefox[ (\/]*([a-z0-9.-]*)/i'$this->_agent$matches&&
  922.                 !$this->containString($this->_agent'Safari')) {
  923.             $this->setBrowser(self::BROWSER_FIREFOX);
  924.             $this->setVersion($matches[1]);
  925.             $this->setMobile(false);
  926.             $this->setRobot(false);
  927.  
  928.             return true;
  929.         }
  930.  
  931.         return false;
  932.     }
  933.  
  934.     /**
  935.      * Determine if the browser is iCab or not.
  936.      * @access protected
  937.      * @link http://www.icab.de/
  938.      * @return boolean Returns true if the browser is iCab, false otherwise.
  939.      */
  940.     protected function checkBrowserIcab()
  941.     {
  942.         //Some (early) iCab versions don't use the standard "iCab/1.0", they uses "iCab 1.0;" instead
  943.         return $this->checkSimpleBrowserUA('iCab'$this->_agentself::BROWSER_ICAB);
  944.     }
  945.  
  946.     /**
  947.      * Determine if the browser is GNU IceCat (formerly known as GNU IceWeasel) or not.
  948.      * @access protected
  949.      * @link https://www.gnu.org/software/gnuzilla/
  950.      * @return boolean Returns true if the browser is GNU IceCat, false otherwise.
  951.      */
  952.     protected function checkBrowserIceCat()
  953.     {
  954.         return $this->checkSimpleBrowserUA('IceCat'$this->_agentself::BROWSER_ICECAT);
  955.     }
  956.  
  957.     /**
  958.      * Determine if the browser is GNU IceWeasel (now know as GNU IceCat) or not.
  959.      * @access protected
  960.      * @see checkBrowserIceCat()
  961.      * @return boolean Returns true if the browser is GNU IceWeasel, false otherwise.
  962.      */
  963.     protected function checkBrowserIceWeasel()
  964.     {
  965.         return $this->checkSimpleBrowserUA('Iceweasel'$this->_agentself::BROWSER_ICEWEASEL);
  966.     }
  967.  
  968.     /**
  969.      * Determine if the browser is Internet Explorer or not.
  970.      * @access protected
  971.      * @link https://www.microsoft.com/ie/
  972.      * @link https://en.wikipedia.org/wiki/Internet_Explorer_Mobile
  973.      * @return boolean Returns true if the browser is Internet Explorer, false otherwise.
  974.      */
  975.     protected function checkBrowserInternetExplorer()
  976.     {
  977.         //Test for Internet Explorer Mobile (formerly Pocket Internet Explorer)
  978.         if ($this->checkSimpleBrowserUA(array('IEMobile''MSPIE')$this->_agentself::BROWSER_IE_MOBILEtrue)) {
  979.             return true;
  980.         }
  981.  
  982.         //Several browsers uses IE compatibility UAs filter these browsers out (but after testing for IE Mobile)
  983.         if ($this->containString($this->_agent'Opera'|| $this->containString($this->_agentarray('BlackBerry''Nokia')truefalse)) {
  984.             return false;
  985.         }
  986.  
  987.         //Test for Internet Explorer 1
  988.         if ($this->checkSimpleBrowserUA('Microsoft Internet Explorer'$this->_agentself::BROWSER_IE)) {
  989.             if ($this->getVersion(== self::VERSION_UNKNOWN{
  990.                 if (preg_match('/308|425|426|474|0b1/i'$this->_agent)) {
  991.                     $this->setVersion('1.5');
  992.                 else {
  993.                     $this->setVersion('1.0');
  994.                 }
  995.             }
  996.             return true;
  997.         }
  998.  
  999.         //Test for Internet Explorer 2+
  1000.         if ($this->containString($this->_agentarray('MSIE''Trident'))) {
  1001.             $version '';
  1002.  
  1003.             if ($this->containString($this->_agent'Trident')) {
  1004.                 //Test for Internet Explorer 11+ (check the rv: string)
  1005.                 if ($this->containString($this->_agent'rv:'truefalse)) {
  1006.                     if ($this->checkSimpleBrowserUA('Trident'$this->_agentself::BROWSER_IEfalse'rv:')) {
  1007.                         return true;
  1008.                     }
  1009.                 else {
  1010.                     //Test for Internet Explorer 8, 9 & 10 (check the Trident string)
  1011.                     if (preg_match('/Trident\/([\d]+)/i'$this->_agent$foundVersion)) {
  1012.                         //Trident started with version 4.0 on IE 8
  1013.                         $verFromTrident $this->parseInt($foundVersion[1]4;
  1014.                         if ($verFromTrident >= 8{
  1015.                             $version $verFromTrident '.0';
  1016.                         }
  1017.                     }
  1018.                 }
  1019.  
  1020.                 //If we have the IE version from Trident, we can check for the compatibility view mode
  1021.                 if ($version != ''{
  1022.                     $emulatedVer '';
  1023.                     preg_match_all('/MSIE\s*([^\s;$]+)/i'$this->_agent$foundVersions);
  1024.                     foreach ($foundVersions[1as $currVer{
  1025.                         //Keep the lowest MSIE version for the emulated version (in compatibility view mode)
  1026.                         if ($emulatedVer == '' || $this->compareVersions($emulatedVer$currVer== 1{
  1027.                             $emulatedVer $currVer;
  1028.                         }
  1029.                     }
  1030.                     //Set the compatibility view mode if $version != $emulatedVer
  1031.                     if ($this->compareVersions($version$emulatedVer!= 0{
  1032.                         $this->_compatibilityViewName = self::BROWSER_IE;
  1033.                         $this->_compatibilityViewVer = $this->cleanVersion($emulatedVer);
  1034.                     }
  1035.                 }
  1036.             }
  1037.  
  1038.             //Test for Internet Explorer 2-7 versions if needed
  1039.             if ($version == ''{
  1040.                 preg_match_all('/MSIE\s+([^\s;$]+)/i'$this->_agent$foundVersions);
  1041.                 foreach ($foundVersions[1as $currVer{
  1042.                     //Keep the highest MSIE version
  1043.                     if ($version == '' || $this->compareVersions($version$currVer== -1{
  1044.                         $version $currVer;
  1045.                     }
  1046.                 }
  1047.             }
  1048.  
  1049.             $this->setBrowser(self::BROWSER_IE);
  1050.             $this->setVersion($version);
  1051.             $this->setMobile(false);
  1052.             $this->setRobot(false);
  1053.  
  1054.             return true;
  1055.         }
  1056.  
  1057.         return false;
  1058.     }
  1059.  
  1060.     /**
  1061.      * Determine if the browser is Konqueror or not.
  1062.      * @access protected
  1063.      * @link https://www.konqueror.org/
  1064.      * @return boolean Returns true if the browser is Konqueror, false otherwise.
  1065.      */
  1066.     protected function checkBrowserKonqueror()
  1067.     {
  1068.         return $this->checkSimpleBrowserUA('Konqueror'$this->_agentself::BROWSER_KONQUEROR);
  1069.     }
  1070.  
  1071.     /**
  1072.      * Determine if the browser is Lynx or not. It is the oldest web browser currently in general use and development.
  1073.      * It is a text-based only Web browser.
  1074.      * @access protected
  1075.      * @link https://en.wikipedia.org/wiki/Lynx_(web_browser)
  1076.      * @return boolean Returns true if the browser is Lynx, false otherwise.
  1077.      */
  1078.     protected function checkBrowserLynx()
  1079.     {
  1080.         return $this->checkSimpleBrowserUA('Lynx'$this->_agentself::BROWSER_LYNX);
  1081.     }
  1082.  
  1083.     /**
  1084.      * Determine if the browser is Mozilla or not.
  1085.      * @access protected
  1086.      * @return boolean Returns true if the browser is Mozilla, false otherwise.
  1087.      */
  1088.     protected function checkBrowserMozilla()
  1089.     {
  1090.         return $this->checkSimpleBrowserUA('Mozilla'$this->_agentself::BROWSER_MOZILLAfalse'rv:');
  1091.     }
  1092.  
  1093.     /**
  1094.      * Determine if the browser is MSN TV (formerly WebTV) or not.
  1095.      * @access protected
  1096.      * @link https://en.wikipedia.org/wiki/MSN_TV
  1097.      * @return boolean Returns true if the browser is WebTv, false otherwise.
  1098.      */
  1099.     protected function checkBrowserMsnTv()
  1100.     {
  1101.         return $this->checkSimpleBrowserUA('webtv'$this->_agentself::BROWSER_MSNTV);
  1102.     }
  1103.  
  1104.     /**
  1105.      * Determine if the browser is Netscape or not. Official support for this browser ended on March 1st, 2008.
  1106.      * @access protected
  1107.      * @link https://en.wikipedia.org/wiki/Netscape
  1108.      * @return boolean Returns true if the browser is Netscape, false otherwise.
  1109.      */
  1110.     protected function checkBrowserNetscape()
  1111.     {
  1112.         //BlackBerry & Nokia UAs can conflict with Netscape UAs
  1113.         if ($this->containString($this->_agentarray('BlackBerry''Nokia')truefalse)) {
  1114.             return false;
  1115.         }
  1116.  
  1117.         //Netscape v6 to v9 check
  1118.         if ($this->checkSimpleBrowserUA(array('Netscape''Navigator''Netscape6')$this->_agentself::BROWSER_NETSCAPE)) {
  1119.             return true;
  1120.         }
  1121.  
  1122.         //Netscape v1-4 (v5 don't exists)
  1123.         $found false;
  1124.         if ($this->containString($this->_agent'Mozilla'&& !$this->containString($this->_agent'rv:'truefalse)) {
  1125.             $version '';
  1126.             $verParts explode('/'stristr($this->_agent'Mozilla'));
  1127.             if (count($verParts1{
  1128.                 $verParts explode(' '$verParts[1]);
  1129.                 $verParts explode('.'$verParts[0]);
  1130.  
  1131.                 $majorVer $this->parseInt($verParts[0]);
  1132.                 if ($majorVer && $majorVer 5{
  1133.                     $version implode('.'$verParts);
  1134.                     $found true;
  1135.  
  1136.                     if (strtolower(substr($version-4)) == '-sgi'{
  1137.                         $version substr($version0-4);
  1138.                     else {
  1139.                         if (strtolower(substr($version-4)) == 'gold'{
  1140.                             $version substr($version0-4' Gold'//Doubles spaces (if any) will be normalized by setVersion()
  1141.                         }
  1142.                     }
  1143.                 }
  1144.             }
  1145.         }
  1146.  
  1147.         if ($found{
  1148.             $this->setBrowser(self::BROWSER_NETSCAPE);
  1149.             $this->setVersion($version);
  1150.             $this->setMobile(false);
  1151.             $this->setRobot(false);
  1152.         }
  1153.  
  1154.         return $found;
  1155.     }
  1156.  
  1157.     /**
  1158.      * Determine if the browser is a Nokia browser or not.
  1159.      * @access protected
  1160.      * @link https://web.archive.org/web/20141012034159/http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices
  1161.      * @return boolean Returns true if the browser is a Nokia browser, false otherwise.
  1162.      */
  1163.     protected function checkBrowserNokia()
  1164.     {
  1165.         if ($this->containString($this->_agentarray('Nokia5800''Nokia5530''Nokia5230')truefalse)) {
  1166.             $this->setBrowser(self::BROWSER_NOKIA);
  1167.             $this->setVersion('7.0');
  1168.             $this->setMobile(true);
  1169.             $this->setRobot(false);
  1170.  
  1171.             return true;
  1172.         }
  1173.  
  1174.         if ($this->checkSimpleBrowserUA(array('NokiaBrowser''BrowserNG''Series60''S60''S40OviBrowser')$this->_agentself::BROWSER_NOKIAtrue)) {
  1175.             return true;
  1176.         }
  1177.  
  1178.         return false;
  1179.     }
  1180.  
  1181.     /**
  1182.      * Determine if the browser is Opera or not.
  1183.      * @access protected
  1184.      * @link https://www.opera.com/
  1185.      * @link https://www.opera.com/mobile/
  1186.      * @link https://web.archive.org/web/20140220123653/http://my.opera.com/community/openweb/idopera/
  1187.      * @return boolean Returns true if the browser is Opera, false otherwise.
  1188.      */
  1189.     protected function checkBrowserOpera()
  1190.     {
  1191.         if ($this->checkBrowserUAWithVersion('Opera Mobi'$this->_agentself::BROWSER_OPERA_MOBILEtrue)) {
  1192.             return true;
  1193.         }
  1194.  
  1195.         if ($this->checkSimpleBrowserUA('Opera Mini'$this->_agentself::BROWSER_OPERA_MINItrue)) {
  1196.             return true;
  1197.         }
  1198.  
  1199.         $version '';
  1200.         $found $this->checkBrowserUAWithVersion('Opera'$this->_agentself::BROWSER_OPERA);
  1201.         if ($found && $this->getVersion(!= self::VERSION_UNKNOWN{
  1202.             $version $this->getVersion();
  1203.         }
  1204.  
  1205.         if (!$found || $version == ''{
  1206.             if ($this->checkSimpleBrowserUA('Opera'$this->_agentself::BROWSER_OPERA)) {
  1207.                 return true;
  1208.             }
  1209.         }
  1210.  
  1211.         if (!$found && $this->checkSimpleBrowserUA('Chrome'$this->_agentself::BROWSER_CHROME) ) {
  1212.             if ($this->checkSimpleBrowserUA('OPR'$this->_agentself::BROWSER_OPERA)) {
  1213.                 return true;
  1214.             }
  1215.         }
  1216.  
  1217.         return $found;
  1218.     }
  1219.  
  1220.     /**
  1221.      * Determine if the browser is Phoenix or not. Phoenix was the name of Firefox from version 0.1 to 0.5.
  1222.      * @access protected
  1223.      * @return boolean Returns true if the browser is Phoenix, false otherwise.
  1224.      */
  1225.     protected function checkBrowserPhoenix()
  1226.     {
  1227.         return $this->checkSimpleBrowserUA('Phoenix'$this->_agentself::BROWSER_PHOENIX);
  1228.     }
  1229.  
  1230.     /**
  1231.      * Determine what is the browser used by the user.
  1232.      * @access protected
  1233.      * @return boolean Returns true if the browser has been identified, false otherwise.
  1234.      */
  1235.     protected function checkBrowser()
  1236.     {
  1237.         //Changing the check order can break the class detection results!
  1238.         return
  1239.                /* Major browsers and browsers that need to be detected in a special order */
  1240.                $this->checkBrowserCustom(||           /* Customs rules are always checked first */
  1241.                $this->checkBrowserMsnTv(||            /* MSN TV is based on IE so we must check for MSN TV before IE */
  1242.                $this->checkBrowserInternetExplorer(||
  1243.                $this->checkBrowserOpera(||            /* Opera must be checked before Firefox, Netscape and Chrome to avoid conflicts */
  1244.                $this->checkBrowserEdge(||             /* Edge must be checked before Firefox, Safari and Chrome to avoid conflicts */
  1245.                $this->checkBrowserSamsung(||          /* Samsung Internet browser must be checked before Chrome and Safari to avoid conflicts */
  1246.                $this->checkBrowserUC(||               /* UC Browser must be checked before Chrome and Safari to avoid conflicts */
  1247.                $this->checkBrowserChrome(||           /* Chrome must be checked before Netscaoe and Mozilla to avoid conflicts */
  1248.                $this->checkBrowserIcab(||             /* Check iCab before Netscape since iCab have Mozilla UAs */
  1249.                $this->checkBrowserNetscape(||         /* Must be checked before Firefox since Netscape 8-9 are based on Firefox */
  1250.                $this->checkBrowserIceCat(||           /* Check IceCat and IceWeasel before Firefox since they are GNU builds of Firefox */
  1251.                $this->checkBrowserIceWeasel(||
  1252.                $this->checkBrowserFirefox(||
  1253.                /* Current browsers that don't need to be detected in any special order */
  1254.                $this->checkBrowserKonqueror(||
  1255.                $this->checkBrowserLynx(||
  1256.                /* Mobile */
  1257.                $this->checkBrowserAndroid(||
  1258.                $this->checkBrowserBlackBerry(||
  1259.                $this->checkBrowserNokia(||
  1260.                /* WebKit base check (after most other checks) */
  1261.                $this->checkBrowserSafari(||
  1262.                /* Deprecated browsers that don't need to be detected in any special order */
  1263.                $this->checkBrowserFirebird(||
  1264.                $this->checkBrowserPhoenix(||
  1265.                /* Mozilla is such an open standard that it must be checked last */
  1266.                $this->checkBrowserMozilla();
  1267.     }
  1268.  
  1269.     /**
  1270.      * Determine if the browser is Safari or not.
  1271.      * @access protected
  1272.      * @link https://www.apple.com/safari/
  1273.      * @link https://web.archive.org/web/20080514173941/http://developer.apple.com/internet/safari/uamatrix.html
  1274.      * @link https://en.wikipedia.org/wiki/Safari_version_history#Release_history
  1275.      * @return boolean Returns true if the browser is Safari, false otherwise.
  1276.      */
  1277.     protected function checkBrowserSafari()
  1278.     {
  1279.         $version '';
  1280.  
  1281.         //Check for current versions of Safari
  1282.         $found $this->checkBrowserUAWithVersion(array('Safari''AppleWebKit')$this->_agentself::BROWSER_SAFARI);
  1283.         if ($found && $this->getVersion(!= self::VERSION_UNKNOWN{
  1284.             $version $this->getVersion();
  1285.         }
  1286.  
  1287.         //Safari 1-2 didn't had a "Version" string in the UA, only a WebKit build and/or Safari build, extract version from these...
  1288.         if (!$found || $version == ''{
  1289.             if (preg_match('/.*Safari[ (\/]*([a-z0-9.-]*)/i'$this->_agent$matches)) {
  1290.                 $version $this->safariBuildToSafariVer($matches[1]);
  1291.                 $found true;
  1292.             }
  1293.         }
  1294.         if (!$found || $version == ''{
  1295.             if (preg_match('/.*AppleWebKit[ (\/]*([a-z0-9.-]*)/i'$this->_agent$matches)) {
  1296.                 $version $this->webKitBuildToSafariVer($matches[1]);
  1297.                 $found true;
  1298.             }
  1299.         }
  1300.  
  1301.         if ($found{
  1302.             $this->setBrowser(self::BROWSER_SAFARI);
  1303.             $this->setVersion($version);
  1304.             $this->setMobile(false);
  1305.             $this->setRobot(false);
  1306.         }
  1307.  
  1308.         return $found;
  1309.     }
  1310.  
  1311.     /**
  1312.      * Determine if the browser is the Samsung Internet browser or not.
  1313.      * @access protected
  1314.      * @return boolean Returns true if the browser is the the Samsung Internet browser, false otherwise.
  1315.      */
  1316.     protected function checkBrowserSamsung()
  1317.     {
  1318.         return $this->checkSimpleBrowserUA('SamsungBrowser'$this->_agentself::BROWSER_SAMSUNGtrue);
  1319.     }
  1320.  
  1321.     /**
  1322.      * Test the user agent for a specific browser that use a "Version" string (like Safari and Opera). The user agent
  1323.      * should look like: "Version/1.0 Browser name/123.456" or "Browser name/123.456 Version/1.0".
  1324.      * @access protected
  1325.      * @param mixed $uaNameToLookFor The string (or array of strings) representing the browser name to find in the user
  1326.      *  agent.
  1327.      * @param string $userAgent The user agent string to work with.
  1328.      * @param string $browserName The literal browser name. Always use a class constant!
  1329.      * @param boolean $isMobile (optional) Determines if the browser is from a mobile device.
  1330.      * @param boolean $findWords (optional) Determines if the needle should match a word to be found. For example "Bar"
  1331.      *  would not be found in "FooBar" when true but would be found in "Foo Bar". When set to false, the needle can be
  1332.      *  found anywhere in the haystack.
  1333.      * @return boolean Returns true if we found the browser we were looking for, false otherwise.
  1334.      */
  1335.     protected function checkBrowserUAWithVersion($uaNameToLookFor$userAgent$browserName$isMobile false$findWords true)
  1336.     {
  1337.         if (!is_array($uaNameToLookFor)) {
  1338.             $uaNameToLookFor array($uaNameToLookFor);
  1339.         }
  1340.  
  1341.         foreach ($uaNameToLookFor as $currUANameToLookFor{
  1342.             if ($this->containString($userAgent$currUANameToLookFortrue$findWords)) {
  1343.                 $version '';
  1344.                 $verParts explode('/'stristr($this->_agent'Version'));
  1345.                 if (count($verParts1{
  1346.                     $verParts explode(' '$verParts[1]);
  1347.                     $version $verParts[0];
  1348.                 }
  1349.  
  1350.                 $this->setBrowser($browserName);
  1351.                 $this->setVersion($version);
  1352.  
  1353.                 $this->setMobile($isMobile);
  1354.  
  1355.                 return true;
  1356.             }
  1357.         }
  1358.  
  1359.         return false;
  1360.     }
  1361.  
  1362.     /**
  1363.      * Determine if the browser is UC Browser or not.
  1364.      * @access protected
  1365.      * @return boolean Returns true if the browser is UC Browser, false otherwise.
  1366.      */
  1367.     protected function checkBrowserUC()
  1368.     {
  1369.         return $this->checkSimpleBrowserUA('UCBrowser'$this->_agentself::BROWSER_UCtrue);
  1370.     }
  1371.  
  1372.     /**
  1373.      * Determine the user's platform.
  1374.      * @access protected
  1375.      */
  1376.     protected function checkPlatform()
  1377.     {
  1378.         if (!$this->checkPlatformCustom()) /* Customs rules are always checked first */
  1379.             /* Mobile platforms */
  1380.             if ($this->containString($this->_agentarray('Windows Phone''IEMobile'))) /* Check Windows Phone (formerly Windows Mobile) before Windows */
  1381.                 $this->setPlatform(self::PLATFORM_WINDOWS_PHONE);
  1382.                 $this->setMobile(true);
  1383.             else if ($this->containString($this->_agent'Windows CE')) /* Check Windows CE before Windows */
  1384.                 $this->setPlatform(self::PLATFORM_WINDOWS_CE);
  1385.                 $this->setMobile(true);
  1386.             else if ($this->containString($this->_agentarray('CPU OS''CPU iPhone OS''iPhone''iPad''iPod'))) /* Check iOS (iPad/iPod/iPhone) before Macintosh */
  1387.                 $this->setPlatform(self::PLATFORM_IOS);
  1388.                 $this->setMobile(true);
  1389.             else if ($this->containString($this->_agentarray('CrOS''Chromebook'))) {
  1390.                 $this->setPlatform(self::PLATFORM_CHROME_OS);
  1391.                 $this->setMobile(true);
  1392.             else if ($this->containString($this->_agent'Android')) {
  1393.                 $this->setPlatform(self::PLATFORM_ANDROID);
  1394.                 $this->setMobile(true);
  1395.             else if ($this->containString($this->_agent'BlackBerry'truefalse|| $this->containString($this->_agentarray('BB10''RIM Tablet OS'))) {
  1396.                 $this->setPlatform(self::PLATFORM_BLACKBERRY);
  1397.                 $this->setMobile(true);
  1398.             else if ($this->containString($this->_agent'Nokia'truefalse)) {
  1399.                 $this->setPlatform(self::PLATFORM_NOKIA);
  1400.                 $this->setMobile(true);
  1401.  
  1402.             /* Desktop platforms */
  1403.             else if ($this->containString($this->_agent'Windows')) {
  1404.                 $this->setPlatform(self::PLATFORM_WINDOWS);
  1405.             else if ($this->containString($this->_agent'Macintosh')) {
  1406.                 $this->setPlatform(self::PLATFORM_MACINTOSH);
  1407.             else if ($this->containString($this->_agent'Linux')) {
  1408.                 $this->setPlatform(self::PLATFORM_LINUX);
  1409.             else if ($this->containString($this->_agent'FreeBSD')) {
  1410.                 $this->setPlatform(self::PLATFORM_FREEBSD);
  1411.             else if ($this->containString($this->_agent'OpenBSD')) {
  1412.                 $this->setPlatform(self::PLATFORM_OPENBSD);
  1413.             else if ($this->containString($this->_agent'NetBSD')) {
  1414.                 $this->setPlatform(self::PLATFORM_NETBSD);
  1415.  
  1416.             /* Discontinued */
  1417.             else if ($this->containString($this->_agentarray('Symbian''SymbianOS'))) {
  1418.                 $this->setPlatform(self::PLATFORM_SYMBIAN);
  1419.                 $this->setMobile(true);
  1420.             else if ($this->containString($this->_agent'OpenSolaris')) {
  1421.                 $this->setPlatform(self::PLATFORM_OPENSOLARIS);
  1422.  
  1423.             /* Generic */
  1424.             else if ($this->containString($this->_agent'Win'truefalse)) {
  1425.                 $this->setPlatform(self::PLATFORM_WINDOWS);
  1426.             else if ($this->containString($this->_agent'Mac'truefalse)) {
  1427.                 $this->setPlatform(self::PLATFORM_MACINTOSH);
  1428.             }
  1429.         }
  1430.  
  1431.         //Check if it's a 64-bit platform
  1432.         if ($this->containString($this->_agentarray('WOW64''Win64''AMD64''x86_64''x86-64''Aarch64''ia64',
  1433.                 'IRIX64''ppc64''sparc64''x64;''x64_64'))) {
  1434.             $this->set64bit(true);
  1435.         }
  1436.  
  1437.         $this->checkPlatformVersion();
  1438.     }
  1439.  
  1440.     /**
  1441.      * Determine if the platform is among the custom platform rules or not. Rules are checked in the order they were
  1442.      * added.
  1443.      * @access protected
  1444.      * @return boolean Returns true if we found the platform we were looking for in the custom rules, false otherwise.
  1445.      */
  1446.     protected function checkPlatformCustom()
  1447.     {
  1448.         foreach ($this->_customPlatformDetection as $platformName => $customPlatform{
  1449.             $platformNameToLookFor $customPlatform['platformNameToLookFor'];
  1450.             $isMobile $customPlatform['isMobile'];
  1451.             $findWords $customPlatform['uaNameFindWords'];
  1452.             if ($this->containString($this->_agent$platformNameToLookFortrue$findWords)) {
  1453.                 $this->setPlatform($platformName);
  1454.                 if ($isMobile{
  1455.                     $this->setMobile(true);
  1456.                 }
  1457.                 return true;
  1458.             }
  1459.         }
  1460.  
  1461.         return false;
  1462.     }
  1463.  
  1464.     /**
  1465.      * Determine the user's platform version.
  1466.      * @access protected
  1467.      */
  1468.     protected function checkPlatformVersion()
  1469.     {
  1470.         $result '';
  1471.         switch ($this->getPlatform()) {
  1472.             case self::PLATFORM_WINDOWS:
  1473.                 if (preg_match('/Windows NT\s*(\d+(?:\.\d+)*)/i'$this->_agent$foundVersion)) {
  1474.                     $result 'NT ' $foundVersion[1];
  1475.                 else {
  1476.                     //https://support.microsoft.com/en-us/kb/158238
  1477.  
  1478.                     if ($this->containString($this->_agentarray('Windows XP''WinXP''Win XP'))) {
  1479.                         $result '5.1';
  1480.                     else if ($this->containString($this->_agent'Windows 2000''Win 2000''Win2000')) {
  1481.                         $result '5.0';
  1482.                     else if ($this->containString($this->_agentarray('Win 9x 4.90''Windows ME''WinME''Win ME'))) {
  1483.                         $result '4.90.3000'//Windows Me version range from 4.90.3000 to 4.90.3000A
  1484.                     else if ($this->containString($this->_agentarray('Windows 98''Win98''Win 98'))) {
  1485.                         $result '4.10'//Windows 98 version range from 4.10.1998 to 4.10.2222B
  1486.                     else if ($this->containString($this->_agentarray('Windows 95''Win95''Win 95'))) {
  1487.                         $result '4.00'//Windows 95 version range from 4.00.950 to 4.03.1214
  1488.                     else if (($foundAt stripos($this->_agent'Windows 3')) !== false{
  1489.                         $result '3';
  1490.                         if (preg_match('/\d+(?:\.\d+)*/'substr($this->_agent$foundAt strlen('Windows 3'))$foundVersion)) {
  1491.                             $result .= '.' $foundVersion[0];
  1492.                         }
  1493.                     else if ($this->containString($this->_agent'Win16')) {
  1494.                         $result '3.1';
  1495.                     }
  1496.                 }
  1497.                 break;
  1498.  
  1499.             case self::PLATFORM_MACINTOSH:
  1500.                 if (preg_match('/Mac OS X\s*(\d+(?:_\d+)+)/i'$this->_agent$foundVersion)) {
  1501.                     $result str_replace('_''.'$this->cleanVersion($foundVersion[1]));
  1502.                 else if ($this->containString($this->_agent'Mac OS X')) {
  1503.                     $result '10';
  1504.                 }
  1505.                 break;
  1506.  
  1507.             case self::PLATFORM_CHROME_OS:
  1508.                 if (preg_match('/CrOS\s*\w*\s*([^\s;$]+)/i'$this->_agent$foundVersion)) {
  1509.                     $result $this->cleanVersion($foundVersion[1]);
  1510.                 }
  1511.                 else if (preg_match('/Chromebook\s+([^\s;$]+)/i'$this->_agent$foundVersion)) {
  1512.                     $result $this->cleanVersion($foundVersion[1]'Build');
  1513.                 }
  1514.                 break;
  1515.  
  1516.             case self::PLATFORM_ANDROID:
  1517.                 if (preg_match('/Android\s+([^\s;$]+)/i'$this->_agent$foundVersion)) {
  1518.                     $result $this->cleanVersion($foundVersion[1]);
  1519.                 }
  1520.                 break;
  1521.  
  1522.             case self::PLATFORM_IOS:
  1523.                 if (preg_match('/(?:CPU OS|iPhone OS|iOS)[\s_]*([\d_]+)/i'$this->_agent$foundVersion)) {
  1524.                     $result str_replace('_''.'$this->cleanVersion($foundVersion[1]));
  1525.                 }
  1526.                 break;
  1527.         }
  1528.  
  1529.         if (trim($result== ''{
  1530.             $result self::PLATFORM_VERSION_UNKNOWN;
  1531.         }
  1532.         $this->setPlatformVersion($result);
  1533.     }
  1534.  
  1535.     /**
  1536.      * Determine if the robot is the Bingbot crawler or not.
  1537.      * @access protected
  1538.      * @link https://www.bing.com/webmaster/help/which-crawlers-does-bing-use-8c184ec0
  1539.      * @return boolean Returns true if the robot is Bingbot, false otherwise.
  1540.      */
  1541.     protected function checkRobotBingbot()
  1542.     {
  1543.         return $this->checkSimpleRobot('bingbot'$this->_agentself::ROBOT_BINGBOT);
  1544.     }
  1545.  
  1546.     /**
  1547.      * Determine if the robot is the Googlebot crawler or not.
  1548.      * @access protected
  1549.      * @return boolean Returns true if the robot is Googlebot, false otherwise.
  1550.      */
  1551.     protected function checkRobotGooglebot()
  1552.     {
  1553.         if ($this->checkSimpleRobot('Googlebot'$this->_agentself::ROBOT_GOOGLEBOT)) {
  1554.             if ($this->containString($this->_agent'googlebot-mobile')) {
  1555.                 $this->setMobile(true);
  1556.             }
  1557.  
  1558.             return true;
  1559.         }
  1560.  
  1561.         return false;
  1562.     }
  1563.  
  1564.     /**
  1565.      * Determine if the robot is the MSNBot crawler or not. In October 2010 it was replaced by the Bingbot robot.
  1566.      * @access protected
  1567.      * @see checkRobotBingbot()
  1568.      * @return boolean Returns true if the robot is MSNBot, false otherwise.
  1569.      */
  1570.     protected function checkRobotMsnBot()
  1571.     {
  1572.         return $this->checkSimpleRobot('msnbot'$this->_agentself::ROBOT_MSNBOT);
  1573.     }
  1574.  
  1575.     /**
  1576.      * Determine if it's a robot crawling the page and find it's name and version.
  1577.      * @access protected
  1578.      */
  1579.     protected function checkRobot()
  1580.     {
  1581.         $this->checkRobotCustom(|| /* Customs rules are always checked first */
  1582.         $this->checkRobotGooglebot(||
  1583.         $this->checkRobotBingbot(||
  1584.         $this->checkRobotMsnBot(||
  1585.         $this->checkRobotSlurp(||
  1586.         $this->checkRobotYahooMultimedia(||
  1587.         $this->checkRobotW3CValidator();
  1588.     }
  1589.  
  1590.     /**
  1591.      * Determine if the robot is among the custom robot rules or not. Rules are checked in the order they were added.
  1592.      * @access protected
  1593.      * @return boolean Returns true if we found the robot we were looking for in the custom rules, false otherwise.
  1594.      */
  1595.     protected function checkRobotCustom()
  1596.     {
  1597.         foreach ($this->_customRobotDetection as $robotName => $customRobot{
  1598.             $uaNameToLookFor $customRobot['uaNameToLookFor'];
  1599.             $isMobile $customRobot['isMobile'];
  1600.             $separator $customRobot['separator'];
  1601.             $uaNameFindWords $customRobot['uaNameFindWords'];
  1602.  
  1603.             if ($this->checkSimpleRobot($uaNameToLookFor$this->_agent$robotName$separator$uaNameFindWords)) {
  1604.                 return true;
  1605.             }
  1606.         }
  1607.         return false;
  1608.     }
  1609.  
  1610.     /**
  1611.      * Determine if the robot is the Yahoo! Slurp crawler or not.
  1612.      * @access protected
  1613.      * @return boolean Returns true if the robot is Yahoo! Slurp, false otherwise.
  1614.      */
  1615.     protected function checkRobotSlurp()
  1616.     {
  1617.         return $this->checkSimpleRobot('Yahoo! Slurp'$this->_agentself::ROBOT_SLURP);
  1618.     }
  1619.  
  1620.     /**
  1621.      * Determine if the robot is the W3C Validator or not.
  1622.      * @access protected
  1623.      * @link https://validator.w3.org/
  1624.      * @return boolean Returns true if the robot is the W3C Validator, false otherwise.
  1625.      */
  1626.     protected function checkRobotW3CValidator()
  1627.     {
  1628.         //Since the W3C validates pages with different robots we will prefix our versions with the part validated on the page...
  1629.  
  1630.         //W3C Link Checker (prefixed with "Link-")
  1631.         if ($this->checkSimpleRobot('W3C-checklink'$this->_agentself::ROBOT_W3CVALIDATOR)) {
  1632.             if ($this->getRobotVersion(!= self::ROBOT_VERSION_UNKNOWN{
  1633.                 $this->setRobotVersion('Link-' $this->getRobotVersion());
  1634.             }
  1635.             return true;
  1636.         }
  1637.  
  1638.         //W3C CSS Validation Service (prefixed with "CSS-")
  1639.         if ($this->checkSimpleRobot('Jigsaw'$this->_agentself::ROBOT_W3CVALIDATOR)) {
  1640.             if ($this->getRobotVersion(!= self::ROBOT_VERSION_UNKNOWN{
  1641.                 $this->setRobotVersion('CSS-' $this->getRobotVersion());
  1642.             }
  1643.             return true;
  1644.         }
  1645.  
  1646.         //W3C mobileOK Checker (prefixed with "mobileOK-")
  1647.         if ($this->checkSimpleRobot('W3C-mobileOK'$this->_agentself::ROBOT_W3CVALIDATOR)) {
  1648.             if ($this->getRobotVersion(!= self::ROBOT_VERSION_UNKNOWN{
  1649.                 $this->setRobotVersion('mobileOK-' $this->getRobotVersion());
  1650.             }
  1651.             return true;
  1652.         }
  1653.  
  1654.         //W3C Markup Validation Service (no prefix)
  1655.         return $this->checkSimpleRobot('W3C_Validator'$this->_agentself::ROBOT_W3CVALIDATOR);
  1656.     }
  1657.  
  1658.     /**
  1659.      * Determine if the robot is the Yahoo! multimedia crawler or not.
  1660.      * @access protected
  1661.      * @return boolean Returns true if the robot is the Yahoo! multimedia crawler, false otherwise.
  1662.      */
  1663.     protected function checkRobotYahooMultimedia()
  1664.     {
  1665.         return $this->checkSimpleRobot('Yahoo-MMCrawler'$this->_agentself::ROBOT_YAHOO_MM);
  1666.     }
  1667.  
  1668.     /**
  1669.      * Test the user agent for a specific browser where the browser name is immediately followed by the version number.
  1670.      * The user agent should look like: "Browser name/1.0" or "Browser 1.0;".
  1671.      * @access protected
  1672.      * @param mixed $uaNameToLookFor The string (or array of strings) representing the browser name to find in the user
  1673.      *  agent.
  1674.      * @param string $userAgent The user agent string to work with.
  1675.      * @param string $browserName The literal browser name. Always use a class constant!
  1676.      * @param boolean $isMobile (optional) Determines if the browser is from a mobile device.
  1677.      * @param string $separator (optional) The separator string used to split the browser name and the version number in
  1678.      *  the user agent.
  1679.      * @param boolean $uaNameFindWords (optional) Determines if the browser name to find should match a word instead of
  1680.      *  a part of a word. For example "Bar" would not be found in "FooBar" when true but would be found in "Foo Bar".
  1681.      *  When set to false, the browser name can be found anywhere in the user agent string.
  1682.      * @return boolean Returns true if we found the browser we were looking for, false otherwise.
  1683.      */
  1684.     protected function checkSimpleBrowserUA($uaNameToLookFor$userAgent$browserName$isMobile false$separator '/'$uaNameFindWords true)
  1685.     {
  1686.         if ($this->findAndGetVersion($uaNameToLookFor$userAgent$version$separator$uaNameFindWords)) {
  1687.             $this->setBrowser($browserName);
  1688.             $this->setVersion($version);
  1689.  
  1690.             $this->setMobile($isMobile);
  1691.  
  1692.             return true;
  1693.         }
  1694.  
  1695.         return false;
  1696.     }
  1697.  
  1698.     /**
  1699.      * Test the user agent for a specific robot where the robot name is immediately followed by the version number.
  1700.      * The user agent should look like: "Robot name/1.0" or "Robot 1.0;".
  1701.      * @access protected
  1702.      * @param mixed $uaNameToLookFor The string (or array of strings) representing the robot name to find in the user
  1703.      *  agent.
  1704.      * @param string $userAgent The user agent string to work with.
  1705.      * @param string $robotName The literal robot name. Always use a class constant!
  1706.      * @param string $separator (optional) The separator string used to split the robot name and the version number in
  1707.      *  the user agent.
  1708.      * @param boolean $uaNameFindWords (optional) Determines if the robot name to find should match a word instead of
  1709.      *  a part of a word. For example "Bar" would not be found in "FooBar" when true but would be found in "Foo Bar".
  1710.      *  When set to false, the robot name can be found anywhere in the user agent string.
  1711.      * @return boolean Returns true if we found the robot we were looking for, false otherwise.
  1712.      */
  1713.     protected function checkSimpleRobot($uaNameToLookFor$userAgent$robotName$separator '/'$uaNameFindWords true)
  1714.     {
  1715.         if ($this->findAndGetVersion($uaNameToLookFor$userAgent$version$separator$uaNameFindWords)) {
  1716.             $this->setRobot(true);
  1717.             $this->setRobotName($robotName);
  1718.             $this->setRobotVersion($version);
  1719.  
  1720.             return true;
  1721.         }
  1722.  
  1723.         return false;
  1724.     }
  1725.  
  1726.     /**
  1727.      * Clean a version string from unwanted characters.
  1728.      * @access protected
  1729.      * @param string $version The version string to clean.
  1730.      * @param mixed $toRemove (optional) String or array of strings representing additional string(s) to remove.
  1731.      * @return string Returns the cleaned version number string.
  1732.      */
  1733.     protected function cleanVersion($version$toRemove NULL)
  1734.     {
  1735.         $cleanVer $version;
  1736.         if ($toRemove !== NULL{
  1737.             $cleanVer str_ireplace($toRemove''$cleanVer);
  1738.         }
  1739.  
  1740.         //Clear anything that is in parentheses (and the parentheses themselves) - will clear started but unclosed ones too
  1741.         $cleanVer preg_replace('/\([^)]+\)?/'''$cleanVer);
  1742.         //Replace with a space any character which is NOT an alphanumeric, dot (.), hyphen (-), underscore (_) or space
  1743.         $cleanVer preg_replace('/[^0-9.a-zA-Z_ -]/'' '$cleanVer);
  1744.  
  1745.         //Remove trailing and leading spaces
  1746.         $cleanVer trim($cleanVer);
  1747.  
  1748.         //Remove trailing dot (.), hyphen (-), underscore (_)
  1749.         while (in_array(substr($cleanVer-1)array('.''-''_'))) {
  1750.             $cleanVer substr($cleanVer0-1);
  1751.         }
  1752.         //Remove leading dot (.), hyphen (-), underscore (_) and character v
  1753.         while (in_array(substr($cleanVer01)array('.''-''_''v''V'))) {
  1754.             $cleanVer substr($cleanVer1);
  1755.         }
  1756.  
  1757.         //Remove double spaces if any
  1758.         while (strpos($cleanVer'  '!== false{
  1759.             $cleanVer str_replace('  '' '$cleanVer);
  1760.         }
  1761.  
  1762.         return trim($cleanVer);
  1763.     }
  1764.  
  1765.     /**
  1766.      * Find if one or more substring is contained in a string.
  1767.      * @access protected
  1768.      * @param string $haystack The string to search in.
  1769.      * @param mixed $needle The string to search for. Can be a string or an array of strings if multiples values are to
  1770.      *  be searched.
  1771.      * @param boolean $insensitive (optional) Determines if we do a case-sensitive search (false) or a case-insensitive
  1772.      *  one (true).
  1773.      * @param boolean $findWords (optional) Determines if the needle should match a word to be found. For example "Bar"
  1774.      *  would not be found in "FooBar" when true but would be found in "Foo Bar". When set to false, the needle can be
  1775.      *  found anywhere in the haystack.
  1776.      * @param int $foundPos (optional) Integer buffer that will contain the position of the needle (if found and if a
  1777.      *  non NULL variable has been passed).
  1778.      * @return boolean Returns true if the needle (or one of the needles) has been found in the haystack, false
  1779.      *  otherwise.
  1780.      */
  1781.     protected function containString($haystack$needle$insensitive true$findWords true&$foundPos NULL)
  1782.     {
  1783.         if (!is_array($needle)) {
  1784.             $needle array($needle);
  1785.         }
  1786.  
  1787.         foreach ($needle as $currNeedle{
  1788.             if ($findWords{
  1789.                  $position $this->wordPos($haystack$currNeedle$insensitive);
  1790.             else {
  1791.                 if ($insensitive{
  1792.                     $position stripos($haystack$currNeedle);
  1793.                 else {
  1794.                     $position strpos($haystack$currNeedle);
  1795.                 }
  1796.             }
  1797.  
  1798.             if ($position !== false{
  1799.                 if ($foundPos !== NULL{
  1800.                     $foundPos $position;
  1801.                 }
  1802.                 return true;
  1803.             }
  1804.         }
  1805.  
  1806.         return false;
  1807.     }
  1808.  
  1809.     /**
  1810.      * Detect the user environment from the details in the user agent string.
  1811.      * @access protected
  1812.      */
  1813.     protected function detect()
  1814.     {
  1815.         $this->checkBrowser();
  1816.         $this->checkPlatform()//Check the platform after the browser since some platforms can change the mobile value
  1817.         $this->checkRobot();
  1818.     }
  1819.  
  1820.     /**
  1821.      * Test the user agent for a specific browser and extract it's version.
  1822.      * @access protected
  1823.      * @param type $uaNameToLookFor The string (or array of strings) representing the browser name to find in the user
  1824.      *  agent.
  1825.      * @param type $userAgent The user agent string to work with.
  1826.      * @param type $version String buffer that will contain the version found (if any).
  1827.      * @param type $separator (optional) The separator string used to split the browser name and the version number in
  1828.      *  the user agent.
  1829.      * @param type $uaNameFindWords (optional) Determines if the browser name to find should match a word instead of
  1830.      *  a part of a word. For example "Bar" would not be found in "FooBar" when true but would be found in "Foo Bar".
  1831.      *  When set to false, the browser name can be found anywhere in the user agent string.
  1832.      * @return boolean Returns true if we found the browser we were looking for, false otherwise.
  1833.      */
  1834.     protected function findAndGetVersion($uaNameToLookFor$userAgent&$version$separator '/'$uaNameFindWords true)
  1835.     {
  1836.         $version '';
  1837.         if (!is_array($uaNameToLookFor)) {
  1838.             $uaNameToLookFor array($uaNameToLookFor);
  1839.         }
  1840.  
  1841.         foreach ($uaNameToLookFor as $currUANameToLookFor{
  1842.             $foundPos = -1;
  1843.             if ($this->containString($userAgent$currUANameToLookFortrue$uaNameFindWords$foundPos)) {
  1844.                 //Many browsers don't use the standard "Browser/1.0" format, they uses "Browser 1.0;" instead
  1845.                 if (stripos($userAgent$currUANameToLookFor $separator=== false{
  1846.                     $userAgent str_ireplace($currUANameToLookFor ' '$currUANameToLookFor $separator$userAgent);
  1847.                 }
  1848.  
  1849.                 $verParts explode($separatorsubstr($userAgent$foundPos));
  1850.                 if (count($verParts1{
  1851.                     $verParts explode(' '$verParts[1]);
  1852.                     $version $verParts[0];
  1853.                 }
  1854.  
  1855.                 return true;
  1856.             }
  1857.         }
  1858.  
  1859.         return false;
  1860.     }
  1861.  
  1862.     /**
  1863.      * Convert the iOS version numbers to the operating system name. For instance '2.0' returns 'iPhone OS 2.0'.
  1864.      * @access protected
  1865.      * @param string $iOSVer The iOS version numbers as a string.
  1866.      * @return string The operating system name.
  1867.      */
  1868.     protected function iOSVerToStr($iOSVer)
  1869.     {
  1870.         if ($this->compareVersions($iOSVer'3.0'<= 0{
  1871.             return 'iPhone OS ' $iOSVer;
  1872.         else {
  1873.             return 'iOS ' $iOSVer;
  1874.         }
  1875.     }
  1876.  
  1877.     /**
  1878.      * Convert the macOS version numbers to the operating system name. For instance '10.7' returns 'Mac OS X Lion'.
  1879.      * @access protected
  1880.      * @param string $macVer The macOS version numbers as a string.
  1881.      * @return string The operating system name or the constant PLATFORM_VERSION_UNKNOWN if nothing match the version
  1882.      *  numbers.
  1883.      */
  1884.     protected function macVerToStr($macVer)
  1885.     {
  1886.         //https://en.wikipedia.org/wiki/OS_X#Release_history
  1887.  
  1888.         if ($this->_platformVersion === '10'{
  1889.             return 'Mac OS X'//Unspecified Mac OS X version
  1890.         else if ($this->compareVersions($macVer'12.0'>= && $this->compareVersions($macVer'13.0'0{
  1891.             return 'macOS Monterey';
  1892.         else if ($this->compareVersions($macVer'11.0'>= && $this->compareVersions($macVer'12.0'0{
  1893.             return 'macOS Big Sur';
  1894.         else if ($this->compareVersions($macVer'10.15'>= && $this->compareVersions($macVer'10.16'0{
  1895.             return 'macOS Catalina';
  1896.         else if ($this->compareVersions($macVer'10.14'>= && $this->compareVersions($macVer'10.15'0{
  1897.             return 'macOS Mojave';
  1898.         else if ($this->compareVersions($macVer'10.13'>= && $this->compareVersions($macVer'10.14'0{
  1899.             return 'macOS High Sierra';
  1900.         else if ($this->compareVersions($macVer'10.12'>= && $this->compareVersions($macVer'10.13'0{
  1901.             return 'macOS Sierra';
  1902.         else if ($this->compareVersions($macVer'10.11'>= && $this->compareVersions($macVer'10.12'0{
  1903.             return 'OS X El Capitan';
  1904.         else if ($this->compareVersions($macVer'10.10'>= && $this->compareVersions($macVer'10.11'0{
  1905.             return 'OS X Yosemite';
  1906.         else if ($this->compareVersions($macVer'10.9'>= && $this->compareVersions($macVer'10.10'0{
  1907.             return 'OS X Mavericks';
  1908.         else if ($this->compareVersions($macVer'10.8'>= && $this->compareVersions($macVer'10.9'0{
  1909.             return 'OS X Mountain Lion';
  1910.         else if ($this->compareVersions($macVer'10.7'>= && $this->compareVersions($macVer'10.8'0{
  1911.             return 'Mac OS X Lion';
  1912.         else if ($this->compareVersions($macVer'10.6'>= && $this->compareVersions($macVer'10.7'0{
  1913.             return 'Mac OS X Snow Leopard';
  1914.         else if ($this->compareVersions($macVer'10.5'>= && $this->compareVersions($macVer'10.6'0{
  1915.             return 'Mac OS X Leopard';
  1916.         else if ($this->compareVersions($macVer'10.4'>= && $this->compareVersions($macVer'10.5'0{
  1917.             return 'Mac OS X Tiger';
  1918.         else if ($this->compareVersions($macVer'10.3'>= && $this->compareVersions($macVer'10.4'0{
  1919.             return 'Mac OS X Panther';
  1920.         else if ($this->compareVersions($macVer'10.2'>= && $this->compareVersions($macVer'10.3'0{
  1921.             return 'Mac OS X Jaguar';
  1922.         else if ($this->compareVersions($macVer'10.1'>= && $this->compareVersions($macVer'10.2'0{
  1923.             return 'Mac OS X Puma';
  1924.         else if ($this->compareVersions($macVer'10.0'>= && $this->compareVersions($macVer'10.1'0{
  1925.             return 'Mac OS X Cheetah';
  1926.         else {
  1927.             return self::PLATFORM_VERSION_UNKNOWN//Unknown/unnamed Mac OS version
  1928.         }
  1929.     }
  1930.  
  1931.     /**
  1932.      * Get the integer value of a string variable.
  1933.      * @access protected
  1934.      * @param string $intStr The scalar value being converted to an integer.
  1935.      * @return int The integer value of $intStr on success, or 0 on failure.
  1936.      */
  1937.     protected function parseInt($intStr)
  1938.     {
  1939.         return intval($intStr10);
  1940.     }
  1941.  
  1942.     /**
  1943.      * Reset all the properties of the class.
  1944.      * @access protected
  1945.      */
  1946.     protected function reset()
  1947.     {
  1948.         $this->_agent = '';
  1949.         $this->_browserName = self::BROWSER_UNKNOWN;
  1950.         $this->_compatibilityViewName = '';
  1951.         $this->_compatibilityViewVer = '';
  1952.         $this->_is64bit = false;
  1953.         $this->_isMobile = false;
  1954.         $this->_isRobot = false;
  1955.         $this->_platform = self::PLATFORM_UNKNOWN;
  1956.         $this->_platformVersion = self::PLATFORM_VERSION_UNKNOWN;
  1957.         $this->_robotName = self::ROBOT_UNKNOWN;
  1958.         $this->_robotVersion = self::ROBOT_VERSION_UNKNOWN;
  1959.         $this->_version = self::VERSION_UNKNOWN;
  1960.     }
  1961.  
  1962.     /**
  1963.      * Convert a Safari build number to a Safari version number.
  1964.      * @access protected
  1965.      * @param string $version A string representing the version number.
  1966.      * @link https://web.archive.org/web/20080514173941/http://developer.apple.com/internet/safari/uamatrix.html
  1967.      * @return string Returns the Safari version string. If the version can't be determined, an empty string is
  1968.      *  returned.
  1969.      */
  1970.     protected function safariBuildToSafariVer($version)
  1971.     {
  1972.         $verParts explode('.'$version);
  1973.  
  1974.         //We need a 3 parts version (version 2 will becomes 2.0.0)
  1975.         while (count($verParts3{
  1976.             $verParts[0;
  1977.         }
  1978.         foreach ($verParts as $i => $currPart{
  1979.             $verParts[$i$this->parseInt($currPart);
  1980.         }
  1981.  
  1982.         switch ($verParts[0]{
  1983.             case 419$result '2.0.4';
  1984.                 break;
  1985.             case 417$result '2.0.3';
  1986.                 break;
  1987.             case 416$result '2.0.2';
  1988.                 break;
  1989.  
  1990.             case 412:
  1991.                 if ($verParts[1>= 5{
  1992.                     $result '2.0.1';
  1993.                 else {
  1994.                     $result '2.0';
  1995.                 }
  1996.                 break;
  1997.  
  1998.             case 312:
  1999.                 if ($verParts[1>= 5{
  2000.                     $result '1.3.2';
  2001.                 else {
  2002.                     if ($verParts[1>= 3{
  2003.                         $result '1.3.1';
  2004.                     else {
  2005.                         $result '1.3';
  2006.                     }
  2007.                 }
  2008.                 break;
  2009.  
  2010.             case 125:
  2011.                 if ($verParts[1>= 11{
  2012.                     $result '1.2.4';
  2013.                 else {
  2014.                     if ($verParts[1>= 9{
  2015.                         $result '1.2.3';
  2016.                     else {
  2017.                         if ($verParts[1>= 7{
  2018.                             $result '1.2.2';
  2019.                         else {
  2020.                             $result '1.2';
  2021.                         }
  2022.                     }
  2023.                 }
  2024.                 break;
  2025.  
  2026.             case 100:
  2027.                 if ($verParts[1>= 1{
  2028.                     $result '1.1.1';
  2029.                 else {
  2030.                     $result '1.1';
  2031.                 }
  2032.                 break;
  2033.  
  2034.             case 85:
  2035.                 if ($verParts[1>= 8{
  2036.                     $result '1.0.3';
  2037.                 else {
  2038.                     if ($verParts[1>= 7{
  2039.                         $result '1.0.2';
  2040.                     else {
  2041.                         $result '1.0';
  2042.                     }
  2043.                 }
  2044.                 break;
  2045.  
  2046.             case 73$result '0.9';
  2047.                 break;
  2048.             case 51$result '0.8.1';
  2049.                 break;
  2050.             case 48$result '0.8';
  2051.                 break;
  2052.  
  2053.             default$result '';
  2054.         }
  2055.  
  2056.         return $result;
  2057.     }
  2058.  
  2059.     /**
  2060.      * Set if the browser is executed from a 64-bit platform.
  2061.      * @access protected
  2062.      * @param boolean $is64bit Value that tells if the browser is executed from a 64-bit platform.
  2063.      */
  2064.     protected function set64bit($is64bit)
  2065.     {
  2066.         $this->_is64bit = $is64bit == true;
  2067.     }
  2068.  
  2069.     /**
  2070.      * Set the name of the browser.
  2071.      * @access protected
  2072.      * @param string $browserName The name of the browser.
  2073.      */
  2074.     protected function setBrowser($browserName)
  2075.     {
  2076.         $this->_browserName = $browserName;
  2077.     }
  2078.  
  2079.     /**
  2080.      * Set the browser to be from a mobile device or not.
  2081.      * @access protected
  2082.      * @param boolean $isMobile (optional) Value that tells if the browser is on a mobile device or not.
  2083.      */
  2084.     protected function setMobile($isMobile true)
  2085.     {
  2086.         $this->_isMobile = $isMobile == true;
  2087.     }
  2088.  
  2089.     /**
  2090.      * Set the platform on which the browser is on.
  2091.      * @access protected
  2092.      * @param string $platform The name of the platform.
  2093.      */
  2094.     protected function setPlatform($platform)
  2095.     {
  2096.         $this->_platform = $platform;
  2097.     }
  2098.  
  2099.     /**
  2100.      * Set the platform version on which the browser is on.
  2101.      * @access protected
  2102.      * @param string $platformVer The version numbers of the platform.
  2103.      */
  2104.     protected function setPlatformVersion($platformVer)
  2105.     {
  2106.         $this->_platformVersion = $platformVer;
  2107.     }
  2108.  
  2109.     /**
  2110.      * Set the browser to be a robot (crawler) or not.
  2111.      * @access protected
  2112.      * @param boolean $isRobot (optional) Value that tells if the browser is a robot or not.
  2113.      */
  2114.     protected function setRobot($isRobot true)
  2115.     {
  2116.         $this->_isRobot = $isRobot == true;
  2117.     }
  2118.  
  2119.     /**
  2120.      * Set the name of the robot.
  2121.      * @access protected
  2122.      * @param string $robotName The name of the robot.
  2123.      */
  2124.     protected function setRobotName($robotName)
  2125.     {
  2126.         $this->_robotName = $robotName;
  2127.     }
  2128.  
  2129.     /**
  2130.      * Set the version of the robot.
  2131.      * @access protected
  2132.      * @param string $robotVersion The version of the robot.
  2133.      */
  2134.     protected function setRobotVersion($robotVersion)
  2135.     {
  2136.         $cleanVer $this->cleanVersion($robotVersion);
  2137.  
  2138.         if ($cleanVer == ''{
  2139.             $this->_robotVersion = self::ROBOT_VERSION_UNKNOWN;
  2140.         else {
  2141.             $this->_robotVersion = $cleanVer;
  2142.         }
  2143.     }
  2144.  
  2145.     /**
  2146.      * Set the version of the browser.
  2147.      * @access protected
  2148.      * @param string $version The version of the browser.
  2149.      */
  2150.     protected function setVersion($version)
  2151.     {
  2152.         $cleanVer $this->cleanVersion($version);
  2153.  
  2154.         if ($cleanVer == ''{
  2155.             $this->_version = self::VERSION_UNKNOWN;
  2156.         else {
  2157.             $this->_version = $cleanVer;
  2158.         }
  2159.     }
  2160.  
  2161.     /**
  2162.      * Convert a WebKit build number to a Safari version number.
  2163.      * @access protected
  2164.      * @param string $version A string representing the version number.
  2165.      * @link https://web.archive.org/web/20080514173941/http://developer.apple.com/internet/safari/uamatrix.html
  2166.      * @return string Returns the Safari version string. If the version can't be determined, an empty string is
  2167.      *  returned.
  2168.      */
  2169.     protected function webKitBuildToSafariVer($version)
  2170.     {
  2171.         $verParts explode('.'$version);
  2172.  
  2173.         //We need a 3 parts version (version 2 will becomes 2.0.0)
  2174.         while (count($verParts3{
  2175.             $verParts[0;
  2176.         }
  2177.         foreach ($verParts as $i => $currPart{
  2178.             $verParts[$i$this->parseInt($currPart);
  2179.         }
  2180.  
  2181.         switch ($verParts[0]{
  2182.             case 419$result '2.0.4';
  2183.                 break;
  2184.  
  2185.             case 418:
  2186.                 if ($verParts[1>= 8{
  2187.                     $result '2.0.4';
  2188.                 else {
  2189.                     $result '2.0.3';
  2190.                 }
  2191.                 break;
  2192.  
  2193.             case 417$result '2.0.3';
  2194.                 break;
  2195.  
  2196.             case 416$result '2.0.2';
  2197.                 break;
  2198.  
  2199.             case 412:
  2200.                 if ($verParts[1>= 7{
  2201.                     $result '2.0.1';
  2202.                 else {
  2203.                     $result '2.0';
  2204.                 }
  2205.                 break;
  2206.  
  2207.             case 312:
  2208.                 if ($verParts[1>= 8{
  2209.                     $result '1.3.2';
  2210.                 else {
  2211.                     if ($verParts[1>= 5{
  2212.                         $result '1.3.1';
  2213.                     else {
  2214.                         $result '1.3';
  2215.                     }
  2216.                 }
  2217.                 break;
  2218.  
  2219.             case 125:
  2220.                 if ($this->compareVersions('5.4'$verParts[1'.' $verParts[2]== -1{
  2221.                     $result '1.2.4'//125.5.5+
  2222.                 else {
  2223.                     if ($verParts[1>= 4{
  2224.                         $result '1.2.3';
  2225.                     else {
  2226.                         if ($verParts[1>= 2{
  2227.                             $result '1.2.2';
  2228.                         else {
  2229.                             $result '1.2';
  2230.                         }
  2231.                     }
  2232.                 }
  2233.                 break;
  2234.  
  2235.             //WebKit 100 can be either Safari 1.1 (Safari build 100) or 1.1.1 (Safari build 100.1)
  2236.             //for this reason, check the Safari build before the WebKit build.
  2237.             case 100$result '1.1.1';
  2238.                 break;
  2239.  
  2240.             case 85:
  2241.                 if ($verParts[1>= 8{
  2242.                     $result '1.0.3';
  2243.                 else {
  2244.                     if ($verParts[1>= 7{
  2245.                         //WebKit 85.7 can be either Safari 1.0 (Safari build 85.5) or 1.0.2 (Safari build 85.7)
  2246.                         //for this reason, check the Safari build before the WebKit build.
  2247.                         $result '1.0.2';
  2248.                     else {
  2249.                         $result '1.0';
  2250.                     }
  2251.                 }
  2252.                 break;
  2253.  
  2254.             case 73$result '0.9';
  2255.                 break;
  2256.             case 51$result '0.8.1';
  2257.                 break;
  2258.             case 48$result '0.8';
  2259.                 break;
  2260.  
  2261.             default$result '';
  2262.         }
  2263.  
  2264.         return $result;
  2265.     }
  2266.  
  2267.     /**
  2268.      * Convert the Windows NT family version numbers to the operating system name. For instance '5.1' returns
  2269.      * 'Windows XP'.
  2270.      * @access protected
  2271.      * @param string $winVer The Windows NT family version numbers as a string.
  2272.      * @param boolean $returnServerFlavor (optional) Since some Windows NT versions have the same values, this flag
  2273.      *  determines if the Server flavor is returned or not. For instance Windows 8.1 and Windows Server 2012 R2 both use
  2274.      *  version 6.3.
  2275.      * @return string The operating system name or the constant PLATFORM_VERSION_UNKNOWN if nothing match the version
  2276.      *  numbers.
  2277.      */
  2278.     protected function windowsNTVerToStr($winVer$returnServerFlavor false)
  2279.     {
  2280.         //https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions
  2281.  
  2282.         $cleanWinVer explode('.'$winVer);
  2283.         while (count($cleanWinVer2{
  2284.             array_pop($cleanWinVer);
  2285.         }
  2286.         $cleanWinVer implode('.'$cleanWinVer);
  2287.  
  2288.         if ($this->compareVersions($cleanWinVer'11'>= 0{
  2289.             return self::PLATFORM_WINDOWS ' ' $winVer;
  2290.         else if ($this->compareVersions($cleanWinVer'10'>= 0{
  2291.             //(Windows Server 2022, 2019 & 2016 have the same version number. Only the build can separate the two - which is not included in the UA)
  2292.             return $returnServerFlavor (self::PLATFORM_WINDOWS ' Server 2022'(self::PLATFORM_WINDOWS ' 10');
  2293.         else if ($this->compareVersions($cleanWinVer'7'0{
  2294.             if ($this->compareVersions($cleanWinVer'6.3'== 0{
  2295.                 return $returnServerFlavor (self::PLATFORM_WINDOWS ' Server 2012 R2'(self::PLATFORM_WINDOWS ' 8.1');
  2296.             else if ($this->compareVersions($cleanWinVer'6.2'== 0{
  2297.                 return $returnServerFlavor (self::PLATFORM_WINDOWS ' Server 2012'(self::PLATFORM_WINDOWS ' 8');
  2298.             else if ($this->compareVersions($cleanWinVer'6.1'== 0{
  2299.                 return $returnServerFlavor (self::PLATFORM_WINDOWS ' Server 2008 R2'(self::PLATFORM_WINDOWS ' 7');
  2300.             else if ($this->compareVersions($cleanWinVer'6'== 0{
  2301.                 return $returnServerFlavor (self::PLATFORM_WINDOWS ' Server 2008'(self::PLATFORM_WINDOWS ' Vista');
  2302.             else if ($this->compareVersions($cleanWinVer'5.2'== 0{
  2303.                 return $returnServerFlavor (self::PLATFORM_WINDOWS ' Server 2003 / ' self::PLATFORM_WINDOWS ' Server 2003 R2'(self::PLATFORM_WINDOWS ' XP x64 Edition');
  2304.             else if ($this->compareVersions($cleanWinVer'5.1'== 0{
  2305.                 return self::PLATFORM_WINDOWS ' XP';
  2306.             else if ($this->compareVersions($cleanWinVer'5'== 0{
  2307.                 return self::PLATFORM_WINDOWS ' 2000';
  2308.             else if ($this->compareVersions($cleanWinVer'5'&& $this->compareVersions($cleanWinVer'3'>= 0{
  2309.                 return self::PLATFORM_WINDOWS ' NT ' $winVer;
  2310.             }
  2311.         }
  2312.  
  2313.         return self::PLATFORM_VERSION_UNKNOWN//Invalid Windows NT version
  2314.     }
  2315.  
  2316.     /**
  2317.      * Convert the Windows 3.x & 9x family version numbers to the operating system name. For instance '4.10.1998'
  2318.      * returns 'Windows 98'.
  2319.      * @access protected
  2320.      * @param string $winVer The Windows 3.x or 9x family version numbers as a string.
  2321.      * @return string The operating system name or the constant PLATFORM_VERSION_UNKNOWN if nothing match the version
  2322.      *  numbers.
  2323.      */
  2324.     protected function windowsVerToStr($winVer)
  2325.     {
  2326.         //https://support.microsoft.com/en-us/kb/158238
  2327.  
  2328.         if ($this->compareVersions($winVer'4.90'>= && $this->compareVersions($winVer'4.91'0{
  2329.             return self::PLATFORM_WINDOWS ' Me'//Normally range from 4.90.3000 to 4.90.3000A
  2330.         else if ($this->compareVersions($winVer'4.10'>= && $this->compareVersions($winVer'4.11'0{
  2331.             return self::PLATFORM_WINDOWS ' 98'//Normally range from 4.10.1998 to 4.10.2222B
  2332.         else if ($this->compareVersions($winVer'4'>= && $this->compareVersions($winVer'4.04'0{
  2333.             return self::PLATFORM_WINDOWS ' 95'//Normally range from 4.00.950 to 4.03.1214
  2334.         else if ($this->compareVersions($winVer'3.1'== || $this->compareVersions($winVer'3.11'== 0{
  2335.             return self::PLATFORM_WINDOWS ' ' $winVer;
  2336.         else if ($this->compareVersions($winVer'3.10'== 0{
  2337.             return self::PLATFORM_WINDOWS ' 3.1';
  2338.         else {
  2339.             return self::PLATFORM_VERSION_UNKNOWN//Invalid Windows version
  2340.         }
  2341.     }
  2342.  
  2343.     /**
  2344.      * Find the position of the first occurrence of a word in a string.
  2345.      * @access protected
  2346.      * @param string $haystack The string to search in.
  2347.      * @param string $needle The string to search for.
  2348.      * @param boolean $insensitive (optional) Determines if we do a case-sensitive search (false) or a case-insensitive
  2349.      *  one (true).
  2350.      * @param int $offset If specified, search will start this number of characters counted from the beginning of the
  2351.      *  string. If the offset is negative, the search will start this number of characters counted from the end of the
  2352.      *  string.
  2353.      * @param string $foundString String buffer that will contain the exact matching needle found. Set to NULL when
  2354.      *  return value of the function is false.
  2355.      * @return mixed Returns the position of the needle (int) if found, false otherwise. Warning this function may
  2356.      *  return Boolean false, but may also return a non-Boolean value which evaluates to false.
  2357.      */
  2358.     protected function wordPos($haystack$needle$insensitive true$offset 0&$foundString NULL)
  2359.     {
  2360.         if ($offset != 0{
  2361.             $haystack substr($haystack$offset);
  2362.         }
  2363.  
  2364.         $parts explode(' '$needle);
  2365.         foreach ($parts as $i => $currPart{
  2366.             $parts[$ipreg_quote($currPart'/');
  2367.         }
  2368.  
  2369.         $regex '/(?<=\A|[\s\/\\.,;:_()-])' implode('[\s\/\\.,;:_()-]'$parts'(?=[\s\/\\.,;:_()-]|$)/';
  2370.         if ($insensitive{
  2371.              $regex .= 'i';
  2372.         }
  2373.  
  2374.         if (preg_match($regex$haystack$matchesPREG_OFFSET_CAPTURE)) {
  2375.             $foundString $matches[0][0];
  2376.             return (int)$matches[0][1];
  2377.         }
  2378.  
  2379.         return false;
  2380.     }
  2381. }

Documentation generated on Tue, 20 Sep 2022 23:35:15 -0400 by phpDocumentor 1.4.3