[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Environment class to aid with the detection and establishment of the working environment. 19 * 20 * @package core 21 * @copyright 2013 Sam Hemelryk 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 /** 26 * The user agent class. 27 * 28 * It's important to note that we do not like browser sniffing and its use in core code is highly discouraged. 29 * No new uses of this API will be integrated unless there is absolutely no alternative. 30 * 31 * This API supports the few browser checks we do have in core, all of which one day will hopefully be removed. 32 * The API will remain to support any third party use out there, however at some point like all code it will be deprecated. 33 * 34 * Use sparingly and only with good cause! 35 * 36 * @package core 37 * @copyright 2013 Sam Hemelryk 38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 */ 40 class core_useragent { 41 42 /** 43 * The default for devices, think of as a computer. 44 */ 45 const DEVICETYPE_DEFAULT = 'default'; 46 /** 47 * Legacy devices, or at least legacy browsers. These are older devices/browsers 48 * that don't support standards. 49 */ 50 const DEVICETYPE_LEGACY = 'legacy'; 51 /** 52 * Mobile devices like your cell phone or hand held gaming device. 53 */ 54 const DEVICETYPE_MOBILE = 'mobile'; 55 /** 56 * Tables, larger than hand held, but still easily portable and smaller than a laptop. 57 */ 58 const DEVICETYPE_TABLET = 'tablet'; 59 60 /** 61 * An instance of this class. 62 * @var core_useragent 63 */ 64 protected static $instance = null; 65 66 /** 67 * The device types we track. 68 * @var array 69 */ 70 public static $devicetypes = array( 71 self::DEVICETYPE_DEFAULT, 72 self::DEVICETYPE_LEGACY, 73 self::DEVICETYPE_MOBILE, 74 self::DEVICETYPE_TABLET 75 ); 76 77 /** 78 * The current requests user agent string if there was one. 79 * @var string|bool|null Null until initialised, false if none available, or string when available. 80 */ 81 protected $useragent = null; 82 83 /** 84 * The users device type, one of self::DEVICETYPE_*. 85 * @var string null until initialised 86 */ 87 protected $devicetype = null; 88 89 /** 90 * Custom device types entered into the admin interface. 91 * @var array 92 */ 93 protected $devicetypecustoms = array(); 94 95 /** 96 * True if the user agent supports the display of svg images. False if not. 97 * @var bool|null Null until initialised, then true or false. 98 */ 99 protected $supportssvg = null; 100 101 /** 102 * Get an instance of the user agent object. 103 * 104 * @param bool $reload If set to true the user agent will be reset and all ascertations remade. 105 * @param string $forceuseragent The string to force as the user agent, don't use unless absolutely unavoidable. 106 * @return core_useragent 107 */ 108 public static function instance($reload = false, $forceuseragent = null) { 109 if (!self::$instance || $reload) { 110 self::$instance = new core_useragent($forceuseragent); 111 } 112 return self::$instance; 113 } 114 115 /** 116 * Constructs a new user agent object. Publically you must use the instance method above. 117 * 118 * @param string|null $forceuseragent Optional a user agent to force. 119 */ 120 protected function __construct($forceuseragent = null) { 121 global $CFG; 122 if (!empty($CFG->devicedetectregex)) { 123 $this->devicetypecustoms = json_decode($CFG->devicedetectregex, true); 124 } 125 if ($this->devicetypecustoms === null) { 126 // This shouldn't happen unless you're hardcoding the config value. 127 debugging('Config devicedetectregex is not valid JSON object'); 128 $this->devicetypecustoms = array(); 129 } 130 if ($forceuseragent !== null) { 131 $this->useragent = $forceuseragent; 132 } else if (!empty($_SERVER['HTTP_USER_AGENT'])) { 133 $this->useragent = $_SERVER['HTTP_USER_AGENT']; 134 } else { 135 $this->useragent = false; 136 $this->devicetype = self::DEVICETYPE_DEFAULT; 137 } 138 } 139 140 /** 141 * Returns the user agent string. 142 * @return bool|string The user agent string or false if one isn't available. 143 */ 144 public static function get_user_agent_string() { 145 $instance = self::instance(); 146 return $instance->useragent; 147 } 148 149 /** 150 * Returns the device type we believe is being used. 151 * @return string 152 */ 153 public static function get_device_type() { 154 $instance = self::instance(); 155 if ($instance->devicetype === null) { 156 return $instance->guess_device_type(); 157 } 158 return $instance->devicetype; 159 } 160 161 /** 162 * Guesses the device type the user agent is running on. 163 * 164 * @return string 165 */ 166 protected function guess_device_type() { 167 global $CFG; 168 if (empty($CFG->enabledevicedetection)) { 169 $this->devicetype = self::DEVICETYPE_DEFAULT; 170 return $this->devicetype; 171 } 172 foreach ($this->devicetypecustoms as $value => $regex) { 173 if (preg_match($regex, $this->useragent)) { 174 $this->devicetype = $value; 175 return $this->devicetype; 176 } 177 } 178 if ($this->is_useragent_mobile()) { 179 $this->devicetype = 'mobile'; 180 } else if ($this->is_useragent_tablet()) { 181 $this->devicetype = 'tablet'; 182 } else if (substr($this->useragent, 0, 34) === 'Mozilla/4.0 (compatible; MSIE 6.0;') { 183 // Safe way to check for IE6 and not get false positives for some IE 7/8 users. 184 $this->devicetype = 'legacy'; 185 } else { 186 $this->devicetype = self::DEVICETYPE_DEFAULT; 187 } 188 return $this->devicetype; 189 } 190 191 /** 192 * Returns true if the user appears to be on a mobile device. 193 * @return bool 194 */ 195 protected function is_useragent_mobile() { 196 // Mobile detection PHP direct copy from open source detectmobilebrowser.com. 197 $phonesregex = '/android .+ mobile|avantgo|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i'; 198 $modelsregex = '/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i'; 199 return (preg_match($phonesregex, $this->useragent) || preg_match($modelsregex, substr($this->useragent, 0, 4))); 200 } 201 202 /** 203 * Returns true if the user appears to be on a tablet. 204 * @return int 205 */ 206 protected function is_useragent_tablet() { 207 $tabletregex = '/Tablet browser|android|iPad|iProd|GT-P1000|GT-I9000|SHW-M180S|SGH-T849|SCH-I800|Build\/ERE27|sholest/i'; 208 return (preg_match($tabletregex, $this->useragent)); 209 } 210 211 /** 212 * Gets a list of known device types. 213 * 214 * @param bool $includecustomtypes If set to true we'll include types that have been added by the admin. 215 * @return array 216 */ 217 public static function get_device_type_list($includecustomtypes = true) { 218 $types = self::$devicetypes; 219 if ($includecustomtypes) { 220 $instance = self::instance(); 221 $types = array_merge($types, array_keys($instance->devicetypecustoms)); 222 } 223 return $types; 224 } 225 226 /** 227 * Returns the theme to use for the given device type. 228 * 229 * This used to be get_selected_theme_for_device_type. 230 * @param null|string $devicetype The device type to find out for. Defaults to the device the user is using, 231 * @return bool 232 */ 233 public static function get_device_type_theme($devicetype = null) { 234 global $CFG; 235 if ($devicetype === null) { 236 $devicetype = self::get_device_type(); 237 } 238 $themevarname = self::get_device_type_cfg_var_name($devicetype); 239 if (empty($CFG->$themevarname)) { 240 return false; 241 } 242 return $CFG->$themevarname; 243 } 244 245 /** 246 * Returns the CFG var used to find the theme to use for the given device. 247 * 248 * Used to be get_device_cfg_var_name. 249 * 250 * @param null|string $devicetype The device type to find out for. Defaults to the device the user is using, 251 * @return string 252 */ 253 public static function get_device_type_cfg_var_name($devicetype = null) { 254 if ($devicetype == self::DEVICETYPE_DEFAULT || empty($devicetype)) { 255 return 'theme'; 256 } 257 return 'theme' . $devicetype; 258 } 259 260 /** 261 * Gets the device type the user is currently using. 262 * @return string 263 */ 264 public static function get_user_device_type() { 265 $device = self::get_device_type(); 266 $switched = get_user_preferences('switchdevice'.$device, false); 267 if ($switched != false) { 268 return $switched; 269 } 270 return $device; 271 } 272 273 /** 274 * Switches the device type we think the user is using to what ever was given. 275 * @param string $newdevice 276 * @return bool 277 * @throws coding_exception 278 */ 279 public static function set_user_device_type($newdevice) { 280 $devicetype = self::get_device_type(); 281 if ($newdevice == $devicetype) { 282 unset_user_preference('switchdevice'.$devicetype); 283 return true; 284 } else { 285 $devicetypes = self::get_device_type_list(); 286 if (in_array($newdevice, $devicetypes)) { 287 set_user_preference('switchdevice'.$devicetype, $newdevice); 288 return true; 289 } 290 } 291 throw new coding_exception('Invalid device type provided to set_user_device_type'); 292 } 293 294 /** 295 * Returns true if the user agent matches the given brand and the version is equal to or greater than that specified. 296 * 297 * @param string $brand The branch to check for. 298 * @param scalar $version The version if we need to find out if it is equal to or greater than that specified. 299 * @return bool 300 */ 301 public static function check_browser_version($brand, $version = null) { 302 switch ($brand) { 303 304 case 'MSIE': 305 // Internet Explorer. 306 return self::check_ie_version($version); 307 308 case 'Firefox': 309 // Mozilla Firefox browsers. 310 return self::check_firefox_version($version); 311 312 case 'Chrome': 313 return self::check_chrome_version($version); 314 315 case 'Opera': 316 // Opera. 317 return self::check_opera_version($version); 318 319 case 'Safari': 320 // Desktop version of Apple Safari browser - no mobile or touch devices. 321 return self::check_safari_version($version); 322 323 case 'Safari iOS': 324 // Safari on iPhone, iPad and iPod touch. 325 return self::check_safari_ios_version($version); 326 327 case 'WebKit': 328 // WebKit based browser - everything derived from it (Safari, Chrome, iOS, Android and other mobiles). 329 return self::check_webkit_version($version); 330 331 case 'Gecko': 332 // Gecko based browsers. 333 return self::check_gecko_version($version); 334 335 case 'WebKit Android': 336 // WebKit browser on Android. 337 return self::check_webkit_android_version($version); 338 339 case 'Camino': 340 // OSX browser using Gecke engine. 341 return self::check_camino_version($version); 342 } 343 // Who knows?! doesn't pass anyway. 344 return false; 345 } 346 347 /** 348 * Checks the user agent is camino based and that the version is equal to or greater than that specified. 349 * 350 * Camino browser is at the end of its life, its no longer being developed or supported, just don't worry about it. 351 * 352 * @param string|int $version A version to check for, returns true if its equal to or greater than that specified. 353 * @return bool 354 */ 355 protected static function check_camino_version($version = null) { 356 // OSX browser using Gecko engine. 357 $useragent = self::get_user_agent_string(); 358 if ($useragent === false) { 359 return false; 360 } 361 if (strpos($useragent, 'Camino') === false) { 362 return false; 363 } 364 if (empty($version)) { 365 return true; // No version specified. 366 } 367 if (preg_match("/Camino\/([0-9\.]+)/i", $useragent, $match)) { 368 if (version_compare($match[1], $version) >= 0) { 369 return true; 370 } 371 } 372 return false; 373 } 374 375 /** 376 * Checks the user agent is Firefox (of any version). 377 * 378 * @return bool true if firefox 379 */ 380 public static function is_firefox() { 381 return self::check_firefox_version(); 382 } 383 384 /** 385 * Checks the user agent is Firefox based and that the version is equal to or greater than that specified. 386 * 387 * @param string|int $version A version to check for, returns true if its equal to or greater than that specified. 388 * @return bool 389 */ 390 public static function check_firefox_version($version = null) { 391 // Mozilla Firefox browsers. 392 $useragent = self::get_user_agent_string(); 393 if ($useragent === false) { 394 return false; 395 } 396 if (strpos($useragent, 'Firefox') === false && strpos($useragent, 'Iceweasel') === false) { 397 return false; 398 } 399 if (empty($version)) { 400 return true; // No version specified.. 401 } 402 if (preg_match("/(Iceweasel|Firefox)\/([0-9\.]+)/i", $useragent, $match)) { 403 if (version_compare($match[2], $version) >= 0) { 404 return true; 405 } 406 } 407 return false; 408 } 409 410 /** 411 * Checks the user agent is Gecko based (of any version). 412 * 413 * @return bool true if Gecko based. 414 */ 415 public static function is_gecko() { 416 return self::check_gecko_version(); 417 } 418 419 /** 420 * Checks the user agent is Gecko based and that the version is equal to or greater than that specified. 421 * 422 * @param string|int $version A version to check for, returns true if its equal to or greater than that specified. 423 * @return bool 424 */ 425 public static function check_gecko_version($version = null) { 426 // Gecko based browsers. 427 // Do not look for dates any more, we expect real Firefox version here. 428 $useragent = self::get_user_agent_string(); 429 if ($useragent === false) { 430 return false; 431 } 432 if (empty($version)) { 433 $version = 1; 434 } else if ($version > 20000000) { 435 // This is just a guess, it is not supposed to be 100% accurate! 436 if (preg_match('/^201/', $version)) { 437 $version = 3.6; 438 } else if (preg_match('/^200[7-9]/', $version)) { 439 $version = 3; 440 } else if (preg_match('/^2006/', $version)) { 441 $version = 2; 442 } else { 443 $version = 1.5; 444 } 445 } 446 if (preg_match("/(Iceweasel|Firefox)\/([0-9\.]+)/i", $useragent, $match)) { 447 // Use real Firefox version if specified in user agent string. 448 if (version_compare($match[2], $version) >= 0) { 449 return true; 450 } 451 } else if (preg_match("/Gecko\/([0-9\.]+)/i", $useragent, $match)) { 452 // Gecko might contain date or Firefox revision, let's just guess the Firefox version from the date. 453 $browserver = $match[1]; 454 if ($browserver > 20000000) { 455 // This is just a guess, it is not supposed to be 100% accurate! 456 if (preg_match('/^201/', $browserver)) { 457 $browserver = 3.6; 458 } else if (preg_match('/^200[7-9]/', $browserver)) { 459 $browserver = 3; 460 } else if (preg_match('/^2006/', $version)) { 461 $browserver = 2; 462 } else { 463 $browserver = 1.5; 464 } 465 } 466 if (version_compare($browserver, $version) >= 0) { 467 return true; 468 } 469 } 470 return false; 471 } 472 473 /** 474 * Checks the user agent is IE (of any version). 475 * 476 * @return bool true if internet exporeer 477 */ 478 public static function is_ie() { 479 return self::check_ie_version(); 480 } 481 482 /** 483 * Checks the user agent is IE and returns its main properties: 484 * - browser version; 485 * - whether running in compatibility view. 486 * 487 * @return bool|array False if not IE, otherwise an associative array of properties. 488 */ 489 public static function check_ie_properties() { 490 // Internet Explorer. 491 $useragent = self::get_user_agent_string(); 492 if ($useragent === false) { 493 return false; 494 } 495 if (strpos($useragent, 'Opera') !== false) { 496 // Reject Opera. 497 return false; 498 } 499 // See: http://www.useragentstring.com/pages/Internet%20Explorer/. 500 if (preg_match("/MSIE ([0-9\.]+)/", $useragent, $match)) { 501 $browser = $match[1]; 502 // See: http://msdn.microsoft.com/en-us/library/ie/bg182625%28v=vs.85%29.aspx for IE11+ useragent details. 503 } else if (preg_match("/Trident\/[0-9\.]+/", $useragent) && preg_match("/rv:([0-9\.]+)/", $useragent, $match)) { 504 $browser = $match[1]; 505 } else { 506 return false; 507 } 508 $compatview = false; 509 // IE8 and later versions may pretend to be IE7 for intranet sites, use Trident version instead, 510 // the Trident should always describe the capabilities of IE in any emulation mode. 511 if ($browser === '7.0' and preg_match("/Trident\/([0-9\.]+)/", $useragent, $match)) { 512 $compatview = true; 513 $browser = $match[1] + 4; // NOTE: Hopefully this will work also for future IE versions. 514 } 515 $browser = round($browser, 1); 516 return array( 517 'version' => $browser, 518 'compatview' => $compatview 519 ); 520 } 521 522 /** 523 * Checks the user agent is IE and that the version is equal to or greater than that specified. 524 * 525 * @param string|int $version A version to check for, returns true if its equal to or greater than that specified. 526 * @return bool 527 */ 528 public static function check_ie_version($version = null) { 529 // Internet Explorer. 530 $properties = self::check_ie_properties(); 531 if (!is_array($properties)) { 532 return false; 533 } 534 // In case of IE we have to deal with BC of the version parameter. 535 if (is_null($version)) { 536 $version = 5.5; // Anything older is not considered a browser at all! 537 } 538 // IE uses simple versions, let's cast it to float to simplify the logic here. 539 $version = round($version, 1); 540 return ($properties['version'] >= $version); 541 } 542 543 /** 544 * Checks the user agent is IE and that IE is running under Compatibility View setting. 545 * 546 * @return bool true if internet explorer runs in Compatibility View mode. 547 */ 548 public static function check_ie_compatibility_view() { 549 // IE User Agent string when in Compatibility View: 550 // - IE 8: "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/4.0; ...)". 551 // - IE 9: "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; ...)". 552 // - IE 10: "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/6.0; ...)". 553 // - IE 11: "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; Trident/7.0; ...)". 554 // Refs: 555 // - http://blogs.msdn.com/b/ie/archive/2009/01/09/the-internet-explorer-8-user-agent-string-updated-edition.aspx. 556 // - http://blogs.msdn.com/b/ie/archive/2010/03/23/introducing-ie9-s-user-agent-string.aspx. 557 // - http://blogs.msdn.com/b/ie/archive/2011/04/15/the-ie10-user-agent-string.aspx. 558 // - http://msdn.microsoft.com/en-us/library/ie/hh869301%28v=vs.85%29.aspx. 559 $properties = self::check_ie_properties(); 560 if (!is_array($properties)) { 561 return false; 562 } 563 return $properties['compatview']; 564 } 565 566 /** 567 * Checks the user agent is Opera (of any version). 568 * 569 * @return bool true if opera 570 */ 571 public static function is_opera() { 572 return self::check_opera_version(); 573 } 574 575 /** 576 * Checks the user agent is Opera and that the version is equal to or greater than that specified. 577 * 578 * @param string|int $version A version to check for, returns true if its equal to or greater than that specified. 579 * @return bool 580 */ 581 public static function check_opera_version($version = null) { 582 // Opera. 583 $useragent = self::get_user_agent_string(); 584 if ($useragent === false) { 585 return false; 586 } 587 if (strpos($useragent, 'Opera') === false) { 588 return false; 589 } 590 if (empty($version)) { 591 return true; // No version specified. 592 } 593 // Recent Opera useragents have Version/ with the actual version, e.g.: 594 // Opera/9.80 (Windows NT 6.1; WOW64; U; en) Presto/2.10.289 Version/12.01 595 // That's Opera 12.01, not 9.8. 596 if (preg_match("/Version\/([0-9\.]+)/i", $useragent, $match)) { 597 if (version_compare($match[1], $version) >= 0) { 598 return true; 599 } 600 } else if (preg_match("/Opera\/([0-9\.]+)/i", $useragent, $match)) { 601 if (version_compare($match[1], $version) >= 0) { 602 return true; 603 } 604 } 605 return false; 606 } 607 608 /** 609 * Checks the user agent is webkit based 610 * 611 * @return bool true if webkit 612 */ 613 public static function is_webkit() { 614 return self::check_webkit_version(); 615 } 616 617 /** 618 * Checks the user agent is Webkit based and that the version is equal to or greater than that specified. 619 * 620 * @param string|int $version A version to check for, returns true if its equal to or greater than that specified. 621 * @return bool 622 */ 623 public static function check_webkit_version($version = null) { 624 // WebKit based browser - everything derived from it (Safari, Chrome, iOS, Android and other mobiles). 625 $useragent = self::get_user_agent_string(); 626 if ($useragent === false) { 627 return false; 628 } 629 if (strpos($useragent, 'AppleWebKit') === false) { 630 return false; 631 } 632 if (empty($version)) { 633 return true; // No version specified. 634 } 635 if (preg_match("/AppleWebKit\/([0-9.]+)/i", $useragent, $match)) { 636 if (version_compare($match[1], $version) >= 0) { 637 return true; 638 } 639 } 640 return false; 641 } 642 643 /** 644 * Checks the user agent is Safari 645 * 646 * @return bool true if safari 647 */ 648 public static function is_safari() { 649 return self::check_safari_version(); 650 } 651 652 /** 653 * Checks the user agent is Safari based and that the version is equal to or greater than that specified. 654 * 655 * @param string|int $version A version to check for, returns true if its equal to or greater than that specified. 656 * @return bool 657 */ 658 public static function check_safari_version($version = null) { 659 // Desktop version of Apple Safari browser - no mobile or touch devices. 660 $useragent = self::get_user_agent_string(); 661 if ($useragent === false) { 662 return false; 663 } 664 if (strpos($useragent, 'AppleWebKit') === false) { 665 return false; 666 } 667 // Look for AppleWebKit, excluding strings with OmniWeb, Shiira and SymbianOS and any other mobile devices. 668 if (strpos($useragent, 'OmniWeb')) { 669 // Reject OmniWeb. 670 return false; 671 } 672 if (strpos($useragent, 'Shiira')) { 673 // Reject Shiira. 674 return false; 675 } 676 if (strpos($useragent, 'SymbianOS')) { 677 // Reject SymbianOS. 678 return false; 679 } 680 if (strpos($useragent, 'Android')) { 681 // Reject Androids too. 682 return false; 683 } 684 if (strpos($useragent, 'iPhone') or strpos($useragent, 'iPad') or strpos($useragent, 'iPod')) { 685 // No Apple mobile devices here - editor does not work, course ajax is not touch compatible, etc. 686 return false; 687 } 688 if (strpos($useragent, 'Chrome')) { // Reject chrome browsers - it needs to be tested explicitly. 689 return false; 690 } 691 692 if (empty($version)) { 693 return true; // No version specified. 694 } 695 if (preg_match("/AppleWebKit\/([0-9.]+)/i", $useragent, $match)) { 696 if (version_compare($match[1], $version) >= 0) { 697 return true; 698 } 699 } 700 return false; 701 } 702 703 /** 704 * Checks the user agent is Chrome 705 * 706 * @return bool true if chrome 707 */ 708 public static function is_chrome() { 709 return self::check_chrome_version(); 710 } 711 712 /** 713 * Checks the user agent is Chrome based and that the version is equal to or greater than that specified. 714 * 715 * @param string|int $version A version to check for, returns true if its equal to or greater than that specified. 716 * @return bool 717 */ 718 public static function check_chrome_version($version = null) { 719 // Chrome. 720 $useragent = self::get_user_agent_string(); 721 if ($useragent === false) { 722 return false; 723 } 724 if (strpos($useragent, 'Chrome') === false) { 725 return false; 726 } 727 if (empty($version)) { 728 return true; // No version specified. 729 } 730 if (preg_match("/Chrome\/(.*)[ ]+/i", $useragent, $match)) { 731 if (version_compare($match[1], $version) >= 0) { 732 return true; 733 } 734 } 735 return false; 736 } 737 738 /** 739 * Checks the user agent is webkit android based. 740 * 741 * @return bool true if webkit based and on Android 742 */ 743 public static function is_webkit_android() { 744 return self::check_webkit_android_version(); 745 } 746 747 /** 748 * Checks the user agent is Webkit based and on Android and that the version is equal to or greater than that specified. 749 * 750 * @param string|int $version A version to check for, returns true if its equal to or greater than that specified. 751 * @return bool 752 */ 753 public static function check_webkit_android_version($version = null) { 754 // WebKit browser on Android. 755 $useragent = self::get_user_agent_string(); 756 if ($useragent === false) { 757 return false; 758 } 759 if (strpos($useragent, 'Linux; U; Android') === false) { 760 return false; 761 } 762 if (empty($version)) { 763 return true; // No version specified. 764 } 765 if (preg_match("/AppleWebKit\/([0-9]+)/i", $useragent, $match)) { 766 if (version_compare($match[1], $version) >= 0) { 767 return true; 768 } 769 } 770 return false; 771 } 772 773 /** 774 * Checks the user agent is Safari on iOS 775 * 776 * @return bool true if Safari on iOS 777 */ 778 public static function is_safari_ios() { 779 return self::check_safari_ios_version(); 780 } 781 782 /** 783 * Checks the user agent is Safari on iOS and that the version is equal to or greater than that specified. 784 * 785 * @param string|int $version A version to check for, returns true if its equal to or greater than that specified. 786 * @return bool 787 */ 788 public static function check_safari_ios_version($version = null) { 789 // Safari on iPhone, iPad and iPod touch. 790 $useragent = self::get_user_agent_string(); 791 if ($useragent === false) { 792 return false; 793 } 794 if (strpos($useragent, 'AppleWebKit') === false or strpos($useragent, 'Safari') === false) { 795 return false; 796 } 797 if (!strpos($useragent, 'iPhone') and !strpos($useragent, 'iPad') and !strpos($useragent, 'iPod')) { 798 return false; 799 } 800 if (empty($version)) { 801 return true; // No version specified. 802 } 803 if (preg_match("/AppleWebKit\/([0-9]+)/i", $useragent, $match)) { 804 if (version_compare($match[1], $version) >= 0) { 805 return true; 806 } 807 } 808 return false; 809 } 810 811 /** 812 * Check if the user agent matches a given brand. 813 * 814 * Known brand: 'Windows','Linux','Macintosh','SGI','SunOS','HP-UX' 815 * 816 * @param string $brand 817 * @return bool 818 */ 819 public static function check_browser_operating_system($brand) { 820 $useragent = self::get_user_agent_string(); 821 return ($useragent !== false && preg_match("/$brand/i", $useragent)); 822 } 823 824 /** 825 * Gets an array of CSS classes to represent the user agent. 826 * @return array 827 */ 828 public static function get_browser_version_classes() { 829 $classes = array(); 830 if (self::is_ie()) { 831 $classes[] = 'ie'; 832 for ($i = 12; $i >= 6; $i--) { 833 if (self::check_ie_version($i)) { 834 $classes[] = 'ie'.$i; 835 break; 836 } 837 } 838 } else if (self::is_firefox() || self::is_gecko() || self::check_camino_version()) { 839 $classes[] = 'gecko'; 840 if (preg_match('/rv\:([1-2])\.([0-9])/', self::get_user_agent_string(), $matches)) { 841 $classes[] = "gecko{$matches[1]}{$matches[2]}"; 842 } 843 } else if (self::is_webkit()) { 844 $classes[] = 'safari'; 845 if (self::is_safari_ios()) { 846 $classes[] = 'ios'; 847 } else if (self::is_webkit_android()) { 848 $classes[] = 'android'; 849 } 850 } else if (self::is_opera()) { 851 $classes[] = 'opera'; 852 } 853 return $classes; 854 } 855 856 /** 857 * Returns true if the user agent supports the display of SVG images. 858 * 859 * @return bool 860 */ 861 public static function supports_svg() { 862 // IE 5 - 8 don't support SVG at all. 863 $instance = self::instance(); 864 if ($instance->supportssvg === null) { 865 if ($instance->useragent === false) { 866 // Can't be sure, just say no. 867 $instance->supportssvg = false; 868 } else if (self::is_ie() and !self::check_ie_version('9')) { 869 // IE < 9 doesn't support SVG. Say no. 870 $instance->supportssvg = false; 871 } else if (self::is_ie() and !self::check_ie_version('10') and self::check_ie_compatibility_view()) { 872 // IE 9 Compatibility View doesn't support SVG. Say no. 873 $instance->supportssvg = false; 874 } else if (preg_match('#Android +[0-2]\.#', $instance->useragent)) { 875 // Android < 3 doesn't support SVG. Say no. 876 $instance->supportssvg = false; 877 } else if (self::is_opera()) { 878 // Opera 12 still does not support SVG well enough. Say no. 879 $instance->supportssvg = false; 880 } else { 881 // Presumed fine. 882 $instance->supportssvg = true; 883 } 884 } 885 return $instance->supportssvg; 886 } 887 888 /** 889 * Returns true if the user agent supports the MIME media type for JSON text, as defined in RFC 4627. 890 * 891 * @return bool 892 */ 893 public static function supports_json_contenttype() { 894 // Modern browsers other than IE correctly supports 'application/json' media type. 895 if (!self::is_ie()) { 896 return true; 897 } 898 899 // IE8+ supports 'application/json' media type, when NOT in Compatibility View mode. 900 // Refs: 901 // - http://blogs.msdn.com/b/ie/archive/2008/09/10/native-json-in-ie8.aspx; 902 // - MDL-39810: issues when using 'text/plain' in Compatibility View for the body of an HTTP POST response. 903 if (self::check_ie_version(8) && !self::check_ie_compatibility_view()) { 904 return true; 905 } 906 907 // This browser does not support json. 908 return false; 909 } 910 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |