File "BrowserDetection.php"
Full Path: /home/pumpbmko/public_html/wp-content/themes/momota/lib/browser-detection/BrowserDetection.php
File size: 84.76 KB
MIME-type: text/x-php
Charset: utf-8
<?php
/**
* Browser detection class file.
* This file contains everything required to use the BrowserDetection class. Tested with PHP 5.3.29 - 7.2.4.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any
* later version (if any).
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details at: https://www.gnu.org/licenses/lgpl-3.0.html
*
* @package Browser_Detection
* @version 2.9.5
* @last-modified February 2, 2020
* @author Alexandre Valiquette
* @copyright Copyright (c) 2020, Wolfcast
* @link https://wolfcast.com/
*/
namespace Wolfcast;
/**
* The BrowserDetection class facilitates the identification of the user's environment such as Web browser, version,
* platform and device type.
*
* Typical usage:
*
* $browser = new Wolfcast\BrowserDetection();
* if ($browser->getName() == Wolfcast\BrowserDetection::BROWSER_FIREFOX &&
* $browser->compareVersions($browser->getVersion(), '5.0') >= 0) {
* echo 'You are using FireFox version 5 or greater.';
* }
*
* The class is a rewrite of Chris Schuld's Browser class version 1.9 which is mostly unmaintained since August 20th,
* 2010. Chris' class was based on the original work from Gary White.
*
* Updates:
*
* 2020-02-02: Version 2.9.5
* + WARNING! Breaking change: complete rework of robots detection. Now robot name and version is detected in addition
* of browser name and version. Use getRobotName() and getRobotVersion() when isRobot() is true.
* + WARNING! Breaking change: due to robots detection rework the following methods signatures has changed (isRobot
* parameter removed): addCustomBrowserDetection(), checkSimpleBrowserUA(), checkBrowserUAWithVersion().
* + Added possibility to support new robots with addCustomRobotDetection().
* + Added support for the new Microsoft Edge based on Chromium.
* + Added version names for Android 10 and later (Google no longer use candy names for new versions).
* + Added macOS Catalina detection.
* + Added Windows Server 2019 detection (Windows Server 2016 can be no longer detected due to the fact that they both
* use the same version number and that the build is not included in the user agent).
*
* 2019-03-27: Version 2.9.3
* + Fixed Edge detection on Android.
* + Added Android Q detection.
* + Now filtering superglobals.
*
* 2019-02-28: Version 2.9.2
* + Fixed Opera detection.
*
* 2018-08-23: Version 2.9.1
* + Fixed Chrome detection under iOS.
* + Added Android Pie detection.
* + Added macOS Mojave detection.
*
* 2018-07-15: Version 2.9.0
* + WARNING! Breaking change: new Wolfcast namespace. Use new Wolfcast\BrowserDetection().
* + iPad, iPhone and iPod are all under iOS now.
* + Added Android Oreo detection.
* + Added macOS High Sierra detection.
* + Added UC Browser detection.
* + Improved regular expressions (even less false positives).
* + Removed AOL detection.
* + Removed the following Web browsers detection: Amaya, Galeon, NetPositive, OmniWeb, Vivaldi detection (use
* addCustomBrowserDetection()).
* + Removed the following legacy platforms detection: BeOS, OS/2, SunOS (use addCustomPlatformDetection()).
*
* 2016-11-28: Version 2.5.1
* + Better detection of 64-bit platforms.
*
* 2016-08-19: Version 2.5.0
* + Platform version and platform version name are now supported for Mac.
* + Fixed platform version name for Android.
*
* 2016-08-02: Version 2.4.0
* + Platform version and platform version name are now supported for Android.
* + Added support for the Samsung Internet browser.
* + Added support for the Vivaldi browser.
* + Better support for legacy Windows versions.
*
* 2016-02-11: Version 2.3.0
* + WARNING! Breaking change: public method getBrowser() is renamed to getName().
* + WARNING! Breaking change: changed the compareVersions() return values to be more in line with other libraries.
* + You can now get the exact platform version (name or version numbers) on which the browser is run on with
* getPlatformVersion(). Only working with Windows operating systems at the moment.
* + You can now determine if the browser is executed from a 64-bit platform with is64bitPlatform().
* + Better detection of mobile platform for Googlebot.
*
* 2016-01-04: Version 2.2.0
* + Added support for Microsoft Edge.
*
* 2014-12-30: Version 2.1.2
* + Better detection of Opera.
*
* 2014-07-11: Version 2.1.1
* + Better detection of mobile devices and platforms.
*
* 2014-06-04: Version 2.1.0
* + Added support for IE 11+.
*
* 2013-05-27: Version 2.0.0 which is (almost) a complete rewrite based on Chris Schuld's Browser class version 1.9 plus
* changes below.
* + Added support for Opera Mobile
* + Added support for the Windows Phone (formerly Windows Mobile) platform
* + Added support for BlackBerry Tablet OS and BlackBerry 10
* + Added support for the Symbian platform
* + Added support for Bingbot
* + Added support for the Yahoo! Multimedia crawler
* + Removed iPhone/iPad/iPod browsers since there are not browsers but platforms - test them with getPlatform()
* + Removed support for Shiretoko (Firefox 3.5 alpha/beta) and MSN Browser
* + Merged Nokia and Nokia S60
* + Updated some deprecated browser names
* + Many public methods are now protected
* + Documentation updated
*
* 2010-07-04:
* + Added detection of IE compatibility view - test with getIECompatibilityView()
* + Added support for all (deprecated) Netscape versions
* + Added support for Safari < 3.0
* + Better Firefox version parsing
* + Better Opera version parsing
* + Better Mozilla detection
*
* @package Browser_Detection
* @version 2.9.5
* @last-modified February 2, 2020
* @author Alexandre Valiquette, Chris Schuld, Gary White
* @copyright Copyright (c) 2020, Wolfcast
* @license https://www.gnu.org/licenses/lgpl-3.0.html
* @link https://wolfcast.com/
* @link https://wolfcast.com/open-source/browser-detection/tutorial.php
* @link https://chrisschuld.com/
* @link https://www.apptools.com/phptools/browser/
*/
class BrowserDetection {
/**#@+
* Constant for the name of the Web browser.
*/
const BROWSER_ANDROID = 'Android';
const BROWSER_BLACKBERRY = 'BlackBerry';
const BROWSER_CHROME = 'Chrome';
const BROWSER_EDGE = 'Edge';
const BROWSER_FIREBIRD = 'Firebird';
const BROWSER_FIREFOX = 'Firefox';
const BROWSER_ICAB = 'iCab';
const BROWSER_ICECAT = 'GNU IceCat';
const BROWSER_ICEWEASEL = 'GNU IceWeasel';
const BROWSER_IE = 'Internet Explorer';
const BROWSER_IE_MOBILE = 'Internet Explorer Mobile';
const BROWSER_KONQUEROR = 'Konqueror';
const BROWSER_LYNX = 'Lynx';
const BROWSER_MOZILLA = 'Mozilla';
const BROWSER_MSNTV = 'MSN TV';
const BROWSER_NETSCAPE = 'Netscape';
const BROWSER_NOKIA = 'Nokia Browser';
const BROWSER_OPERA = 'Opera';
const BROWSER_OPERA_MINI = 'Opera Mini';
const BROWSER_OPERA_MOBILE = 'Opera Mobile';
const BROWSER_PHOENIX = 'Phoenix';
const BROWSER_SAFARI = 'Safari';
const BROWSER_SAMSUNG = 'Samsung Internet';
const BROWSER_TABLET_OS = 'BlackBerry Tablet OS';
const BROWSER_UC = 'UC Browser';
const BROWSER_UNKNOWN = 'unknown';
/**#@-*/
/**#@+
* Constant for the name of the platform on which the Web browser runs.
*/
const PLATFORM_ANDROID = 'Android';
const PLATFORM_BLACKBERRY = 'BlackBerry';
const PLATFORM_FREEBSD = 'FreeBSD';
const PLATFORM_IOS = 'iOS';
const PLATFORM_LINUX = 'Linux';
const PLATFORM_MACINTOSH = 'Macintosh';
const PLATFORM_NETBSD = 'NetBSD';
const PLATFORM_NOKIA = 'Nokia';
const PLATFORM_OPENBSD = 'OpenBSD';
const PLATFORM_OPENSOLARIS = 'OpenSolaris';
const PLATFORM_SYMBIAN = 'Symbian';
const PLATFORM_UNKNOWN = 'unknown';
const PLATFORM_VERSION_UNKNOWN = 'unknown';
const PLATFORM_WINDOWS = 'Windows';
const PLATFORM_WINDOWS_CE = 'Windows CE';
const PLATFORM_WINDOWS_PHONE = 'Windows Phone';
/**#@-*/
/**#@+
* Constant for the name of the robot.
*/
const ROBOT_BINGBOT = 'Bingbot';
const ROBOT_GOOGLEBOT = 'Googlebot';
const ROBOT_MSNBOT = 'MSNBot';
const ROBOT_SLURP = 'Yahoo! Slurp';
const ROBOT_UNKNOWN = '';
const ROBOT_VERSION_UNKNOWN = '';
const ROBOT_W3CVALIDATOR = 'W3C Validator';
const ROBOT_YAHOO_MM = 'Yahoo! Multimedia';
/**#@-*/
/**
* Version unknown constant.
*/
const VERSION_UNKNOWN = 'unknown';
/**
* @var string
* @access private
*/
private $_agent = '';
/**
* @var string
* @access private
*/
private $_browserName = '';
/**
* @var string
* @access private
*/
private $_compatibilityViewName = '';
/**
* @var string
* @access private
*/
private $_compatibilityViewVer = '';
/**
* @var array
* @access private
*/
private $_customBrowserDetection = array();
/**
* @var array
* @access private
*/
private $_customPlatformDetection = array();
/**
* @var array
* @access private
*/
private $_customRobotDetection = array();
/**
* @var boolean
* @access private
*/
private $_is64bit = false;
/**
* @var boolean
* @access private
*/
private $_isMobile = false;
/**
* @var boolean
* @access private
*/
private $_isRobot = false;
/**
* @var string
* @access private
*/
private $_platform = '';
/**
* @var string
* @access private
*/
private $_platformVersion = '';
/**
* @var string
* @access private
*/
private $_robotName = '';
/**
* @var string
* @access private
*/
private $_robotVersion = '';
/**
* @var string
* @access private
*/
private $_version = '';
//--- MAGIC METHODS ------------------------------------------------------------------------------------------------
/**
* BrowserDetection class constructor.
* @param string $useragent (optional) The user agent to work with. Leave empty for the current user agent
* (contained in $_SERVER['HTTP_USER_AGENT']).
*/
public function __construct( $useragent = '' ) {
$this->setUserAgent( $useragent );
}
/**
* Determine how the class will react when it is treated like a string.
* @return string Returns an HTML formatted string with a summary of the browser informations.
*/
public function __toString() {
$result = '';
$values = array();
$values[] = array(
'label' => 'User agent',
'value' => $this->getUserAgent(),
);
$values[] = array(
'label' => 'Browser name',
'value' => $this->getName(),
);
$values[] = array(
'label' => 'Browser version',
'value' => $this->getVersion(),
);
$values[] = array(
'label' => 'Platform family',
'value' => $this->getPlatform(),
);
$values[] = array(
'label' => 'Platform version',
'value' => $this->getPlatformVersion( true ),
);
$values[] = array(
'label' => 'Platform version name',
'value' => $this->getPlatformVersion(),
);
$values[] = array(
'label' => 'Platform is 64-bit',
'value' => $this->is64bitPlatform() ? 'true' : 'false',
);
$values[] = array(
'label' => 'Is mobile',
'value' => $this->isMobile() ? 'true' : 'false',
);
$values[] = array(
'label' => 'Is robot',
'value' => $this->isRobot() ? 'true' : 'false',
);
$values[] = array(
'label' => 'Robot name',
'value' => $this->isRobot() ? ( $this->getRobotName() != self::ROBOT_UNKNOWN ? $this->getRobotName() : 'Unknown' ) : 'Not applicable',
);
$values[] = array(
'label' => 'Robot version',
'value' => $this->isRobot() ? ( $this->getRobotVersion() != self::ROBOT_VERSION_UNKNOWN ? $this->getRobotVersion() : 'Unknown' ) : 'Not applicable',
);
$values[] = array(
'label' => 'IE is in compatibility view',
'value' => $this->isInIECompatibilityView() ? 'true' : 'false',
);
$values[] = array(
'label' => 'Emulated IE version',
'value' => $this->isInIECompatibilityView() ? $this->getIECompatibilityView() : 'Not applicable',
);
$values[] = array(
'label' => 'Is Chrome Frame',
'value' => $this->isChromeFrame() ? 'true' : 'false',
);
foreach ( $values as $currVal ) {
$result .= '<strong>' . htmlspecialchars( $currVal['label'], ENT_NOQUOTES ) . ':</strong> ' . $currVal['value'] . '<br />' . PHP_EOL;
}
return $result;
}
//--- PUBLIC MEMBERS -----------------------------------------------------------------------------------------------
/**
* Dynamically add support for a new Web browser.
* @param string $browserName The Web browser name (used for display).
* @param mixed $uaNameToLookFor (optional) The string (or array of strings) representing the browser name to find
* in the user agent. If omitted, $browserName will be used.
* @param boolean $isMobile (optional) Determines if the browser is from a mobile device.
* @param string $separator (optional) The separator string used to split the browser name and the version number in
* the user agent.
* @param boolean $uaNameFindWords (optional) Determines if the browser name to find should match a word instead of
* a part of a word. For example "Bar" would not be found in "FooBar" when true but would be found in "Foo Bar".
* When set to false, the browser name can be found anywhere in the user agent string.
* @see removeCustomBrowserDetection()
* @return boolean Returns true if the custom rule has been added, false otherwise.
*/
public function addCustomBrowserDetection( $browserName, $uaNameToLookFor = '', $isMobile = false, $separator = '/', $uaNameFindWords = true ) {
if ( $browserName == '' ) {
return false;
}
if ( array_key_exists( $browserName, $this->_customBrowserDetection ) ) {
unset( $this->_customBrowserDetection[ $browserName ] );
}
if ( $uaNameToLookFor == '' ) {
$uaNameToLookFor = $browserName;
}
$this->_customBrowserDetection[ $browserName ] = array(
'uaNameToLookFor' => $uaNameToLookFor,
'isMobile' => $isMobile == true,
'separator' => $separator,
'uaNameFindWords' => $uaNameFindWords == true,
);
return true;
}
/**
* Dynamically add support for a new platform.
* @param string $platformName The platform name (used for display).
* @param mixed $platformNameToLookFor (optional) The string (or array of strings) representing the platform name to
* find in the user agent. If omitted, $platformName will be used.
* @param boolean $isMobile (optional) Determines if the platform is from a mobile device.
* @param boolean $uaNameFindWords (optional) Determines if the platform name to find should match a word instead of
* a part of a word. For example "Bar" would not be found in "FooBar" when true but would be found in "Foo Bar".
* @see removeCustomPlatformDetection()
* @return boolean Returns true if the custom rule has been added, false otherwise.
*/
public function addCustomPlatformDetection( $platformName, $platformNameToLookFor = '', $isMobile = false, $uaNameFindWords = true ) {
if ( $platformName == '' ) {
return false;
}
if ( array_key_exists( $platformName, $this->_customPlatformDetection ) ) {
unset( $this->_customPlatformDetection[ $platformName ] );
}
if ( $platformNameToLookFor == '' ) {
$platformNameToLookFor = $platformName;
}
$this->_customPlatformDetection[ $platformName ] = array(
'platformNameToLookFor' => $platformNameToLookFor,
'isMobile' => $isMobile == true,
'uaNameFindWords' => $uaNameFindWords == true,
);
return true;
}
/**
* Dynamically add support for a new robot.
* @param string $robotName The robot name (used for display).
* @param mixed $uaNameToLookFor (optional) The string (or array of strings) representing the robot name to find
* in the user agent. If omitted, $robotName will be used.
* @param boolean $isMobile (optional) Determines if the robot should be considered as mobile or not.
* @param string $separator (optional) The separator string used to split the robot name and the version number in
* the user agent.
* @param boolean $uaNameFindWords (optional) Determines if the robot name to find should match a word instead of
* a part of a word. For example "Bar" would not be found in "FooBar" when true but would be found in "Foo Bar".
* When set to false, the robot name can be found anywhere in the user agent string.
* @see removeCustomRobotDetection()
* @return boolean Returns true if the custom rule has been added, false otherwise.
*/
public function addCustomRobotDetection( $robotName, $uaNameToLookFor = '', $isMobile = false, $separator = '/', $uaNameFindWords = true ) {
if ( $robotName == '' ) {
return false;
}
if ( array_key_exists( $robotName, $this->_customRobotDetection ) ) {
unset( $this->_customRobotDetection[ $robotName ] );
}
if ( $uaNameToLookFor == '' ) {
$uaNameToLookFor = $robotName;
}
$this->_customRobotDetection[ $robotName ] = array(
'uaNameToLookFor' => $uaNameToLookFor,
'isMobile' => $isMobile == true,
'separator' => $separator,
'uaNameFindWords' => $uaNameFindWords == true,
);
return true;
}
/**
* Compare two version number strings.
* @param string $sourceVer The source version number.
* @param string $compareVer The version number to compare with the source version number.
* @return int Returns -1 if $sourceVer < $compareVer, 0 if $sourceVer == $compareVer or 1 if $sourceVer >
* $compareVer.
*/
public function compareVersions( $sourceVer, $compareVer ) {
$sourceVer = explode( '.', $sourceVer );
foreach ( $sourceVer as $k => $v ) {
$sourceVer[ $k ] = $this->parseInt( $v );
}
$compareVer = explode( '.', $compareVer );
foreach ( $compareVer as $k => $v ) {
$compareVer[ $k ] = $this->parseInt( $v );
}
if ( count( $sourceVer ) != count( $compareVer ) ) {
if ( count( $sourceVer ) > count( $compareVer ) ) {
for ( $i = count( $compareVer ); $i < count( $sourceVer ); $i++ ) {
$compareVer[ $i ] = 0;
}
} else {
for ( $i = count( $sourceVer ); $i < count( $compareVer ); $i++ ) {
$sourceVer[ $i ] = 0;
}
}
}
foreach ( $sourceVer as $i => $srcVerPart ) {
if ( $srcVerPart > $compareVer[ $i ] ) {
return 1;
} else {
if ( $srcVerPart < $compareVer[ $i ] ) {
return -1;
}
}
}
return 0;
}
/**
* Get the name and version of the browser emulated in the compatibility view mode (if any). Since Internet
* Explorer 8, IE can be put in compatibility mode to make websites that were created for older browsers, especially
* IE 6 and 7, look better in IE 8+ which renders web pages closer to the standards and thus differently from those
* older versions of IE.
* @param boolean $asArray (optional) Determines if the return value must be an array (true) or a string (false).
* @return mixed If a string was requested, the function returns the name and version of the browser emulated in
* the compatibility view mode or an empty string if the browser is not in compatibility view mode. If an array was
* requested, an array with the keys 'browser' and 'version' is returned.
*/
public function getIECompatibilityView( $asArray = false ) {
if ( $asArray ) {
return array(
'browser' => $this->_compatibilityViewName,
'version' => $this->_compatibilityViewVer,
);
} else {
return trim( $this->_compatibilityViewName . ' ' . $this->_compatibilityViewVer );
}
}
/**
* Return the BrowserDetection class version.
* @return string Returns the version as a sting with the #.#.# format.
*/
public function getLibVersion() {
return '2.9.5';
}
/**
* Get the name of the browser. All of the return values are class constants. You can compare them like this:
* $myBrowserInstance->getName() == BrowserDetection::BROWSER_FIREFOX.
* @return string Returns the name of the browser or BrowserDetection::BROWSER_UNKNOWN if unknown.
*/
public function getName() {
return $this->_browserName;
}
/**
* Get the name of the platform family on which the browser is run on (such as Windows, Apple, etc.). All of
* the return values are class constants. You can compare them like this:
* $myBrowserInstance->getPlatform() == BrowserDetection::PLATFORM_ANDROID.
* @return string Returns the name of the platform or BrowserDetection::PLATFORM_UNKNOWN if unknown.
*/
public function getPlatform() {
return $this->_platform;
}
/**
* Get the platform version on which the browser is run on. It can be returned as a string number like 'NT 6.3' or
* as a name like 'Windows 8.1'. When returning version string numbers for Windows NT OS families the number is
* prefixed by 'NT ' to differentiate from older Windows 3.x & 9x release. At the moment only the Windows and
* Android operating systems are supported.
* @param boolean $returnVersionNumbers (optional) Determines if the return value must be versions numbers as a
* string (true) or the version name (false).
* @param boolean $returnServerFlavor (optional) Since some Windows NT versions have the same values, this flag
* determines if the Server flavor is returned or not. For instance Windows 8.1 and Windows Server 2012 R2 both use
* version 6.3. This parameter is only useful when testing for Windows.
* @return string Returns the version name/version numbers of the platform or the constant PLATFORM_VERSION_UNKNOWN
* if unknown.
*/
public function getPlatformVersion( $returnVersionNumbers = false, $returnServerFlavor = false ) {
if ( $this->_platformVersion == self::PLATFORM_VERSION_UNKNOWN || $this->_platformVersion == '' ) {
return self::PLATFORM_VERSION_UNKNOWN;
}
if ( $returnVersionNumbers ) {
return $this->_platformVersion;
} else {
switch ( $this->getPlatform() ) {
case self::PLATFORM_WINDOWS:
if ( substr( $this->_platformVersion, 0, 3 ) == 'NT ' ) {
return $this->windowsNTVerToStr( substr( $this->_platformVersion, 3 ), $returnServerFlavor );
} else {
return $this->windowsVerToStr( $this->_platformVersion );
}
break;
case self::PLATFORM_MACINTOSH:
return $this->macVerToStr( $this->_platformVersion );
case self::PLATFORM_ANDROID:
return $this->androidVerToStr( $this->_platformVersion );
case self::PLATFORM_IOS:
return $this->iOSVerToStr( $this->_platformVersion );
default:
return self::PLATFORM_VERSION_UNKNOWN;
}
}
}
/**
* Get the name of the robot. All of the return values are class constants. You can compare them like this:
* $myBrowserInstance->getRobotName() == BrowserDetection::ROBOT_GOOGLEBOT.
* @return string Returns the name of the robot or BrowserDetection::ROBOT_UNKNOWN if unknown.
*/
public function getRobotName() {
return $this->_robotName;
}
/**
* Get the version of the robot.
* @return string Returns the version of the robot or BrowserDetection::ROBOT_VERSION_UNKNOWN if unknown.
*/
public function getRobotVersion() {
return $this->_robotVersion;
}
/**
* Get the user agent value used by the class to determine the browser details.
* @return string The user agent string.
*/
public function getUserAgent() {
return $this->_agent;
}
/**
* Get the version of the browser.
* @return string Returns the version of the browser or BrowserDetection::VERSION_UNKNOWN if unknown.
*/
public function getVersion() {
return $this->_version;
}
/**
* Determine if the browser is executed from a 64-bit platform. Keep in mind that not all platforms/browsers report
* this and the result may not always be accurate.
* @return boolean Returns true if the browser is executed from a 64-bit platform.
*/
public function is64bitPlatform() {
return $this->_is64bit;
}
/**
* Determine if the browser runs Google Chrome Frame (it's a plug-in designed for Internet Explorer 6+ based on the
* open-source Chromium project - it's like a Chrome browser within IE).
* @return boolean Returns true if the browser is using Google Chrome Frame, false otherwise.
*/
public function isChromeFrame() {
return $this->containString( $this->_agent, 'chromeframe' );
}
/**
* Determine if the browser is in compatibility view or not. Since Internet Explorer 8, IE can be put in
* compatibility mode to make websites that were created for older browsers, especially IE 6 and 7, look better in
* IE 8+ which renders web pages closer to the standards and thus differently from those older versions of IE.
* @return boolean Returns true if the browser is in compatibility view, false otherwise.
*/
public function isInIECompatibilityView() {
return ( $this->_compatibilityViewName != '' ) || ( $this->_compatibilityViewVer != '' );
}
/**
* Determine if the browser is from a mobile device or not.
* @return boolean Returns true if the browser is from a mobile device, false otherwise.
*/
public function isMobile() {
return $this->_isMobile;
}
/**
* Determine if the browser is a robot (Googlebot, Bingbot, Yahoo! Slurp...) or not.
* @return boolean Returns true if the browser is a robot, false otherwise.
*/
public function isRobot() {
return $this->_isRobot;
}
/**
* Remove support for a previously added Web browser.
* @param string $browserName The Web browser name as used when added.
* @see addCustomBrowserDetection()
* @return boolean Returns true if the custom rule has been found and removed, false otherwise.
*/
public function removeCustomBrowserDetection( $browserName ) {
if ( array_key_exists( $browserName, $this->_customBrowserDetection ) ) {
unset( $this->_customBrowserDetection[ $browserName ] );
return true;
}
return false;
}
/**
* Remove support for a previously added platform.
* @param string $platformName The platform name as used when added.
* @see addCustomPlatformDetection()
* @return boolean Returns true if the custom rule has been found and removed, false otherwise.
*/
public function removeCustomPlatformDetection( $platformName ) {
if ( array_key_exists( $platformName, $this->_customPlatformDetection ) ) {
unset( $this->_customPlatformDetection[ $platformName ] );
return true;
}
return false;
}
/**
* Remove support for a previously added robot.
* @param string $robotName The robot name as used when added.
* @see addCustomRobotDetection()
* @return boolean Returns true if the custom rule has been found and removed, false otherwise.
*/
public function removeCustomRobotDetection( $robotName ) {
if ( array_key_exists( $robotName, $this->_customRobotDetection ) ) {
unset( $this->_customRobotDetection[ $robotName ] );
return true;
}
return false;
}
/**
* Set the user agent to use with the class.
* @param string $agentString (optional) The value of the user agent. If an empty string is sent (default),
* $_SERVER['HTTP_USER_AGENT'] will be used.
*/
public function setUserAgent( $agentString = '' ) {
if ( ! is_string( $agentString ) || trim( $agentString ) == '' ) {
//https://bugs.php.net/bug.php?id=49184
if ( array_key_exists( 'HTTP_USER_AGENT', $_GET ) && filter_has_var( INPUT_SERVER, 'HTTP_USER_AGENT' ) ) {
$agentString = htmlspecialchars( $_GET['HTTP_USER_AGENT'] );
} elseif ( array_key_exists( 'HTTP_USER_AGENT', $_SERVER ) && is_string( $_SERVER['HTTP_USER_AGENT'] ) ) {
$agentString = htmlspecialchars( $_SERVER['HTTP_USER_AGENT'] );
} else {
$agentString = '';
}
if ( $agentString === false || $agentString === null ) {
//filter_input or filter_var failed
$agentString = '';
}
}
$this->reset();
$this->_agent = $agentString;
$this->detect();
}
//--- PROTECTED MEMBERS --------------------------------------------------------------------------------------------
/**
* Convert the Android version numbers to the operating system name. For instance '1.6' returns 'Donut'.
* @access protected
* @param string $androidVer The Android version numbers as a string.
* @return string The operating system name or the constant PLATFORM_VERSION_UNKNOWN if nothing match the version
* numbers.
*/
protected function androidVerToStr( $androidVer ) {
//https://en.wikipedia.org/wiki/Android_version_history
if ( $this->compareVersions( $androidVer, '10' ) >= 0 ) {
$majorVer = strstr( $androidVer, '.', true );
if ( $majorVer == '' ) {
$majorVer = $androidVer;
}
return self::BROWSER_ANDROID . ' ' . $majorVer;
} elseif ( $this->compareVersions( $androidVer, '9' ) >= 0 && $this->compareVersions( $androidVer, '10' ) < 0 ) {
return 'Pie';
} elseif ( $this->compareVersions( $androidVer, '8' ) >= 0 && $this->compareVersions( $androidVer, '9' ) < 0 ) {
return 'Oreo';
} elseif ( $this->compareVersions( $androidVer, '7' ) >= 0 && $this->compareVersions( $androidVer, '8' ) < 0 ) {
return 'Nougat';
} elseif ( $this->compareVersions( $androidVer, '6' ) >= 0 && $this->compareVersions( $androidVer, '7' ) < 0 ) {
return 'Marshmallow';
} elseif ( $this->compareVersions( $androidVer, '5' ) >= 0 && $this->compareVersions( $androidVer, '5.2' ) < 0 ) {
return 'Lollipop';
} elseif ( $this->compareVersions( $androidVer, '4.4' ) >= 0 && $this->compareVersions( $androidVer, '4.5' ) < 0 ) {
return 'KitKat';
} elseif ( $this->compareVersions( $androidVer, '4.1' ) >= 0 && $this->compareVersions( $androidVer, '4.4' ) < 0 ) {
return 'Jelly Bean';
} elseif ( $this->compareVersions( $androidVer, '4' ) >= 0 && $this->compareVersions( $androidVer, '4.1' ) < 0 ) {
return 'Ice Cream Sandwich';
} elseif ( $this->compareVersions( $androidVer, '3' ) >= 0 && $this->compareVersions( $androidVer, '3.3' ) < 0 ) {
return 'Honeycomb';
} elseif ( $this->compareVersions( $androidVer, '2.3' ) >= 0 && $this->compareVersions( $androidVer, '2.4' ) < 0 ) {
return 'Gingerbread';
} elseif ( $this->compareVersions( $androidVer, '2.2' ) >= 0 && $this->compareVersions( $androidVer, '2.3' ) < 0 ) {
return 'Froyo';
} elseif ( $this->compareVersions( $androidVer, '2' ) >= 0 && $this->compareVersions( $androidVer, '2.2' ) < 0 ) {
return 'Eclair';
} elseif ( $this->compareVersions( $androidVer, '1.6' ) == 0 ) {
return 'Donut';
} elseif ( $this->compareVersions( $androidVer, '1.5' ) == 0 ) {
return 'Cupcake';
} else {
return self::PLATFORM_VERSION_UNKNOWN; //Unknown/unnamed Android version
}
}
/**
* Determine if the browser is the Android browser (based on the WebKit layout engine and coupled with Chrome's
* JavaScript engine) or not.
* @access protected
* @return boolean Returns true if the browser is the Android browser, false otherwise.
*/
protected function checkBrowserAndroid() {
//Android don't use the standard "Android/1.0", it uses "Android 1.0;" instead
return $this->checkSimpleBrowserUA( 'Android', $this->_agent, self::BROWSER_ANDROID, true );
}
/**
* Determine if the browser is the BlackBerry browser or not.
* @access protected
* @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
* @return boolean Returns true if the browser is the BlackBerry browser, false otherwise.
*/
protected function checkBrowserBlackBerry() {
$found = false;
//Tablet OS check
if ( $this->checkSimpleBrowserUA( 'RIM Tablet OS', $this->_agent, self::BROWSER_TABLET_OS, true ) ) {
return true;
}
//Version 6, 7 & 10 check (versions 8 & 9 does not exists)
if ( $this->checkBrowserUAWithVersion( array( 'BlackBerry', 'BB10' ), $this->_agent, self::BROWSER_BLACKBERRY, true ) ) {
if ( $this->getVersion() == self::VERSION_UNKNOWN ) {
$found = true;
} else {
return true;
}
}
//Version 4.2 to 5.0 check
if ( $this->checkSimpleBrowserUA( 'BlackBerry', $this->_agent, self::BROWSER_BLACKBERRY, true, '/', false ) ) {
if ( $this->getVersion() == self::VERSION_UNKNOWN ) {
$found = true;
} else {
return true;
}
}
return $found;
}
/**
* Determine if the browser is Chrome or not.
* @access protected
* @link https://www.google.com/chrome/
* @return boolean Returns true if the browser is Chrome, false otherwise.
*/
protected function checkBrowserChrome() {
return $this->checkSimpleBrowserUA( array( 'Chrome', 'CriOS' ), $this->_agent, self::BROWSER_CHROME );
}
/**
* Determine if the browser is among the custom browser rules or not. Rules are checked in the order they were
* added.
* @access protected
* @return boolean Returns true if we found the browser we were looking for in the custom rules, false otherwise.
*/
protected function checkBrowserCustom() {
foreach ( $this->_customBrowserDetection as $browserName => $customBrowser ) {
$uaNameToLookFor = $customBrowser['uaNameToLookFor'];
$isMobile = $customBrowser['isMobile'];
$separator = $customBrowser['separator'];
$uaNameFindWords = $customBrowser['uaNameFindWords'];
if ( $this->checkSimpleBrowserUA( $uaNameToLookFor, $this->_agent, $browserName, $isMobile, $separator, $uaNameFindWords ) ) {
return true;
}
}
return false;
}
/**
* Determine if the browser is Edge or not.
* @access protected
* @return boolean Returns true if the browser is Edge, false otherwise.
*/
protected function checkBrowserEdge() {
return $this->checkSimpleBrowserUA( array( 'Edg', 'Edge', 'EdgA' ), $this->_agent, self::BROWSER_EDGE );
}
/**
* Determine if the browser is Firebird or not. Firebird was the name of Firefox from version 0.6 to 0.7.1.
* @access protected
* @return boolean Returns true if the browser is Firebird, false otherwise.
*/
protected function checkBrowserFirebird() {
return $this->checkSimpleBrowserUA( 'Firebird', $this->_agent, self::BROWSER_FIREBIRD );
}
/**
* Determine if the browser is Firefox or not.
* @access protected
* @link https://www.mozilla.org/en-US/firefox/new/
* @return boolean Returns true if the browser is Firefox, false otherwise.
*/
protected function checkBrowserFirefox() {
//Safari heavily matches with Firefox, ensure that Safari is filtered out...
if ( preg_match( '/.*Firefox[ (\/]*([a-z0-9.-]*)/i', $this->_agent, $matches ) &&
! $this->containString( $this->_agent, 'Safari' ) ) {
$this->setBrowser( self::BROWSER_FIREFOX );
$this->setVersion( $matches[1] );
$this->setMobile( false );
$this->setRobot( false );
return true;
}
return false;
}
/**
* Determine if the browser is iCab or not.
* @access protected
* @link http://www.icab.de/
* @return boolean Returns true if the browser is iCab, false otherwise.
*/
protected function checkBrowserIcab() {
//Some (early) iCab versions don't use the standard "iCab/1.0", they uses "iCab 1.0;" instead
return $this->checkSimpleBrowserUA( 'iCab', $this->_agent, self::BROWSER_ICAB );
}
/**
* Determine if the browser is GNU IceCat (formerly known as GNU IceWeasel) or not.
* @access protected
* @link https://www.gnu.org/software/gnuzilla/
* @return boolean Returns true if the browser is GNU IceCat, false otherwise.
*/
protected function checkBrowserIceCat() {
return $this->checkSimpleBrowserUA( 'IceCat', $this->_agent, self::BROWSER_ICECAT );
}
/**
* Determine if the browser is GNU IceWeasel (now know as GNU IceCat) or not.
* @access protected
* @see checkBrowserIceCat()
* @return boolean Returns true if the browser is GNU IceWeasel, false otherwise.
*/
protected function checkBrowserIceWeasel() {
return $this->checkSimpleBrowserUA( 'Iceweasel', $this->_agent, self::BROWSER_ICEWEASEL );
}
/**
* Determine if the browser is Internet Explorer or not.
* @access protected
* @link https://www.microsoft.com/ie/
* @link https://en.wikipedia.org/wiki/Internet_Explorer_Mobile
* @return boolean Returns true if the browser is Internet Explorer, false otherwise.
*/
protected function checkBrowserInternetExplorer() {
//Test for Internet Explorer Mobile (formerly Pocket Internet Explorer)
if ( $this->checkSimpleBrowserUA( array( 'IEMobile', 'MSPIE' ), $this->_agent, self::BROWSER_IE_MOBILE, true ) ) {
return true;
}
//Several browsers uses IE compatibility UAs filter these browsers out (but after testing for IE Mobile)
if ( $this->containString( $this->_agent, 'Opera' ) || $this->containString( $this->_agent, array( 'BlackBerry', 'Nokia' ), true, false ) ) {
return false;
}
//Test for Internet Explorer 1
if ( $this->checkSimpleBrowserUA( 'Microsoft Internet Explorer', $this->_agent, self::BROWSER_IE ) ) {
if ( $this->getVersion() == self::VERSION_UNKNOWN ) {
if ( preg_match( '/308|425|426|474|0b1/i', $this->_agent ) ) {
$this->setVersion( '1.5' );
} else {
$this->setVersion( '1.0' );
}
}
return true;
}
//Test for Internet Explorer 2+
if ( $this->containString( $this->_agent, array( 'MSIE', 'Trident' ) ) ) {
$version = '';
if ( $this->containString( $this->_agent, 'Trident' ) ) {
//Test for Internet Explorer 11+ (check the rv: string)
if ( $this->containString( $this->_agent, 'rv:', true, false ) ) {
if ( $this->checkSimpleBrowserUA( 'Trident', $this->_agent, self::BROWSER_IE, false, 'rv:' ) ) {
return true;
}
} else {
//Test for Internet Explorer 8, 9 & 10 (check the Trident string)
if ( preg_match( '/Trident\/([\d]+)/i', $this->_agent, $foundVersion ) ) {
//Trident started with version 4.0 on IE 8
$verFromTrident = $this->parseInt( $foundVersion[1] ) + 4;
if ( $verFromTrident >= 8 ) {
$version = $verFromTrident . '.0';
}
}
}
//If we have the IE version from Trident, we can check for the compatibility view mode
if ( $version != '' ) {
$emulatedVer = '';
preg_match_all( '/MSIE\s*([^\s;$]+)/i', $this->_agent, $foundVersions );
foreach ( $foundVersions[1] as $currVer ) {
//Keep the lowest MSIE version for the emulated version (in compatibility view mode)
if ( $emulatedVer == '' || $this->compareVersions( $emulatedVer, $currVer ) == 1 ) {
$emulatedVer = $currVer;
}
}
//Set the compatibility view mode if $version != $emulatedVer
if ( $this->compareVersions( $version, $emulatedVer ) != 0 ) {
$this->_compatibilityViewName = self::BROWSER_IE;
$this->_compatibilityViewVer = $this->cleanVersion( $emulatedVer );
}
}
}
//Test for Internet Explorer 2-7 versions if needed
if ( $version == '' ) {
preg_match_all( '/MSIE\s+([^\s;$]+)/i', $this->_agent, $foundVersions );
foreach ( $foundVersions[1] as $currVer ) {
//Keep the highest MSIE version
if ( $version == '' || $this->compareVersions( $version, $currVer ) == -1 ) {
$version = $currVer;
}
}
}
$this->setBrowser( self::BROWSER_IE );
$this->setVersion( $version );
$this->setMobile( false );
$this->setRobot( false );
return true;
}
return false;
}
/**
* Determine if the browser is Konqueror or not.
* @access protected
* @link https://www.konqueror.org/
* @return boolean Returns true if the browser is Konqueror, false otherwise.
*/
protected function checkBrowserKonqueror() {
return $this->checkSimpleBrowserUA( 'Konqueror', $this->_agent, self::BROWSER_KONQUEROR );
}
/**
* Determine if the browser is Lynx or not. It is the oldest web browser currently in general use and development.
* It is a text-based only Web browser.
* @access protected
* @link https://en.wikipedia.org/wiki/Lynx_(web_browser)
* @return boolean Returns true if the browser is Lynx, false otherwise.
*/
protected function checkBrowserLynx() {
return $this->checkSimpleBrowserUA( 'Lynx', $this->_agent, self::BROWSER_LYNX );
}
/**
* Determine if the browser is Mozilla or not.
* @access protected
* @return boolean Returns true if the browser is Mozilla, false otherwise.
*/
protected function checkBrowserMozilla() {
return $this->checkSimpleBrowserUA( 'Mozilla', $this->_agent, self::BROWSER_MOZILLA, false, 'rv:' );
}
/**
* Determine if the browser is MSN TV (formerly WebTV) or not.
* @access protected
* @link https://en.wikipedia.org/wiki/MSN_TV
* @return boolean Returns true if the browser is WebTv, false otherwise.
*/
protected function checkBrowserMsnTv() {
return $this->checkSimpleBrowserUA( 'webtv', $this->_agent, self::BROWSER_MSNTV );
}
/**
* Determine if the browser is Netscape or not. Official support for this browser ended on March 1st, 2008.
* @access protected
* @link https://en.wikipedia.org/wiki/Netscape
* @return boolean Returns true if the browser is Netscape, false otherwise.
*/
protected function checkBrowserNetscape() {
//BlackBerry & Nokia UAs can conflict with Netscape UAs
if ( $this->containString( $this->_agent, array( 'BlackBerry', 'Nokia' ), true, false ) ) {
return false;
}
//Netscape v6 to v9 check
if ( $this->checkSimpleBrowserUA( array( 'Netscape', 'Navigator', 'Netscape6' ), $this->_agent, self::BROWSER_NETSCAPE ) ) {
return true;
}
//Netscape v1-4 (v5 don't exists)
$found = false;
if ( $this->containString( $this->_agent, 'Mozilla' ) && ! $this->containString( $this->_agent, 'rv:', true, false ) ) {
$version = '';
$verParts = explode( '/', stristr( $this->_agent, 'Mozilla' ) );
if ( count( $verParts ) > 1 ) {
$verParts = explode( ' ', $verParts[1] );
$verParts = explode( '.', $verParts[0] );
$majorVer = $this->parseInt( $verParts[0] );
if ( $majorVer > 0 && $majorVer < 5 ) {
$version = implode( '.', $verParts );
$found = true;
if ( strtolower( substr( $version, -4 ) ) == '-sgi' ) {
$version = substr( $version, 0, -4 );
} else {
if ( strtolower( substr( $version, -4 ) ) == 'gold' ) {
$version = substr( $version, 0, -4 ) . ' Gold'; //Doubles spaces (if any) will be normalized by setVersion()
}
}
}
}
}
if ( $found ) {
$this->setBrowser( self::BROWSER_NETSCAPE );
$this->setVersion( $version );
$this->setMobile( false );
$this->setRobot( false );
}
return $found;
}
/**
* Determine if the browser is a Nokia browser or not.
* @access protected
* @link https://web.archive.org/web/20141012034159/http://www.developer.nokia.com/Community/Wiki/User-Agent_headers_for_Nokia_devices
* @return boolean Returns true if the browser is a Nokia browser, false otherwise.
*/
protected function checkBrowserNokia() {
if ( $this->containString( $this->_agent, array( 'Nokia5800', 'Nokia5530', 'Nokia5230' ), true, false ) ) {
$this->setBrowser( self::BROWSER_NOKIA );
$this->setVersion( '7.0' );
$this->setMobile( true );
$this->setRobot( false );
return true;
}
if ( $this->checkSimpleBrowserUA( array( 'NokiaBrowser', 'BrowserNG', 'Series60', 'S60', 'S40OviBrowser' ), $this->_agent, self::BROWSER_NOKIA, true ) ) {
return true;
}
return false;
}
/**
* Determine if the browser is Opera or not.
* @access protected
* @link https://www.opera.com/
* @link https://www.opera.com/mobile/
* @link https://web.archive.org/web/20140220123653/http://my.opera.com/community/openweb/idopera/
* @return boolean Returns true if the browser is Opera, false otherwise.
*/
protected function checkBrowserOpera() {
if ( $this->checkBrowserUAWithVersion( 'Opera Mobi', $this->_agent, self::BROWSER_OPERA_MOBILE, true ) ) {
return true;
}
if ( $this->checkSimpleBrowserUA( 'Opera Mini', $this->_agent, self::BROWSER_OPERA_MINI, true ) ) {
return true;
}
$version = '';
$found = $this->checkBrowserUAWithVersion( 'Opera', $this->_agent, self::BROWSER_OPERA );
if ( $found && $this->getVersion() != self::VERSION_UNKNOWN ) {
$version = $this->getVersion();
}
if ( ! $found || $version == '' ) {
if ( $this->checkSimpleBrowserUA( 'Opera', $this->_agent, self::BROWSER_OPERA ) ) {
return true;
}
}
if ( ! $found && $this->checkSimpleBrowserUA( 'Chrome', $this->_agent, self::BROWSER_CHROME ) ) {
if ( $this->checkSimpleBrowserUA( 'OPR', $this->_agent, self::BROWSER_OPERA ) ) {
return true;
}
}
return $found;
}
/**
* Determine if the browser is Phoenix or not. Phoenix was the name of Firefox from version 0.1 to 0.5.
* @access protected
* @return boolean Returns true if the browser is Phoenix, false otherwise.
*/
protected function checkBrowserPhoenix() {
return $this->checkSimpleBrowserUA( 'Phoenix', $this->_agent, self::BROWSER_PHOENIX );
}
/**
* Determine what is the browser used by the user.
* @access protected
* @return boolean Returns true if the browser has been identified, false otherwise.
*/
protected function checkBrowser() {
//Changing the check order can break the class detection results!
return
/* Major browsers and browsers that need to be detected in a special order */
$this->checkBrowserCustom() || /* Customs rules are always checked first */
$this->checkBrowserMsnTv() || /* MSN TV is based on IE so we must check for MSN TV before IE */
$this->checkBrowserInternetExplorer() ||
$this->checkBrowserOpera() || /* Opera must be checked before Firefox, Netscape and Chrome to avoid conflicts */
$this->checkBrowserEdge() || /* Edge must be checked before Firefox, Safari and Chrome to avoid conflicts */
$this->checkBrowserSamsung() || /* Samsung Internet browser must be checked before Chrome and Safari to avoid conflicts */
$this->checkBrowserUC() || /* UC Browser must be checked before Chrome and Safari to avoid conflicts */
$this->checkBrowserChrome() || /* Chrome must be checked before Netscaoe and Mozilla to avoid conflicts */
$this->checkBrowserIcab() || /* Check iCab before Netscape since iCab have Mozilla UAs */
$this->checkBrowserNetscape() || /* Must be checked before Firefox since Netscape 8-9 are based on Firefox */
$this->checkBrowserIceCat() || /* Check IceCat and IceWeasel before Firefox since they are GNU builds of Firefox */
$this->checkBrowserIceWeasel() ||
$this->checkBrowserFirefox() ||
/* Current browsers that don't need to be detected in any special order */
$this->checkBrowserKonqueror() ||
$this->checkBrowserLynx() ||
/* Mobile */
$this->checkBrowserAndroid() ||
$this->checkBrowserBlackBerry() ||
$this->checkBrowserNokia() ||
/* WebKit base check (after most other checks) */
$this->checkBrowserSafari() ||
/* Deprecated browsers that don't need to be detected in any special order */
$this->checkBrowserFirebird() ||
$this->checkBrowserPhoenix() ||
/* Mozilla is such an open standard that it must be checked last */
$this->checkBrowserMozilla();
}
/**
* Determine if the browser is Safari or not.
* @access protected
* @link https://www.apple.com/safari/
* @link https://web.archive.org/web/20080514173941/http://developer.apple.com/internet/safari/uamatrix.html
* @link https://en.wikipedia.org/wiki/Safari_version_history#Release_history
* @return boolean Returns true if the browser is Safari, false otherwise.
*/
protected function checkBrowserSafari() {
$version = '';
//Check for current versions of Safari
$found = $this->checkBrowserUAWithVersion( array( 'Safari', 'AppleWebKit' ), $this->_agent, self::BROWSER_SAFARI );
if ( $found && $this->getVersion() != self::VERSION_UNKNOWN ) {
$version = $this->getVersion();
}
//Safari 1-2 didn't had a "Version" string in the UA, only a WebKit build and/or Safari build, extract version from these...
if ( ! $found || $version == '' ) {
if ( preg_match( '/.*Safari[ (\/]*([a-z0-9.-]*)/i', $this->_agent, $matches ) ) {
$version = $this->safariBuildToSafariVer( $matches[1] );
$found = true;
}
}
if ( ! $found || $version == '' ) {
if ( preg_match( '/.*AppleWebKit[ (\/]*([a-z0-9.-]*)/i', $this->_agent, $matches ) ) {
$version = $this->webKitBuildToSafariVer( $matches[1] );
$found = true;
}
}
if ( $found ) {
$this->setBrowser( self::BROWSER_SAFARI );
$this->setVersion( $version );
$this->setMobile( false );
$this->setRobot( false );
}
return $found;
}
/**
* Determine if the browser is the Samsung Internet browser or not.
* @access protected
* @return boolean Returns true if the browser is the the Samsung Internet browser, false otherwise.
*/
protected function checkBrowserSamsung() {
return $this->checkSimpleBrowserUA( 'SamsungBrowser', $this->_agent, self::BROWSER_SAMSUNG, true );
}
/**
* Test the user agent for a specific browser that use a "Version" string (like Safari and Opera). The user agent
* should look like: "Version/1.0 Browser name/123.456" or "Browser name/123.456 Version/1.0".
* @access protected
* @param mixed $uaNameToLookFor The string (or array of strings) representing the browser name to find in the user
* agent.
* @param string $userAgent The user agent string to work with.
* @param string $browserName The literal browser name. Always use a class constant!
* @param boolean $isMobile (optional) Determines if the browser is from a mobile device.
* @param boolean $findWords (optional) Determines if the needle should match a word to be found. For example "Bar"
* would not be found in "FooBar" when true but would be found in "Foo Bar". When set to false, the needle can be
* found anywhere in the haystack.
* @return boolean Returns true if we found the browser we were looking for, false otherwise.
*/
protected function checkBrowserUAWithVersion( $uaNameToLookFor, $userAgent, $browserName, $isMobile = false, $findWords = true ) {
if ( ! is_array( $uaNameToLookFor ) ) {
$uaNameToLookFor = array( $uaNameToLookFor );
}
foreach ( $uaNameToLookFor as $currUANameToLookFor ) {
if ( $this->containString( $userAgent, $currUANameToLookFor, true, $findWords ) ) {
$version = '';
$verParts = explode( '/', stristr( $this->_agent, 'Version' ) );
if ( count( $verParts ) > 1 ) {
$verParts = explode( ' ', $verParts[1] );
$version = $verParts[0];
}
$this->setBrowser( $browserName );
$this->setVersion( $version );
$this->setMobile( $isMobile );
return true;
}
}
return false;
}
/**
* Determine if the browser is UC Browser or not.
* @access protected
* @return boolean Returns true if the browser is UC Browser, false otherwise.
*/
protected function checkBrowserUC() {
return $this->checkSimpleBrowserUA( 'UCBrowser', $this->_agent, self::BROWSER_UC, true );
}
/**
* Determine the user's platform.
* @access protected
*/
protected function checkPlatform() {
if ( ! $this->checkPlatformCustom() ) { /* Customs rules are always checked first */
/* Mobile platforms */
if ( $this->containString( $this->_agent, array( 'Windows Phone', 'IEMobile' ) ) ) { /* Check Windows Phone (formerly Windows Mobile) before Windows */
$this->setPlatform( self::PLATFORM_WINDOWS_PHONE );
$this->setMobile( true );
} elseif ( $this->containString( $this->_agent, 'Windows CE' ) ) { /* Check Windows CE before Windows */
$this->setPlatform( self::PLATFORM_WINDOWS_CE );
$this->setMobile( true );
} elseif ( $this->containString( $this->_agent, array( 'CPU OS', 'CPU iPhone OS', 'iPhone', 'iPad', 'iPod' ) ) ) { /* Check iOS (iPad/iPod/iPhone) before Macintosh */
$this->setPlatform( self::PLATFORM_IOS );
$this->setMobile( true );
} elseif ( $this->containString( $this->_agent, 'Android' ) ) {
$this->setPlatform( self::PLATFORM_ANDROID );
$this->setMobile( true );
} elseif ( $this->containString( $this->_agent, 'BlackBerry', true, false ) || $this->containString( $this->_agent, array( 'BB10', 'RIM Tablet OS' ) ) ) {
$this->setPlatform( self::PLATFORM_BLACKBERRY );
$this->setMobile( true );
} elseif ( $this->containString( $this->_agent, 'Nokia', true, false ) ) {
$this->setPlatform( self::PLATFORM_NOKIA );
$this->setMobile( true );
/* Desktop platforms */
} elseif ( $this->containString( $this->_agent, 'Windows' ) ) {
$this->setPlatform( self::PLATFORM_WINDOWS );
} elseif ( $this->containString( $this->_agent, 'Macintosh' ) ) {
$this->setPlatform( self::PLATFORM_MACINTOSH );
} elseif ( $this->containString( $this->_agent, 'Linux' ) ) {
$this->setPlatform( self::PLATFORM_LINUX );
} elseif ( $this->containString( $this->_agent, 'FreeBSD' ) ) {
$this->setPlatform( self::PLATFORM_FREEBSD );
} elseif ( $this->containString( $this->_agent, 'OpenBSD' ) ) {
$this->setPlatform( self::PLATFORM_OPENBSD );
} elseif ( $this->containString( $this->_agent, 'NetBSD' ) ) {
$this->setPlatform( self::PLATFORM_NETBSD );
/* Discontinued */
} elseif ( $this->containString( $this->_agent, array( 'Symbian', 'SymbianOS' ) ) ) {
$this->setPlatform( self::PLATFORM_SYMBIAN );
$this->setMobile( true );
} elseif ( $this->containString( $this->_agent, 'OpenSolaris' ) ) {
$this->setPlatform( self::PLATFORM_OPENSOLARIS );
/* Generic */
} elseif ( $this->containString( $this->_agent, 'Win', true, false ) ) {
$this->setPlatform( self::PLATFORM_WINDOWS );
} elseif ( $this->containString( $this->_agent, 'Mac', true, false ) ) {
$this->setPlatform( self::PLATFORM_MACINTOSH );
}
}
//Check if it's a 64-bit platform
if ( $this->containString(
$this->_agent,
array(
'WOW64',
'Win64',
'AMD64',
'x86_64',
'x86-64',
'ia64',
'IRIX64',
'ppc64',
'sparc64',
'x64;',
'x64_64',
)
) ) {
$this->set64bit( true );
}
$this->checkPlatformVersion();
}
/**
* Determine if the platform is among the custom platform rules or not. Rules are checked in the order they were
* added.
* @access protected
* @return boolean Returns true if we found the platform we were looking for in the custom rules, false otherwise.
*/
protected function checkPlatformCustom() {
foreach ( $this->_customPlatformDetection as $platformName => $customPlatform ) {
$platformNameToLookFor = $customPlatform['platformNameToLookFor'];
$isMobile = $customPlatform['isMobile'];
$findWords = $customPlatform['uaNameFindWords'];
if ( $this->containString( $this->_agent, $platformNameToLookFor, true, $findWords ) ) {
$this->setPlatform( $platformName );
if ( $isMobile ) {
$this->setMobile( true );
}
return true;
}
}
return false;
}
/**
* Determine the user's platform version.
* @access protected
*/
protected function checkPlatformVersion() {
$result = '';
switch ( $this->getPlatform() ) {
case self::PLATFORM_WINDOWS:
if ( preg_match( '/Windows NT\s*(\d+(?:\.\d+)*)/i', $this->_agent, $foundVersion ) ) {
$result = 'NT ' . $foundVersion[1];
} else {
//https://support.microsoft.com/en-us/kb/158238
if ( $this->containString( $this->_agent, array( 'Windows XP', 'WinXP', 'Win XP' ) ) ) {
$result = '5.1';
} elseif ( $this->containString( $this->_agent, 'Windows 2000', 'Win 2000', 'Win2000' ) ) {
$result = '5.0';
} elseif ( $this->containString( $this->_agent, array( 'Win 9x 4.90', 'Windows ME', 'WinME', 'Win ME' ) ) ) {
$result = '4.90.3000'; //Windows Me version range from 4.90.3000 to 4.90.3000A
} elseif ( $this->containString( $this->_agent, array( 'Windows 98', 'Win98', 'Win 98' ) ) ) {
$result = '4.10'; //Windows 98 version range from 4.10.1998 to 4.10.2222B
} elseif ( $this->containString( $this->_agent, array( 'Windows 95', 'Win95', 'Win 95' ) ) ) {
$result = '4.00'; //Windows 95 version range from 4.00.950 to 4.03.1214
} elseif ( ( $foundAt = stripos( $this->_agent, 'Windows 3' ) ) !== false ) {
$result = '3';
if ( preg_match( '/\d+(?:\.\d+)*/', substr( $this->_agent, $foundAt + strlen( 'Windows 3' ) ), $foundVersion ) ) {
$result .= '.' . $foundVersion[0];
}
} elseif ( $this->containString( $this->_agent, 'Win16' ) ) {
$result = '3.1';
}
}
break;
case self::PLATFORM_MACINTOSH:
if ( preg_match( '/Mac OS X\s*(\d+(?:_\d+)+)/i', $this->_agent, $foundVersion ) ) {
$result = str_replace( '_', '.', $this->cleanVersion( $foundVersion[1] ) );
} elseif ( $this->containString( $this->_agent, 'Mac OS X' ) ) {
$result = '10';
}
break;
case self::PLATFORM_ANDROID:
if ( preg_match( '/Android\s+([^\s;$]+)/i', $this->_agent, $foundVersion ) ) {
$result = $this->cleanVersion( $foundVersion[1] );
}
break;
case self::PLATFORM_IOS:
if ( preg_match( '/(?:CPU OS|iPhone OS|iOS)[\s_]*([\d_]+)/i', $this->_agent, $foundVersion ) ) {
$result = str_replace( '_', '.', $this->cleanVersion( $foundVersion[1] ) );
}
break;
}
if ( trim( $result ) == '' ) {
$result = self::PLATFORM_VERSION_UNKNOWN;
}
$this->setPlatformVersion( $result );
}
/**
* Determine if the robot is the Bingbot crawler or not.
* @access protected
* @link https://www.bing.com/webmaster/help/which-crawlers-does-bing-use-8c184ec0
* @return boolean Returns true if the robot is Bingbot, false otherwise.
*/
protected function checkRobotBingbot() {
return $this->checkSimpleRobot( 'bingbot', $this->_agent, self::ROBOT_BINGBOT );
}
/**
* Determine if the robot is the Googlebot crawler or not.
* @access protected
* @return boolean Returns true if the robot is Googlebot, false otherwise.
*/
protected function checkRobotGooglebot() {
if ( $this->checkSimpleRobot( 'Googlebot', $this->_agent, self::ROBOT_GOOGLEBOT ) ) {
if ( $this->containString( $this->_agent, 'googlebot-mobile' ) ) {
$this->setMobile( true );
}
return true;
}
return false;
}
/**
* Determine if the robot is the MSNBot crawler or not. In October 2010 it was replaced by the Bingbot robot.
* @access protected
* @see checkRobotBingbot()
* @return boolean Returns true if the robot is MSNBot, false otherwise.
*/
protected function checkRobotMsnBot() {
return $this->checkSimpleRobot( 'msnbot', $this->_agent, self::ROBOT_MSNBOT );
}
/**
* Determine if it's a robot crawling the page and find it's name and version.
* @access protected
*/
protected function checkRobot() {
$this->checkRobotCustom() || /* Customs rules are always checked first */
$this->checkRobotGooglebot() ||
$this->checkRobotBingbot() ||
$this->checkRobotMsnBot() ||
$this->checkRobotSlurp() ||
$this->checkRobotYahooMultimedia() ||
$this->checkRobotW3CValidator();
}
/**
* Determine if the robot is among the custom robot rules or not. Rules are checked in the order they were added.
* @access protected
* @return boolean Returns true if we found the robot we were looking for in the custom rules, false otherwise.
*/
protected function checkRobotCustom() {
foreach ( $this->_customRobotDetection as $robotName => $customRobot ) {
$uaNameToLookFor = $customRobot['uaNameToLookFor'];
$isMobile = $customRobot['isMobile'];
$separator = $customRobot['separator'];
$uaNameFindWords = $customRobot['uaNameFindWords'];
if ( $this->checkSimpleRobot( $uaNameToLookFor, $this->_agent, $robotName, $separator, $uaNameFindWords ) ) {
return true;
}
}
return false;
}
/**
* Determine if the robot is the Yahoo! Slurp crawler or not.
* @access protected
* @return boolean Returns true if the robot is Yahoo! Slurp, false otherwise.
*/
protected function checkRobotSlurp() {
return $this->checkSimpleRobot( 'Yahoo! Slurp', $this->_agent, self::ROBOT_SLURP );
}
/**
* Determine if the robot is the W3C Validator or not.
* @access protected
* @link https://validator.w3.org/
* @return boolean Returns true if the robot is the W3C Validator, false otherwise.
*/
protected function checkRobotW3CValidator() {
//Since the W3C validates pages with different robots we will prefix our versions with the part validated on the page...
//W3C Link Checker (prefixed with "Link-")
if ( $this->checkSimpleRobot( 'W3C-checklink', $this->_agent, self::ROBOT_W3CVALIDATOR ) ) {
if ( $this->getRobotVersion() != self::ROBOT_VERSION_UNKNOWN ) {
$this->setRobotVersion( 'Link-' . $this->getRobotVersion() );
}
return true;
}
//W3C CSS Validation Service (prefixed with "CSS-")
if ( $this->checkSimpleRobot( 'Jigsaw', $this->_agent, self::ROBOT_W3CVALIDATOR ) ) {
if ( $this->getRobotVersion() != self::ROBOT_VERSION_UNKNOWN ) {
$this->setRobotVersion( 'CSS-' . $this->getRobotVersion() );
}
return true;
}
//W3C mobileOK Checker (prefixed with "mobileOK-")
if ( $this->checkSimpleRobot( 'W3C-mobileOK', $this->_agent, self::ROBOT_W3CVALIDATOR ) ) {
if ( $this->getRobotVersion() != self::ROBOT_VERSION_UNKNOWN ) {
$this->setRobotVersion( 'mobileOK-' . $this->getRobotVersion() );
}
return true;
}
//W3C Markup Validation Service (no prefix)
return $this->checkSimpleRobot( 'W3C_Validator', $this->_agent, self::ROBOT_W3CVALIDATOR );
}
/**
* Determine if the robot is the Yahoo! multimedia crawler or not.
* @access protected
* @return boolean Returns true if the robot is the Yahoo! multimedia crawler, false otherwise.
*/
protected function checkRobotYahooMultimedia() {
return $this->checkSimpleRobot( 'Yahoo-MMCrawler', $this->_agent, self::ROBOT_YAHOO_MM );
}
/**
* Test the user agent for a specific browser where the browser name is immediately followed by the version number.
* The user agent should look like: "Browser name/1.0" or "Browser 1.0;".
* @access protected
* @param mixed $uaNameToLookFor The string (or array of strings) representing the browser name to find in the user
* agent.
* @param string $userAgent The user agent string to work with.
* @param string $browserName The literal browser name. Always use a class constant!
* @param boolean $isMobile (optional) Determines if the browser is from a mobile device.
* @param string $separator (optional) The separator string used to split the browser name and the version number in
* the user agent.
* @param boolean $uaNameFindWords (optional) Determines if the browser name to find should match a word instead of
* a part of a word. For example "Bar" would not be found in "FooBar" when true but would be found in "Foo Bar".
* When set to false, the browser name can be found anywhere in the user agent string.
* @return boolean Returns true if we found the browser we were looking for, false otherwise.
*/
protected function checkSimpleBrowserUA( $uaNameToLookFor, $userAgent, $browserName, $isMobile = false, $separator = '/', $uaNameFindWords = true ) {
if ( $this->findAndGetVersion( $uaNameToLookFor, $userAgent, $version, $separator, $uaNameFindWords ) ) {
$this->setBrowser( $browserName );
$this->setVersion( $version );
$this->setMobile( $isMobile );
return true;
}
return false;
}
/**
* Test the user agent for a specific robot where the robot name is immediately followed by the version number.
* The user agent should look like: "Robot name/1.0" or "Robot 1.0;".
* @access protected
* @param mixed $uaNameToLookFor The string (or array of strings) representing the robot name to find in the user
* agent.
* @param string $userAgent The user agent string to work with.
* @param string $robotName The literal robot name. Always use a class constant!
* @param string $separator (optional) The separator string used to split the robot name and the version number in
* the user agent.
* @param boolean $uaNameFindWords (optional) Determines if the robot name to find should match a word instead of
* a part of a word. For example "Bar" would not be found in "FooBar" when true but would be found in "Foo Bar".
* When set to false, the robot name can be found anywhere in the user agent string.
* @return boolean Returns true if we found the robot we were looking for, false otherwise.
*/
protected function checkSimpleRobot( $uaNameToLookFor, $userAgent, $robotName, $separator = '/', $uaNameFindWords = true ) {
if ( $this->findAndGetVersion( $uaNameToLookFor, $userAgent, $version, $separator, $uaNameFindWords ) ) {
$this->setRobot( true );
$this->setRobotName( $robotName );
$this->setRobotVersion( $version );
return true;
}
return false;
}
/**
* Clean a version string from unwanted characters.
* @access protected
* @param string $version The version string to clean.
* @return string Returns the cleaned version number string.
*/
protected function cleanVersion( $version ) {
//Clear anything that is in parentheses (and the parentheses themselves) - will clear started but unclosed ones too
$cleanVer = preg_replace( '/\([^)]+\)?/', '', $version );
//Replace with a space any character which is NOT an alphanumeric, dot (.), hyphen (-), underscore (_) or space
$cleanVer = preg_replace( '/[^0-9.a-zA-Z_ -]/', ' ', $cleanVer );
//Remove trailing and leading spaces
$cleanVer = trim( $cleanVer );
//Remove trailing dot (.), hyphen (-), underscore (_)
while ( in_array( substr( $cleanVer, -1 ), array( '.', '-', '_' ) ) ) {
$cleanVer = substr( $cleanVer, 0, -1 );
}
//Remove leading dot (.), hyphen (-), underscore (_) and character v
while ( in_array( substr( $cleanVer, 0, 1 ), array( '.', '-', '_', 'v', 'V' ) ) ) {
$cleanVer = substr( $cleanVer, 1 );
}
//Remove double spaces if any
while ( strpos( $cleanVer, ' ' ) !== false ) {
$cleanVer = str_replace( ' ', ' ', $cleanVer );
}
return trim( $cleanVer );
}
/**
* Find if one or more substring is contained in a string.
* @access protected
* @param string $haystack The string to search in.
* @param mixed $needle The string to search for. Can be a string or an array of strings if multiples values are to
* be searched.
* @param boolean $insensitive (optional) Determines if we do a case-sensitive search (false) or a case-insensitive
* one (true).
* @param boolean $findWords (optional) Determines if the needle should match a word to be found. For example "Bar"
* would not be found in "FooBar" when true but would be found in "Foo Bar". When set to false, the needle can be
* found anywhere in the haystack.
* @return boolean Returns true if the needle (or one of the needles) has been found in the haystack, false
* otherwise.
*/
protected function containString( $haystack, $needle, $insensitive = true, $findWords = true ) {
if ( ! is_array( $needle ) ) {
$needle = array( $needle );
}
foreach ( $needle as $currNeedle ) {
if ( $findWords ) {
$found = $this->wordPos( $haystack, $currNeedle, $insensitive ) !== false;
} else {
if ( $insensitive ) {
$found = stripos( $haystack, $currNeedle ) !== false;
} else {
$found = strpos( $haystack, $currNeedle ) !== false;
}
}
if ( $found ) {
return true;
}
}
return false;
}
/**
* Detect the user environment from the details in the user agent string.
* @access protected
*/
protected function detect() {
$this->checkBrowser();
$this->checkPlatform(); //Check the platform after the browser since some platforms can change the mobile value
$this->checkRobot();
}
/**
* Test the user agent for a specific browser and extract it's version.
* @access protected
* @param type $uaNameToLookFor The string (or array of strings) representing the browser name to find in the user
* agent.
* @param type $userAgent The user agent string to work with.
* @param type $version String buffer that will contain the version found (if any).
* @param type $separator (optional) The separator string used to split the browser name and the version number in
* the user agent.
* @param type $uaNameFindWords (optional) Determines if the browser name to find should match a word instead of
* a part of a word. For example "Bar" would not be found in "FooBar" when true but would be found in "Foo Bar".
* When set to false, the browser name can be found anywhere in the user agent string.
* @return boolean Returns true if we found the browser we were looking for, false otherwise.
*/
protected function findAndGetVersion( $uaNameToLookFor, $userAgent, &$version, $separator = '/', $uaNameFindWords = true ) {
$version = '';
if ( ! is_array( $uaNameToLookFor ) ) {
$uaNameToLookFor = array( $uaNameToLookFor );
}
foreach ( $uaNameToLookFor as $currUANameToLookFor ) {
if ( $this->containString( $userAgent, $currUANameToLookFor, true, $uaNameFindWords ) ) {
//Many browsers don't use the standard "Browser/1.0" format, they uses "Browser 1.0;" instead
if ( stripos( $userAgent, $currUANameToLookFor . $separator ) === false ) {
$userAgent = str_ireplace( $currUANameToLookFor . ' ', $currUANameToLookFor . $separator, $userAgent );
}
$verParts = explode( $separator, stristr( $userAgent, $currUANameToLookFor ) );
if ( count( $verParts ) > 1 ) {
$verParts = explode( ' ', $verParts[1] );
$version = $verParts[0];
}
return true;
}
}
return false;
}
/**
* Convert the iOS version numbers to the operating system name. For instance '2.0' returns 'iPhone OS 2.0'.
* @access protected
* @param string $iOSVer The iOS version numbers as a string.
* @return string The operating system name.
*/
protected function iOSVerToStr( $iOSVer ) {
if ( $this->compareVersions( $iOSVer, '3.0' ) <= 0 ) {
return 'iPhone OS ' . $iOSVer;
} else {
return 'iOS ' . $iOSVer;
}
}
/**
* Convert the macOS version numbers to the operating system name. For instance '10.7' returns 'Mac OS X Lion'.
* @access protected
* @param string $macVer The macOS version numbers as a string.
* @return string The operating system name or the constant PLATFORM_VERSION_UNKNOWN if nothing match the version
* numbers.
*/
protected function macVerToStr( $macVer ) {
//https://en.wikipedia.org/wiki/OS_X#Release_history
if ( $this->_platformVersion === '10' ) {
return 'Mac OS X'; //Unspecified Mac OS X version
} elseif ( $this->compareVersions( $macVer, '10.15' ) >= 0 && $this->compareVersions( $macVer, '10.16' ) < 0 ) {
return 'macOS Catalina';
} elseif ( $this->compareVersions( $macVer, '10.14' ) >= 0 && $this->compareVersions( $macVer, '10.15' ) < 0 ) {
return 'macOS Mojave';
} elseif ( $this->compareVersions( $macVer, '10.13' ) >= 0 && $this->compareVersions( $macVer, '10.14' ) < 0 ) {
return 'macOS High Sierra';
} elseif ( $this->compareVersions( $macVer, '10.12' ) >= 0 && $this->compareVersions( $macVer, '10.13' ) < 0 ) {
return 'macOS Sierra';
} elseif ( $this->compareVersions( $macVer, '10.11' ) >= 0 && $this->compareVersions( $macVer, '10.12' ) < 0 ) {
return 'OS X El Capitan';
} elseif ( $this->compareVersions( $macVer, '10.10' ) >= 0 && $this->compareVersions( $macVer, '10.11' ) < 0 ) {
return 'OS X Yosemite';
} elseif ( $this->compareVersions( $macVer, '10.9' ) >= 0 && $this->compareVersions( $macVer, '10.10' ) < 0 ) {
return 'OS X Mavericks';
} elseif ( $this->compareVersions( $macVer, '10.8' ) >= 0 && $this->compareVersions( $macVer, '10.9' ) < 0 ) {
return 'OS X Mountain Lion';
} elseif ( $this->compareVersions( $macVer, '10.7' ) >= 0 && $this->compareVersions( $macVer, '10.8' ) < 0 ) {
return 'Mac OS X Lion';
} elseif ( $this->compareVersions( $macVer, '10.6' ) >= 0 && $this->compareVersions( $macVer, '10.7' ) < 0 ) {
return 'Mac OS X Snow Leopard';
} elseif ( $this->compareVersions( $macVer, '10.5' ) >= 0 && $this->compareVersions( $macVer, '10.6' ) < 0 ) {
return 'Mac OS X Leopard';
} elseif ( $this->compareVersions( $macVer, '10.4' ) >= 0 && $this->compareVersions( $macVer, '10.5' ) < 0 ) {
return 'Mac OS X Tiger';
} elseif ( $this->compareVersions( $macVer, '10.3' ) >= 0 && $this->compareVersions( $macVer, '10.4' ) < 0 ) {
return 'Mac OS X Panther';
} elseif ( $this->compareVersions( $macVer, '10.2' ) >= 0 && $this->compareVersions( $macVer, '10.3' ) < 0 ) {
return 'Mac OS X Jaguar';
} elseif ( $this->compareVersions( $macVer, '10.1' ) >= 0 && $this->compareVersions( $macVer, '10.2' ) < 0 ) {
return 'Mac OS X Puma';
} elseif ( $this->compareVersions( $macVer, '10.0' ) >= 0 && $this->compareVersions( $macVer, '10.1' ) < 0 ) {
return 'Mac OS X Cheetah';
} else {
return self::PLATFORM_VERSION_UNKNOWN; //Unknown/unnamed Mac OS version
}
}
/**
* Get the integer value of a string variable.
* @access protected
* @param string $intStr The scalar value being converted to an integer.
* @return int The integer value of $intStr on success, or 0 on failure.
*/
protected function parseInt( $intStr ) {
return intval( $intStr, 10 );
}
/**
* Reset all the properties of the class.
* @access protected
*/
protected function reset() {
$this->_agent = '';
$this->_browserName = self::BROWSER_UNKNOWN;
$this->_compatibilityViewName = '';
$this->_compatibilityViewVer = '';
$this->_is64bit = false;
$this->_isMobile = false;
$this->_isRobot = false;
$this->_platform = self::PLATFORM_UNKNOWN;
$this->_platformVersion = self::PLATFORM_VERSION_UNKNOWN;
$this->_robotName = self::ROBOT_UNKNOWN;
$this->_robotVersion = self::ROBOT_VERSION_UNKNOWN;
$this->_version = self::VERSION_UNKNOWN;
}
/**
* Convert a Safari build number to a Safari version number.
* @access protected
* @param string $version A string representing the version number.
* @link https://web.archive.org/web/20080514173941/http://developer.apple.com/internet/safari/uamatrix.html
* @return string Returns the Safari version string. If the version can't be determined, an empty string is
* returned.
*/
protected function safariBuildToSafariVer( $version ) {
$verParts = explode( '.', $version );
//We need a 3 parts version (version 2 will becomes 2.0.0)
while ( count( $verParts ) < 3 ) {
$verParts[] = 0;
}
foreach ( $verParts as $i => $currPart ) {
$verParts[ $i ] = $this->parseInt( $currPart );
}
switch ( $verParts[0] ) {
case 419:
$result = '2.0.4';
break;
case 417:
$result = '2.0.3';
break;
case 416:
$result = '2.0.2';
break;
case 412:
if ( $verParts[1] >= 5 ) {
$result = '2.0.1';
} else {
$result = '2.0';
}
break;
case 312:
if ( $verParts[1] >= 5 ) {
$result = '1.3.2';
} else {
if ( $verParts[1] >= 3 ) {
$result = '1.3.1';
} else {
$result = '1.3';
}
}
break;
case 125:
if ( $verParts[1] >= 11 ) {
$result = '1.2.4';
} else {
if ( $verParts[1] >= 9 ) {
$result = '1.2.3';
} else {
if ( $verParts[1] >= 7 ) {
$result = '1.2.2';
} else {
$result = '1.2';
}
}
}
break;
case 100:
if ( $verParts[1] >= 1 ) {
$result = '1.1.1';
} else {
$result = '1.1';
}
break;
case 85:
if ( $verParts[1] >= 8 ) {
$result = '1.0.3';
} else {
if ( $verParts[1] >= 7 ) {
$result = '1.0.2';
} else {
$result = '1.0';
}
}
break;
case 73:
$result = '0.9';
break;
case 51:
$result = '0.8.1';
break;
case 48:
$result = '0.8';
break;
default:
$result = '';
}
return $result;
}
/**
* Set if the browser is executed from a 64-bit platform.
* @access protected
* @param boolean $is64bit Value that tells if the browser is executed from a 64-bit platform.
*/
protected function set64bit( $is64bit ) {
$this->_is64bit = $is64bit == true;
}
/**
* Set the name of the browser.
* @access protected
* @param string $browserName The name of the browser.
*/
protected function setBrowser( $browserName ) {
$this->_browserName = $browserName;
}
/**
* Set the browser to be from a mobile device or not.
* @access protected
* @param boolean $isMobile (optional) Value that tells if the browser is on a mobile device or not.
*/
protected function setMobile( $isMobile = true ) {
$this->_isMobile = $isMobile == true;
}
/**
* Set the platform on which the browser is on.
* @access protected
* @param string $platform The name of the platform.
*/
protected function setPlatform( $platform ) {
$this->_platform = $platform;
}
/**
* Set the platform version on which the browser is on.
* @access protected
* @param string $platformVer The version numbers of the platform.
*/
protected function setPlatformVersion( $platformVer ) {
$this->_platformVersion = $platformVer;
}
/**
* Set the browser to be a robot (crawler) or not.
* @access protected
* @param boolean $isRobot (optional) Value that tells if the browser is a robot or not.
*/
protected function setRobot( $isRobot = true ) {
$this->_isRobot = $isRobot == true;
}
/**
* Set the name of the robot.
* @access protected
* @param string $robotName The name of the robot.
*/
protected function setRobotName( $robotName ) {
$this->_robotName = $robotName;
}
/**
* Set the version of the robot.
* @access protected
* @param string $robotVersion The version of the robot.
*/
protected function setRobotVersion( $robotVersion ) {
$cleanVer = $this->cleanVersion( $robotVersion );
if ( $cleanVer == '' ) {
$this->_robotVersion = self::ROBOT_VERSION_UNKNOWN;
} else {
$this->_robotVersion = $cleanVer;
}
}
/**
* Set the version of the browser.
* @access protected
* @param string $version The version of the browser.
*/
protected function setVersion( $version ) {
$cleanVer = $this->cleanVersion( $version );
if ( $cleanVer == '' ) {
$this->_version = self::VERSION_UNKNOWN;
} else {
$this->_version = $cleanVer;
}
}
/**
* Convert a WebKit build number to a Safari version number.
* @access protected
* @param string $version A string representing the version number.
* @link https://web.archive.org/web/20080514173941/http://developer.apple.com/internet/safari/uamatrix.html
* @return string Returns the Safari version string. If the version can't be determined, an empty string is
* returned.
*/
protected function webKitBuildToSafariVer( $version ) {
$verParts = explode( '.', $version );
//We need a 3 parts version (version 2 will becomes 2.0.0)
while ( count( $verParts ) < 3 ) {
$verParts[] = 0;
}
foreach ( $verParts as $i => $currPart ) {
$verParts[ $i ] = $this->parseInt( $currPart );
}
switch ( $verParts[0] ) {
case 419:
$result = '2.0.4';
break;
case 418:
if ( $verParts[1] >= 8 ) {
$result = '2.0.4';
} else {
$result = '2.0.3';
}
break;
case 417:
$result = '2.0.3';
break;
case 416:
$result = '2.0.2';
break;
case 412:
if ( $verParts[1] >= 7 ) {
$result = '2.0.1';
} else {
$result = '2.0';
}
break;
case 312:
if ( $verParts[1] >= 8 ) {
$result = '1.3.2';
} else {
if ( $verParts[1] >= 5 ) {
$result = '1.3.1';
} else {
$result = '1.3';
}
}
break;
case 125:
if ( $this->compareVersions( '5.4', $verParts[1] . '.' . $verParts[2] ) == -1 ) {
$result = '1.2.4'; //125.5.5+
} else {
if ( $verParts[1] >= 4 ) {
$result = '1.2.3';
} else {
if ( $verParts[1] >= 2 ) {
$result = '1.2.2';
} else {
$result = '1.2';
}
}
}
break;
//WebKit 100 can be either Safari 1.1 (Safari build 100) or 1.1.1 (Safari build 100.1)
//for this reason, check the Safari build before the WebKit build.
case 100:
$result = '1.1.1';
break;
case 85:
if ( $verParts[1] >= 8 ) {
$result = '1.0.3';
} else {
if ( $verParts[1] >= 7 ) {
//WebKit 85.7 can be either Safari 1.0 (Safari build 85.5) or 1.0.2 (Safari build 85.7)
//for this reason, check the Safari build before the WebKit build.
$result = '1.0.2';
} else {
$result = '1.0';
}
}
break;
case 73:
$result = '0.9';
break;
case 51:
$result = '0.8.1';
break;
case 48:
$result = '0.8';
break;
default:
$result = '';
}
return $result;
}
/**
* Convert the Windows NT family version numbers to the operating system name. For instance '5.1' returns
* 'Windows XP'.
* @access protected
* @param string $winVer The Windows NT family version numbers as a string.
* @param boolean $returnServerFlavor (optional) Since some Windows NT versions have the same values, this flag
* determines if the Server flavor is returned or not. For instance Windows 8.1 and Windows Server 2012 R2 both use
* version 6.3.
* @return string The operating system name or the constant PLATFORM_VERSION_UNKNOWN if nothing match the version
* numbers.
*/
protected function windowsNTVerToStr( $winVer, $returnServerFlavor = false ) {
//https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions
$cleanWinVer = explode( '.', $winVer );
while ( count( $cleanWinVer ) > 2 ) {
array_pop( $cleanWinVer );
}
$cleanWinVer = implode( '.', $cleanWinVer );
if ( $this->compareVersions( $cleanWinVer, '11' ) >= 0 ) {
//Future versions of Windows
return self::PLATFORM_WINDOWS . ' ' . $winVer;
} elseif ( $this->compareVersions( $cleanWinVer, '10' ) >= 0 ) {
//Current version of Windows
//(Windows Server 2019 & 2016 have the same version number. Only the build can separate the two - which is not included in the UA)
return $returnServerFlavor ? ( self::PLATFORM_WINDOWS . ' Server 2019' ) : ( self::PLATFORM_WINDOWS . ' 10' );
} elseif ( $this->compareVersions( $cleanWinVer, '7' ) < 0 ) {
if ( $this->compareVersions( $cleanWinVer, '6.3' ) == 0 ) {
return $returnServerFlavor ? ( self::PLATFORM_WINDOWS . ' Server 2012 R2' ) : ( self::PLATFORM_WINDOWS . ' 8.1' );
} elseif ( $this->compareVersions( $cleanWinVer, '6.2' ) == 0 ) {
return $returnServerFlavor ? ( self::PLATFORM_WINDOWS . ' Server 2012' ) : ( self::PLATFORM_WINDOWS . ' 8' );
} elseif ( $this->compareVersions( $cleanWinVer, '6.1' ) == 0 ) {
return $returnServerFlavor ? ( self::PLATFORM_WINDOWS . ' Server 2008 R2' ) : ( self::PLATFORM_WINDOWS . ' 7' );
} elseif ( $this->compareVersions( $cleanWinVer, '6' ) == 0 ) {
return $returnServerFlavor ? ( self::PLATFORM_WINDOWS . ' Server 2008' ) : ( self::PLATFORM_WINDOWS . ' Vista' );
} elseif ( $this->compareVersions( $cleanWinVer, '5.2' ) == 0 ) {
return $returnServerFlavor ? ( self::PLATFORM_WINDOWS . ' Server 2003 / ' . self::PLATFORM_WINDOWS . ' Server 2003 R2' ) : ( self::PLATFORM_WINDOWS . ' XP x64 Edition' );
} elseif ( $this->compareVersions( $cleanWinVer, '5.1' ) == 0 ) {
return self::PLATFORM_WINDOWS . ' XP';
} elseif ( $this->compareVersions( $cleanWinVer, '5' ) == 0 ) {
return self::PLATFORM_WINDOWS . ' 2000';
} elseif ( $this->compareVersions( $cleanWinVer, '5' ) < 0 && $this->compareVersions( $cleanWinVer, '3' ) >= 0 ) {
return self::PLATFORM_WINDOWS . ' NT ' . $winVer;
}
}
return self::PLATFORM_VERSION_UNKNOWN; //Invalid Windows NT version
}
/**
* Convert the Windows 3.x & 9x family version numbers to the operating system name. For instance '4.10.1998'
* returns 'Windows 98'.
* @access protected
* @param string $winVer The Windows 3.x or 9x family version numbers as a string.
* @return string The operating system name or the constant PLATFORM_VERSION_UNKNOWN if nothing match the version
* numbers.
*/
protected function windowsVerToStr( $winVer ) {
//https://support.microsoft.com/en-us/kb/158238
if ( $this->compareVersions( $winVer, '4.90' ) >= 0 && $this->compareVersions( $winVer, '4.91' ) < 0 ) {
return self::PLATFORM_WINDOWS . ' Me'; //Normally range from 4.90.3000 to 4.90.3000A
} elseif ( $this->compareVersions( $winVer, '4.10' ) >= 0 && $this->compareVersions( $winVer, '4.11' ) < 0 ) {
return self::PLATFORM_WINDOWS . ' 98'; //Normally range from 4.10.1998 to 4.10.2222B
} elseif ( $this->compareVersions( $winVer, '4' ) >= 0 && $this->compareVersions( $winVer, '4.04' ) < 0 ) {
return self::PLATFORM_WINDOWS . ' 95'; //Normally range from 4.00.950 to 4.03.1214
} elseif ( $this->compareVersions( $winVer, '3.1' ) == 0 || $this->compareVersions( $winVer, '3.11' ) == 0 ) {
return self::PLATFORM_WINDOWS . ' ' . $winVer;
} elseif ( $this->compareVersions( $winVer, '3.10' ) == 0 ) {
return self::PLATFORM_WINDOWS . ' 3.1';
} else {
return self::PLATFORM_VERSION_UNKNOWN; //Invalid Windows version
}
}
/**
* Find the position of the first occurrence of a word in a string.
* @access protected
* @param string $haystack The string to search in.
* @param string $needle The string to search for.
* @param boolean $insensitive (optional) Determines if we do a case-sensitive search (false) or a case-insensitive
* one (true).
* @param int $offset If specified, search will start this number of characters counted from the beginning of the
* string. If the offset is negative, the search will start this number of characters counted from the end of the
* string.
* @param string $foundString String buffer that will contain the exact matching needle found. Set to NULL when
* return value of the function is false.
* @return mixed Returns the position of the needle (int) if found, false otherwise. Warning this function may
* return Boolean false, but may also return a non-Boolean value which evaluates to false.
*/
protected function wordPos( $haystack, $needle, $insensitive = true, $offset = 0, &$foundString = null ) {
if ( $offset != 0 ) {
$haystack = substr( $haystack, $offset );
}
$parts = explode( ' ', $needle );
foreach ( $parts as $i => $currPart ) {
$parts[ $i ] = preg_quote( $currPart, '/' );
}
$regex = '/(?<=\A|[\s\/\\.,;:_()-])' . implode( '[\s\/\\.,;:_()-]', $parts ) . '(?=[\s\/\\.,;:_()-]|$)/';
if ( $insensitive ) {
$regex .= 'i';
}
if ( preg_match( $regex, $haystack, $matches, PREG_OFFSET_CAPTURE ) ) {
$foundString = $matches[0][0];
return (int) $matches[0][1];
}
return false;
}
}