[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/joomla/application/src/Web/ -> WebClient.php (source)

   1  <?php
   2  /**
   3   * Part of the Joomla Framework Application Package
   4   *
   5   * @copyright  Copyright (C) 2005 - 2021 Open Source Matters, Inc. All rights reserved.
   6   * @license    GNU General Public License version 2 or later; see LICENSE
   7   */
   8  
   9  namespace Joomla\Application\Web;
  10  
  11  /**
  12   * Class to model a Web Client.
  13   *
  14   * @property-read  integer  $platform        The detected platform on which the web client runs.
  15   * @property-read  boolean  $mobile          True if the web client is a mobile device.
  16   * @property-read  integer  $engine          The detected rendering engine used by the web client.
  17   * @property-read  integer  $browser         The detected browser used by the web client.
  18   * @property-read  string   $browserVersion  The detected browser version used by the web client.
  19   * @property-read  array    $languages       The priority order detected accepted languages for the client.
  20   * @property-read  array    $encodings       The priority order detected accepted encodings for the client.
  21   * @property-read  string   $userAgent       The web client's user agent string.
  22   * @property-read  string   $acceptEncoding  The web client's accepted encoding string.
  23   * @property-read  string   $acceptLanguage  The web client's accepted languages string.
  24   * @property-read  array    $detection       An array of flags determining whether or not a detection routine has been run.
  25   * @property-read  boolean  $robot           True if the web client is a robot
  26   * @property-read  array    $headers         An array of all headers sent by client
  27   *
  28   * @since  1.0
  29   */
  30  class WebClient
  31  {
  32      const WINDOWS       = 1;
  33      const WINDOWS_PHONE = 2;
  34      const WINDOWS_CE    = 3;
  35      const IPHONE        = 4;
  36      const IPAD          = 5;
  37      const IPOD          = 6;
  38      const MAC           = 7;
  39      const BLACKBERRY    = 8;
  40      const ANDROID       = 9;
  41      const LINUX         = 10;
  42      const TRIDENT       = 11;
  43      const WEBKIT        = 12;
  44      const GECKO         = 13;
  45      const PRESTO        = 14;
  46      const KHTML         = 15;
  47      const AMAYA         = 16;
  48      const IE            = 17;
  49      const FIREFOX       = 18;
  50      const CHROME        = 19;
  51      const SAFARI        = 20;
  52      const OPERA         = 21;
  53      const ANDROIDTABLET = 22;
  54      const EDGE          = 23;
  55      const BLINK         = 24;
  56      const EDG           = 25;
  57  
  58      /**
  59       * The detected platform on which the web client runs.
  60       *
  61       * @var    integer
  62       * @since  1.0
  63       */
  64      protected $platform;
  65  
  66      /**
  67       * True if the web client is a mobile device.
  68       *
  69       * @var    boolean
  70       * @since  1.0
  71       */
  72      protected $mobile = false;
  73  
  74      /**
  75       * The detected rendering engine used by the web client.
  76       *
  77       * @var    integer
  78       * @since  1.0
  79       */
  80      protected $engine;
  81  
  82      /**
  83       * The detected browser used by the web client.
  84       *
  85       * @var    integer
  86       * @since  1.0
  87       */
  88      protected $browser;
  89  
  90      /**
  91       * The detected browser version used by the web client.
  92       *
  93       * @var    string
  94       * @since  1.0
  95       */
  96      protected $browserVersion;
  97  
  98      /**
  99       * The priority order detected accepted languages for the client.
 100       *
 101       * @var    array
 102       * @since  1.0
 103       */
 104      protected $languages = [];
 105  
 106      /**
 107       * The priority order detected accepted encodings for the client.
 108       *
 109       * @var    array
 110       * @since  1.0
 111       */
 112      protected $encodings = [];
 113  
 114      /**
 115       * The web client's user agent string.
 116       *
 117       * @var    string
 118       * @since  1.0
 119       */
 120      protected $userAgent;
 121  
 122      /**
 123       * The web client's accepted encoding string.
 124       *
 125       * @var    string
 126       * @since  1.0
 127       */
 128      protected $acceptEncoding;
 129  
 130      /**
 131       * The web client's accepted languages string.
 132       *
 133       * @var    string
 134       * @since  1.0
 135       */
 136      protected $acceptLanguage;
 137  
 138      /**
 139       * True if the web client is a robot.
 140       *
 141       * @var    boolean
 142       * @since  1.0
 143       */
 144      protected $robot = false;
 145  
 146      /**
 147       * An array of flags determining whether or not a detection routine has been run.
 148       *
 149       * @var    array
 150       * @since  1.0
 151       */
 152      protected $detection = [];
 153  
 154      /**
 155       * An array of headers sent by client.
 156       *
 157       * @var    array
 158       * @since  1.3.0
 159       */
 160      protected $headers;
 161  
 162      /**
 163       * Class constructor.
 164       *
 165       * @param   string  $userAgent       The optional user-agent string to parse.
 166       * @param   string  $acceptEncoding  The optional client accept encoding string to parse.
 167       * @param   string  $acceptLanguage  The optional client accept language string to parse.
 168       *
 169       * @since   1.0
 170       */
 171  	public function __construct($userAgent = null, $acceptEncoding = null, $acceptLanguage = null)
 172      {
 173          // If no explicit user agent string was given attempt to use the implicit one from server environment.
 174          if (empty($userAgent) && isset($_SERVER['HTTP_USER_AGENT']))
 175          {
 176              $this->userAgent = $_SERVER['HTTP_USER_AGENT'];
 177          }
 178          else
 179          {
 180              $this->userAgent = $userAgent;
 181          }
 182  
 183          // If no explicit acceptable encoding string was given attempt to use the implicit one from server environment.
 184          if (empty($acceptEncoding) && isset($_SERVER['HTTP_ACCEPT_ENCODING']))
 185          {
 186              $this->acceptEncoding = $_SERVER['HTTP_ACCEPT_ENCODING'];
 187          }
 188          else
 189          {
 190              $this->acceptEncoding = $acceptEncoding;
 191          }
 192  
 193          // If no explicit acceptable languages string was given attempt to use the implicit one from server environment.
 194          if (empty($acceptLanguage) && isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
 195          {
 196              $this->acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
 197          }
 198          else
 199          {
 200              $this->acceptLanguage = $acceptLanguage;
 201          }
 202      }
 203  
 204      /**
 205       * Magic method to get an object property's value by name.
 206       *
 207       * @param   string  $name  Name of the property for which to return a value.
 208       *
 209       * @return  mixed  The requested value if it exists.
 210       *
 211       * @since   1.0
 212       */
 213  	public function __get($name)
 214      {
 215          switch ($name)
 216          {
 217              case 'mobile':
 218              case 'platform':
 219                  if (empty($this->detection['platform']))
 220                  {
 221                      $this->detectPlatform($this->userAgent);
 222                  }
 223  
 224                  break;
 225  
 226              case 'engine':
 227                  if (empty($this->detection['engine']))
 228                  {
 229                      $this->detectEngine($this->userAgent);
 230                  }
 231  
 232                  break;
 233  
 234              case 'browser':
 235              case 'browserVersion':
 236                  if (empty($this->detection['browser']))
 237                  {
 238                      $this->detectBrowser($this->userAgent);
 239                  }
 240  
 241                  break;
 242  
 243              case 'languages':
 244                  if (empty($this->detection['acceptLanguage']))
 245                  {
 246                      $this->detectLanguage($this->acceptLanguage);
 247                  }
 248  
 249                  break;
 250  
 251              case 'encodings':
 252                  if (empty($this->detection['acceptEncoding']))
 253                  {
 254                      $this->detectEncoding($this->acceptEncoding);
 255                  }
 256  
 257                  break;
 258  
 259              case 'robot':
 260                  if (empty($this->detection['robot']))
 261                  {
 262                      $this->detectRobot($this->userAgent);
 263                  }
 264  
 265                  break;
 266  
 267              case 'headers':
 268                  if (empty($this->detection['headers']))
 269                  {
 270                      $this->detectHeaders();
 271                  }
 272  
 273                  break;
 274          }
 275  
 276          // Return the property if it exists.
 277          if (property_exists($this, $name))
 278          {
 279              return $this->$name;
 280          }
 281  
 282          $trace = debug_backtrace();
 283          trigger_error(
 284              'Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'],
 285              E_USER_NOTICE
 286          );
 287      }
 288  
 289      /**
 290       * Detects the client browser and version in a user agent string.
 291       *
 292       * @param   string  $userAgent  The user-agent string to parse.
 293       *
 294       * @return  void
 295       *
 296       * @since   1.0
 297       */
 298  	protected function detectBrowser($userAgent)
 299      {
 300          $patternBrowser = '';
 301  
 302          // Attempt to detect the browser type.  Obviously we are only worried about major browsers.
 303          if ((stripos($userAgent, 'MSIE') !== false) && (stripos($userAgent, 'Opera') === false))
 304          {
 305              $this->browser  = self::IE;
 306              $patternBrowser = 'MSIE';
 307          }
 308          elseif (stripos($userAgent, 'Trident') !== false)
 309          {
 310              $this->browser  = self::IE;
 311              $patternBrowser = ' rv';
 312          }
 313          elseif (stripos($userAgent, 'Edge') !== false)
 314          {
 315              $this->browser  = self::EDGE;
 316              $patternBrowser = 'Edge';
 317          }
 318          elseif (stripos($userAgent, 'Edg') !== false)
 319          {
 320              $this->browser  = self::EDG;
 321              $patternBrowser = 'Edg';
 322          }
 323          elseif ((stripos($userAgent, 'Firefox') !== false) && (stripos($userAgent, 'like Firefox') === false))
 324          {
 325              $this->browser  = self::FIREFOX;
 326              $patternBrowser = 'Firefox';
 327          }
 328          elseif (stripos($userAgent, 'OPR') !== false)
 329          {
 330              $this->browser  = self::OPERA;
 331              $patternBrowser = 'OPR';
 332          }
 333          elseif (stripos($userAgent, 'Chrome') !== false)
 334          {
 335              $this->browser  = self::CHROME;
 336              $patternBrowser = 'Chrome';
 337          }
 338          elseif (stripos($userAgent, 'Safari') !== false)
 339          {
 340              $this->browser  = self::SAFARI;
 341              $patternBrowser = 'Safari';
 342          }
 343          elseif (stripos($userAgent, 'Opera') !== false)
 344          {
 345              $this->browser  = self::OPERA;
 346              $patternBrowser = 'Opera';
 347          }
 348  
 349          // If we detected a known browser let's attempt to determine the version.
 350          if ($this->browser)
 351          {
 352              // Build the REGEX pattern to match the browser version string within the user agent string.
 353              $pattern = '#(?<browser>Version|' . $patternBrowser . ')[/ :]+(?<version>[0-9.|a-zA-Z.]*)#';
 354  
 355              // Attempt to find version strings in the user agent string.
 356              $matches = [];
 357  
 358              if (preg_match_all($pattern, $userAgent, $matches))
 359              {
 360                  // Do we have both a Version and browser match?
 361                  if (\count($matches['browser']) == 2)
 362                  {
 363                      // See whether Version or browser came first, and use the number accordingly.
 364                      if (strripos($userAgent, 'Version') < strripos($userAgent, $patternBrowser))
 365                      {
 366                          $this->browserVersion = $matches['version'][0];
 367                      }
 368                      else
 369                      {
 370                          $this->browserVersion = $matches['version'][1];
 371                      }
 372                  }
 373                  elseif (\count($matches['browser']) > 2)
 374                  {
 375                      $key = array_search('Version', $matches['browser']);
 376  
 377                      if ($key)
 378                      {
 379                          $this->browserVersion = $matches['version'][$key];
 380                      }
 381                  }
 382                  else
 383                  {
 384                      // We only have a Version or a browser so use what we have.
 385                      $this->browserVersion = $matches['version'][0];
 386                  }
 387              }
 388          }
 389  
 390          // Mark this detection routine as run.
 391          $this->detection['browser'] = true;
 392      }
 393  
 394      /**
 395       * Method to detect the accepted response encoding by the client.
 396       *
 397       * @param   string  $acceptEncoding  The client accept encoding string to parse.
 398       *
 399       * @return  void
 400       *
 401       * @since   1.0
 402       */
 403  	protected function detectEncoding($acceptEncoding)
 404      {
 405          // Parse the accepted encodings.
 406          $this->encodings = array_map('trim', (array) explode(',', $acceptEncoding));
 407  
 408          // Mark this detection routine as run.
 409          $this->detection['acceptEncoding'] = true;
 410      }
 411  
 412      /**
 413       * Detects the client rendering engine in a user agent string.
 414       *
 415       * @param   string  $userAgent  The user-agent string to parse.
 416       *
 417       * @return  void
 418       *
 419       * @since   1.0
 420       */
 421  	protected function detectEngine($userAgent)
 422      {
 423          if (stripos($userAgent, 'MSIE') !== false || stripos($userAgent, 'Trident') !== false)
 424          {
 425              // Attempt to detect the client engine -- starting with the most popular ... for now.
 426              $this->engine = self::TRIDENT;
 427          }
 428          elseif (stripos($userAgent, 'Edge') !== false || stripos($userAgent, 'EdgeHTML') !== false)
 429          {
 430              $this->engine = self::EDGE;
 431          }
 432          elseif (stripos($userAgent, 'Edg') !== false)
 433          {
 434              $this->engine = self::BLINK;
 435          }
 436          elseif (stripos($userAgent, 'Chrome') !== false)
 437          {
 438              $result  = explode('/', stristr($userAgent, 'Chrome'));
 439              $version = explode(' ', $result[1]);
 440  
 441              if ($version[0] >= 28)
 442              {
 443                  $this->engine = self::BLINK;
 444              }
 445              else
 446              {
 447                  $this->engine = self::WEBKIT;
 448              }
 449          }
 450          elseif (stripos($userAgent, 'AppleWebKit') !== false || stripos($userAgent, 'blackberry') !== false)
 451          {
 452              if (stripos($userAgent, 'AppleWebKit') !== false)
 453              {
 454                  $result  = explode('/', stristr($userAgent, 'AppleWebKit'));
 455                  $version = explode(' ', $result[1]);
 456  
 457                  if ($version[0] === 537.36)
 458                  {
 459                      // AppleWebKit/537.36 is Blink engine specific, exception is Blink emulated IEMobile, Trident or Edge
 460                      $this->engine = self::BLINK;
 461                  }
 462              }
 463  
 464              // Evidently blackberry uses WebKit and doesn't necessarily report it.  Bad RIM.
 465              $this->engine = self::WEBKIT;
 466          }
 467          elseif (stripos($userAgent, 'Gecko') !== false && stripos($userAgent, 'like Gecko') === false)
 468          {
 469              // We have to check for like Gecko because some other browsers spoof Gecko.
 470              $this->engine = self::GECKO;
 471          }
 472          elseif (stripos($userAgent, 'Opera') !== false || stripos($userAgent, 'Presto') !== false)
 473          {
 474              $version = false;
 475  
 476              if (preg_match('/Opera[\/| ]?([0-9.]+)/u', $userAgent, $match))
 477              {
 478                  $version = (float) ($match[1]);
 479              }
 480  
 481              if (preg_match('/Version\/([0-9.]+)/u', $userAgent, $match))
 482              {
 483                  if ((float) ($match[1]) >= 10)
 484                  {
 485                      $version = (float) ($match[1]);
 486                  }
 487              }
 488  
 489              if ($version !== false && $version >= 15)
 490              {
 491                  $this->engine = self::BLINK;
 492              }
 493              else
 494              {
 495                  $this->engine = self::PRESTO;
 496              }
 497          }
 498          elseif (stripos($userAgent, 'KHTML') !== false)
 499          {
 500              // *sigh*
 501              $this->engine = self::KHTML;
 502          }
 503          elseif (stripos($userAgent, 'Amaya') !== false)
 504          {
 505              // Lesser known engine but it finishes off the major list from Wikipedia :-)
 506              $this->engine = self::AMAYA;
 507          }
 508  
 509          // Mark this detection routine as run.
 510          $this->detection['engine'] = true;
 511      }
 512  
 513      /**
 514       * Method to detect the accepted languages by the client.
 515       *
 516       * @param   mixed  $acceptLanguage  The client accept language string to parse.
 517       *
 518       * @return  void
 519       *
 520       * @since   1.0
 521       */
 522  	protected function detectLanguage($acceptLanguage)
 523      {
 524          // Parse the accepted encodings.
 525          $this->languages = array_map('trim', (array) explode(',', $acceptLanguage));
 526  
 527          // Mark this detection routine as run.
 528          $this->detection['acceptLanguage'] = true;
 529      }
 530  
 531      /**
 532       * Detects the client platform in a user agent string.
 533       *
 534       * @param   string  $userAgent  The user-agent string to parse.
 535       *
 536       * @return  void
 537       *
 538       * @since   1.0
 539       */
 540  	protected function detectPlatform($userAgent)
 541      {
 542          // Attempt to detect the client platform.
 543          if (stripos($userAgent, 'Windows') !== false)
 544          {
 545              $this->platform = self::WINDOWS;
 546  
 547              // Let's look at the specific mobile options in the Windows space.
 548              if (stripos($userAgent, 'Windows Phone') !== false)
 549              {
 550                  $this->mobile   = true;
 551                  $this->platform = self::WINDOWS_PHONE;
 552              }
 553              elseif (stripos($userAgent, 'Windows CE') !== false)
 554              {
 555                  $this->mobile   = true;
 556                  $this->platform = self::WINDOWS_CE;
 557              }
 558          }
 559          elseif (stripos($userAgent, 'iPhone') !== false)
 560          {
 561              // Interestingly 'iPhone' is present in all iOS devices so far including iPad and iPods.
 562              $this->mobile   = true;
 563              $this->platform = self::IPHONE;
 564  
 565              // Let's look at the specific mobile options in the iOS space.
 566              if (stripos($userAgent, 'iPad') !== false)
 567              {
 568                  $this->platform = self::IPAD;
 569              }
 570              elseif (stripos($userAgent, 'iPod') !== false)
 571              {
 572                  $this->platform = self::IPOD;
 573              }
 574          }
 575          elseif (stripos($userAgent, 'iPad') !== false)
 576          {
 577              // In case where iPhone is not mentioed in iPad user agent string
 578              $this->mobile   = true;
 579              $this->platform = self::IPAD;
 580          }
 581          elseif (stripos($userAgent, 'iPod') !== false)
 582          {
 583              // In case where iPhone is not mentioed in iPod user agent string
 584              $this->mobile   = true;
 585              $this->platform = self::IPOD;
 586          }
 587          elseif (preg_match('/macintosh|mac os x/i', $userAgent))
 588          {
 589              // This has to come after the iPhone check because mac strings are also present in iOS devices.
 590              $this->platform = self::MAC;
 591          }
 592          elseif (stripos($userAgent, 'Blackberry') !== false)
 593          {
 594              $this->mobile   = true;
 595              $this->platform = self::BLACKBERRY;
 596          }
 597          elseif (stripos($userAgent, 'Android') !== false)
 598          {
 599              $this->mobile   = true;
 600              $this->platform = self::ANDROID;
 601  
 602              /*
 603               * Attempt to distinguish between Android phones and tablets
 604               * There is no totally foolproof method but certain rules almost always hold
 605               *   Android 3.x is only used for tablets
 606               *   Some devices and browsers encourage users to change their UA string to include Tablet.
 607               *   Google encourages manufacturers to exclude the string Mobile from tablet device UA strings.
 608               *   In some modes Kindle Android devices include the string Mobile but they include the string Silk.
 609               */
 610              if (stripos($userAgent, 'Android 3') !== false || stripos($userAgent, 'Tablet') !== false
 611                  || stripos($userAgent, 'Mobile') === false || stripos($userAgent, 'Silk') !== false)
 612              {
 613                  $this->platform = self::ANDROIDTABLET;
 614              }
 615          }
 616          elseif (stripos($userAgent, 'Linux') !== false)
 617          {
 618              $this->platform = self::LINUX;
 619          }
 620  
 621          // Mark this detection routine as run.
 622          $this->detection['platform'] = true;
 623      }
 624  
 625      /**
 626       * Determines if the browser is a robot or not.
 627       *
 628       * @param   string  $userAgent  The user-agent string to parse.
 629       *
 630       * @return  void
 631       *
 632       * @since   1.0
 633       */
 634  	protected function detectRobot($userAgent)
 635      {
 636          $this->robot = (bool) preg_match('/http|bot|robot|spider|crawler|curl|^$/i', $userAgent);
 637  
 638          $this->detection['robot'] = true;
 639      }
 640  
 641      /**
 642       * Fills internal array of headers
 643       *
 644       * @return  void
 645       *
 646       * @since   1.3.0
 647       */
 648  	protected function detectHeaders()
 649      {
 650          if (\function_exists('getallheaders'))
 651          {
 652              // If php is working under Apache, there is a special function
 653              $this->headers = getallheaders();
 654          }
 655          else
 656          {
 657              // Else we fill headers from $_SERVER variable
 658              $this->headers = [];
 659  
 660              foreach ($_SERVER as $name => $value)
 661              {
 662                  if (substr($name, 0, 5) == 'HTTP_')
 663                  {
 664                      $this->headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
 665                  }
 666              }
 667          }
 668  
 669          // Mark this detection routine as run.
 670          $this->detection['headers'] = true;
 671      }
 672  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer