PageRenderTime 22ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/phpSniff/phpSniff.core.php

https://github.com/timschofield/2.8
PHP | 534 lines | 362 code | 30 blank | 142 comment | 49 complexity | c7f31969c3a328f0d968a1f87db677c5 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, GPL-2.0
  1. <?php
  2. /*******************************************************************************
  3. $Id: phpSniff.core.php 4304 2005-09-19 11:25:56Z flash2005 $
  4. phpSniff: HTTP_USER_AGENT Client Sniffer for PHP
  5. Copyright (C) 2001 Roger Raymond ~ epsilon7@users.sourceforge.net
  6. This library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Lesser General Public
  8. License as published by the Free Software Foundation; either
  9. version 2.1 of the License, or (at your option) any later version.
  10. This library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. Lesser General Public License for more details.
  14. You should have received a copy of the GNU Lesser General Public
  15. License along with this library; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *******************************************************************************/
  18. class phpSniff_core
  19. { // initialize some vars
  20. var $_browser_info = array(
  21. 'ua' => '',
  22. 'browser' => 'Unknown',
  23. 'version' => 0,
  24. 'maj_ver' => 0,
  25. 'min_ver' => 0,
  26. 'letter_ver' => '',
  27. 'javascript' => '0.0',
  28. 'platform' => 'Unknown',
  29. 'os' => 'Unknown',
  30. 'ip' => 'Unknown',
  31. 'cookies' => 'Unknown', // remains for backwards compatability
  32. 'ss_cookies' => 'Unknown',
  33. 'st_cookies' => 'Unknown',
  34. 'language' => '',
  35. 'long_name' => '',
  36. 'gecko' => '',
  37. 'gecko_ver' => ''
  38. );
  39. var $_feature_set = array(
  40. 'html' => true,
  41. 'images' => true,
  42. 'frames' => true,
  43. 'tables' => true,
  44. 'java' => true,
  45. 'plugins' => true,
  46. 'iframes' => false,
  47. 'css2' => false,
  48. 'css1' => false,
  49. 'xml' => false,
  50. 'dom' => false,
  51. 'wml' => false,
  52. 'hdml' => false
  53. );
  54. var $_quirks = array(
  55. 'must_cache_forms' => false,
  56. 'avoid_popup_windows' => false,
  57. 'cache_ssl_downloads' => false,
  58. 'break_disposition_header' => false,
  59. 'empty_file_input_value' => false,
  60. 'scrollbar_in_way' => false
  61. );
  62. var $_get_languages_ran_once = false;
  63. var $_browser_search_regex = '([a-z]+)([0-9]*)([0-9.]*)(up|dn)?';
  64. var $_language_search_regex = '([a-z-]{2,})';
  65. /**
  66. * init
  67. * this method starts the madness
  68. **/
  69. function init ()
  70. {
  71. // collect the ip
  72. $this->_get_ip();
  73. // run the cookie check routine first
  74. // [note: method only runs if allowed]
  75. $this->_test_cookies();
  76. // rip the user agent to pieces
  77. $this->_get_browser_info();
  78. // look for other languages
  79. $this->_get_languages();
  80. // establish the operating platform
  81. $this->_get_os_info();
  82. // determine javascript version
  83. $this->_get_javascript();
  84. // determine current feature set
  85. $this->_get_features();
  86. // point out any quirks
  87. $this->_get_quirks();
  88. // gecko build
  89. $this->_get_gecko();
  90. }
  91. /**
  92. * property
  93. * @param $p property to return . optional (null returns entire array)
  94. * @return array/string entire array or value of property
  95. **/
  96. function property ($p=null)
  97. { if($p==null)
  98. { return $this->_browser_info;
  99. }
  100. else
  101. { return $this->_browser_info[strtolower($p)];
  102. }
  103. }
  104. /**
  105. * get_property
  106. * alias for property
  107. **/
  108. function get_property ($p)
  109. { return $this->property($p);
  110. }
  111. /**
  112. * is
  113. * @param $s string search phrase format = l:lang;b:browser
  114. * @return bool true on success
  115. * ex: $client->is('b:OP5Up');
  116. **/
  117. function is ($s)
  118. { // perform language search
  119. if(preg_match('/l:'.$this->_language_search_regex.'/i',$s,$match))
  120. { if($match) return $this->_perform_language_search($match);
  121. }
  122. // perform browser search
  123. elseif(preg_match('/b:'.$this->_browser_search_regex.'/i',$s,$match))
  124. { if($match) return $this->_perform_browser_search($match);
  125. }
  126. return false;
  127. }
  128. /**
  129. * browser_is
  130. * @param $s string search phrase for browser
  131. * @return bool true on success
  132. * ex: $client->browser_is('OP5Up');
  133. **/
  134. function browser_is ($s)
  135. { preg_match('/'.$this->_browser_search_regex.'/i',$s,$match);
  136. if($match) return $this->_perform_browser_search($match);
  137. }
  138. /**
  139. * language_is
  140. * @param $s string search phrase for language
  141. * @return bool true on success
  142. * ex: $client->language_is('en-US');
  143. **/
  144. function language_is ($s)
  145. { preg_match('/'.$this->_language_search_regex.'/i',$s,$match);
  146. if($match) return $this->_perform_language_search($match);
  147. }
  148. /**
  149. * has_feature
  150. * @param $s string feature we're checking on
  151. * @return bool true on success
  152. * ex: $client->has_feature('html');
  153. **/
  154. function has_feature ($s)
  155. { return $this->_feature_set[$s];
  156. }
  157. /**
  158. * has_quirk
  159. * @param $s string quirk we're looking for
  160. * @return bool true on success
  161. * ex: $client->has_quirk('avoid_popup_windows');
  162. **/
  163. function has_quirk ($s)
  164. { return $this->_quirks[$s];
  165. }
  166. /**
  167. * _perform_browser_search
  168. * @param $data string what we're searching for
  169. * @return bool true on success
  170. * @private
  171. **/
  172. function _perform_browser_search ($data)
  173. { $search = array();
  174. $search['phrase'] = isset($data[0]) ? $data[0] : '';
  175. $search['name'] = isset($data[1]) ? strtolower($data[1]) : '';
  176. $search['maj_ver'] = isset($data[2]) ? $data[2] : '';
  177. $search['min_ver'] = isset($data[3]) ? $data[3] : '';
  178. $search['direction'] = isset($data[4]) ? strtolower($data[4]) : '';
  179. $looking_for = $search['maj_ver'].$search['min_ver'];
  180. if($search['name'] == 'aol' || $search['name'] == 'webtv')
  181. { return stristr($this->_browser_info['ua'],$search['name']);
  182. }
  183. elseif($this->_browser_info['browser'] == $search['name'])
  184. { $majv = $search['maj_ver'] ? $this->_browser_info['maj_ver'] : '';
  185. $minv = $search['min_ver'] ? $this->_browser_info['min_ver'] : '';
  186. $what_we_are = $majv.$minv;
  187. if($search['direction'] == 'up' && ($what_we_are >= $looking_for))
  188. { return true;
  189. }
  190. elseif($search['direction'] == 'dn' && ($what_we_are <= $looking_for))
  191. { return true;
  192. }
  193. elseif($what_we_are == $looking_for)
  194. { return true;
  195. }
  196. }
  197. return false;
  198. }
  199. function _perform_language_search ($data)
  200. { // if we've not grabbed the languages, then do so.
  201. $this->_get_languages();
  202. return stristr($this->_browser_info['language'],$data[1]);
  203. }
  204. function _get_languages ()
  205. { // capture available languages and insert into container
  206. if(!$this->_get_languages_ran_once)
  207. { if($languages = getenv('HTTP_ACCEPT_LANGUAGE'))
  208. { $languages = preg_replace('/(;q=[0-9]+.[0-9]+)/i','',$languages);
  209. }
  210. else
  211. { $languages = $this->_default_language;
  212. }
  213. $this->_set_browser('language',$languages);
  214. $this->_get_languages_ran_once = true;
  215. }
  216. }
  217. function _get_os_info ()
  218. { // regexes to use
  219. $regex_windows = '/([^dar]win[dows]*)[\s]?([0-9a-z]*)[\w\s]?([a-z0-9.]*)/i';
  220. $regex_mac = '/(68[k0]{1,3})|(ppc mac os x)|([p\S]{1,5}pc)|(darwin)/i';
  221. $regex_os2 = '/os\/2|ibm-webexplorer/i';
  222. $regex_sunos = '/(sun|i86)[os\s]*([0-9]*)/i';
  223. $regex_irix = '/(irix)[\s]*([0-9]*)/i';
  224. $regex_hpux = '/(hp-ux)[\s]*([0-9]*)/i';
  225. $regex_aix = '/aix([0-9]*)/i';
  226. $regex_dec = '/dec|osfl|alphaserver|ultrix|alphastation/i';
  227. $regex_vms = '/vax|openvms/i';
  228. $regex_sco = '/sco|unix_sv/i';
  229. $regex_linux = '/x11|inux/i';
  230. $regex_bsd = '/(free)?(bsd)/i';
  231. // look for Windows Box
  232. if(preg_match_all($regex_windows,$this->_browser_info['ua'],$match))
  233. { /** Windows has some of the most ridiculous HTTP_USER_AGENT strings */
  234. //$match[1][count($match[0])-1];
  235. $v = $match[2][count($match[0])-1];
  236. $v2 = $match[3][count($match[0])-1];
  237. // Establish NT 5.1 as Windows XP
  238. if(stristr($v,'NT') && $v2 == 5.1) $v = 'xp';
  239. // Establish NT 5.0 and Windows 2000 as win2k
  240. elseif($v == '2000') $v = '2k';
  241. elseif(stristr($v,'NT') && $v2 == 5.0) $v = '2k';
  242. // Establish 9x 4.90 as Windows 98
  243. elseif(stristr($v,'9x') && $v2 == 4.9) $v = '98';
  244. // See if we're running windows 3.1
  245. elseif($v.$v2 == '16bit') $v = '31';
  246. // otherwise display as is (31,95,98,NT,ME,XP)
  247. else $v .= $v2;
  248. // update browser info container array
  249. if(empty($v)) $v = 'win';
  250. $this->_set_browser('os',strtolower($v));
  251. $this->_set_browser('platform','win');
  252. }
  253. // look for OS2
  254. elseif( preg_match($regex_os2,$this->_browser_info['ua']))
  255. { $this->_set_browser('os','os2');
  256. $this->_set_browser('platform','os2');
  257. }
  258. // look for mac
  259. // sets: platform = mac ; os = 68k or ppc
  260. elseif( preg_match($regex_mac,$this->_browser_info['ua'],$match) )
  261. { $this->_set_browser('platform','mac');
  262. $os = !empty($match[1]) ? '68k' : '';
  263. $os = !empty($match[2]) ? 'osx' : $os;
  264. $os = !empty($match[3]) ? 'ppc' : $os;
  265. $os = !empty($match[4]) ? 'osx' : $os;
  266. $this->_set_browser('os',$os);
  267. }
  268. // look for *nix boxes
  269. // sunos sets: platform = *nix ; os = sun|sun4|sun5|suni86
  270. elseif(preg_match($regex_sunos,$this->_browser_info['ua'],$match))
  271. { $this->_set_browser('platform','*nix');
  272. if(!stristr('sun',$match[1])) $match[1] = 'sun'.$match[1];
  273. $this->_set_browser('os',$match[1].$match[2]);
  274. }
  275. // irix sets: platform = *nix ; os = irix|irix5|irix6|...
  276. elseif(preg_match($regex_irix,$this->_browser_info['ua'],$match))
  277. { $this->_set_browser('platform','*nix');
  278. $this->_set_browser('os',$match[1].$match[2]);
  279. }
  280. // hp-ux sets: platform = *nix ; os = hpux9|hpux10|...
  281. elseif(preg_match($regex_hpux,$this->_browser_info['ua'],$match))
  282. { $this->_set_browser('platform','*nix');
  283. $match[1] = str_replace('-','',$match[1]);
  284. $match[2] = (int) $match[2];
  285. $this->_set_browser('os',$match[1].$match[2]);
  286. }
  287. // aix sets: platform = *nix ; os = aix|aix1|aix2|aix3|...
  288. elseif(preg_match($regex_aix,$this->_browser_info['ua'],$match))
  289. { $this->_set_browser('platform','*nix');
  290. $this->_set_browser('os','aix'.$match[1]);
  291. }
  292. // dec sets: platform = *nix ; os = dec
  293. elseif(preg_match($regex_dec,$this->_browser_info['ua'],$match))
  294. { $this->_set_browser('platform','*nix');
  295. $this->_set_browser('os','dec');
  296. }
  297. // vms sets: platform = *nix ; os = vms
  298. elseif(preg_match($regex_vms,$this->_browser_info['ua'],$match))
  299. { $this->_set_browser('platform','*nix');
  300. $this->_set_browser('os','vms');
  301. }
  302. // sco sets: platform = *nix ; os = sco
  303. elseif(preg_match($regex_sco,$this->_browser_info['ua'],$match))
  304. { $this->_set_browser('platform','*nix');
  305. $this->_set_browser('os','sco');
  306. }
  307. // unixware sets: platform = *nix ; os = unixware
  308. elseif(stristr('unix_system_v',$this->_browser_info['ua']))
  309. { $this->_set_browser('platform','*nix');
  310. $this->_set_browser('os','unixware');
  311. }
  312. // mpras sets: platform = *nix ; os = mpras
  313. elseif(stristr('ncr',$this->_browser_info['ua']))
  314. { $this->_set_browser('platform','*nix');
  315. $this->_set_browser('os','mpras');
  316. }
  317. // reliant sets: platform = *nix ; os = reliant
  318. elseif(stristr('reliantunix',$this->_browser_info['ua']))
  319. { $this->_set_browser('platform','*nix');
  320. $this->_set_browser('os','reliant');
  321. }
  322. // sinix sets: platform = *nix ; os = sinix
  323. elseif(stristr('sinix',$this->_browser_info['ua']))
  324. { $this->_set_browser('platform','*nix');
  325. $this->_set_browser('os','sinix');
  326. }
  327. // bsd sets: platform = *nix ; os = bsd|freebsd
  328. elseif(preg_match($regex_bsd,$this->_browser_info['ua'],$match))
  329. { $this->_set_browser('platform','*nix');
  330. $this->_set_browser('os',$match[1].$match[2]);
  331. }
  332. // last one to look for
  333. // linux sets: platform = *nix ; os = linux
  334. elseif(preg_match($regex_linux,$this->_browser_info['ua'],$match))
  335. { $this->_set_browser('platform','*nix');
  336. $this->_set_browser('os','linux');
  337. }
  338. }
  339. function _get_browser_info ()
  340. { $this->_build_regex();
  341. if(preg_match_all($this->_browser_regex,$this->_browser_info['ua'],$results))
  342. { // get the position of the last browser found
  343. $count = count($results[0])-1;
  344. // if we're allowing masquerading, revert to the next to last browser found
  345. // if possible, otherwise stay put
  346. if($this->_allow_masquerading && $count > 0) $count--;
  347. // insert findings into the container
  348. $this->_set_browser('browser',$this->_get_short_name($results[1][$count]));
  349. $this->_set_browser('long_name',$results[1][$count]);
  350. $this->_set_browser('maj_ver',$results[2][$count]);
  351. // parse the minor version string and look for alpha chars
  352. preg_match('/([.\0-9]+)?([\.a-z0-9]+)?/i',$results[3][$count],$match);
  353. if(isset($match[1])) {
  354. $this->_set_browser('min_ver',$match[1]);
  355. } else {
  356. $this->_set_browser('min_ver','.0');
  357. }
  358. if(isset($match[2])) $this->_set_browser('letter_ver',$match[2]);
  359. // insert findings into container
  360. $this->_set_browser('version',$this->_browser_info['maj_ver'].$this->property('min_ver'));
  361. }
  362. }
  363. function _get_ip ()
  364. { if(getenv('HTTP_CLIENT_IP'))
  365. { $ip = getenv('HTTP_CLIENT_IP');
  366. }
  367. else
  368. { $ip = getenv('REMOTE_ADDR');
  369. }
  370. $this->_set_browser('ip',$ip);
  371. }
  372. function _build_regex ()
  373. { $browsers = '';
  374. while(list($k,) = each($this->_browsers))
  375. { if(!empty($browsers)) $browsers .= "|";
  376. $browsers .= $k;
  377. }
  378. $version_string = "[\/\sa-z]*([0-9]+)([\.0-9a-z]+)?";
  379. $this->_browser_regex = "/($browsers)$version_string/i";
  380. }
  381. function _get_short_name ($long_name)
  382. { return $this->_browsers[strtolower($long_name)];
  383. }
  384. /*
  385. function _test_cookies ()
  386. { global $ctest,$phpSniff_testCookie;
  387. if($this->_check_cookies)
  388. { if ($ctest != 1)
  389. { SetCookie('phpSniff_testCookie','test',0,'/');
  390. // See if we were passed anything in the QueryString we might need
  391. $QS = getenv('QUERY_STRING');
  392. // fix compatability issues when PHP is
  393. // running as CGI ~ 6/28/2001 v2.0.2 ~ RR
  394. $script_path = getenv('PATH_INFO') ? getenv('PATH_INFO') : getenv('SCRIPT_NAME');
  395. $location = $script_path . ($QS=="" ? "?ctest=1" : "?" . $QS . "&ctest=1");
  396. header("Location: $location");
  397. exit;
  398. }
  399. // Check for the cookie on page reload
  400. elseif ($phpSniff_testCookie == "test")
  401. { $this->_set_browser('cookies',true);
  402. }
  403. else
  404. { $this->_set_browser('cookies',false);
  405. }
  406. }
  407. else $this->_set_browser('cookies',false);
  408. }
  409. */
  410. // medianes :: new test cookie routine
  411. function _test_cookies()
  412. { global $phpSniff_session,$phpSniff_stored;
  413. if($this->_check_cookies)
  414. { $fp = @fopen($this->_temp_file_path.$this->property('ip'),'r');
  415. if(!$fp)
  416. { $fp = @fopen($this->_temp_file_path.$this->property('ip'),'a');
  417. fclose($fp);
  418. setcookie('phpSniff_session','ss');
  419. setcookie('phpSniff_stored','st',time()+3600*24*365);
  420. $QS=getenv('QUERY_STRING');
  421. $script_path=getenv('PATH_INFO')?getenv('PATH_INFO'):getenv('SCRIPT_NAME');
  422. if(is_integer($pos=strpos(strrev($script_path),"php.xedni/"))&&!$pos) {
  423. $script_path=strrev(substr(strrev($script_path),9));
  424. }
  425. $location='http://'.getenv('SERVER_NAME').$script_path.($QS==''?'':'?'.$QS);
  426. header("Location: $location");
  427. exit;
  428. }
  429. else
  430. { unlink($this->_temp_file_path.$this->property('ip'));
  431. fclose($fp);
  432. // remains for backwards compatability
  433. $this->_set_browser('cookies',$phpSniff_session=='ss'?'true':'false');
  434. // new cookie settings
  435. $this->_set_browser('ss_cookies',$phpSniff_session=='ss'?'true':'false');
  436. $this->_set_browser('st_cookies',$phpSniff_stored=='st'?'true':'false');
  437. setcookie('phpSniff_stored','');
  438. }
  439. }
  440. }
  441. function _get_javascript()
  442. { $set=false;
  443. // see if we have any matches
  444. while(list($version,$browser) = each($this->_javascript_versions))
  445. { $browser = explode(',',$browser);
  446. while(list(,$search) = each($browser))
  447. { if($this->is('b:'.$search))
  448. { $this->_set_browser('javascript',$version);
  449. $set = true;
  450. break;
  451. }
  452. }
  453. if($set) break;
  454. }
  455. }
  456. function _get_features ()
  457. { while(list($feature,$browser) = each($this->_browser_features))
  458. { $browser = explode(',',$browser);
  459. while(list(,$search) = each($browser))
  460. { if($this->browser_is($search))
  461. { $this->_set_feature($feature);
  462. break;
  463. }
  464. }
  465. }
  466. }
  467. function _get_quirks ()
  468. { while(list($quirk,$browser) = each($this->_browser_quirks))
  469. { $browser = explode(',',$browser);
  470. while(list(,$search) = each($browser))
  471. { if($this->browser_is($search))
  472. { $this->_set_quirk($quirk);
  473. break;
  474. }
  475. }
  476. }
  477. }
  478. function _get_gecko ()
  479. { if(preg_match('/gecko\/([0-9]+)/i',$this->property('ua'),$match))
  480. { $this->_set_browser('gecko',$match[1]);
  481. if (preg_match('/rv:([0-9a-z.+]+)/i',$this->property('ua'),$mozv))
  482. { $this->_set_browser('gecko_ver',$mozv[1]);
  483. }
  484. elseif (preg_match('/(m[0-9]+)/i',$this->property('ua'),$mozv))
  485. { $this->_set_browser('gecko_ver',$mozv[1]);
  486. }
  487. }
  488. }
  489. function _set_browser ($k,$v)
  490. { $this->_browser_info[strtolower($k)] = strtolower($v);
  491. }
  492. function _set_feature ($k)
  493. { $this->_feature_set[strtolower($k)] = !$this->_feature_set[strtolower($k)];
  494. }
  495. function _set_quirk ($k)
  496. { $this->_quirks[strtolower($k)] = true;
  497. }
  498. }
  499. ?>