├── LICENSE ├── composer.json └── src ├── AcceptLanguage.php ├── Browser.php ├── BrowserDetector.php ├── DetectorInterface.php ├── Device.php ├── DeviceDetector.php ├── InvalidArgumentException.php ├── Language.php ├── LanguageDetector.php ├── Os.php ├── OsDetector.php └── UserAgent.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2017 Chris Schuld 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sinergi/browser-detector", 3 | "description": "Detecting the user's browser, operating system and language.", 4 | "keywords": ["browser", "os", "operating system", "language", "detection"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Gabriel Bull", 9 | "email": "me@gabrielbull.com" 10 | }, 11 | { 12 | "name": "Chris Schuld" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=7.2" 17 | }, 18 | "require-dev": { 19 | "phpunit/phpunit": "^8.0 || ^9.4" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "Sinergi\\BrowserDetector\\": "src" 24 | } 25 | }, 26 | "autoload-dev": { 27 | "psr-4": { 28 | "Sinergi\\BrowserDetector\\Tests\\": ["tests/BrowserDetector/Tests", "tests/BrowserDetector/Tests/_includes"] 29 | } 30 | }, 31 | "minimum-stability": "dev", 32 | "prefer-stable": true 33 | } 34 | -------------------------------------------------------------------------------- /src/AcceptLanguage.php: -------------------------------------------------------------------------------- 1 | setAcceptLanguageString($acceptLanguageString); 19 | } 20 | } 21 | 22 | /** 23 | * @param string $acceptLanguageString 24 | * 25 | * @return $this 26 | */ 27 | public function setAcceptLanguageString($acceptLanguageString) 28 | { 29 | $this->acceptLanguageString = $acceptLanguageString; 30 | 31 | return $this; 32 | } 33 | 34 | /** 35 | * @return string 36 | */ 37 | public function getAcceptLanguageString() 38 | { 39 | if (null === $this->acceptLanguageString) { 40 | $this->createAcceptLanguageString(); 41 | } 42 | 43 | return $this->acceptLanguageString; 44 | } 45 | 46 | /** 47 | * @return string 48 | */ 49 | public function createAcceptLanguageString() 50 | { 51 | $acceptLanguageString = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : null; 52 | $this->setAcceptLanguageString($acceptLanguageString); 53 | 54 | return $acceptLanguageString; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Browser.php: -------------------------------------------------------------------------------- 1 | setUserAgent($userAgent); 96 | } elseif (null === $userAgent || is_string($userAgent)) { 97 | $this->setUserAgent(new UserAgent($userAgent)); 98 | } else { 99 | throw new InvalidArgumentException(); 100 | } 101 | } 102 | 103 | /** 104 | * Set the name of the OS. 105 | * 106 | * @param string $name 107 | * 108 | * @return $this 109 | */ 110 | public function setName($name) 111 | { 112 | $this->name = (string)$name; 113 | 114 | return $this; 115 | } 116 | 117 | /** 118 | * Return the name of the Browser. 119 | * 120 | * @return string 121 | */ 122 | public function getName() 123 | { 124 | if (!isset($this->name)) { 125 | BrowserDetector::detect($this, $this->getUserAgent()); 126 | } 127 | 128 | return $this->name; 129 | } 130 | 131 | /** 132 | * Check to see if the specific browser is valid. 133 | * 134 | * @param string $name 135 | * 136 | * @return bool 137 | */ 138 | public function isBrowser($name) 139 | { 140 | return (0 == strcasecmp($this->getName(), trim($name))); 141 | } 142 | 143 | /** 144 | * Set the version of the browser. 145 | * 146 | * @param string $version 147 | * 148 | * @return $this 149 | */ 150 | public function setVersion($version) 151 | { 152 | $this->version = (string)$version; 153 | 154 | return $this; 155 | } 156 | 157 | /** 158 | * The version of the browser. 159 | * 160 | * @return string 161 | */ 162 | public function getVersion() 163 | { 164 | if (!isset($this->name)) { 165 | BrowserDetector::detect($this, $this->getUserAgent()); 166 | } 167 | 168 | return (string) $this->version; 169 | } 170 | 171 | /** 172 | * Set the Browser to be a robot. 173 | * 174 | * @param bool $isRobot 175 | * 176 | * @return $this 177 | */ 178 | public function setIsRobot($isRobot) 179 | { 180 | $this->isRobot = (bool)$isRobot; 181 | 182 | return $this; 183 | } 184 | 185 | /** 186 | * Is the browser from a robot (ex Slurp,GoogleBot)? 187 | * 188 | * @return bool 189 | */ 190 | public function getIsRobot() 191 | { 192 | if (!isset($this->name)) { 193 | BrowserDetector::detect($this, $this->getUserAgent()); 194 | } 195 | 196 | return $this->isRobot; 197 | } 198 | 199 | /** 200 | * @return bool 201 | */ 202 | public function isRobot() 203 | { 204 | return $this->getIsRobot(); 205 | } 206 | 207 | /** 208 | * @param bool $isChromeFrame 209 | * 210 | * @return $this 211 | */ 212 | public function setIsChromeFrame($isChromeFrame) 213 | { 214 | $this->isChromeFrame = (bool)$isChromeFrame; 215 | 216 | return $this; 217 | } 218 | 219 | /** 220 | * Used to determine if the browser is actually "chromeframe". 221 | * 222 | * @return bool 223 | */ 224 | public function getIsChromeFrame() 225 | { 226 | if (!isset($this->name)) { 227 | BrowserDetector::detect($this, $this->getUserAgent()); 228 | } 229 | 230 | return $this->isChromeFrame; 231 | } 232 | 233 | /** 234 | * @return bool 235 | */ 236 | public function isChromeFrame() 237 | { 238 | return $this->getIsChromeFrame(); 239 | } 240 | 241 | /** 242 | * @param bool $isFacebookWebView 243 | * 244 | * @return $this 245 | */ 246 | public function setIsFacebookWebView($isFacebookWebView) 247 | { 248 | $this->isFacebookWebView = (bool) $isFacebookWebView; 249 | 250 | return $this; 251 | } 252 | 253 | /** 254 | * Used to determine if the browser is actually "facebook". 255 | * 256 | * @return bool 257 | */ 258 | public function getIsFacebookWebView() 259 | { 260 | if (!isset($this->name)) { 261 | BrowserDetector::detect($this, $this->getUserAgent()); 262 | } 263 | 264 | return $this->isFacebookWebView; 265 | } 266 | 267 | /** 268 | * @return bool 269 | */ 270 | public function isFacebookWebView() 271 | { 272 | return $this->getIsFacebookWebView(); 273 | } 274 | 275 | /** 276 | * @param UserAgent $userAgent 277 | * 278 | * @return $this 279 | */ 280 | public function setUserAgent(UserAgent $userAgent) 281 | { 282 | $this->userAgent = $userAgent; 283 | 284 | return $this; 285 | } 286 | 287 | /** 288 | * @return UserAgent 289 | */ 290 | public function getUserAgent() 291 | { 292 | return $this->userAgent; 293 | } 294 | 295 | /** 296 | * @param bool 297 | * 298 | * @return $this 299 | */ 300 | public function setIsCompatibilityMode($isCompatibilityMode) 301 | { 302 | $this->isCompatibilityMode = $isCompatibilityMode; 303 | 304 | return $this; 305 | } 306 | 307 | /** 308 | * @return bool 309 | */ 310 | public function isCompatibilityMode() 311 | { 312 | return $this->isCompatibilityMode; 313 | } 314 | 315 | /** 316 | * Render pages outside of IE's compatibility mode. 317 | */ 318 | public function endCompatibilityMode() 319 | { 320 | header('X-UA-Compatible: IE=edge'); 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /src/BrowserDetector.php: -------------------------------------------------------------------------------- 1 | getUserAgent(); 87 | } 88 | self::$userAgentString = $userAgent->getUserAgentString(); 89 | 90 | self::$browser->setName(Browser::UNKNOWN); 91 | self::$browser->setVersion(Browser::VERSION_UNKNOWN); 92 | 93 | self::checkChromeFrame(); 94 | self::checkFacebookWebView(); 95 | 96 | foreach (self::$browsersList as $browserName) { 97 | $funcName = self::FUNC_PREFIX . $browserName; 98 | 99 | if (self::$funcName()) { 100 | return true; 101 | } 102 | } 103 | 104 | return false; 105 | } 106 | 107 | /** 108 | * Determine if the user is using Chrome Frame. 109 | * 110 | * @return bool 111 | */ 112 | public static function checkChromeFrame() 113 | { 114 | if (strpos(self::$userAgentString, 'chromeframe') !== false) { 115 | self::$browser->setIsChromeFrame(true); 116 | 117 | return true; 118 | } 119 | 120 | return false; 121 | } 122 | 123 | /** 124 | * Determine if the user is using Facebook. 125 | * 126 | * @return bool 127 | */ 128 | public static function checkFacebookWebView() 129 | { 130 | if (strpos(self::$userAgentString, 'FBAV') !== false) { 131 | self::$browser->setIsFacebookWebView(true); 132 | 133 | return true; 134 | } 135 | 136 | return false; 137 | } 138 | 139 | /** 140 | * Determine if the user is using a BlackBerry. 141 | * 142 | * @return bool 143 | */ 144 | public static function checkBrowserBlackBerry() 145 | { 146 | if (stripos(self::$userAgentString, 'blackberry') !== false) { 147 | if (stripos(self::$userAgentString, 'Version/') !== false) { 148 | $aresult = explode('Version/', self::$userAgentString); 149 | if (isset($aresult[1])) { 150 | $aversion = explode(' ', $aresult[1]); 151 | self::$browser->setVersion($aversion[0]); 152 | } 153 | } else { 154 | $aresult = explode('/', stristr(self::$userAgentString, 'BlackBerry')); 155 | if (isset($aresult[1])) { 156 | $aversion = explode(' ', $aresult[1]); 157 | self::$browser->setVersion($aversion[0]); 158 | } 159 | } 160 | self::$browser->setName(Browser::BLACKBERRY); 161 | 162 | return true; 163 | } elseif (stripos(self::$userAgentString, 'BB10') !== false) { 164 | $aresult = explode('Version/10.', self::$userAgentString); 165 | if (isset($aresult[1])) { 166 | $aversion = explode(' ', $aresult[1]); 167 | self::$browser->setVersion('10.' . $aversion[0]); 168 | } 169 | self::$browser->setName(Browser::BLACKBERRY); 170 | return true; 171 | } 172 | 173 | return false; 174 | } 175 | 176 | /** 177 | * Determine if the browser is a robot. 178 | * 179 | * @return bool 180 | */ 181 | public static function checkBrowserRobot() 182 | { 183 | if (stripos(self::$userAgentString, 'bot') !== false || 184 | stripos(self::$userAgentString, 'spider') !== false || 185 | stripos(self::$userAgentString, 'crawler') !== false 186 | ) { 187 | self::$browser->setIsRobot(true); 188 | 189 | return true; 190 | } 191 | 192 | return false; 193 | } 194 | 195 | /** 196 | * Determine if the browser is Internet Explorer. 197 | * 198 | * @return bool 199 | */ 200 | public static function checkBrowserInternetExplorer() 201 | { 202 | // Test for v1 - v1.5 IE 203 | if (stripos(self::$userAgentString, 'microsoft internet explorer') !== false) { 204 | self::$browser->setName(Browser::IE); 205 | self::$browser->setVersion('1.0'); 206 | $aresult = stristr(self::$userAgentString, '/'); 207 | if (preg_match('/308|425|426|474|0b1/i', $aresult)) { 208 | self::$browser->setVersion('1.5'); 209 | } 210 | 211 | return true; 212 | } // Test for versions > 1.5 and < 11 and some cases of 11 213 | else { 214 | if (stripos(self::$userAgentString, 'msie') !== false && stripos(self::$userAgentString, 'opera') === false 215 | ) { 216 | // See if the browser is the odd MSN Explorer 217 | if (stripos(self::$userAgentString, 'msnb') !== false) { 218 | $aresult = explode(' ', stristr(str_replace(';', '; ', self::$userAgentString), 'MSN')); 219 | self::$browser->setName(Browser::MSN); 220 | if (isset($aresult[1])) { 221 | self::$browser->setVersion(str_replace(array('(', ')', ';'), '', $aresult[1])); 222 | } 223 | 224 | return true; 225 | } 226 | $aresult = explode(' ', stristr(str_replace(';', '; ', self::$userAgentString), 'msie')); 227 | self::$browser->setName(Browser::IE); 228 | if (isset($aresult[1])) { 229 | self::$browser->setVersion(str_replace(array('(', ')', ';'), '', $aresult[1])); 230 | } 231 | // See https://msdn.microsoft.com/en-us/library/ie/hh869301%28v=vs.85%29.aspx 232 | // Might be 11, anyway ! 233 | if (stripos(self::$userAgentString, 'trident') !== false) { 234 | preg_match('/rv:(\d+\.\d+)/', self::$userAgentString, $matches); 235 | if (isset($matches[1])) { 236 | self::$browser->setVersion($matches[1]); 237 | } 238 | 239 | // At this poing in the method, we know the MSIE and Trident 240 | // strings are present in the $userAgentString. If we're in 241 | // compatibility mode, we need to determine the true version. 242 | // If the MSIE version is 7.0, we can look at the Trident 243 | // version to *approximate* the true IE version. If we don't 244 | // find a matching pair, ( e.g. MSIE 7.0 && Trident/7.0 ) 245 | // we're *not* in compatibility mode and the browser really 246 | // is version 7.0. 247 | if (stripos(self::$userAgentString, 'MSIE 7.0;')) { 248 | if (stripos(self::$userAgentString, 'Trident/7.0;')) { 249 | // IE11 in compatibility mode 250 | self::$browser->setVersion('11.0'); 251 | self::$browser->setIsCompatibilityMode(true); 252 | } elseif (stripos(self::$userAgentString, 'Trident/6.0;')) { 253 | // IE10 in compatibility mode 254 | self::$browser->setVersion('10.0'); 255 | self::$browser->setIsCompatibilityMode(true); 256 | } elseif (stripos(self::$userAgentString, 'Trident/5.0;')) { 257 | // IE9 in compatibility mode 258 | self::$browser->setVersion('9.0'); 259 | self::$browser->setIsCompatibilityMode(true); 260 | } elseif (stripos(self::$userAgentString, 'Trident/4.0;')) { 261 | // IE8 in compatibility mode 262 | self::$browser->setVersion('8.0'); 263 | self::$browser->setIsCompatibilityMode(true); 264 | } 265 | } 266 | } 267 | 268 | return true; 269 | } // Test for versions >= 11 270 | else { 271 | if (stripos(self::$userAgentString, 'trident') !== false) { 272 | self::$browser->setName(Browser::IE); 273 | 274 | preg_match('/rv:(\d+\.\d+)/', self::$userAgentString, $matches); 275 | if (isset($matches[1])) { 276 | self::$browser->setVersion($matches[1]); 277 | 278 | return true; 279 | } else { 280 | return false; 281 | } 282 | } // Test for Pocket IE 283 | else { 284 | if (stripos(self::$userAgentString, 'mspie') !== false || 285 | stripos( 286 | self::$userAgentString, 287 | 'pocket' 288 | ) !== false 289 | ) { 290 | $aresult = explode(' ', stristr(self::$userAgentString, 'mspie')); 291 | self::$browser->setName(Browser::POCKET_IE); 292 | 293 | if (stripos(self::$userAgentString, 'mspie') !== false) { 294 | if (isset($aresult[1])) { 295 | self::$browser->setVersion($aresult[1]); 296 | } 297 | } else { 298 | $aversion = explode('/', self::$userAgentString); 299 | if (isset($aversion[1])) { 300 | self::$browser->setVersion($aversion[1]); 301 | } 302 | } 303 | 304 | return true; 305 | } 306 | } 307 | } 308 | } 309 | 310 | return false; 311 | } 312 | 313 | /** 314 | * Determine if the browser is Opera. 315 | * 316 | * @return bool 317 | */ 318 | public static function checkBrowserOpera() 319 | { 320 | if (stripos(self::$userAgentString, 'opera mini') !== false) { 321 | $resultant = stristr(self::$userAgentString, 'opera mini'); 322 | if (preg_match('/\//', $resultant)) { 323 | $aresult = explode('/', $resultant); 324 | if (isset($aresult[1])) { 325 | $aversion = explode(' ', $aresult[1]); 326 | self::$browser->setVersion($aversion[0]); 327 | } 328 | } else { 329 | $aversion = explode(' ', stristr($resultant, 'opera mini')); 330 | if (isset($aversion[1])) { 331 | self::$browser->setVersion($aversion[1]); 332 | } 333 | } 334 | self::$browser->setName(Browser::OPERA_MINI); 335 | 336 | return true; 337 | } elseif (stripos(self::$userAgentString, 'OPiOS') !== false) { 338 | $aresult = explode('/', stristr(self::$userAgentString, 'OPiOS')); 339 | if (isset($aresult[1])) { 340 | $aversion = explode(' ', $aresult[1]); 341 | self::$browser->setVersion($aversion[0]); 342 | } 343 | self::$browser->setName(Browser::OPERA_MINI); 344 | 345 | return true; 346 | } elseif (stripos(self::$userAgentString, 'opera') !== false) { 347 | $resultant = stristr(self::$userAgentString, 'opera'); 348 | if (preg_match('/Version\/(1[0-2].*)$/', $resultant, $matches)) { 349 | if (isset($matches[1])) { 350 | self::$browser->setVersion($matches[1]); 351 | } 352 | } elseif (preg_match('/\//', $resultant)) { 353 | $aresult = explode('/', str_replace('(', ' ', $resultant)); 354 | if (isset($aresult[1])) { 355 | $aversion = explode(' ', $aresult[1]); 356 | self::$browser->setVersion($aversion[0]); 357 | } 358 | } else { 359 | $aversion = explode(' ', stristr($resultant, 'opera')); 360 | self::$browser->setVersion(isset($aversion[1]) ? $aversion[1] : ''); 361 | } 362 | self::$browser->setName(Browser::OPERA); 363 | 364 | return true; 365 | } elseif (stripos(self::$userAgentString, ' OPR/') !== false) { 366 | self::$browser->setName(Browser::OPERA); 367 | if (preg_match('/OPR\/([\d\.]*)/', self::$userAgentString, $matches)) { 368 | if (isset($matches[1])) { 369 | self::$browser->setVersion($matches[1]); 370 | } 371 | } 372 | 373 | return true; 374 | } 375 | 376 | return false; 377 | } 378 | 379 | /** 380 | * Determine if the browser is Samsung. 381 | * 382 | * @return bool 383 | */ 384 | public static function checkBrowserSamsung() 385 | { 386 | if (stripos(self::$userAgentString, 'SamsungBrowser') !== false) { 387 | $aresult = explode('/', stristr(self::$userAgentString, 'SamsungBrowser')); 388 | if (isset($aresult[1])) { 389 | $aversion = explode(' ', $aresult[1]); 390 | self::$browser->setVersion($aversion[0]); 391 | } 392 | self::$browser->setName(Browser::SAMSUNG_BROWSER); 393 | 394 | return true; 395 | } 396 | 397 | return false; 398 | } 399 | 400 | /** 401 | * Determine if the browser is Chrome. 402 | * 403 | * @return bool 404 | */ 405 | public static function checkBrowserChrome() 406 | { 407 | if (stripos(self::$userAgentString, 'Chrome') !== false) { 408 | $aresult = explode('/', stristr(self::$userAgentString, 'Chrome')); 409 | if (isset($aresult[1])) { 410 | $aversion = explode(' ', $aresult[1]); 411 | self::$browser->setVersion($aversion[0]); 412 | } 413 | self::$browser->setName(Browser::CHROME); 414 | 415 | return true; 416 | } elseif (stripos(self::$userAgentString, 'CriOS') !== false) { 417 | $aresult = explode('/', stristr(self::$userAgentString, 'CriOS')); 418 | if (isset($aresult[1])) { 419 | $aversion = explode(' ', $aresult[1]); 420 | self::$browser->setVersion($aversion[0]); 421 | } 422 | self::$browser->setName(Browser::CHROME); 423 | 424 | return true; 425 | } 426 | 427 | return false; 428 | } 429 | 430 | /** 431 | * Determine if the browser is Vivaldi. 432 | * 433 | * @return bool 434 | */ 435 | public static function checkBrowserVivaldi() 436 | { 437 | if (stripos(self::$userAgentString, 'Vivaldi') !== false) { 438 | $aresult = explode('/', stristr(self::$userAgentString, 'Vivaldi')); 439 | if (isset($aresult[1])) { 440 | $aversion = explode(' ', $aresult[1]); 441 | self::$browser->setVersion($aversion[0]); 442 | } 443 | self::$browser->setName(Browser::VIVALDI); 444 | 445 | return true; 446 | } 447 | 448 | return false; 449 | } 450 | 451 | /** 452 | * Determine if the browser is Microsoft Edge. 453 | * 454 | * @return bool 455 | */ 456 | public static function checkBrowserEdge() 457 | { 458 | if (stripos(self::$userAgentString, 'Edge') !== false) { 459 | $version = explode('Edge/', self::$userAgentString); 460 | if (isset($version[1])) { 461 | self::$browser->setVersion((float)$version[1]); 462 | } 463 | self::$browser->setName(Browser::EDGE); 464 | 465 | return true; 466 | } elseif (stripos(self::$userAgentString, 'Edg') !== false) { 467 | $version = explode('Edg/', self::$userAgentString); 468 | if (isset($version[1])) { 469 | self::$browser->setVersion(trim($version[1])); 470 | } 471 | self::$browser->setName(Browser::EDGE); 472 | 473 | return true; 474 | } 475 | 476 | return false; 477 | } 478 | 479 | /** 480 | * Determine if the browser is Google Search Appliance. 481 | * 482 | * @return bool 483 | */ 484 | public static function checkBrowserGsa() 485 | { 486 | if (stripos(self::$userAgentString, 'GSA') !== false) { 487 | $aresult = explode('/', stristr(self::$userAgentString, 'GSA')); 488 | if (isset($aresult[1])) { 489 | $aversion = explode(' ', $aresult[1]); 490 | self::$browser->setVersion($aversion[0]); 491 | } 492 | self::$browser->setName(Browser::GSA); 493 | 494 | return true; 495 | } 496 | 497 | return false; 498 | } 499 | 500 | /** 501 | * Determine if the browser is WebTv. 502 | * 503 | * @return bool 504 | */ 505 | public static function checkBrowserWebTv() 506 | { 507 | if (stripos(self::$userAgentString, 'webtv') !== false) { 508 | $aresult = explode('/', stristr(self::$userAgentString, 'webtv')); 509 | if (isset($aresult[1])) { 510 | $aversion = explode(' ', $aresult[1]); 511 | self::$browser->setVersion($aversion[0]); 512 | } 513 | self::$browser->setName(Browser::WEBTV); 514 | 515 | return true; 516 | } 517 | 518 | return false; 519 | } 520 | 521 | /** 522 | * Determine if the browser is NetPositive. 523 | * 524 | * @return bool 525 | */ 526 | public static function checkBrowserNetPositive() 527 | { 528 | if (stripos(self::$userAgentString, 'NetPositive') !== false) { 529 | $aresult = explode('/', stristr(self::$userAgentString, 'NetPositive')); 530 | if (isset($aresult[1])) { 531 | $aversion = explode(' ', $aresult[1]); 532 | self::$browser->setVersion(str_replace(array('(', ')', ';'), '', $aversion[0])); 533 | } 534 | self::$browser->setName(Browser::NETPOSITIVE); 535 | 536 | return true; 537 | } 538 | 539 | return false; 540 | } 541 | 542 | /** 543 | * Determine if the browser is Galeon. 544 | * 545 | * @return bool 546 | */ 547 | public static function checkBrowserGaleon() 548 | { 549 | if (stripos(self::$userAgentString, 'galeon') !== false) { 550 | $aresult = explode(' ', stristr(self::$userAgentString, 'galeon')); 551 | $aversion = explode('/', $aresult[0]); 552 | if (isset($aversion[1])) { 553 | self::$browser->setVersion($aversion[1]); 554 | } 555 | self::$browser->setName(Browser::GALEON); 556 | 557 | return true; 558 | } 559 | 560 | return false; 561 | } 562 | 563 | /** 564 | * Determine if the browser is Konqueror. 565 | * 566 | * @return bool 567 | */ 568 | public static function checkBrowserKonqueror() 569 | { 570 | if (stripos(self::$userAgentString, 'Konqueror') !== false) { 571 | $aresult = explode(' ', stristr(self::$userAgentString, 'Konqueror')); 572 | $aversion = explode('/', $aresult[0]); 573 | if (isset($aversion[1])) { 574 | self::$browser->setVersion($aversion[1]); 575 | } 576 | self::$browser->setName(Browser::KONQUEROR); 577 | 578 | return true; 579 | } 580 | 581 | return false; 582 | } 583 | 584 | /** 585 | * Determine if the browser is iCab. 586 | * 587 | * @return bool 588 | */ 589 | public static function checkBrowserIcab() 590 | { 591 | if (stripos(self::$userAgentString, 'icab') !== false) { 592 | $aversion = explode(' ', stristr(str_replace('/', ' ', self::$userAgentString), 'icab')); 593 | if (isset($aversion[1])) { 594 | self::$browser->setVersion($aversion[1]); 595 | } 596 | self::$browser->setName(Browser::ICAB); 597 | 598 | return true; 599 | } 600 | 601 | return false; 602 | } 603 | 604 | /** 605 | * Determine if the browser is OmniWeb. 606 | * 607 | * @return bool 608 | */ 609 | public static function checkBrowserOmniWeb() 610 | { 611 | if (stripos(self::$userAgentString, 'omniweb') !== false) { 612 | $aresult = explode('/', stristr(self::$userAgentString, 'omniweb')); 613 | $aversion = explode(' ', isset($aresult[1]) ? $aresult[1] : ''); 614 | self::$browser->setVersion($aversion[0]); 615 | self::$browser->setName(Browser::OMNIWEB); 616 | 617 | return true; 618 | } 619 | 620 | return false; 621 | } 622 | 623 | /** 624 | * Determine if the browser is Phoenix. 625 | * 626 | * @return bool 627 | */ 628 | public static function checkBrowserPhoenix() 629 | { 630 | if (stripos(self::$userAgentString, 'Phoenix') !== false) { 631 | $aversion = explode('/', stristr(self::$userAgentString, 'Phoenix')); 632 | if (isset($aversion[1])) { 633 | self::$browser->setVersion($aversion[1]); 634 | } 635 | self::$browser->setName(Browser::PHOENIX); 636 | 637 | return true; 638 | } 639 | 640 | return false; 641 | } 642 | 643 | /** 644 | * Determine if the browser is Firebird. 645 | * 646 | * @return bool 647 | */ 648 | public static function checkBrowserFirebird() 649 | { 650 | if (stripos(self::$userAgentString, 'Firebird') !== false) { 651 | $aversion = explode('/', stristr(self::$userAgentString, 'Firebird')); 652 | if (isset($aversion[1])) { 653 | self::$browser->setVersion($aversion[1]); 654 | } 655 | self::$browser->setName(Browser::FIREBIRD); 656 | 657 | return true; 658 | } 659 | 660 | return false; 661 | } 662 | 663 | /** 664 | * Determine if the browser is Netscape Navigator 9+. 665 | * 666 | * @return bool 667 | */ 668 | public static function checkBrowserNetscapeNavigator9Plus() 669 | { 670 | if (stripos(self::$userAgentString, 'Firefox') !== false && 671 | preg_match('/Navigator\/([^ ]*)/i', self::$userAgentString, $matches) 672 | ) { 673 | if (isset($matches[1])) { 674 | self::$browser->setVersion($matches[1]); 675 | } 676 | self::$browser->setName(Browser::NETSCAPE_NAVIGATOR); 677 | 678 | return true; 679 | } elseif (stripos(self::$userAgentString, 'Firefox') === false && 680 | preg_match('/Netscape6?\/([^ ]*)/i', self::$userAgentString, $matches) 681 | ) { 682 | if (isset($matches[1])) { 683 | self::$browser->setVersion($matches[1]); 684 | } 685 | self::$browser->setName(Browser::NETSCAPE_NAVIGATOR); 686 | 687 | return true; 688 | } 689 | 690 | return false; 691 | } 692 | 693 | /** 694 | * Determine if the browser is Shiretoko. 695 | * 696 | * @return bool 697 | */ 698 | public static function checkBrowserShiretoko() 699 | { 700 | if (stripos(self::$userAgentString, 'Mozilla') !== false && 701 | preg_match('/Shiretoko\/([^ ]*)/i', self::$userAgentString, $matches) 702 | ) { 703 | if (isset($matches[1])) { 704 | self::$browser->setVersion($matches[1]); 705 | } 706 | self::$browser->setName(Browser::SHIRETOKO); 707 | 708 | return true; 709 | } 710 | 711 | return false; 712 | } 713 | 714 | /** 715 | * Determine if the browser is Ice Cat. 716 | * 717 | * @return bool 718 | */ 719 | public static function checkBrowserIceCat() 720 | { 721 | if (stripos(self::$userAgentString, 'Mozilla') !== false && 722 | preg_match('/IceCat\/([^ ]*)/i', self::$userAgentString, $matches) 723 | ) { 724 | if (isset($matches[1])) { 725 | self::$browser->setVersion($matches[1]); 726 | } 727 | self::$browser->setName(Browser::ICECAT); 728 | 729 | return true; 730 | } 731 | 732 | return false; 733 | } 734 | 735 | /** 736 | * Determine if the browser is Nokia. 737 | * 738 | * @return bool 739 | */ 740 | public static function checkBrowserNokia() 741 | { 742 | if (preg_match("/Nokia([^\/]+)\/([^ SP]+)/i", self::$userAgentString, $matches)) { 743 | self::$browser->setVersion($matches[2]); 744 | if (stripos(self::$userAgentString, 'Series60') !== false || 745 | strpos(self::$userAgentString, 'S60') !== false 746 | ) { 747 | self::$browser->setName(Browser::NOKIA_S60); 748 | } else { 749 | self::$browser->setName(Browser::NOKIA); 750 | } 751 | 752 | return true; 753 | } 754 | 755 | return false; 756 | } 757 | 758 | /** 759 | * Determine if the browser is Firefox. 760 | * 761 | * @return bool 762 | */ 763 | public static function checkBrowserFirefox() 764 | { 765 | if (stripos(self::$userAgentString, 'safari') === false) { 766 | if (preg_match("/Firefox[\/ \(]([^ ;\)]+)/i", self::$userAgentString, $matches)) { 767 | if (isset($matches[1])) { 768 | self::$browser->setVersion($matches[1]); 769 | } 770 | self::$browser->setName(Browser::FIREFOX); 771 | 772 | return true; 773 | } elseif (preg_match('/Firefox$/i', self::$userAgentString, $matches)) { 774 | self::$browser->setVersion(''); 775 | self::$browser->setName(Browser::FIREFOX); 776 | 777 | return true; 778 | } 779 | } 780 | 781 | return false; 782 | } 783 | 784 | /** 785 | * Determine if the browser is SeaMonkey. 786 | * 787 | * @return bool 788 | */ 789 | public static function checkBrowserSeaMonkey() 790 | { 791 | if (stripos(self::$userAgentString, 'safari') === false) { 792 | if (preg_match("/SeaMonkey[\/ \(]([^ ;\)]+)/i", self::$userAgentString, $matches)) { 793 | if (isset($matches[1])) { 794 | self::$browser->setVersion($matches[1]); 795 | } 796 | self::$browser->setName(Browser::SEAMONKEY); 797 | 798 | return true; 799 | } elseif (preg_match('/SeaMonkey$/i', self::$userAgentString, $matches)) { 800 | self::$browser->setVersion(''); 801 | self::$browser->setName(Browser::SEAMONKEY); 802 | 803 | return true; 804 | } 805 | } 806 | 807 | return false; 808 | } 809 | 810 | /** 811 | * Determine if the browser is Iceweasel. 812 | * 813 | * @return bool 814 | */ 815 | public static function checkBrowserIceweasel() 816 | { 817 | if (stripos(self::$userAgentString, 'Iceweasel') !== false) { 818 | $aresult = explode('/', stristr(self::$userAgentString, 'Iceweasel')); 819 | if (isset($aresult[1])) { 820 | $aversion = explode(' ', $aresult[1]); 821 | self::$browser->setVersion($aversion[0]); 822 | } 823 | self::$browser->setName(Browser::ICEWEASEL); 824 | 825 | return true; 826 | } 827 | 828 | return false; 829 | } 830 | 831 | /** 832 | * Determine if the browser is Mozilla. 833 | * 834 | * @return bool 835 | */ 836 | public static function checkBrowserMozilla() 837 | { 838 | if (stripos(self::$userAgentString, 'mozilla') !== false && 839 | preg_match('/rv:[0-9].[0-9][a-b]?/i', self::$userAgentString) && 840 | stripos(self::$userAgentString, 'netscape') === false 841 | ) { 842 | $aversion = explode(' ', stristr(self::$userAgentString, 'rv:')); 843 | preg_match('/rv:[0-9].[0-9][a-b]?/i', self::$userAgentString, $aversion); 844 | self::$browser->setVersion(str_replace('rv:', '', $aversion[0])); 845 | self::$browser->setName(Browser::MOZILLA); 846 | 847 | return true; 848 | } elseif (stripos(self::$userAgentString, 'mozilla') !== false && 849 | preg_match('/rv:[0-9]\.[0-9]/i', self::$userAgentString) && 850 | stripos(self::$userAgentString, 'netscape') === false 851 | ) { 852 | $aversion = explode('', stristr(self::$userAgentString, 'rv:')); 853 | self::$browser->setVersion(str_replace('rv:', '', $aversion[0])); 854 | self::$browser->setName(Browser::MOZILLA); 855 | 856 | return true; 857 | } elseif (stripos(self::$userAgentString, 'mozilla') !== false && 858 | preg_match('/mozilla\/([^ ]*)/i', self::$userAgentString, $matches) && 859 | stripos(self::$userAgentString, 'netscape') === false 860 | ) { 861 | if (isset($matches[1])) { 862 | self::$browser->setVersion($matches[1]); 863 | } 864 | self::$browser->setName(Browser::MOZILLA); 865 | 866 | return true; 867 | } 868 | 869 | return false; 870 | } 871 | 872 | /** 873 | * Determine if the browser is Lynx. 874 | * 875 | * @return bool 876 | */ 877 | public static function checkBrowserLynx() 878 | { 879 | if (stripos(self::$userAgentString, 'lynx') !== false) { 880 | $aresult = explode('/', stristr(self::$userAgentString, 'Lynx')); 881 | $aversion = explode(' ', (isset($aresult[1]) ? $aresult[1] : '')); 882 | self::$browser->setVersion($aversion[0]); 883 | self::$browser->setName(Browser::LYNX); 884 | 885 | return true; 886 | } 887 | 888 | return false; 889 | } 890 | 891 | /** 892 | * Determine if the browser is Amaya. 893 | * 894 | * @return bool 895 | */ 896 | public static function checkBrowserAmaya() 897 | { 898 | if (stripos(self::$userAgentString, 'amaya') !== false) { 899 | $aresult = explode('/', stristr(self::$userAgentString, 'Amaya')); 900 | if (isset($aresult[1])) { 901 | $aversion = explode(' ', $aresult[1]); 902 | self::$browser->setVersion($aversion[0]); 903 | } 904 | self::$browser->setName(Browser::AMAYA); 905 | 906 | return true; 907 | } 908 | 909 | return false; 910 | } 911 | 912 | /** 913 | * Determine if the browser is Safari. 914 | * 915 | * @return bool 916 | */ 917 | public static function checkBrowserWkhtmltopdf() 918 | { 919 | if (stripos(self::$userAgentString, 'wkhtmltopdf') !== false) { 920 | self::$browser->setName(Browser::WKHTMLTOPDF); 921 | return true; 922 | } 923 | 924 | return false; 925 | } 926 | /** 927 | * Determine if the browser is Safari. 928 | * 929 | * @return bool 930 | */ 931 | public static function checkBrowserSafari() 932 | { 933 | if (stripos(self::$userAgentString, 'Safari') !== false) { 934 | $aresult = explode('/', stristr(self::$userAgentString, 'Version')); 935 | if (isset($aresult[1])) { 936 | $aversion = explode(' ', $aresult[1]); 937 | self::$browser->setVersion($aversion[0]); 938 | } else { 939 | self::$browser->setVersion(Browser::VERSION_UNKNOWN); 940 | } 941 | self::$browser->setName(Browser::SAFARI); 942 | 943 | return true; 944 | } 945 | 946 | return false; 947 | } 948 | 949 | /** 950 | * Determine if the browser is Yandex. 951 | * 952 | * @return bool 953 | */ 954 | public static function checkBrowserYandex() 955 | { 956 | if (stripos(self::$userAgentString, 'YaBrowser') !== false) { 957 | $aresult = explode('/', stristr(self::$userAgentString, 'YaBrowser')); 958 | if (isset($aresult[1])) { 959 | $aversion = explode(' ', $aresult[1]); 960 | self::$browser->setVersion($aversion[0]); 961 | } 962 | self::$browser->setName(Browser::YANDEX); 963 | 964 | return true; 965 | } 966 | 967 | return false; 968 | } 969 | 970 | /** 971 | * Determine if the browser is Comodo Dragon / Ice Dragon / Chromodo. 972 | * 973 | * @return bool 974 | */ 975 | public static function checkBrowserDragon() 976 | { 977 | if (stripos(self::$userAgentString, 'Dragon') !== false) { 978 | $aresult = explode('/', stristr(self::$userAgentString, 'Dragon')); 979 | if (isset($aresult[1])) { 980 | $aversion = explode(' ', $aresult[1]); 981 | self::$browser->setVersion($aversion[0]); 982 | } 983 | self::$browser->setName(Browser::DRAGON); 984 | 985 | return true; 986 | } 987 | 988 | return false; 989 | } 990 | 991 | /** 992 | * Determine if the browser is Android. 993 | * 994 | * @return bool 995 | */ 996 | public static function checkBrowserAndroid() 997 | { 998 | // Navigator 999 | if (stripos(self::$userAgentString, 'Android') !== false) { 1000 | if (preg_match('/Version\/([\d\.]*)/i', self::$userAgentString, $matches)) { 1001 | if (isset($matches[1])) { 1002 | self::$browser->setVersion($matches[1]); 1003 | } 1004 | } else { 1005 | self::$browser->setVersion(Browser::VERSION_UNKNOWN); 1006 | } 1007 | self::$browser->setName(Browser::NAVIGATOR); 1008 | 1009 | return true; 1010 | } 1011 | 1012 | return false; 1013 | } 1014 | } 1015 | -------------------------------------------------------------------------------- /src/DetectorInterface.php: -------------------------------------------------------------------------------- 1 | setUserAgent($userAgent); 32 | } elseif (null === $userAgent || is_string($userAgent)) { 33 | $this->setUserAgent(new UserAgent($userAgent)); 34 | } else { 35 | throw new InvalidArgumentException(); 36 | } 37 | } 38 | 39 | /** 40 | * @param UserAgent $userAgent 41 | * 42 | * @return $this 43 | */ 44 | public function setUserAgent(UserAgent $userAgent) 45 | { 46 | $this->userAgent = $userAgent; 47 | 48 | return $this; 49 | } 50 | 51 | /** 52 | * @return UserAgent 53 | */ 54 | public function getUserAgent() 55 | { 56 | return $this->userAgent; 57 | } 58 | 59 | /** 60 | * @return string 61 | */ 62 | public function getName() 63 | { 64 | if (!isset($this->name)) { 65 | DeviceDetector::detect($this, $this->getUserAgent()); 66 | } 67 | 68 | return $this->name; 69 | } 70 | 71 | /** 72 | * @param string $name 73 | * 74 | * @return $this 75 | */ 76 | public function setName($name) 77 | { 78 | $this->name = (string)$name; 79 | 80 | return $this; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/DeviceDetector.php: -------------------------------------------------------------------------------- 1 | setName($device::UNKNOWN); 17 | 18 | return ( 19 | self::checkIpad($device, $userAgent) || 20 | self::checkIphone($device, $userAgent) || 21 | self::checkWindowsPhone($device, $userAgent) || 22 | self::checkSamsungPhone($device, $userAgent) 23 | ); 24 | } 25 | 26 | /** 27 | * Determine if the device is iPad. 28 | * 29 | * @param Device $device 30 | * @param UserAgent $userAgent 31 | * @return bool 32 | */ 33 | private static function checkIpad(Device $device, UserAgent $userAgent) 34 | { 35 | if (stripos($userAgent->getUserAgentString(), 'ipad') !== false) { 36 | $device->setName(Device::IPAD); 37 | return true; 38 | } 39 | 40 | return false; 41 | } 42 | 43 | /** 44 | * Determine if the device is iPhone. 45 | * 46 | * @param Device $device 47 | * @param UserAgent $userAgent 48 | * @return bool 49 | */ 50 | private static function checkIphone(Device $device, UserAgent $userAgent) 51 | { 52 | if (stripos($userAgent->getUserAgentString(), 'iphone;') !== false) { 53 | $device->setName(Device::IPHONE); 54 | return true; 55 | } 56 | 57 | return false; 58 | } 59 | 60 | /** 61 | * Determine if the device is Windows Phone. 62 | * 63 | * @param Device $device 64 | * @param UserAgent $userAgent 65 | * @return bool 66 | */ 67 | private static function checkWindowsPhone(Device $device, UserAgent $userAgent) 68 | { 69 | if (stripos($userAgent->getUserAgentString(), 'Windows Phone') !== false) { 70 | if (preg_match('/Microsoft; (Lumia [^)]*)\)/', $userAgent->getUserAgentString(), $matches)) { 71 | $device->setName($matches[1]); 72 | return true; 73 | } 74 | 75 | $device->setName($device::WINDOWS_PHONE); 76 | return true; 77 | } 78 | return false; 79 | } 80 | 81 | /** 82 | * Determine if the device is Windows Phone. 83 | * 84 | * @param Device $device 85 | * @param UserAgent $userAgent 86 | * @return bool 87 | */ 88 | private static function checkSamsungPhone(Device $device, UserAgent $userAgent) 89 | { 90 | if (preg_match('/SAMSUNG SM-([^ ]*)/i', $userAgent->getUserAgentString(), $matches)) { 91 | $device->setName(str_ireplace('SAMSUNG', 'Samsung', $matches[0])); 92 | return true; 93 | } 94 | return false; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | setAcceptLanguage($acceptLanguage); 29 | } elseif (null === $acceptLanguage || is_string($acceptLanguage)) { 30 | $this->setAcceptLanguage(new AcceptLanguage($acceptLanguage)); 31 | } else { 32 | throw new InvalidArgumentException(); 33 | } 34 | } 35 | 36 | /** 37 | * Get all user's languages. 38 | * 39 | * @return array 40 | */ 41 | public function getLanguages() 42 | { 43 | if (!is_array($this->languages)) { 44 | LanguageDetector::detect($this, $this->getAcceptLanguage()); 45 | } 46 | 47 | return $this->languages; 48 | } 49 | 50 | /** 51 | * Set languages. 52 | * 53 | * @param array $languages 54 | * 55 | * @return $this 56 | */ 57 | public function setLanguages($languages) 58 | { 59 | $this->languages = $languages; 60 | 61 | return $this; 62 | } 63 | 64 | /** 65 | * Get a user's language. 66 | * 67 | * @return string 68 | */ 69 | public function getLanguage() 70 | { 71 | if (!is_array($this->languages)) { 72 | LanguageDetector::detect($this, $this->getAcceptLanguage()); 73 | } 74 | 75 | return strtolower(substr(reset($this->languages), 0, 2)); 76 | } 77 | 78 | /** 79 | * Get a user's language and locale. 80 | * 81 | * @param string $separator 82 | * 83 | * @return string 84 | */ 85 | public function getLanguageLocale($separator = '-') 86 | { 87 | if (!is_array($this->languages)) { 88 | LanguageDetector::detect($this, $this->getAcceptLanguage()); 89 | } 90 | 91 | $userLanguage = $this->getLanguage(); 92 | foreach ($this->languages as $language) { 93 | if (strlen($language) === 5 && strpos($language, $userLanguage) === 0) { 94 | $locale = substr($language, -2); 95 | break; 96 | } 97 | } 98 | 99 | if (!empty($locale)) { 100 | return $userLanguage . $separator . strtoupper($locale); 101 | } else { 102 | return $userLanguage; 103 | } 104 | } 105 | 106 | /** 107 | * @param AcceptLanguage $acceptLanguage 108 | * 109 | * @return $this 110 | */ 111 | public function setAcceptLanguage(AcceptLanguage $acceptLanguage) 112 | { 113 | $this->acceptLanguage = $acceptLanguage; 114 | 115 | return $this; 116 | } 117 | 118 | /** 119 | * @return AcceptLanguage 120 | */ 121 | public function getAcceptLanguage() 122 | { 123 | return $this->acceptLanguage; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/LanguageDetector.php: -------------------------------------------------------------------------------- 1 | getAcceptLanguageString(); 21 | $languages = array(); 22 | $language->setLanguages($languages); 23 | 24 | if (!empty($acceptLanguageString)) { 25 | // Split by ranges (en-US,en;q=0.8) and keep priority value (0.8) 26 | $httpLanguages = preg_split( 27 | '/q=([\d\.]*)/', 28 | $acceptLanguageString, 29 | -1, 30 | PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE 31 | ); 32 | 33 | // Group by priority 34 | $key = 0; 35 | foreach (array_reverse($httpLanguages) as $value) { 36 | $value = trim($value, ',; .'); 37 | if (is_numeric($value)) { 38 | $key = $value; 39 | } elseif ($value) { 40 | $languages[$key] = preg_split('/[^\w-]+/', $value); 41 | } 42 | } 43 | 44 | // Sort by priority 45 | krsort($languages); 46 | 47 | // Flatten array and remove duplicates 48 | $result = []; 49 | foreach ($languages as $values) { 50 | foreach ($values as $value) { 51 | $result[$value] = true; 52 | } 53 | } 54 | 55 | $language->setLanguages(array_keys($result)); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Os.php: -------------------------------------------------------------------------------- 1 | setUserAgent($userAgent); 60 | } elseif (null === $userAgent || is_string($userAgent)) { 61 | $this->setUserAgent(new UserAgent($userAgent)); 62 | } else { 63 | throw new InvalidArgumentException(); 64 | } 65 | } 66 | 67 | /** 68 | * Return the name of the OS. 69 | * 70 | * @return string 71 | */ 72 | public function getName() 73 | { 74 | if (!isset($this->name)) { 75 | OsDetector::detect($this, $this->getUserAgent()); 76 | } 77 | 78 | return $this->name; 79 | } 80 | 81 | /** 82 | * Set the name of the OS. 83 | * 84 | * @param string $name 85 | * 86 | * @return $this 87 | */ 88 | public function setName($name) 89 | { 90 | $this->name = (string)$name; 91 | 92 | return $this; 93 | } 94 | 95 | /** 96 | * Return the version of the OS. 97 | * 98 | * @return string 99 | */ 100 | public function getVersion() 101 | { 102 | if (isset($this->version)) { 103 | return (string)$this->version; 104 | } else { 105 | OsDetector::detect($this, $this->getUserAgent()); 106 | 107 | return (string)$this->version; 108 | } 109 | } 110 | 111 | /** 112 | * Set the version of the OS. 113 | * 114 | * @param string $version 115 | * 116 | * @return $this 117 | */ 118 | public function setVersion($version) 119 | { 120 | $this->version = (string)$version; 121 | 122 | return $this; 123 | } 124 | 125 | /** 126 | * Is the browser from a mobile device? 127 | * 128 | * @return bool 129 | */ 130 | public function getIsMobile() 131 | { 132 | if (!isset($this->name)) { 133 | OsDetector::detect($this, $this->getUserAgent()); 134 | } 135 | 136 | return $this->isMobile; 137 | } 138 | 139 | /** 140 | * @return bool 141 | */ 142 | public function isMobile() 143 | { 144 | return $this->getIsMobile(); 145 | } 146 | 147 | /** 148 | * Set the Browser to be mobile. 149 | * 150 | * @param bool $isMobile 151 | */ 152 | public function setIsMobile($isMobile = true) 153 | { 154 | $this->isMobile = (bool)$isMobile; 155 | } 156 | 157 | /** 158 | * @param UserAgent $userAgent 159 | * 160 | * @return $this 161 | */ 162 | public function setUserAgent(UserAgent $userAgent) 163 | { 164 | $this->userAgent = $userAgent; 165 | 166 | return $this; 167 | } 168 | 169 | /** 170 | * @return UserAgent 171 | */ 172 | public function getUserAgent() 173 | { 174 | return $this->userAgent; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/OsDetector.php: -------------------------------------------------------------------------------- 1 | setName($os::UNKNOWN); 18 | $os->setVersion($os::VERSION_UNKNOWN); 19 | $os->setIsMobile(false); 20 | 21 | self::checkMobileBrowsers($os, $userAgent); 22 | 23 | return ( 24 | // Chrome OS before OS X 25 | self::checkChromeOs($os, $userAgent) || 26 | // iOS before OS X 27 | self::checkIOS($os, $userAgent) || 28 | self::checkOSX($os, $userAgent) || 29 | self::checkSymbOS($os, $userAgent) || 30 | self::checkWindows($os, $userAgent) || 31 | self::checkWindowsPhone($os, $userAgent) || 32 | self::checkFreeBSD($os, $userAgent) || 33 | self::checkOpenBSD($os, $userAgent) || 34 | self::checkNetBSD($os, $userAgent) || 35 | self::checkOpenSolaris($os, $userAgent) || 36 | self::checkSunOS($os, $userAgent) || 37 | self::checkOS2($os, $userAgent) || 38 | self::checkBeOS($os, $userAgent) || 39 | // Android before Linux 40 | self::checkAndroid($os, $userAgent) || 41 | self::checkLinux($os, $userAgent) || 42 | self::checkNokia($os, $userAgent) || 43 | self::checkBlackBerry($os, $userAgent) 44 | ); 45 | } 46 | 47 | /** 48 | * Determine if the user's browser is on a mobile device. 49 | * 50 | * @param Os $os 51 | * @param UserAgent $userAgent 52 | * 53 | * @return bool 54 | */ 55 | public static function checkMobileBrowsers(Os $os, UserAgent $userAgent) 56 | { 57 | // Check for Opera Mini 58 | if (stripos($userAgent->getUserAgentString(), 'opera mini') !== false) { 59 | $os->setIsMobile(true); 60 | } // Set is mobile for Pocket IE 61 | elseif (stripos($userAgent->getUserAgentString(), 'mspie') !== false || 62 | stripos($userAgent->getUserAgentString(), 'pocket') !== false) { 63 | $os->setIsMobile(true); 64 | } 65 | } 66 | 67 | /** 68 | * Determine if the user's operating system is iOS. 69 | * 70 | * @param Os $os 71 | * @param UserAgent $userAgent 72 | * 73 | * @return bool 74 | */ 75 | private static function checkIOS(Os $os, UserAgent $userAgent) 76 | { 77 | if (stripos($userAgent->getUserAgentString(), 'CPU OS') !== false || 78 | stripos($userAgent->getUserAgentString(), 'iPhone OS') !== false && 79 | stripos($userAgent->getUserAgentString(), 'OS X')) { 80 | $os->setName($os::IOS); 81 | if (preg_match('/CPU( iPhone)? OS ([\d_]*)/i', $userAgent->getUserAgentString(), $matches)) { 82 | $os->setVersion(str_replace('_', '.', $matches[2])); 83 | } 84 | $os->setIsMobile(true); 85 | 86 | return true; 87 | } 88 | 89 | return false; 90 | } 91 | 92 | /** 93 | * Determine if the user's operating system is Chrome OS. 94 | * 95 | * @param Os $os 96 | * @param UserAgent $userAgent 97 | * 98 | * @return bool 99 | */ 100 | private static function checkChromeOs(Os $os, UserAgent $userAgent) 101 | { 102 | if (stripos($userAgent->getUserAgentString(), ' CrOS') !== false || 103 | stripos($userAgent->getUserAgentString(), 'CrOS ') !== false 104 | ) { 105 | $os->setName($os::CHROME_OS); 106 | if (preg_match('/Chrome\/([\d\.]*)/i', $userAgent->getUserAgentString(), $matches)) { 107 | $os->setVersion($matches[1]); 108 | } 109 | return true; 110 | } 111 | 112 | return false; 113 | } 114 | 115 | /** 116 | * Determine if the user's operating system is OS X. 117 | * 118 | * @param Os $os 119 | * @param UserAgent $userAgent 120 | * 121 | * @return bool 122 | */ 123 | private static function checkOSX(Os $os, UserAgent $userAgent) 124 | { 125 | if (stripos($userAgent->getUserAgentString(), 'OS X') !== false) { 126 | $os->setName($os::OSX); 127 | if (preg_match('/OS X ([\d\._]*)/i', $userAgent->getUserAgentString(), $matches)) { 128 | if (isset($matches[1])) { 129 | $os->setVersion(str_replace('_', '.', $matches[1])); 130 | } 131 | } 132 | 133 | return true; 134 | } 135 | 136 | return false; 137 | } 138 | 139 | /** 140 | * Determine if the user's operating system is Windows. 141 | * 142 | * @param Os $os 143 | * @param UserAgent $userAgent 144 | * 145 | * @return bool 146 | */ 147 | private static function checkWindows(Os $os, UserAgent $userAgent) 148 | { 149 | if (stripos($userAgent->getUserAgentString(), 'Windows NT') !== false) { 150 | $os->setName($os::WINDOWS); 151 | // Windows version 152 | if (preg_match('/Windows NT ([\d\.]*)/i', $userAgent->getUserAgentString(), $matches)) { 153 | if (isset($matches[1])) { 154 | switch (str_replace('_', '.', $matches[1])) { 155 | case '6.3': 156 | $os->setVersion('8.1'); 157 | break; 158 | case '6.2': 159 | $os->setVersion('8'); 160 | break; 161 | case '6.1': 162 | $os->setVersion('7'); 163 | break; 164 | case '6.0': 165 | $os->setVersion('Vista'); 166 | break; 167 | case '5.2': 168 | case '5.1': 169 | $os->setVersion('XP'); 170 | break; 171 | case '5.01': 172 | case '5.0': 173 | $os->setVersion('2000'); 174 | break; 175 | case '4.0': 176 | $os->setVersion('NT 4.0'); 177 | break; 178 | default: 179 | if ((float)$matches[1] >= 10.0) { 180 | $os->setVersion($matches[1]); 181 | } 182 | break; 183 | } 184 | } 185 | } 186 | 187 | return true; 188 | } // Windows Me, Windows 98, Windows 95, Windows CE 189 | elseif (preg_match( 190 | '/(Windows 98; Win 9x 4\.90|Windows 98|Windows 95|Windows CE)/i', 191 | $userAgent->getUserAgentString(), 192 | $matches 193 | )) { 194 | $os->setName($os::WINDOWS); 195 | switch (strtolower($matches[0])) { 196 | case 'windows 98; win 9x 4.90': 197 | $os->setVersion('Me'); 198 | break; 199 | case 'windows 98': 200 | $os->setVersion('98'); 201 | break; 202 | case 'windows 95': 203 | $os->setVersion('95'); 204 | break; 205 | case 'windows ce': 206 | $os->setVersion('CE'); 207 | break; 208 | } 209 | 210 | return true; 211 | } 212 | 213 | return false; 214 | } 215 | 216 | /** 217 | * Determine if the user's operating system is Windows Phone. 218 | * 219 | * @param Os $os 220 | * @param UserAgent $userAgent 221 | * 222 | * @return bool 223 | */ 224 | private static function checkWindowsPhone(Os $os, UserAgent $userAgent) 225 | { 226 | if (stripos($userAgent->getUserAgentString(), 'Windows Phone') !== false) { 227 | $os->setIsMobile(true); 228 | $os->setName($os::WINDOWS_PHONE); 229 | // Windows version 230 | if (preg_match('/Windows Phone ([\d\.]*)/i', $userAgent->getUserAgentString(), $matches)) { 231 | if (isset($matches[1])) { 232 | $os->setVersion((float)$matches[1]); 233 | } 234 | } 235 | 236 | return true; 237 | } 238 | return false; 239 | } 240 | 241 | /** 242 | * Determine if the user's operating system is SymbOS. 243 | * 244 | * @param Os $os 245 | * @param UserAgent $userAgent 246 | * 247 | * @return bool 248 | */ 249 | private static function checkSymbOS(Os $os, UserAgent $userAgent) 250 | { 251 | if (stripos($userAgent->getUserAgentString(), 'SymbOS') !== false) { 252 | $os->setName($os::SYMBOS); 253 | 254 | return true; 255 | } 256 | 257 | return false; 258 | } 259 | 260 | /** 261 | * Determine if the user's operating system is Linux. 262 | * 263 | * @param Os $os 264 | * @param UserAgent $userAgent 265 | * 266 | * @return bool 267 | */ 268 | private static function checkLinux(Os $os, UserAgent $userAgent) 269 | { 270 | if (stripos($userAgent->getUserAgentString(), 'Linux') !== false) { 271 | $os->setVersion($os::VERSION_UNKNOWN); 272 | $os->setName($os::LINUX); 273 | 274 | return true; 275 | } 276 | 277 | return false; 278 | } 279 | 280 | /** 281 | * Determine if the user's operating system is Nokia. 282 | * 283 | * @param Os $os 284 | * @param UserAgent $userAgent 285 | * 286 | * @return bool 287 | */ 288 | private static function checkNokia(Os $os, UserAgent $userAgent) 289 | { 290 | if (stripos($userAgent->getUserAgentString(), 'Nokia') !== false) { 291 | $os->setVersion($os::VERSION_UNKNOWN); 292 | $os->setName($os::NOKIA); 293 | $os->setIsMobile(true); 294 | 295 | return true; 296 | } 297 | 298 | return false; 299 | } 300 | 301 | /** 302 | * Determine if the user's operating system is BlackBerry. 303 | * 304 | * @param Os $os 305 | * @param UserAgent $userAgent 306 | * 307 | * @return bool 308 | */ 309 | private static function checkBlackBerry(Os $os, UserAgent $userAgent) 310 | { 311 | if (stripos($userAgent->getUserAgentString(), 'BlackBerry') !== false) { 312 | if (stripos($userAgent->getUserAgentString(), 'Version/') !== false) { 313 | $aresult = explode('Version/', $userAgent->getUserAgentString()); 314 | if (isset($aresult[1])) { 315 | $aversion = explode(' ', $aresult[1]); 316 | $os->setVersion($aversion[0]); 317 | } 318 | } else { 319 | $os->setVersion($os::VERSION_UNKNOWN); 320 | } 321 | $os->setName($os::BLACKBERRY); 322 | $os->setIsMobile(true); 323 | 324 | return true; 325 | } elseif (stripos($userAgent->getUserAgentString(), 'BB10') !== false) { 326 | $aresult = explode('Version/10.', $userAgent->getUserAgentString()); 327 | if (isset($aresult[1])) { 328 | $aversion = explode(' ', $aresult[1]); 329 | $os->setVersion('10.' . $aversion[0]); 330 | } else { 331 | $os->setVersion('10'); 332 | } 333 | $os->setName($os::BLACKBERRY); 334 | $os->setIsMobile(true); 335 | 336 | return true; 337 | } 338 | 339 | return false; 340 | } 341 | 342 | /** 343 | * Determine if the user's operating system is Android. 344 | * 345 | * @param Os $os 346 | * @param UserAgent $userAgent 347 | * 348 | * @return bool 349 | */ 350 | private static function checkAndroid(Os $os, UserAgent $userAgent) 351 | { 352 | if (stripos($userAgent->getUserAgentString(), 'Android') !== false) { 353 | if (preg_match('/Android ([\d\.]*)/i', $userAgent->getUserAgentString(), $matches)) { 354 | if (isset($matches[1])) { 355 | $os->setVersion($matches[1]); 356 | } 357 | } else { 358 | $os->setVersion($os::VERSION_UNKNOWN); 359 | } 360 | $os->setName($os::ANDROID); 361 | $os->setIsMobile(true); 362 | 363 | return true; 364 | } 365 | 366 | return false; 367 | } 368 | 369 | /** 370 | * Determine if the user's operating system is FreeBSD. 371 | * 372 | * @param Os $os 373 | * @param UserAgent $userAgent 374 | * 375 | * @return bool 376 | */ 377 | private static function checkFreeBSD(Os $os, UserAgent $userAgent) 378 | { 379 | if (stripos($userAgent->getUserAgentString(), 'FreeBSD') !== false) { 380 | $os->setVersion($os::VERSION_UNKNOWN); 381 | $os->setName($os::FREEBSD); 382 | 383 | return true; 384 | } 385 | 386 | return false; 387 | } 388 | 389 | /** 390 | * Determine if the user's operating system is OpenBSD. 391 | * 392 | * @param Os $os 393 | * @param UserAgent $userAgent 394 | * 395 | * @return bool 396 | */ 397 | private static function checkOpenBSD(Os $os, UserAgent $userAgent) 398 | { 399 | if (stripos($userAgent->getUserAgentString(), 'OpenBSD') !== false) { 400 | $os->setVersion($os::VERSION_UNKNOWN); 401 | $os->setName($os::OPENBSD); 402 | 403 | return true; 404 | } 405 | 406 | return false; 407 | } 408 | 409 | /** 410 | * Determine if the user's operating system is SunOS. 411 | * 412 | * @param Os $os 413 | * @param UserAgent $userAgent 414 | * 415 | * @return bool 416 | */ 417 | private static function checkSunOS(Os $os, UserAgent $userAgent) 418 | { 419 | if (stripos($userAgent->getUserAgentString(), 'SunOS') !== false) { 420 | $os->setVersion($os::VERSION_UNKNOWN); 421 | $os->setName($os::SUNOS); 422 | 423 | return true; 424 | } 425 | 426 | return false; 427 | } 428 | 429 | /** 430 | * Determine if the user's operating system is NetBSD. 431 | * 432 | * @param Os $os 433 | * @param UserAgent $userAgent 434 | * 435 | * @return bool 436 | */ 437 | private static function checkNetBSD(Os $os, UserAgent $userAgent) 438 | { 439 | if (stripos($userAgent->getUserAgentString(), 'NetBSD') !== false) { 440 | $os->setVersion($os::VERSION_UNKNOWN); 441 | $os->setName($os::NETBSD); 442 | 443 | return true; 444 | } 445 | 446 | return false; 447 | } 448 | 449 | /** 450 | * Determine if the user's operating system is OpenSolaris. 451 | * 452 | * @param Os $os 453 | * @param UserAgent $userAgent 454 | * 455 | * @return bool 456 | */ 457 | private static function checkOpenSolaris(Os $os, UserAgent $userAgent) 458 | { 459 | if (stripos($userAgent->getUserAgentString(), 'OpenSolaris') !== false) { 460 | $os->setVersion($os::VERSION_UNKNOWN); 461 | $os->setName($os::OPENSOLARIS); 462 | 463 | return true; 464 | } 465 | 466 | return false; 467 | } 468 | 469 | /** 470 | * Determine if the user's operating system is OS2. 471 | * 472 | * @param Os $os 473 | * @param UserAgent $userAgent 474 | * 475 | * @return bool 476 | */ 477 | private static function checkOS2(Os $os, UserAgent $userAgent) 478 | { 479 | if (stripos($userAgent->getUserAgentString(), 'OS\/2') !== false) { 480 | $os->setVersion($os::VERSION_UNKNOWN); 481 | $os->setName($os::OS2); 482 | 483 | return true; 484 | } 485 | 486 | return false; 487 | } 488 | 489 | /** 490 | * Determine if the user's operating system is BeOS. 491 | * 492 | * @param Os $os 493 | * @param UserAgent $userAgent 494 | * 495 | * @return bool 496 | */ 497 | private static function checkBeOS(Os $os, UserAgent $userAgent) 498 | { 499 | if (stripos($userAgent->getUserAgentString(), 'BeOS') !== false) { 500 | $os->setVersion($os::VERSION_UNKNOWN); 501 | $os->setName($os::BEOS); 502 | 503 | return true; 504 | } 505 | 506 | return false; 507 | } 508 | } 509 | -------------------------------------------------------------------------------- /src/UserAgent.php: -------------------------------------------------------------------------------- 1 | setUserAgentString($userAgentString); 19 | } 20 | } 21 | 22 | /** 23 | * @param string $userAgentString 24 | * 25 | * @return $this 26 | */ 27 | public function setUserAgentString($userAgentString) 28 | { 29 | $this->userAgentString = (string)$userAgentString; 30 | 31 | return $this; 32 | } 33 | 34 | /** 35 | * @return string 36 | */ 37 | public function getUserAgentString() 38 | { 39 | if (null === $this->userAgentString) { 40 | $this->createUserAgentString(); 41 | } 42 | 43 | return $this->userAgentString; 44 | } 45 | 46 | /** 47 | * @return string 48 | */ 49 | public function createUserAgentString() 50 | { 51 | $userAgentString = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null; 52 | $this->setUserAgentString($userAgentString); 53 | 54 | return $userAgentString; 55 | } 56 | } 57 | --------------------------------------------------------------------------------