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

Documentation generated on Sun, 02 Feb 2020 00:29:49 -0500 by phpDocumentor 1.4.3