Joomla Platform  13.1
Documentation des API du framework Joomla Platform
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Pages
browser.php
Aller à la documentation de ce fichier.
1 <?php
2 /**
3  * @package Joomla.Platform
4  * @subpackage Environment
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  * Browser class, provides capability information about the current web client.
14  *
15  * Browser identification is performed by examining the HTTP_USER_AGENT
16  * environment variable provided by the web server.
17  *
18  * This class has many influences from the lib/Browser.php code in
19  * version 3 of Horde by Chuck Hagenbuch and Jon Parise.
20  *
21  * @package Joomla.Platform
22  * @subpackage Environment
23  * @since 11.1
24  */
25 class JBrowser
26 {
27  /**
28  * @var integer Major version number
29  * @since 12.1
30  */
31  protected $majorVersion = 0;
32 
33  /**
34  * @var integer Minor version number
35  * @since 12.1
36  */
37  protected $minorVersion = 0;
38 
39  /**
40  * @var string Browser name.
41  * @since 12.1
42  */
43  protected $browser = '';
44 
45  /**
46  * @var string Full user agent string.
47  * @since 12.1
48  */
49  protected $agent = '';
50 
51  /**
52  * @var string Lower-case user agent string
53  * @since 12.1
54  */
55  protected $lowerAgent = '';
56 
57  /**
58  * @var string HTTP_ACCEPT string.
59  * @since 12.1
60  */
61  protected $accept = '';
62 
63  /**
64  * @var array Parsed HTTP_ACCEPT string
65  * @since 12.1
66  */
67  protected $acceptParsed = array();
68 
69  /**
70  * @var string Platform the browser is running on
71  * @since 12.1
72  */
73  protected $platform = '';
74 
75  /**
76  * @var array Known robots.
77  * @since 12.1
78  */
79  protected $robots = array(
80  /* The most common ones. */
81  'Googlebot',
82  'msnbot',
83  'Slurp',
84  'Yahoo',
85  /* The rest alphabetically. */
86  'Arachnoidea',
87  'ArchitextSpider',
88  'Ask Jeeves',
89  'B-l-i-t-z-Bot',
90  'Baiduspider',
91  'BecomeBot',
92  'cfetch',
93  'ConveraCrawler',
94  'ExtractorPro',
95  'FAST-WebCrawler',
96  'FDSE robot',
97  'fido',
98  'geckobot',
99  'Gigabot',
100  'Girafabot',
101  'grub-client',
102  'Gulliver',
103  'HTTrack',
104  'ia_archiver',
105  'InfoSeek',
106  'kinjabot',
107  'KIT-Fireball',
108  'larbin',
109  'LEIA',
110  'lmspider',
111  'Lycos_Spider',
112  'Mediapartners-Google',
113  'MuscatFerret',
114  'NaverBot',
115  'OmniExplorer_Bot',
116  'polybot',
117  'Pompos',
118  'Scooter',
119  'Teoma',
120  'TheSuBot',
121  'TurnitinBot',
122  'Ultraseek',
123  'ViolaBot',
124  'webbandit',
125  'www.almaden.ibm.com/cs/crawler',
126  'ZyBorg');
127 
128  /**
129  * @var boolean Is this a mobile browser?
130  * @since 12.1
131  */
132  protected $mobile = false;
133 
134  /**
135  * List of viewable image MIME subtypes.
136  * This list of viewable images works for IE and Netscape/Mozilla.
137  *
138  * @var array
139  * @since 12.1
140  */
141  protected $images = array('jpeg', 'gif', 'png', 'pjpeg', 'x-png', 'bmp');
142 
143  /**
144  * @var array JBrowser instances container.
145  * @since 11.3
146  */
147  protected static $instances = array();
148 
149  /**
150  * Create a browser instance (constructor).
151  *
152  * @param string $userAgent The browser string to parse.
153  * @param string $accept The HTTP_ACCEPT settings to use.
154  *
155  * @since 11.1
156  */
157  public function __construct($userAgent = null, $accept = null)
158  {
159  $this->match($userAgent, $accept);
160  }
161 
162  /**
163  * Returns the global Browser object, only creating it
164  * if it doesn't already exist.
165  *
166  * @param string $userAgent The browser string to parse.
167  * @param string $accept The HTTP_ACCEPT settings to use.
168  *
169  * @return JBrowser The Browser object.
170  *
171  * @since 11.1
172  */
173  public static function getInstance($userAgent = null, $accept = null)
174  {
175  $signature = serialize(array($userAgent, $accept));
176 
177  if (empty(self::$instances[$signature]))
178  {
179  self::$instances[$signature] = new JBrowser($userAgent, $accept);
180  }
181 
182  return self::$instances[$signature];
183  }
184 
185  /**
186  * Parses the user agent string and inititializes the object with
187  * all the known features and quirks for the given browser.
188  *
189  * @param string $userAgent The browser string to parse.
190  * @param string $accept The HTTP_ACCEPT settings to use.
191  *
192  * @return void
193  *
194  * @since 11.1
195  */
196  public function match($userAgent = null, $accept = null)
197  {
198  // Set our agent string.
199  if (is_null($userAgent))
200  {
201  if (isset($_SERVER['HTTP_USER_AGENT']))
202  {
203  $this->agent = trim($_SERVER['HTTP_USER_AGENT']);
204  }
205  }
206  else
207  {
208  $this->agent = $userAgent;
209  }
210 
211  $this->lowerAgent = strtolower($this->agent);
212 
213  // Set our accept string.
214  if (is_null($accept))
215  {
216  if (isset($_SERVER['HTTP_ACCEPT']))
217  {
218  $this->accept = strtolower(trim($_SERVER['HTTP_ACCEPT']));
219  }
220  }
221  else
222  {
223  $this->accept = strtolower($accept);
224  }
225 
226  if (!empty($this->agent))
227  {
228  $this->_setPlatform();
229 
230  if (strpos($this->lowerAgent, 'mobileexplorer') !== false
231  || strpos($this->lowerAgent, 'openwave') !== false
232  || strpos($this->lowerAgent, 'opera mini') !== false
233  || strpos($this->lowerAgent, 'opera mobi') !== false
234  || strpos($this->lowerAgent, 'operamini') !== false)
235  {
236  $this->mobile = true;
237  }
238  elseif (preg_match('|Opera[/ ]([0-9.]+)|', $this->agent, $version))
239  {
240  $this->setBrowser('opera');
241  list ($this->majorVersion, $this->minorVersion) = explode('.', $version[1]);
242 
243  /* Due to changes in Opera UA, we need to check Version/xx.yy,
244  * but only if version is > 9.80. See: http://dev.opera.com/articles/view/opera-ua-string-changes/ */
245  if ($this->majorVersion == 9 && $this->minorVersion >= 80)
246  {
247  $this->identifyBrowserVersion();
248  }
249  }
250  elseif (preg_match('|Chrome[/ ]([0-9.]+)|', $this->agent, $version))
251  {
252  $this->setBrowser('chrome');
253  list ($this->majorVersion, $this->minorVersion) = explode('.', $version[1]);
254  }
255  elseif (preg_match('|CrMo[/ ]([0-9.]+)|', $this->agent, $version))
256  {
257  $this->setBrowser('chrome');
258  list ($this->majorVersion, $this->minorVersion) = explode('.', $version[1]);
259  }
260  elseif (preg_match('|CriOS[/ ]([0-9.]+)|', $this->agent, $version))
261  {
262  $this->setBrowser('chrome');
263  list ($this->majorVersion, $this->minorVersion) = explode('.', $version[1]);
264  $this->mobile = true;
265  }
266  elseif (strpos($this->lowerAgent, 'elaine/') !== false
267  || strpos($this->lowerAgent, 'palmsource') !== false
268  || strpos($this->lowerAgent, 'digital paths') !== false)
269  {
270  $this->setBrowser('palm');
271  $this->mobile = true;
272  }
273  elseif ((preg_match('|MSIE ([0-9.]+)|', $this->agent, $version)) || (preg_match('|Internet Explorer/([0-9.]+)|', $this->agent, $version)))
274  {
275  $this->setBrowser('msie');
276 
277  if (strpos($version[1], '.') !== false)
278  {
279  list ($this->majorVersion, $this->minorVersion) = explode('.', $version[1]);
280  }
281  else
282  {
283  $this->majorVersion = $version[1];
284  $this->minorVersion = 0;
285  }
286 
287  /* Some Handhelds have their screen resolution in the
288  * user agent string, which we can use to look for
289  * mobile agents.
290  */
291  if (preg_match('/; (120x160|240x280|240x320|320x320)\)/', $this->agent))
292  {
293  $this->mobile = true;
294  }
295  }
296  elseif (preg_match('|amaya/([0-9.]+)|', $this->agent, $version))
297  {
298  $this->setBrowser('amaya');
299  $this->majorVersion = $version[1];
300 
301  if (isset($version[2]))
302  {
303  $this->minorVersion = $version[2];
304  }
305  }
306  elseif (preg_match('|ANTFresco/([0-9]+)|', $this->agent, $version))
307  {
308  $this->setBrowser('fresco');
309  }
310  elseif (strpos($this->lowerAgent, 'avantgo') !== false)
311  {
312  $this->setBrowser('avantgo');
313  $this->mobile = true;
314  }
315  elseif (preg_match('|Konqueror/([0-9]+)|', $this->agent, $version) || preg_match('|Safari/([0-9]+)\.?([0-9]+)?|', $this->agent, $version))
316  {
317  // Konqueror and Apple's Safari both use the KHTML
318  // rendering engine.
319  $this->setBrowser('konqueror');
320  $this->majorVersion = $version[1];
321 
322  if (isset($version[2]))
323  {
324  $this->minorVersion = $version[2];
325  }
326 
327  if (strpos($this->agent, 'Safari') !== false && $this->majorVersion >= 60)
328  {
329  // Safari.
330  $this->setBrowser('safari');
331  $this->identifyBrowserVersion();
332  }
333  }
334  elseif (preg_match('|Mozilla/([0-9.]+)|', $this->agent, $version))
335  {
336  $this->setBrowser('mozilla');
337 
338  list ($this->majorVersion, $this->minorVersion) = explode('.', $version[1]);
339  }
340  elseif (preg_match('|Lynx/([0-9]+)|', $this->agent, $version))
341  {
342  $this->setBrowser('lynx');
343  }
344  elseif (preg_match('|Links \(([0-9]+)|', $this->agent, $version))
345  {
346  $this->setBrowser('links');
347  }
348  elseif (preg_match('|HotJava/([0-9]+)|', $this->agent, $version))
349  {
350  $this->setBrowser('hotjava');
351  }
352  elseif (strpos($this->agent, 'UP/') !== false || strpos($this->agent, 'UP.B') !== false || strpos($this->agent, 'UP.L') !== false)
353  {
354  $this->setBrowser('up');
355  $this->mobile = true;
356  }
357  elseif (strpos($this->agent, 'Xiino/') !== false)
358  {
359  $this->setBrowser('xiino');
360  $this->mobile = true;
361  }
362  elseif (strpos($this->agent, 'Palmscape/') !== false)
363  {
364  $this->setBrowser('palmscape');
365  $this->mobile = true;
366  }
367  elseif (strpos($this->agent, 'Nokia') !== false)
368  {
369  $this->setBrowser('nokia');
370  $this->mobile = true;
371  }
372  elseif (strpos($this->agent, 'Ericsson') !== false)
373  {
374  $this->setBrowser('ericsson');
375  $this->mobile = true;
376  }
377  elseif (strpos($this->lowerAgent, 'wap') !== false)
378  {
379  $this->setBrowser('wap');
380  $this->mobile = true;
381  }
382  elseif (strpos($this->lowerAgent, 'docomo') !== false || strpos($this->lowerAgent, 'portalmmm') !== false)
383  {
384  $this->setBrowser('imode');
385  $this->mobile = true;
386  }
387  elseif (strpos($this->agent, 'BlackBerry') !== false)
388  {
389  $this->setBrowser('blackberry');
390  $this->mobile = true;
391  }
392  elseif (strpos($this->agent, 'MOT-') !== false)
393  {
394  $this->setBrowser('motorola');
395  $this->mobile = true;
396  }
397  elseif (strpos($this->lowerAgent, 'j-') !== false)
398  {
399  $this->setBrowser('mml');
400  $this->mobile = true;
401  }
402  }
403  }
404 
405  /**
406  * Match the platform of the browser.
407  *
408  * This is a pretty simplistic implementation, but it's intended
409  * to let us tell what line breaks to send, so it's good enough
410  * for its purpose.
411  *
412  * @return void
413  *
414  * @since 11.1
415  */
416  protected function _setPlatform()
417  {
418  if (strpos($this->lowerAgent, 'wind') !== false)
419  {
420  $this->platform = 'win';
421  }
422  elseif (strpos($this->lowerAgent, 'mac') !== false)
423  {
424  $this->platform = 'mac';
425  }
426  else
427  {
428  $this->platform = 'unix';
429  }
430  }
431 
432  /**
433  * Return the currently matched platform.
434  *
435  * @return string The user's platform.
436  *
437  * @since 11.1
438  */
439  public function getPlatform()
440  {
441  return $this->platform;
442  }
443 
444  /**
445  * Set browser version, not by engine version
446  * Fallback to use when no other method identify the engine version
447  *
448  * @return void
449  *
450  * @since 11.1
451  */
452  protected function identifyBrowserVersion()
453  {
454  if (preg_match('|Version[/ ]([0-9.]+)|', $this->agent, $version))
455  {
456  list ($this->majorVersion, $this->minorVersion) = explode('.', $version[1]);
457 
458  return;
459  }
460 
461  // Can't identify browser version
462  $this->majorVersion = 0;
463  $this->minorVersion = 0;
464  JLog::add("Can't identify browser version. Agent: " . $this->agent, JLog::NOTICE);
465  }
466 
467  /**
468  * Sets the current browser.
469  *
470  * @param string $browser The browser to set as current.
471  *
472  * @return void
473  *
474  * @since 11.1
475  */
476  public function setBrowser($browser)
477  {
478  $this->browser = $browser;
479  }
480 
481  /**
482  * Retrieve the current browser.
483  *
484  * @return string The current browser.
485  *
486  * @since 11.1
487  */
488  public function getBrowser()
489  {
490  return $this->browser;
491  }
492 
493  /**
494  * Retrieve the current browser's major version.
495  *
496  * @return integer The current browser's major version
497  *
498  * @since 11.1
499  */
500  public function getMajor()
501  {
502  return $this->majorVersion;
503  }
504 
505  /**
506  * Retrieve the current browser's minor version.
507  *
508  * @return integer The current browser's minor version.
509  *
510  * @since 11.1
511  */
512  public function getMinor()
513  {
514  return $this->minorVersion;
515  }
516 
517  /**
518  * Retrieve the current browser's version.
519  *
520  * @return string The current browser's version.
521  *
522  * @since 11.1
523  */
524  public function getVersion()
525  {
526  return $this->majorVersion . '.' . $this->minorVersion;
527  }
528 
529  /**
530  * Return the full browser agent string.
531  *
532  * @return string The browser agent string
533  *
534  * @since 11.1
535  */
536  public function getAgentString()
537  {
538  return $this->agent;
539  }
540 
541  /**
542  * Returns the server protocol in use on the current server.
543  *
544  * @return string The HTTP server protocol version.
545  *
546  * @since 11.1
547  */
548  public function getHTTPProtocol()
549  {
550  if (isset($_SERVER['SERVER_PROTOCOL']))
551  {
552  if (($pos = strrpos($_SERVER['SERVER_PROTOCOL'], '/')))
553  {
554  return substr($_SERVER['SERVER_PROTOCOL'], $pos + 1);
555  }
556  }
557 
558  return null;
559  }
560 
561  /**
562  * Determines if a browser can display a given MIME type.
563  *
564  * Note that image/jpeg and image/pjpeg *appear* to be the same
565  * entity, but Mozilla doesn't seem to want to accept the latter.
566  * For our purposes, we will treat them the same.
567  *
568  * @param string $mimetype The MIME type to check.
569  *
570  * @return boolean True if the browser can display the MIME type.
571  *
572  * @since 11.1
573  */
574  public function isViewable($mimetype)
575  {
576  $mimetype = strtolower($mimetype);
577  list ($type, $subtype) = explode('/', $mimetype);
578 
579  if (!empty($this->accept))
580  {
581  $wildcard_match = false;
582 
583  if (strpos($this->accept, $mimetype) !== false)
584  {
585  return true;
586  }
587 
588  if (strpos($this->accept, '*/*') !== false)
589  {
590  $wildcard_match = true;
591 
592  if ($type != 'image')
593  {
594  return true;
595  }
596  }
597 
598  // Deal with Mozilla pjpeg/jpeg issue
599  if ($this->isBrowser('mozilla') && ($mimetype == 'image/pjpeg') && (strpos($this->accept, 'image/jpeg') !== false))
600  {
601  return true;
602  }
603 
604  if (!$wildcard_match)
605  {
606  return false;
607  }
608  }
609 
610  if (!$this->hasFeature('images') || ($type != 'image'))
611  {
612  return false;
613  }
614 
615  return (in_array($subtype, $this->images));
616  }
617 
618  /**
619  * Determine if the given browser is the same as the current.
620  *
621  * @param string $browser The browser to check.
622  *
623  * @return boolean Is the given browser the same as the current?
624  *
625  * @since 11.1
626  */
627  public function isBrowser($browser)
628  {
629  return ($this->browser === $browser);
630  }
631 
632  /**
633  * Determines if the browser is a robot or not.
634  *
635  * @return boolean True if browser is a known robot.
636  *
637  * @since 11.1
638  */
639  public function isRobot()
640  {
641  foreach ($this->robots as $robot)
642  {
643  if (strpos($this->agent, $robot) !== false)
644  {
645  return true;
646  }
647  }
648 
649  return false;
650  }
651 
652  /**
653  * Determines if the browser is mobile version or not.
654  *
655  * @return boolean True if browser is a known mobile version.
656  *
657  * @since 11.1
658  */
659  public function isMobile()
660  {
661  return $this->mobile;
662  }
663 
664  /**
665  * Determine if we are using a secure (SSL) connection.
666  *
667  * @return boolean True if using SSL, false if not.
668  *
669  * @since 11.1
670  * @deprecated 13.3 (Platform) & 4.0 (CMS) - Use the isSSLConnection method on the application object.
671  */
672  public function isSSLConnection()
673  {
674  JLog::add('JBrowser::isSSLConnection() is deprecated. Use the isSSLConnection method on the application object instead.',
675  JLog::WARNING, 'deprecated');
676 
677  return ((isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on')) || getenv('SSL_PROTOCOL_VERSION'));
678  }
679 }