Source for file browser.php

Documentation is available at browser.php


1 <?php
2
3 /**
4 * @copyright Copyright &copy; 2002-2003 Marco Von Ballmoos
5 * @author Marco Von Ballmoos <marco@earthli.com>
6 * @filesource
7 * @version 2.2.1
8 * @since 2.2.1
9 * @package webcore
10 * @subpackage util
11 */
12 /**************************************************************************
13
14 Copyright (c) 2002-2003 Marco Von Ballmoos
15
16 This file is part of earthli WebCore.
17
18 earthli WebCore is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation; either version 2 of the License, or
21 (at your option) any later version.
22
23 earthli WebCore is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with earthli WebCore; if not, write to the Free Software
30 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31
32 For more information about the earthli WebCore, visit:
33
34 http://www.earthli.com/software/webcore
35
36 ****************************************************************************/
36
37 /** Does the browser support DHTML? */
37
38 define ('Browser_DHTML', 1);
39 /** Does the browser support PNG images with alpha-transparency? */
39
40 define ('Browser_alpha_PNG', 2);
41 /** Does the browser support CSS Level 1? */
41
42 define ('Browser_CSS_1', 3);
43 /** Does the browser support Javascript? */
43
44 define ('Browser_JavaScript', 4);
45 /** Does the browser support setting/getting cookies? */
45
46 define ('Browser_cookie', 5);
47 /** Are HTML entities translated in textarea tags?.
48 * Some browsers translate HTML entities into their target characters before placing them in
49 * text-boxes. This is bad when you're editing content in which you've used entities directly.
50 * This property identifies those browsers, so the forms library can escape the entity characters
51 * to render properly.
52 * @see FORM::html_at() */
53 define ('Browser_preserves_entities_in_textbox', 8);
54 /** Does the browser support the Javascript document.clear command?.
55 * This allows a document to be cleared of text without closing the window.
56 * @see JS_CONSOLE_LOGGER */
57 define ('Browser_supports_document_clear', 9);
58 /** Does the browser support alpha PNG using behaviors?.
59 * This is a hideous hack for IE browsers to support alpha-PNG files using a DirectX api,
60 * but, sadly, only works if absolute dimensions are given with the image. */
60
61 define ('Browser_alpha_PNG_through_behaviors', 10);
62 /** Browser uses the Netscape 4 renderer. */
62
63 define ('Browser_netscape_4', 'netscape_4');
64 /** Browser uses the Gecko renderer.
65 * @see BROWSER::gecko_date() */
66 define ('Browser_gecko', 'gecko');
67 /** Browser uses the Konqueror/KHTML renderer. */
67
68 define ('Browser_konqueror', 'konqueror');
69 /** Browser uses the Opera renderer. */
69
70 define ('Browser_opera', 'opera');
71 /** Browser uses the WebTV renderer. */
71
72 define ('Browser_webtv', 'webtv');
73 /** Browser uses the Internet Explorer renderer. */
73
74 define ('Browser_ie', 'ie');
75 /** Browser uses the Omniweb renderer.
76 * Mac OS X only. */
76
77 define ('Browser_omniweb', 'omniweb');
78 /** Browser uses the Safari renderer.
79 * Derived from KHTML (Mac OS X only) */
79
80 define ('Browser_safari', 'safari');
81 /** Browser is running on Win32. */
81
82 define ('Browser_os_windows', 'windows');
83 /** Browser is running on MacOS (Classic or OS X). */
83
84 define ('Browser_os_mac', 'macos');
85 /** Browser is running on Linux (some form). */
85
86 define ('Browser_os_linux', 'linux');
87 /** Identifies the browser for this session.
88 * Identifies as much as possible of the browser name and version, OS name and version,
89 * and the renderer name and version. The renderer is then used to determine which
90 * capabilites are supported.
91 * @see BROWSER::is()
92 * @see BROWSER::supports() */
93 class BROWSER
94 {
95 /** User-agent string received in HTTP request.
96 * @var string */
97 var $user_agent_string;
98
99 function BROWSER ()
100 {
101 $this->user_agent_string = $_SERVER ['HTTP_USER_AGENT'];
102 $this->_normalized_ua = strtolower ($this->user_agent_string);
103 }
104
105 /** Identifies the technology used by this browser.
106 * This is often different than the name, since many browsers employ embedded
107 * renderers like Gecko, or are rebranded like Opera Composer browsers.
108 * @return string */
109 function renderer_name ()
110 {
111 $this->_ensure_loaded ();
112 return $this->_renderer_name;
113 }
114
115 /** Identifies the version of the technology used by this browser.
116 * This is the number used internall to identify whether a feature is supported.
117 * @see BROWSER::supports()
118 * @return string */
119 function renderer_version ()
120 {
121 $this->_ensure_loaded ();
122 return $this->_renderer_version;
123 }
124
125 /** Name of the browser.
126 * Not necessarily the same as the renderer name. AOL uses the IE engine or the
127 * Gecko engine, depending on version. MSN uses the IE engine.
128 * @return string */
129 function name ()
130 {
131 $this->_ensure_loaded ();
132 return $this->_name;
133 }
134
135 /** Version of the browser.
136 * Not necessarily the same as the renderer version. Largely useless identifier
137 * for determining feature support, but nice to use when showing a user which
138 * browser they are running. e.g. displaying 'MSN 7.0' instead of 'IE 5.5sp1'.
139 * @return string */
140 function version ()
141 {
142 $this->_ensure_loaded ();
143 return $this->_version;
144 }
145
146 /** Specific name of the operating system.
147 * @return string */
148 function system_name ()
149 {
150 $this->_ensure_loaded ();
151 return $this->_system_name;
152 }
153
154 /** Operating system version.
155 * This is specific, like Windows NT 5.1 (Windows 2000) will return 5.1, not 2000.
156 * @return string */
157 function system_version ()
158 {
159 $this->_ensure_loaded ();
160 return $this->_system_version;
161 }
162
163 /** Calculated system name.
164 * The most likely operating system derived from the user agent string.
165 * @return string */
166 function interpreted_system_name ()
167 {
168 $this->_ensure_loaded ();
169 return $this->_interpreted_system_name;
170 }
171
172 /** Fully formatted operating system id.
173 * Returns as much information about the operating system as possible.
174 * - Windows 5.1 will return Windows 5.1 (Windows 2000)
175 * - 'Linux i686 ... Debian/1.2.0' will return Debian 1.2.0 (Linux)
176 * @return string */
177 function system_id ()
178 {
179 $this->_ensure_loaded ();
180 if ($this->_system_name)
181 {
182 // favor the interpreted system name because it's capitalized more nicely.
183
184 if (strcasecmp ($this->_system_name, $this->_interpreted_system_name) == 0)
185 return "$this->_interpreted_system_name $this->_system_version";
186 else
187 return "$this->_system_name $this->_system_version ($this->_interpreted_system_name)";
188 }
189 else
190 return $this->_interpreted_system_name;
191 }
192
193 /** Build date of the browser, if built with Gecko.
194 * Gecko is the mozilla browser technology. Conforming user agent strings include
195 * the build date of the Gecko component. (Can be empty)
196 * @return DATE_TIME */
197 function gecko_date ()
198 {
199 $this->_ensure_loaded ();
200 return $this->_gecko_date;
201 }
202
203 /** Does the browser use this renderer or run on this operating system?.
204 * See the browser renderer/OS constants.
205 * @param integer $code
206 * @return bool */
207 function is ($code)
208 {
209 $this->_ensure_loaded ();
210 return ($code == $this->_renderer_id) || ($code == $this->_os_id);
211 }
212
213 /** Is the requested functionality supported?.
214 * See the browser functionality constants.
215 * @param integer $code
216 * @return bool */
217 function supports ($code)
218 {
219 $this->_ensure_loaded ();
220
221 switch ($code)
222 {
223 case Browser_DHTML:
224 return (($this->is (Browser_gecko)) ||
225 ($this->is (Browser_opera) && ($this->_major_version >= 7)) ||
226 ($this->is (Browser_ie) && $this->_major_version >= 5) ||
227 ($this->is (Browser_safari)) ||
228 ($this->is (Browser_konqueror)));
229
230 case Browser_alpha_PNG:
231 return (($this->is (Browser_gecko)) ||
232 ($this->is (Browser_opera) && (($this->_major_version >= 6) ||
233 ($this->is (Browser_os_mac) && ($this->_major_version >= 5)))) ||
234 ($this->is (Browser_ie) && $this->is (Browser_os_mac) && ($this->_major_version >= 5)) ||
235 ($this->is (Browser_omniweb) && ($this->_major_version >= 4)) ||
236 ($this->is (Browser_safari)) ||
237 ($this->is (Browser_konqueror)));
238
239 case Browser_CSS_1:
240 return (($this->is (Browser_gecko)) ||
241 ($this->is (Browser_opera) && ($this->_major_version >= 4)) ||
242 ($this->is (Browser_ie) && ($this->_major_version >= 5)) ||
243 ($this->is (Browser_safari)) ||
244 ($this->is (Browser_konqueror)));
245
246 case Browser_JavaScript:
247 return $this->_renderer_name != 'Unknown';
248
249 case Browser_cookie:
250 return $this->_renderer_name != 'Unknown';
251
252 case Browser_preserves_entities_in_textbox:
253 return (($this->is (Browser_gecko) && ($this->_major_version < 1)) ||
254 ($this->is (Browser_ie) && $this->is (Browser_os_mac)));
255
256 case Browser_supports_document_clear:
257 return $this->is (Browser_opera);
258
259 case Browser_alpha_PNG_through_behaviors:
260 return $this->is (Browser_ie) && $this->is (Browser_os_windows);
261
262 }
263 }
264
265 /** Resolve the domain name of the browser.
266 * @return string */
267 function domain ()
268 // reverse-name lookup of the user_agent ip address
269 {
270 return @gethostbyaddr ($this->ip_address ());
271 }
272
273 /** Return actual ip address of browser (resolves proxies).
274 * @return string */
275 function ip_address ()
276 {
277 if ($_SERVER ['HTTP_X_FORWARDED_FOR'])
278 return $_SERVER ['HTTP_X_FORWARDED_FOR'];
279 else if ($_SERVER ['REMOTE_ADDR'])
280 return $_SERVER ['REMOTE_ADDR'];
281 else
282 return $_SERVER ['REMOTE_HOST'];
283 }
284
285 /** Determine browser name, technology, operating system and versions.
286 * Called from the attribute access functions to make sure the user agent
287 * has been parsed.
288 * @access private */
289 function _ensure_loaded ()
290 {
291 if (! $this->_name)
292 {
293 preg_match_all ('/(\w[-&\w ]+)[-\/: ]([v]?[0-9][0-9a-z]*(\.[0-9][0-9a-z]*)*)/', $this->_normalized_ua, $parts);
294
295 $ids = $parts [1];
296 $vers = $parts [2];
297
298 $ignored_ids = $this->_ignored_ids ();
299 $system_ids = $this->_system_ids ();
300 $renderers = $this->_renderer_ids ();
301
302 // Determine browser and renderer
303
304 for ($idx_id = 0; $idx_id < sizeof ($ids); $idx_id++)
305 {
306 $id = $ids [$idx_id];
307
308 // Sniff out renderer-specific information
309
310 if ($id == 'gecko')
311 // Gecko release date
312 {
313 $this->_renderer_id = Browser_gecko;
314 $this->_renderer_name = $renderers [$id][1];
315 preg_match ('/([0-9]{4})([0-9]{2})([0-9]{2})/', $vers [$idx_id], $gecko_date_parts);
316 if (sizeof ($gecko_date_parts))
317 $this->_gecko_date = new DATE_TIME (mktime (0, 0, 0, $gecko_date_parts [2], $gecko_date_parts [3], $gecko_date_parts [1]));
318 }
319 else
320 {
321 $renderer = $renderers [$id];
322 if ($renderer)
323 {
324 if ($renderer [2] > $current_renderer [2])
325 {
326 // If the major version is greater than 4, it's gecko, not netscape 4
327
328 if (($renderer [0] == Browser_netscape_4) && ($vers [$idx_id] [0] > 4))
329 {
330 $renderer [0] = Browser_gecko;
331 $renderer [1] = 'Gecko';
332 }
333
334 $this->_renderer_id = $renderer [0];
335 $this->_renderer_name = $renderer [1];
336 $this->_renderer_version = $vers [$idx_id];
337 $current_renderer = $renderer;
338 }
339 }
340 }
341
342 // If this id is not ignored, then assume it signifies the
343 // browser name and version. This algorithm always uses the
344 // last non-ignored browser name and version.
345
346 if (! $ignored_ids [$id])
347 {
348 // Retrieve the version number and clean off the 'v', if given
349
350 $this->_version = $vers [$idx_id];
351 if ($this->_version [0] == 'v')
352 $this->_version = substr ($this->_version, 1);
353
354 // Get the actual name, if it's different from the id
355
356 $renderer = $renderers [$id];
357 if ($renderer)
358 {
359 if (($renderer [0] == Browser_netscape_4) && ($this->_version [0] > 4))
360 $renderer [1] = 'Mozilla';
361
362 $this->_name = $renderer [1];
363 }
364 else
365 $this->_name = ucfirst ($id);
366 }
367
368 // If the id is a recognized system id, extract the version information
369
370 if ($system_ids [$id])
371 {
372 $this->_system_name = ucfirst ($id);
373 $this->_system_version = $vers [$idx_id];
374 }
375 }
376
377 // Browser could not be determined (user agent string absolutely non-standard)
378
379 if (! $this->_name)
380 $this->_name = 'Unknown';
381
382 // Unknown renderer
383
384 if (! $this->_renderer_name)
385 $this->_renderer_name = 'Unknown';
386
387 // Extract version info
388
389 if ($this->_renderer_version)
390 list ($this->_major_version, $this->_minor_version, $this->_build_number) = explode ('.', $this->_renderer_version);
391
392 // Determine the operating system. Since most user agents don't specify an OS
393 // with version (Linux is a standout here), we examine the user agent in a
394 // non version-specific way for the OS.
395
396 $oss =& $this->_os_ids ();
397
398 while (! $this->_interpreted_system_name && (list ($key, $value) = each ($oss)))
399 {
400 if ($key)
401 {
402 $keys = split (',', $key);
403 $match = TRUE;
404 foreach ($keys as $key)
405 $match = $match && (strpos ($this->_normalized_ua, $key) !== FALSE);
406 if ($match)
407 $this->_interpreted_system_name = $value;
408 }
409 }
410
411 if (! $this->_interpreted_system_name)
412 $this->_interpreted_system_name = 'Unknown';
413
414 // Now, register the OS as a property of the browser
415
416 if ($this->_contains ($this->_interpreted_system_name, 'Windows'))
417 $this->_os_id = Browser_os_windows;
418 if ($this->_contains ($this->_interpreted_system_name, 'MacOS'))
419 $this->_os_id = Browser_os_mac;
420 if ($this->_contains ($this->_interpreted_system_name, 'Linux'))
421 $this->_os_id = Browser_os_linux;
422 }
423 }
424
425 /** @param string $haystack
426 * @param string $needle
427 * @return bool
428 * @access private */
429 function _contains ($haystack, $needle)
430 {
431 return strpos ($haystack, $needle) !== FALSE;
432 }
433
434 /** A list of the known rendering technologies.
435 * Each id maps to the rendering technology to record (retrieved later with the 'is' function),
436 * a pretty-printed name for the renderer and a level. The level determines which renderers override
437 * others if more than one renderer is specified. That is, almost every user-agent on the planet
438 * returns mozilla x.x, but that renderer declaration is overridden by any other one that comes along.
439 * IE is the next weakest because many user agents spoof as IE as well. If either or both of these are
440 * specified, they are recorded, but if any other renderer is specified, that one is used instead.
441 * @return array
442 * @access private */
443 function &_renderer_ids ()
444 {
445 return array ('mozilla' => array (Browser_netscape_4, 'Netscape 4.x', 1),
446 'msie' => array (Browser_ie, 'Internet Explorer', 2),
447 'rv' => array (Browser_gecko, 'Gecko', 3),
448 'gecko' => array (Browser_gecko, 'Gecko', 3),
449 'netscape6' => array (Browser_gecko, 'Netscape', 3),
450 'opera' => array (Browser_opera, 'Opera', 3),
451 'konqueror' => array (Browser_konqueror, 'Konqueror', 3),
452 'safari' => array (Browser_safari, 'Safari', 3),
453 'omniweb' => array (Browser_omniweb, 'OmniWeb', 3),
454 'webtv' => array (Browser_webtv, 'WebTV', 3));
455 }
456
457 /** A list of ids known to be spurious or system ids.
458 * The algorithm always uses the last non-ignored id as the browser id; this
459 * list determines which ids are ignored.
460 * @return array
461 * @access private */
462 function &_ignored_ids ()
463 {
464 return array ('windows' => 1,
465 'windows nt' => 1,
466 'win 9x' => 1,
467 'linux' => 1,
468 'debian' => 1,
469 'amigaos' => 1,
470 'gecko' => 1, // gecko build date
471 'rv' => 1, // gecko version number
472 'libwww-fm' => 1, // lynx
473 'openssl' => 1, // lynx
474 'ssl-mm' => 1, // lynx
475 'ycomp' => 1, // IE plugin
476 'sbcydsl' => 1, // IE plugin
477 'hotbar' => 1, // IE plugin
478 'yplus' => 1, // IE plugin
479 'net clr' => 1, // msn
480 'i386-unknown-freebsd' => 1,
481 'libcurl' => 1,
482 'r1' => 1
483 );
484 }
485
486 /** A list of systems known to provide version info in the user agent.
487 * @return array
488 * @access private */
489 function &_system_ids ()
490 {
491 return array ('windows nt' => TRUE,
492 'win 9x' => TRUE,
493 'linux' => TRUE,
494 'debian' => TRUE,
495 'amigaos' => TRUE
496 );
497 }
498
499 /** A mapping of user agent fragments to platform ids.
500 * The platform id is a nicely formatted, standardized name for the operating system. This
501 * array maps the different user agent platform ids onto these standard ones. (e.g. 'nt 4'
502 * and 'nt4' both map onto 'Windows NT 4.x').
503 * @return array
504 * @access private */
505 function &_os_ids ()
506 {
507 return array ('win,nt 5' => 'Windows 2000',
508 'win,2000' => 'Windows 2000',
509 'win,98' => 'Windows 98',
510 'win,95' => 'Windows 95',
511 'win,nt 4' => 'Windows NT 4.x',
512 'win,nt4' => 'Windows NT 4.x',
513 'win,nt 3' => 'Windows NT 3.x',
514 'win,nt' => 'Windows NT',
515 'win,16' => 'Windows 3.x',
516 'win' => 'Windows',
517 'mac,68k' => 'MacOS 68k',
518 'mac,68000' => 'MacOS 68k',
519 'mac,os x' => 'Mac OS X',
520 'mac,ppc' => 'MacOS PPC',
521 'mac,powerpc' => 'MacOS PPC',
522 'macintosh' => 'MacOS',
523 'linux' => 'Linux',
524 'amigaos' => 'AmigaOS',
525 'beos' => 'BeOS',
526 'os/2' => 'OS/2',
527 'webtv' => 'WebTV',
528 'sunos' => 'Sun/Solaris',
529 'irix' => 'Irix',
530 'hpux' => 'HP Unix',
531 'aix' => 'AIX',
532 'dec' => 'DEC-Alpha',
533 'alpha' => 'DEC-Alpha',
534 'osf1' => 'DEC-Alpha',
535 'ultrix' => 'DEC-Alpha',
536 'sco' => 'SCO',
537 'unix_sv' => 'SCO',
538 'vax' => 'VMS',
539 'openvms' => 'VMS',
540 'sinix' => 'Sinix',
541 'reliantunix' => 'Reliant/Unix',
542 'freebsd' => 'FreeBSD',
543 'openbsd' => 'OpenBSD',
544 'netbsd' => 'NetBSD',
545 'bsd' => 'BSD',
546 'unix_system_v' => 'UnixWare',
547 'ncr' => 'MPRAS',
548 'x11' => 'Unix');
549 }
550
551 /**#@+
552 * @var string
553 * @access private
554 */
555 var $_name;
556 var $_version;
557 var $_renderer_name;
558 var $_renderer_version;
559 var $_renderer_id;
560 var $_system_name;
561 var $_system_version;
562 var $_interpreted_system_name;
563 var $_os_id;
564 /**#@-*/
565
566 /**#@+
567 * @var integer
568 * @access private
569 */
570 var $_major_version;
571 var $_minor_version;
572 var $_build_number;
573 /**#@-*/
574
575 /** Lowercase version of the user agent string.
576 * @var string
577 * @access private */
578 var $_normalized_ua;
579 }
580 ?>

Documention generated on Sun, 23 Feb 2003 12:34:40 +0100 by phpDocumentor 1.2.0rc1