Source for file client.php

Documentation is available at client.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Platform
  4.  * @subpackage  Application
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE
  8.  */
  9.  
  10. defined('JPATH_PLATFORM'or die;
  11.  
  12. /**
  13.  * Class to model a Web Client.
  14.  *
  15.  * @property-read  integer  $platform        The detected platform on which the web client runs.
  16.  * @property-read  boolean  $mobile          True if the web client is a mobile device.
  17.  * @property-read  integer  $engine          The detected rendering engine used by the web client.
  18.  * @property-read  integer  $browser         The detected browser used by the web client.
  19.  * @property-read  string   $browserVersion  The detected browser version used by the web client.
  20.  * @property-read  array    $languages       The priority order detected accepted languages for the client.
  21.  * @property-read  array    $encodings       The priority order detected accepted encodings for the client.
  22.  * @property-read  string   $userAgent       The web client's user agent string.
  23.  * @property-read  string   $acceptEncoding  The web client's accepted encoding string.
  24.  * @property-read  string   $acceptLanguage  The web client's accepted languages string.
  25.  * @property-read  array    $detection       An array of flags determining whether or not a detection routine has been run.
  26.  * @property-read  boolean  $robot           True if the web client is a robot
  27.  *
  28.  * @package     Joomla.Platform
  29.  * @subpackage  Application
  30.  * @since       12.1
  31.  */
  32. {
  33.     const WINDOWS 1;
  34.     const WINDOWS_PHONE 2;
  35.     const WINDOWS_CE 3;
  36.     const IPHONE 4;
  37.     const IPAD 5;
  38.     const IPOD 6;
  39.     const MAC 7;
  40.     const BLACKBERRY 8;
  41.     const ANDROID 9;
  42.     const LINUX 10;
  43.     const TRIDENT 11;
  44.     const WEBKIT 12;
  45.     const GECKO 13;
  46.     const PRESTO 14;
  47.     const KHTML 15;
  48.     const AMAYA 16;
  49.     const IE 17;
  50.     const FIREFOX 18;
  51.     const CHROME 19;
  52.     const SAFARI 20;
  53.     const OPERA 21;
  54.     const ANDROIDTABLET 22;
  55.  
  56.     /**
  57.      * @var    integer  The detected platform on which the web client runs.
  58.      * @since  12.1
  59.      */
  60.     protected $platform;
  61.  
  62.     /**
  63.      * @var    boolean  True if the web client is a mobile device.
  64.      * @since  12.1
  65.      */
  66.     protected $mobile = false;
  67.  
  68.     /**
  69.      * @var    integer  The detected rendering engine used by the web client.
  70.      * @since  12.1
  71.      */
  72.     protected $engine;
  73.  
  74.     /**
  75.      * @var    integer  The detected browser used by the web client.
  76.      * @since  12.1
  77.      */
  78.     protected $browser;
  79.  
  80.     /**
  81.      * @var    string  The detected browser version used by the web client.
  82.      * @since  12.1
  83.      */
  84.     protected $browserVersion;
  85.  
  86.     /**
  87.      * @var    array  The priority order detected accepted languages for the client.
  88.      * @since  12.1
  89.      */
  90.     protected $languages = array();
  91.  
  92.     /**
  93.      * @var    array  The priority order detected accepted encodings for the client.
  94.      * @since  12.1
  95.      */
  96.     protected $encodings = array();
  97.  
  98.     /**
  99.      * @var    string  The web client's user agent string.
  100.      * @since  12.1
  101.      */
  102.     protected $userAgent;
  103.  
  104.     /**
  105.      * @var    string  The web client's accepted encoding string.
  106.      * @since  12.1
  107.      */
  108.     protected $acceptEncoding;
  109.  
  110.     /**
  111.      * @var    string  The web client's accepted languages string.
  112.      * @since  12.1
  113.      */
  114.     protected $acceptLanguage;
  115.  
  116.     /**
  117.      * @var    boolean  True if the web client is a robot.
  118.      * @since  12.3
  119.      */
  120.     protected $robot = false;
  121.  
  122.     /**
  123.      * @var    array  An array of flags determining whether or not a detection routine has been run.
  124.      * @since  12.1
  125.      */
  126.     protected $detection = array();
  127.  
  128.     /**
  129.      * Class constructor.
  130.      *
  131.      * @param   string  $userAgent       The optional user-agent string to parse.
  132.      * @param   string  $acceptEncoding  The optional client accept encoding string to parse.
  133.      * @param   string  $acceptLanguage  The optional client accept language string to parse.
  134.      *
  135.      * @since   12.1
  136.      */
  137.     public function __construct($userAgent null$acceptEncoding null$acceptLanguage null)
  138.     {
  139.         // If no explicit user agent string was given attempt to use the implicit one from server environment.
  140.         if (empty($userAgent&& isset($_SERVER['HTTP_USER_AGENT']))
  141.         {
  142.             $this->userAgent = $_SERVER['HTTP_USER_AGENT'];
  143.         }
  144.         else
  145.         {
  146.             $this->userAgent = $userAgent;
  147.         }
  148.  
  149.         // If no explicit acceptable encoding string was given attempt to use the implicit one from server environment.
  150.         if (empty($acceptEncoding&& isset($_SERVER['HTTP_ACCEPT_ENCODING']))
  151.         {
  152.             $this->acceptEncoding = $_SERVER['HTTP_ACCEPT_ENCODING'];
  153.         }
  154.         else
  155.         {
  156.             $this->acceptEncoding = $acceptEncoding;
  157.         }
  158.  
  159.         // If no explicit acceptable languages string was given attempt to use the implicit one from server environment.
  160.         if (empty($acceptLanguage&& isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
  161.         {
  162.             $this->acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
  163.         }
  164.         else
  165.         {
  166.             $this->acceptLanguage = $acceptLanguage;
  167.         }
  168.     }
  169.  
  170.     /**
  171.      * Magic method to get an object property's value by name.
  172.      *
  173.      * @param   string  $name  Name of the property for which to return a value.
  174.      *
  175.      * @return  mixed  The requested value if it exists.
  176.      *
  177.      * @since   12.1
  178.      */
  179.     public function __get($name)
  180.     {
  181.         switch ($name)
  182.         {
  183.             case 'mobile':
  184.             case 'platform':
  185.                 if (empty($this->detection['platform']))
  186.                 {
  187.                     $this->detectPlatform($this->userAgent);
  188.                 }
  189.                 break;
  190.  
  191.             case 'engine':
  192.                 if (empty($this->detection['engine']))
  193.                 {
  194.                     $this->detectEngine($this->userAgent);
  195.                 }
  196.                 break;
  197.  
  198.             case 'browser':
  199.             case 'browserVersion':
  200.                 if (empty($this->detection['browser']))
  201.                 {
  202.                     $this->detectBrowser($this->userAgent);
  203.                 }
  204.                 break;
  205.  
  206.             case 'languages':
  207.                 if (empty($this->detection['acceptLanguage']))
  208.                 {
  209.                     $this->detectLanguage($this->acceptLanguage);
  210.                 }
  211.                 break;
  212.  
  213.             case 'encodings':
  214.                 if (empty($this->detection['acceptEncoding']))
  215.                 {
  216.                     $this->detectEncoding($this->acceptEncoding);
  217.                 }
  218.                 break;
  219.  
  220.             case 'robot':
  221.                 if (empty($this->detection['robot']))
  222.                 {
  223.                     $this->detectRobot($this->userAgent);
  224.                 }
  225.                 break;
  226.         }
  227.  
  228.         // Return the property if it exists.
  229.         if (isset($this->$name))
  230.         {
  231.             return $this->$name;
  232.         }
  233.     }
  234.  
  235.     /**
  236.      * Detects the client browser and version in a user agent string.
  237.      *
  238.      * @param   string  $userAgent  The user-agent string to parse.
  239.      *
  240.      * @return  void 
  241.      *
  242.      * @since   12.1
  243.      */
  244.     protected function detectBrowser($userAgent)
  245.     {
  246.         // Attempt to detect the browser type.  Obviously we are only worried about major browsers.
  247.         if ((stripos($userAgent'MSIE'!== false&& (stripos($userAgent'Opera'=== false))
  248.         {
  249.             $this->browser = self::IE;
  250.             $patternBrowser 'MSIE';
  251.         }
  252.         elseif ((stripos($userAgent'Firefox'!== false&& (stripos($userAgent'like Firefox'=== false))
  253.         {
  254.             $this->browser = self::FIREFOX;
  255.             $patternBrowser 'Firefox';
  256.         }
  257.         elseif (stripos($userAgent'Chrome'!== false)
  258.         {
  259.             $this->browser = self::CHROME;
  260.             $patternBrowser 'Chrome';
  261.         }
  262.         elseif (stripos($userAgent'Safari'!== false)
  263.         {
  264.             $this->browser = self::SAFARI;
  265.             $patternBrowser 'Safari';
  266.         }
  267.         elseif (stripos($userAgent'Opera'!== false)
  268.         {
  269.             $this->browser = self::OPERA;
  270.             $patternBrowser 'Opera';
  271.         }
  272.  
  273.         // If we detected a known browser let's attempt to determine the version.
  274.         if ($this->browser)
  275.         {
  276.             // Build the REGEX pattern to match the browser version string within the user agent string.
  277.             $pattern '#(?<browser>Version|' $patternBrowser ')[/ ]+(?<version>[0-9.|a-zA-Z.]*)#';
  278.  
  279.             // Attempt to find version strings in the user agent string.
  280.             $matches array();
  281.  
  282.             if (preg_match_all($pattern$userAgent$matches))
  283.             {
  284.                 // Do we have both a Version and browser match?
  285.                 if (count($matches['browser']== 2)
  286.                 {
  287.                     // See whether Version or browser came first, and use the number accordingly.
  288.                     if (strripos($userAgent'Version'strripos($userAgent$patternBrowser))
  289.                     {
  290.                         $this->browserVersion = $matches['version'][0];
  291.                     }
  292.                     else
  293.                     {
  294.                         $this->browserVersion = $matches['version'][1];
  295.                     }
  296.                 }
  297.                 elseif (count($matches['browser']2)
  298.                 {
  299.                     $key array_search('Version'$matches['browser']);
  300.  
  301.                     if ($key)
  302.                     {
  303.                         $this->browserVersion = $matches['version'][$key];
  304.                     }
  305.                 }
  306.                 // We only have a Version or a browser so use what we have.
  307.                 else
  308.                 {
  309.                     $this->browserVersion = $matches['version'][0];
  310.                 }
  311.             }
  312.         }
  313.  
  314.         // Mark this detection routine as run.
  315.         $this->detection['browser'true;
  316.     }
  317.  
  318.     /**
  319.      * Method to detect the accepted response encoding by the client.
  320.      *
  321.      * @param   string  $acceptEncoding  The client accept encoding string to parse.
  322.      *
  323.      * @return  void 
  324.      *
  325.      * @since   12.1
  326.      */
  327.     protected function detectEncoding($acceptEncoding)
  328.     {
  329.         // Parse the accepted encodings.
  330.         $this->encodings = array_map('trim'(array) explode(','$acceptEncoding));
  331.  
  332.         // Mark this detection routine as run.
  333.         $this->detection['acceptEncoding'true;
  334.     }
  335.  
  336.     /**
  337.      * Detects the client rendering engine in a user agent string.
  338.      *
  339.      * @param   string  $userAgent  The user-agent string to parse.
  340.      *
  341.      * @return  void 
  342.      *
  343.      * @since   12.1
  344.      */
  345.     protected function detectEngine($userAgent)
  346.     {
  347.         // Attempt to detect the client engine -- starting with the most popular ... for now.
  348.         if (stripos($userAgent'MSIE'!== false || stripos($userAgent'Trident'!== false)
  349.         {
  350.             $this->engine = self::TRIDENT;
  351.         }
  352.         // Evidently blackberry uses WebKit and doesn't necessarily report it.  Bad RIM.
  353.         elseif (stripos($userAgent'AppleWebKit'!== false || stripos($userAgent'blackberry'!== false)
  354.         {
  355.             $this->engine = self::WEBKIT;
  356.         }
  357.         // We have to check for like Gecko because some other browsers spoof Gecko.
  358.         elseif (stripos($userAgent'Gecko'!== false && stripos($userAgent'like Gecko'=== false)
  359.         {
  360.             $this->engine = self::GECKO;
  361.         }
  362.         // Sometimes Opera browsers don't say Presto.
  363.         elseif (stripos($userAgent'Opera'!== false || stripos($userAgent'Presto'!== false)
  364.         {
  365.             $this->engine = self::PRESTO;
  366.         }
  367.         // *sigh*
  368.         elseif (stripos($userAgent'KHTML'!== false)
  369.         {
  370.             $this->engine = self::KHTML;
  371.         }
  372.         // Lesser known engine but it finishes off the major list from Wikipedia :-)
  373.         elseif (stripos($userAgent'Amaya'!== false)
  374.         {
  375.             $this->engine = self::AMAYA;
  376.         }
  377.  
  378.         // Mark this detection routine as run.
  379.         $this->detection['engine'true;
  380.     }
  381.  
  382.     /**
  383.      * Method to detect the accepted languages by the client.
  384.      *
  385.      * @param   mixed  $acceptLanguage  The client accept language string to parse.
  386.      *
  387.      * @return  void 
  388.      *
  389.      * @since   12.1
  390.      */
  391.     protected function detectLanguage($acceptLanguage)
  392.     {
  393.         // Parse the accepted encodings.
  394.         $this->languages = array_map('trim'(array) explode(','$acceptLanguage));
  395.  
  396.         // Mark this detection routine as run.
  397.         $this->detection['acceptLanguage'true;
  398.     }
  399.  
  400.     /**
  401.      * Detects the client platform in a user agent string.
  402.      *
  403.      * @param   string  $userAgent  The user-agent string to parse.
  404.      *
  405.      * @return  void 
  406.      *
  407.      * @since   12.1
  408.      */
  409.     protected function detectPlatform($userAgent)
  410.     {
  411.         // Attempt to detect the client platform.
  412.         if (stripos($userAgent'Windows'!== false)
  413.         {
  414.             $this->platform = self::WINDOWS;
  415.  
  416.             // Let's look at the specific mobile options in the Windows space.
  417.             if (stripos($userAgent'Windows Phone'!== false)
  418.             {
  419.                 $this->mobile = true;
  420.                 $this->platform = self::WINDOWS_PHONE;
  421.             }
  422.             elseif (stripos($userAgent'Windows CE'!== false)
  423.             {
  424.                 $this->mobile = true;
  425.                 $this->platform = self::WINDOWS_CE;
  426.             }
  427.         }
  428.         // Interestingly 'iPhone' is present in all iOS devices so far including iPad and iPods.
  429.         elseif (stripos($userAgent'iPhone'!== false)
  430.         {
  431.             $this->mobile = true;
  432.             $this->platform = self::IPHONE;
  433.  
  434.             // Let's look at the specific mobile options in the iOS space.
  435.             if (stripos($userAgent'iPad'!== false)
  436.             {
  437.                 $this->platform = self::IPAD;
  438.             }
  439.             elseif (stripos($userAgent'iPod'!== false)
  440.             {
  441.                 $this->platform = self::IPOD;
  442.             }
  443.         }
  444.             // In case where iPhone is not mentioed in iPad user agent string
  445.             elseif (stripos($userAgent'iPad'!== false)
  446.             {
  447.                 $this->mobile = true;
  448.                 $this->platform = self::IPAD;
  449.             }
  450.             // In case where iPhone is not mentioed in iPod user agent string
  451.             elseif (stripos($userAgent'iPod'!== false)
  452.             {
  453.                 $this->mobile = true;
  454.                 $this->platform = self::IPOD;
  455.             }
  456.         // This has to come after the iPhone check because mac strings are also present in iOS devices.
  457.         elseif (preg_match('/macintosh|mac os x/i'$userAgent))
  458.         {
  459.             $this->platform = self::MAC;
  460.         }
  461.         elseif (stripos($userAgent'Blackberry'!== false)
  462.         {
  463.             $this->mobile = true;
  464.             $this->platform = self::BLACKBERRY;
  465.         }
  466.         elseif (stripos($userAgent'Android'!== false)
  467.         {
  468.             $this->mobile = true;
  469.             $this->platform = self::ANDROID;
  470.             /**
  471.              * Attempt to distinguish between Android phones and tablets
  472.              * There is no totally foolproof method but certain rules almost always hold
  473.              *   Android 3.x is only used for tablets
  474.              *   Some devices and browsers encourage users to change their UA string to include Tablet.
  475.              *   Google encourages manufacturers to exclude the string Mobile from tablet device UA strings.
  476.              *   In some modes Kindle Android devices include the string Mobile but they include the string Silk.
  477.              */
  478.             if (stripos($userAgent'Android 3'!== false || stripos($userAgent'Tablet'!== false
  479.                 || stripos($userAgent'Mobile'=== false || stripos($userAgent'Silk'!== false )
  480.             {
  481.                 $this->platform = self::ANDROIDTABLET;
  482.             }
  483.         }
  484.         elseif (stripos($userAgent'Linux'!== false)
  485.         {
  486.             $this->platform = self::LINUX;
  487.         }
  488.  
  489.         // Mark this detection routine as run.
  490.         $this->detection['platform'true;
  491.     }
  492.  
  493.     /**
  494.      * Determines if the browser is a robot or not.
  495.      *
  496.      * @param   string  $userAgent  The user-agent string to parse.
  497.      *
  498.      * @return  void 
  499.      *
  500.      * @since   12.3
  501.      */
  502.     protected function detectRobot($userAgent)
  503.     {
  504.         if (preg_match('/http|bot|robot|spider|crawler|curl|^$/i'$userAgent))
  505.         {
  506.             $this->robot = true;
  507.         }
  508.         else
  509.         {
  510.             $this->robot = false;
  511.         }
  512.  
  513.         $this->detection['robot'true;
  514.     }
  515. }

Documentation generated on Tue, 19 Nov 2013 14:55:50 +0100 by phpDocumentor 1.4.3