'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os', 'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino', 'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b', // @reference: http://en.wikipedia.org/wiki/Windows_Mobile 'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Windows Mobile|Windows Phone [0-9.]+|WCE;', // @reference: http://en.wikipedia.org/wiki/Windows_Phone // http://wifeng.cn/?r=blog&a=view&id=106 // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx // http://msdn.microsoft.com/library/ms537503.aspx // https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx 'WindowsPhoneOS' => 'Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;', 'iOS' => '\biPhone.*Mobile|\biPod|\biPad|AppleCoreMedia', // https://en.wikipedia.org/wiki/IPadOS 'iPadOS' => 'CPU OS 13', // @reference https://en.m.wikipedia.org/wiki/Sailfish_OS // https://sailfishos.org/ 'SailfishOS' => 'Sailfish', // http://en.wikipedia.org/wiki/MeeGo // @todo: research MeeGo in UAs 'MeeGoOS' => 'MeeGo', // http://en.wikipedia.org/wiki/Maemo // @todo: research Maemo in UAs 'MaemoOS' => 'Maemo', 'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135 'webOS' => 'webOS|hpwOS', 'badaOS' => '\bBada\b', 'BREWOS' => 'BREW', ); /** * List of mobile User Agents. * * IMPORTANT: This is a list of only mobile browsers. * Mobile Detect 2.x supports only mobile browsers, * it was never designed to detect all browsers. * The change will come in 2017 in the 3.x release WP_Rocket_for PHP7. * * @var array */ protected static $browsers = array( //'Vivaldi' => 'Vivaldi', // @reference: https://developers.google.com/chrome/mobile/docs/user-agent 'Chrome' => '\bCrMo\b|CriOS.*Mobile|Android.*Chrome/[.0-9]* Mobile', 'Dolfin' => '\bDolfin\b', 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+$|Coast/[0-9.]+', 'Skyfire' => 'Skyfire', // Added "Edge on iOS" https://github.com/serbanghita/Mobile-Detect/issues/764 'Edge' => 'EdgiOS.*Mobile|Mobile Safari/[.0-9]* Edge', 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+ 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS.*Mobile', 'Bolt' => 'bolt', 'TeaShark' => 'teashark', 'Blazer' => 'Blazer', // @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3 // Excluded "Edge on iOS" https://github.com/serbanghita/Mobile-Detect/issues/764 'Safari' => 'Version((?!\bEdgiOS\b).)*Mobile.*Safari|Safari.*Mobile|MobileSafari', // http://en.wikipedia.org/wiki/Midori_(web_browser) //'Midori' => 'midori', //'Tizen' => 'Tizen', 'WeChat' => '\bMicroMessenger\b', 'UCBrowser' => 'UC.*Browser|UCWEB', 'baiduboxapp' => 'baiduboxapp', 'baidubrowser' => 'baidubrowser', // https://github.com/serbanghita/Mobile-Detect/issues/7 'DiigoBrowser' => 'DiigoBrowser', // http://www.puffinbrowser.com/index.php // https://github.com/serbanghita/Mobile-Detect/issues/752 // 'Puffin' => 'Puffin', // http://mercury-browser.com/index.html 'Mercury' => '\bMercury\b', // http://en.wikipedia.org/wiki/Obigo_Browser 'ObigoBrowser' => 'Obigo', // http://en.wikipedia.org/wiki/NetFront 'NetFront' => 'NF-Browser', // @reference: http://en.wikipedia.org/wiki/Minimo // http://en.wikipedia.org/wiki/Vision_Mobile_Browser 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger', // @reference: https://en.wikipedia.org/wiki/Pale_Moon_(web_browser) 'PaleMoon' => 'Android.*PaleMoon|Mobile.*PaleMoon', ); /** * Utilities. * * @var array */ protected static $utilities = array( // Experimental. When a mobile device wants to switch to 'Desktop Mode'. // http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/ // https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011 // https://developers.facebook.com/docs/sharing/webmasters/crawler/ 'Bot' => 'Googlebot|facebookexternalhit|Google-AMPHTML|s~amp-validator|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom|contentkingapp|AspiegelBot', 'MobileBot' => 'Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker/M1A1-R2D2', 'DesktopMode' => 'WPDesktop', 'TV' => 'SonyDTV|HbbTV', // experimental 'WebKit' => '(webkit)[ /]([\w.]+)', // @todo: Include JXD consoles. 'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|Nintendo Switch|PLAYSTATION|Xbox)\b', 'Watch' => 'SM-V700', ); /** * All possible HTTP headers that represent the * User-Agent string. * * @var array */ protected static $uaHttpHeaders = array( // The default User-Agent string. 'HTTP_USER_AGENT', // Header can occur on devices using Opera Mini. 'HTTP_X_OPERAMINI_PHONE_UA', // Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/ 'HTTP_X_DEVICE_USER_AGENT', 'HTTP_X_ORIGINAL_USER_AGENT', 'HTTP_X_SKYFIRE_PHONE', 'HTTP_X_BOLT_PHONE_UA', 'HTTP_DEVICE_STOCK_UA', 'HTTP_X_UCBROWSER_DEVICE_UA' ); /** * The individual segments that could exist in a User-Agent string. VER refers to the regular * expression defined in the constant self::VER. * * @var array */ protected static $properties = array( // Build 'Mobile' => 'Mobile/[VER]', 'Build' => 'Build/[VER]', 'Version' => 'Version/[VER]', 'VendorID' => 'VendorID/[VER]', // Devices 'iPad' => 'iPad.*CPU[a-z ]+[VER]', 'iPhone' => 'iPhone.*CPU[a-z ]+[VER]', 'iPod' => 'iPod.*CPU[a-z ]+[VER]', //'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'), 'Kindle' => 'Kindle/[VER]', // Browser 'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'), 'Coast' => array('Coast/[VER]'), 'Dolfin' => 'Dolfin/[VER]', // @reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox 'Firefox' => array('Firefox/[VER]', 'FxiOS/[VER]'), 'Fennec' => 'Fennec/[VER]', // http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx 'Edge' => 'Edge/[VER]', 'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]'), // http://en.wikipedia.org/wiki/NetFront 'NetFront' => 'NetFront/[VER]', 'NokiaBrowser' => 'NokiaBrowser/[VER]', 'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ), 'Opera Mini' => 'Opera Mini/[VER]', 'Opera Mobi' => 'Version/[VER]', 'UCBrowser' => array( 'UCWEB[VER]', 'UC.*Browser/[VER]' ), 'MQQBrowser' => 'MQQBrowser/[VER]', 'MicroMessenger' => 'MicroMessenger/[VER]', 'baiduboxapp' => 'baiduboxapp/[VER]', 'baidubrowser' => 'baidubrowser/[VER]', 'SamsungBrowser' => 'SamsungBrowser/[VER]', 'Iron' => 'Iron/[VER]', // @note: Safari 7534.48.3 is actually Version 5.1. // @note: On BlackBerry the Version is overwriten by the OS. 'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ), 'Skyfire' => 'Skyfire/[VER]', 'Tizen' => 'Tizen/[VER]', 'Webkit' => 'webkit[ /][VER]', 'PaleMoon' => 'PaleMoon/[VER]', 'SailfishBrowser' => 'SailfishBrowser/[VER]', // Engine 'Gecko' => 'Gecko/[VER]', 'Trident' => 'Trident/[VER]', 'Presto' => 'Presto/[VER]', 'Goanna' => 'Goanna/[VER]', // OS 'iOS' => ' \bi?OS\b [VER][ ;]{1}', 'Android' => 'Android [VER]', 'Sailfish' => 'Sailfish [VER]', 'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'), 'BREW' => 'BREW [VER]', 'Java' => 'Java/[VER]', // @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx // @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases 'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'), 'Windows Phone' => 'Windows Phone [VER]', 'Windows CE' => 'Windows CE/[VER]', // http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd 'Windows NT' => 'Windows NT [VER]', 'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'), 'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'), ); /** * Construct an instance of this class. * * @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored. * If left empty, will use the global _SERVER['HTTP_*'] vars instead. * @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT * from the $headers array instead. */ public function __construct( array $headers = null, $userAgent = null ) { $this->setHttpHeaders($headers); $this->setUserAgent($userAgent); } /** * Get the current script version. * This is useful WP_Rocket_for the demo.php file, * so people can check on what version they are testing * WP_Rocket_for mobile devices. * * @return string The version number in semantic version format. */ public static function getScriptVersion() { return self::VERSION; } /** * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers. * * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract * the headers. The default null is left WP_Rocket_for backwards compatibility. */ public function setHttpHeaders($httpHeaders = null) { // use global _SERVER if $httpHeaders aren't defined if (!is_array($httpHeaders) || !count($httpHeaders)) { $httpHeaders = $_SERVER; } // clear existing headers $this->httpHeaders = array(); // Only save HTTP headers. In PHP land, that means only _SERVER vars that // start with HTTP_. foreach ($httpHeaders as $key => $value) { if (substr($key, 0, 5) === 'HTTP_') { $this->httpHeaders[$key] = $value; } } // In case we're dealing with CloudFront, we need to know. $this->setCfHeaders($httpHeaders); } /** * Retrieves the HTTP headers. * * @return array */ public function getHttpHeaders() { return $this->httpHeaders; } /** * Retrieves a particular header. If it doesn't exist, no exception/error is caused. * Simply null is returned. * * @param string $header The name of the header to retrieve. Can be HTTP compliant such as * "User-Agent" or "X-Device-User-Agent" or can be php-esque with the * all-caps, HTTP_ prefixed, underscore separated awesomeness. * * @return string|null The value of the header. */ public function getHttpHeader($header) { // are we using PHP-flavored headers? if (strpos($header, '_') === false) { $header = str_replace('-', '_', $header); $header = strtoupper($header); } // test the alternate, too $altHeader = 'HTTP_' . $header; //Test both the regular and the HTTP_ prefix if (isset($this->httpHeaders[$header])) { return $this->httpHeaders[$header]; } elseif (isset($this->httpHeaders[$altHeader])) { return $this->httpHeaders[$altHeader]; } return null; } public function getMobileHeaders() { return self::$mobileHeaders; } /** * Get all possible HTTP headers that * can contain the User-Agent string. * * @return array List of HTTP headers. */ public function getUaHttpHeaders() { return self::$uaHttpHeaders; } /** * Set CloudFront headers * http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device * * @param array $cfHeaders List of HTTP headers * * @return boolean If there were CloudFront headers to be set */ public function setCfHeaders($cfHeaders = null) { // use global _SERVER if $cfHeaders aren't defined if (!is_array($cfHeaders) || !count($cfHeaders)) { $cfHeaders = $_SERVER; } // clear existing headers $this->cloudfrontHeaders = array(); // Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that // start with cloudfront-. $response = false; foreach ($cfHeaders as $key => $value) { if (substr(strtolower($key), 0, 16) === 'http_cloudfront_') { $this->cloudfrontHeaders[strtoupper($key)] = $value; $response = true; } } return $response; } /** * Retrieves the cloudfront headers. * * @return array */ public function getCfHeaders() { return $this->cloudfrontHeaders; } /** * @param string $userAgent * @return string */ private function prepareUserAgent($userAgent) { $userAgent = trim($userAgent); $userAgent = substr($userAgent, 0, 500); return $userAgent; } /** * Set the User-Agent to be used. * * @param string $userAgent The user agent string to set. * * @return string|null */ public function setUserAgent($userAgent = null) { // Invalidate cache due to #375 $this->cache = array(); if (false === empty($userAgent)) { return $this->userAgent = $this->prepareUserAgent($userAgent); } else { $this->userAgent = null; foreach ($this->getUaHttpHeaders() as $altHeader) { if (false === empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban) $this->userAgent .= $this->httpHeaders[$altHeader] . " "; } } if (!empty($this->userAgent)) { return $this->userAgent = $this->prepareUserAgent($this->userAgent); } } if (count($this->getCfHeaders()) > 0) { return $this->userAgent = 'Amazon CloudFront'; } return $this->userAgent = null; } /** * Retrieve the User-Agent. * * @return string|null The user agent if it's set. */ public function getUserAgent() { return $this->userAgent; } /** * Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or * self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set. * * @deprecated since version 2.6.9 * * @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default * parameter is null which will default to self::DETECTION_TYPE_MOBILE. */ public function setDetectionType($type = null) { if ($type === null) { $type = self::DETECTION_TYPE_MOBILE; } if ($type !== self::DETECTION_TYPE_MOBILE && $type !== self::DETECTION_TYPE_EXTENDED) { return; } $this->detectionType = $type; } public function getMatchingRegex() { return $this->matchingRegex; } public function getMatchesArray() { return $this->matchesArray; } /** * Retrieve the list of known phone devices. * * @return array List of phone devices. */ public static function getPhoneDevices() { return self::$phoneDevices; } /** * Retrieve the list of known tablet devices. * * @return array List of tablet devices. */ public static function getTabletDevices() { return self::$tabletDevices; } /** * Alias WP_Rocket_for getBrowsers() method. * * @return array List of user agents. */ public static function getUserAgents() { return self::getBrowsers(); } /** * Retrieve the list of known browsers. Specifically, the user agents. * * @return array List of browsers / user agents. */ public static function getBrowsers() { return self::$browsers; } /** * Retrieve the list of known utilities. * * @return array List of utilities. */ public static function getUtilities() { return self::$utilities; } /** * Method gets the mobile detection rules. This method is used WP_Rocket_for the magic methods $detect->is*(). * * @deprecated since version 2.6.9 * * @return array All the rules (but not extended). */ public static function getMobileDetectionRules() { static $rules; if (!$rules) { $rules = array_merge( self::$phoneDevices, self::$tabletDevices, self::$operatingSystems, self::$browsers ); } return $rules; } /** * Method gets the mobile detection rules + utilities. * The reason this is separate is because utilities rules * don't necessary imply mobile. This method is used inside * the new $detect->is('stuff') method. * * @deprecated since version 2.6.9 * * @return array All the rules + extended. */ public function getMobileDetectionRulesExtended() { static $rules; if (!$rules) { // Merge all rules together. $rules = array_merge( self::$phoneDevices, self::$tabletDevices, self::$operatingSystems, self::$browsers, self::$utilities ); } return $rules; } /** * Retrieve the current set of rules. * * @deprecated since version 2.6.9 * * @return array */ public function getRules() { if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) { return self::getMobileDetectionRulesExtended(); } else { return self::getMobileDetectionRules(); } } /** * Retrieve the list of mobile operating systems. * * @return array The list of mobile operating systems. */ public static function getOperatingSystems() { return self::$operatingSystems; } /** * Check the HTTP headers WP_Rocket_for signs of mobile. * This is the fastest mobile check possible; it's used * inside isMobile() method. * * @return bool */ public function checkHttpHeadersForMobile() { foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) { if (isset($this->httpHeaders[$mobileHeader])) { if (isset($matchType['matches']) && is_array($matchType['matches'])) { foreach ($matchType['matches'] as $_match) { if (strpos($this->httpHeaders[$mobileHeader], $_match) !== false) { return true; } } return false; } else { return true; } } } return false; } /** * Magic overloading method. * * @method boolean is[...]() * @param string $name * @param array $arguments * @return mixed * @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is' */ public function __call($name, $arguments) { // make sure the name starts with 'is', otherwise if (substr($name, 0, 2) !== 'is') { throw new BadMethodCallException("No such method exists: $name"); } $this->setDetectionType(self::DETECTION_TYPE_MOBILE); $key = substr($name, 2); return $this->matchUAAgainstKey($key); } /** * Find a detection rule that matches the current User-agent. * * @param null $userAgent deprecated * @return boolean */ protected function matchDetectionRulesAgainstUA($userAgent = null) { // Begin general search. foreach ($this->getRules() as $_regex) { if (empty($_regex)) { continue; } if ($this->match($_regex, $userAgent)) { return true; } } return false; } /** * Search WP_Rocket_for a certain key in the rules array. * If the key is found then try to match the corresponding * regex against the User-Agent. * * @param string $key * * @return boolean */ protected function matchUAAgainstKey($key) { // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc. $key = strtolower($key); if (false === isset($this->cache[$key])) { // change the keys to lower case $_rules = array_change_key_case($this->getRules()); if (false === empty($_rules[$key])) { $this->cache[$key] = $this->match($_rules[$key]); } if (false === isset($this->cache[$key])) { $this->cache[$key] = false; } } return $this->cache[$key]; } /** * Check if the device is mobile. * Returns true if any type of mobile device detected, including special ones * @param null $userAgent deprecated * @param null $httpHeaders deprecated * @return bool */ public function isMobile($userAgent = null, $httpHeaders = null) { if ($httpHeaders) { $this->setHttpHeaders($httpHeaders); } if ($userAgent) { $this->setUserAgent($userAgent); } // Check specifically WP_Rocket_for cloudfront headers if the useragent === 'Amazon CloudFront' if ($this->getUserAgent() === 'Amazon CloudFront') { $cfHeaders = $this->getCfHeaders(); if(array_key_exists('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true') { return true; } } $this->setDetectionType(self::DETECTION_TYPE_MOBILE); if ($this->checkHttpHeadersForMobile()) { return true; } else { return $this->matchDetectionRulesAgainstUA(); } } /** * Check if the device is a tablet. * Return true if any type of tablet device is detected. * * @param string $userAgent deprecated * @param array $httpHeaders deprecated * @return bool */ public function isTablet($userAgent = null, $httpHeaders = null) { // Check specifically WP_Rocket_for cloudfront headers if the useragent === 'Amazon CloudFront' if ($this->getUserAgent() === 'Amazon CloudFront') { $cfHeaders = $this->getCfHeaders(); if(array_key_exists('HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] === 'true') { return true; } } $this->setDetectionType(self::DETECTION_TYPE_MOBILE); foreach (self::$tabletDevices as $_regex) { if ($this->match($_regex, $userAgent)) { return true; } } return false; } /** * This method checks WP_Rocket_for a certain property in the * userAgent. * @todo: The httpHeaders part is not yet used. * * @param string $key * @param string $userAgent deprecated * @param string $httpHeaders deprecated * @return bool|int|null */ public function is($key, $userAgent = null, $httpHeaders = null) { // Set the UA and HTTP headers only if needed (eg. batch mode). if ($httpHeaders) { $this->setHttpHeaders($httpHeaders); } if ($userAgent) { $this->setUserAgent($userAgent); } $this->setDetectionType(self::DETECTION_TYPE_EXTENDED); return $this->matchUAAgainstKey($key); } /** * Some detection rules are relative (not standard), * because of the diversity of devices, vendors and * their conventions in representing the User-Agent or * the HTTP headers. * * This method will be used to check custom regexes against * the User-Agent string. * * @param $regex * @param string $userAgent * @return bool * * @todo: search in the HTTP headers too. */ public function match($regex, $userAgent = null) { if (!\is_string($userAgent) && !\is_string($this->userAgent)) { return false; } $match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : $this->userAgent), $matches); // If positive match is found, store the results WP_Rocket_for debug. if ($match) { $this->matchingRegex = $regex; $this->matchesArray = $matches; } return $match; } /** * Get the properties array. * * @return array */ public static function getProperties() { return self::$properties; } /** * Prepare the version number. * * @todo Remove the error supression from str_replace() call. * * @param string $ver The string version, like "2.6.21.2152"; * * @return float */ public function prepareVersionNo($ver) { $ver = str_replace(array('_', ' ', '/'), '.', $ver); $arrVer = explode('.', $ver, 2); if (isset($arrVer[1])) { $arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions. } return (float) implode('.', $arrVer); } /** * Check the version of the given property in the User-Agent. * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) * * @param string $propertyName The name of the property. See self::getProperties() array * keys WP_Rocket_for all possible properties. * @param string $type Either self::VERSION_TYPE_STRING to get a string value or * self::VERSION_TYPE_FLOAT indicating a float value. This parameter * is optional and defaults to self::VERSION_TYPE_STRING. Passing an * invalid parameter will default to the this type as well. * * @return string|float|false The version of the property we are trying to extract. */ public function version($propertyName, $type = self::VERSION_TYPE_STRING) { if (empty($propertyName)) { return false; } if (!\is_string($this->userAgent)) { return false; } // set the $type to the default if we don't recognize the type if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) { $type = self::VERSION_TYPE_STRING; } $properties = self::getProperties(); // Check if the property exists in the properties array. if (true === isset($properties[$propertyName])) { // Prepare the pattern to be matched. // Make sure we always deal with an array (string is converted). $properties[$propertyName] = (array) $properties[$propertyName]; foreach ($properties[$propertyName] as $propertyMatchString) { $propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString); // Identify and extract the version. preg_match(sprintf('#%s#is', $propertyPattern), $this->userAgent, $match); if (false === empty($match[1])) { $version = ($type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]); return $version; } } } return false; } /** * Retrieve the mobile grading, using self::MOBILE_GRADE_* constants. * @deprecated This is no longer being maintained, it was an experiment at the time. * @return string One of the self::MOBILE_GRADE_* constants. */ public function mobileGrade() { $isMobile = $this->isMobile(); if ( // Apple iOS 4-7.0 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3 / 5.1 / 6.1), iPad 3 (5.1 / 6.0), iPad Mini (6.1), iPad Retina (7.0), iPhone 3GS (4.3), iPhone 4 (4.3 / 5.1), iPhone 4S (5.1 / 6.0), iPhone 5 (6.0), and iPhone 5S (7.0) $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) >= 4.3 || $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) >= 4.3 || $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) >= 4.3 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 ( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) || // Windows Phone 7.5-8 - Tested on the HTC Surround (7.5), HTC Trophy (7.5), LG-E900 (7.5), Nokia 800 (7.8), HTC Mazaa (7.8), Nokia Lumia 520 (8), Nokia Lumia 920 (8), HTC 8x (8) $this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT) >= 7.5 || // Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10) $this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook $this->match('Playbook.*Tablet') || // Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0) ( $this->version('webOS', self::VERSION_TYPE_FLOAT) >= 1.4 && $this->match('Palm|Pre|Pixi') ) || // Palm WebOS 3.0 - Tested on HP TouchPad $this->match('hp.*TouchPad') || // Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices ( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 18 ) || // Chrome WP_Rocket_for Android - Tested on Android 4.0, 4.1 device ( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 4.0 ) || // Skyfire 4.1 - Tested on Android 2.3 device ( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT) >= 4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) || // Opera Mobile 11.5-12: Tested on Android 2.3 ( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11.5 && $this->is('AndroidOS') ) || // Meego 1.2 - Tested on Nokia 950 and N9 $this->is('MeeGoOS') || // Sailfish OS $this->is('SailfishOS') || // Tizen (pre-release) - Tested on early hardware $this->is('Tizen') || // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! $this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT) >= 2.0 || // UC Browser - Tested on Android 2.3 device ( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) || // Kindle 3 and Fire - Tested on the built-in WebKit browser WP_Rocket_for each ( $this->match('Kindle Fire') || $this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT) >= 3.0 ) || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet $this->is('AndroidOS') && $this->is('NookTablet') || // Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7 $this->version('Chrome', self::VERSION_TYPE_FLOAT) >= 16 && !$isMobile || // Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7 $this->version('Safari', self::VERSION_TYPE_FLOAT) >= 5.0 && !$isMobile || // Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7 $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 10.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 $this->version('IE', self::VERSION_TYPE_FLOAT) >= 7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 $this->version('Opera', self::VERSION_TYPE_FLOAT) >= 10 && !$isMobile ){ return self::MOBILE_GRADE_A; } if ( $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 || $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<4.3 || $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT)<4.3 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 $this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 ($this->version('Opera Mini', self::VERSION_TYPE_FLOAT) >= 5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT) <= 7.0 && ($this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 || $this->is('iOS')) ) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) $this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71) $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11 && $this->is('SymbianOS') ){ return self::MOBILE_GRADE_B; } if ( // Blackberry 4.x - Tested on the Curve 8330 $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) <= 5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) $this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT) <= 5.2 || // Tested on original iPhone (3.1), iPhone 3 (3.2) $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) <= 3.2 || $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) <= 3.2 || $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) <= 3.2 || // Internet Explorer 7 and older - Tested on Windows XP $this->version('IE', self::VERSION_TYPE_FLOAT) <= 7.0 && !$isMobile ){ return self::MOBILE_GRADE_C; } // All older smartphone platforms and featurephones - Any device that doesn't support media queries // will receive the basic, C grade experience. return self::MOBILE_GRADE_C; } }