2
0

AbstractDevice.php 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Http
  17. * @subpackage UserAgent
  18. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. require_once 'Zend/Http/UserAgent/Device.php';
  22. /**
  23. * Abstract Class to define a browser device.
  24. *
  25. * @category Zend
  26. * @package Zend_Http
  27. * @subpackage UserAgent
  28. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  29. * @license http://framework.zend.com/license/new-bsd New BSD License
  30. */
  31. abstract class Zend_Http_UserAgent_AbstractDevice
  32. implements Zend_Http_UserAgent_Device
  33. {
  34. /**
  35. * Browser signature
  36. *
  37. * @var string
  38. */
  39. protected $_browser = '';
  40. /**
  41. * Browser version
  42. *
  43. * @var string
  44. */
  45. protected $_browserVersion = '';
  46. /**
  47. * Configuration
  48. *
  49. * @var array
  50. */
  51. protected $_config;
  52. /**
  53. * User Agent chain
  54. *
  55. * @var string
  56. */
  57. protected $_userAgent;
  58. /**
  59. * Server variable
  60. *
  61. * @var array
  62. */
  63. protected $_server;
  64. /**
  65. * Image types
  66. *
  67. * @var array
  68. */
  69. protected $_images = array(
  70. 'jpeg',
  71. 'gif',
  72. 'png',
  73. 'pjpeg',
  74. 'x-png',
  75. 'bmp',
  76. );
  77. /**
  78. * Browser/Device features
  79. *
  80. * @var array
  81. */
  82. protected $_aFeatures = array();
  83. /**
  84. * Browser/Device features groups
  85. *
  86. * @var array
  87. */
  88. protected $_aGroup = array();
  89. /**
  90. * Constructor
  91. *
  92. * @param null|string|array $userAgent If array, restores from serialized version
  93. * @param array $server
  94. * @param array $config
  95. * @return void
  96. */
  97. public function __construct($userAgent = null, array $server = array(), array $config = array())
  98. {
  99. if (is_array($userAgent)) {
  100. // Restoring from serialized array
  101. $this->_restoreFromArray($userAgent);
  102. } else {
  103. // Constructing new object
  104. $this->setUserAgent($userAgent);
  105. $this->_server = $server;
  106. $this->_config = $config;
  107. $this->_getDefaultFeatures();
  108. $this->_defineFeatures();
  109. }
  110. }
  111. /**
  112. * Serialize object
  113. *
  114. * @return string
  115. */
  116. public function serialize()
  117. {
  118. $spec = array(
  119. '_aFeatures' => $this->_aFeatures,
  120. '_aGroup' => $this->_aGroup,
  121. '_browser' => $this->_browser,
  122. '_browserVersion' => $this->_browserVersion,
  123. '_userAgent' => $this->_userAgent,
  124. '_images' => $this->_images,
  125. );
  126. return serialize($spec);
  127. }
  128. /**
  129. * Unserialize
  130. *
  131. * @param string $serialized
  132. * @return void
  133. */
  134. public function unserialize($serialized)
  135. {
  136. $spec = unserialize($serialized);
  137. $this->_restoreFromArray($spec);
  138. }
  139. /**
  140. * Restore object state from array
  141. *
  142. * @param array $spec
  143. * @return void
  144. */
  145. protected function _restoreFromArray(array $spec)
  146. {
  147. foreach ($spec as $key => $value) {
  148. if (property_exists($this, $key)) {
  149. $this->{$key} = $value;
  150. }
  151. }
  152. }
  153. /**
  154. * Look for features
  155. *
  156. * @return array|null
  157. */
  158. protected function _defineFeatures()
  159. {
  160. $features = $this->_loadFeaturesAdapter();
  161. if (is_array($features)) {
  162. $this->_aFeatures = array_merge($this->_aFeatures, $features);
  163. }
  164. return $this->_aFeatures;
  165. }
  166. /**
  167. * Gets the browser type identifier
  168. *
  169. * @return string
  170. */
  171. abstract public function getType();
  172. /**
  173. * Check a feature for the current browser/device.
  174. *
  175. * @param string $feature The feature to check.
  176. * @return bool
  177. */
  178. public function hasFeature($feature)
  179. {
  180. return (!empty($this->_aFeatures[$feature]));
  181. }
  182. /**
  183. * Gets the value of the current browser/device feature
  184. *
  185. * @param string $feature Feature to search
  186. * @return string|null
  187. */
  188. public function getFeature($feature)
  189. {
  190. if ($this->hasFeature($feature)) {
  191. return $this->_aFeatures[$feature];
  192. }
  193. }
  194. /**
  195. * Set a feature for the current browser/device.
  196. *
  197. * @param string $feature The feature to set.
  198. * @param string $value (option) feature value.
  199. * @param string $group (option) Group to associate with the feature
  200. * @return Zend_Http_UserAgent_AbstractDevice
  201. */
  202. public function setFeature($feature, $value = false, $group = '')
  203. {
  204. $this->_aFeatures[$feature] = $value;
  205. if (!empty($group)) {
  206. $this->setGroup($group, $feature);
  207. }
  208. return $this;
  209. }
  210. /**
  211. * Affects a feature to a group
  212. *
  213. * @param string $group Group name
  214. * @param string $feature Feature name
  215. * @return Zend_Http_UserAgent_AbstractDevice
  216. */
  217. public function setGroup($group, $feature)
  218. {
  219. if (!isset($this->_aGroup[$group])) {
  220. $this->_aGroup[$group] = array();
  221. }
  222. if (!in_array($feature, $this->_aGroup[$group])) {
  223. $this->_aGroup[$group][] = $feature;
  224. }
  225. return $this;
  226. }
  227. /**
  228. * Gets an array of features associated to a group
  229. *
  230. * @param string $group Group param
  231. * @return array
  232. */
  233. public function getGroup($group)
  234. {
  235. return $this->_aGroup[$group];
  236. }
  237. /**
  238. * Gets all the browser/device features
  239. *
  240. * @return array
  241. */
  242. public function getAllFeatures()
  243. {
  244. return $this->_aFeatures;
  245. }
  246. /**
  247. * Gets all the browser/device features' groups
  248. *
  249. * @return array
  250. */
  251. public function getAllGroups()
  252. {
  253. return $this->_aGroup;
  254. }
  255. /**
  256. * Sets all the standard features extracted from the User Agent chain and $this->_server
  257. * vars
  258. *
  259. * @return void
  260. */
  261. protected function _getDefaultFeatures()
  262. {
  263. $server = array();
  264. // gets info from user agent chain
  265. $uaExtract = $this->extractFromUserAgent($this->getUserAgent());
  266. if (is_array($uaExtract)) {
  267. foreach ($uaExtract as $key => $info) {
  268. $this->setFeature($key, $info, 'product_info');
  269. }
  270. }
  271. if (isset($uaExtract['browser_name'])) {
  272. $this->_browser = $uaExtract['browser_name'];
  273. }
  274. if (isset($uaExtract['browser_version'])) {
  275. $this->_browserVersion = $uaExtract['browser_version'];
  276. }
  277. if (isset($uaExtract['device_os'])) {
  278. $this->device_os = $uaExtract['device_os_name'];
  279. }
  280. /* browser & device info */
  281. $this->setFeature('is_wireless_device', false, 'product_info');
  282. $this->setFeature('is_mobile', false, 'product_info');
  283. $this->setFeature('is_desktop', false, 'product_info');
  284. $this->setFeature('is_tablet', false, 'product_info');
  285. $this->setFeature('is_bot', false, 'product_info');
  286. $this->setFeature('is_email', false, 'product_info');
  287. $this->setFeature('is_text', false, 'product_info');
  288. $this->setFeature('device_claims_web_support', false, 'product_info');
  289. $this->setFeature('is_' . strtolower($this->getType()), true, 'product_info');
  290. /* sets the browser name */
  291. if (isset($this->list) && empty($this->_browser)) {
  292. $lowerUserAgent = strtolower($this->getUserAgent());
  293. foreach ($this->list as $browser_signature) {
  294. if (strpos($lowerUserAgent, $browser_signature) !== false) {
  295. $this->_browser = strtolower($browser_signature);
  296. $this->setFeature('browser_name', $this->_browser, 'product_info');
  297. }
  298. }
  299. }
  300. /* sets the client IP */
  301. if (isset($this->_server['remote_addr'])) {
  302. $this->setFeature('client_ip', $this->_server['remote_addr'], 'product_info');
  303. } elseif (isset($this->_server['http_x_forwarded_for'])) {
  304. $this->setFeature('client_ip', $this->_server['http_x_forwarded_for'], 'product_info');
  305. } elseif (isset($this->_server['http_client_ip'])) {
  306. $this->setFeature('client_ip', $this->_server['http_client_ip'], 'product_info');
  307. }
  308. /* sets the server infos */
  309. if (isset($this->_server['server_software'])) {
  310. if (strpos($this->_server['server_software'], 'Apache') !== false || strpos($this->_server['server_software'], 'LiteSpeed') !== false) {
  311. $server['version'] = 1;
  312. if (strpos($this->_server['server_software'], 'Apache/2') !== false) {
  313. $server['version'] = 2;
  314. }
  315. $server['server'] = 'apache';
  316. }
  317. if (strpos($this->_server['server_software'], 'Microsoft-IIS') !== false) {
  318. $server['server'] = 'iis';
  319. }
  320. if (strpos($this->_server['server_software'], 'Unix') !== false) {
  321. $server['os'] = 'unix';
  322. if (isset($_ENV['MACHTYPE'])) {
  323. if (strpos($_ENV['MACHTYPE'], 'linux') !== false) {
  324. $server['os'] = 'linux';
  325. }
  326. }
  327. } elseif (strpos($this->_server['server_software'], 'Win') !== false) {
  328. $server['os'] = 'windows';
  329. }
  330. if (preg_match('/Apache\/([0-9\.]*)/', $this->_server['server_software'], $arr)) {
  331. if ($arr[1]) {
  332. $server['version'] = $arr[1];
  333. $server['server'] = 'apache';
  334. }
  335. }
  336. }
  337. $this->setFeature('php_version', phpversion(), 'server_info');
  338. if (isset($server['server'])) {
  339. $this->setFeature('server_os', $server['server'], 'server_info');
  340. }
  341. if (isset($server['version'])) {
  342. $this->setFeature('server_os_version', $server['version'], 'server_info');
  343. }
  344. if (isset($this->_server['http_accept'])) {
  345. $this->setFeature('server_http_accept', $this->_server['http_accept'], 'server_info');
  346. }
  347. if (isset($this->_server['http_accept_language'])) {
  348. $this->setFeature('server_http_accept_language', $this->_server['http_accept_language'], 'server_info');
  349. }
  350. if (isset($this->_server['server_addr'])) {
  351. $this->setFeature('server_ip', $this->_server['server_addr'], 'server_info');
  352. }
  353. if (isset($this->_server['server_name'])) {
  354. $this->setFeature('server_name', $this->_server['server_name'], 'server_info');
  355. }
  356. }
  357. /**
  358. * Extract and sets informations from the User Agent chain
  359. *
  360. * @param string $userAgent User Agent chain
  361. * @return array
  362. */
  363. public static function extractFromUserAgent($userAgent)
  364. {
  365. $userAgent = trim($userAgent);
  366. /**
  367. * @see http://www.texsoft.it/index.php?c=software&m=sw.php.useragent&l=it
  368. */
  369. $pattern = "(([^/\s]*)(/(\S*))?)(\s*\[[a-zA-Z][a-zA-Z]\])?\s*(\\((([^()]|(\\([^()]*\\)))*)\\))?\s*";
  370. preg_match("#^$pattern#", $userAgent, $match);
  371. $comment = array();
  372. if (isset($match[7])) {
  373. $comment = explode(';', $match[7]);
  374. }
  375. // second part if exists
  376. $end = substr($userAgent, strlen($match[0]));
  377. if (!empty($end)) {
  378. $result['others']['full'] = $end;
  379. }
  380. $match2 = array();
  381. if (isset($result['others'])) {
  382. preg_match_all('/(([^\/\s]*)(\/)?([^\/\(\)\s]*)?)(\s\((([^\)]*)*)\))?/i', $result['others']['full'], $match2);
  383. }
  384. $result['user_agent'] = trim($match[1]);
  385. $result['product_name'] = isset($match[2]) ? trim($match[2]) : '';
  386. $result['browser_name'] = $result['product_name'];
  387. if (isset($match[4]) && trim($match[4])) {
  388. $result['product_version'] = trim($match[4]);
  389. $result['browser_version'] = trim($match[4]);
  390. }
  391. if (count($comment) && !empty($comment[0])) {
  392. $result['comment']['full'] = trim($match[7]);
  393. $result['comment']['detail'] = $comment;
  394. $result['compatibility_flag'] = trim($comment[0]);
  395. if (isset($comment[1])) {
  396. $result['browser_token'] = trim($comment[1]);
  397. }
  398. if (isset($comment[2])) {
  399. $result['device_os_token'] = trim($comment[2]);
  400. }
  401. }
  402. if (empty($result['device_os_token']) && !empty($result['compatibility_flag'])) {
  403. // some browsers do not have a platform token
  404. $result['device_os_token'] = $result['compatibility_flag'];
  405. }
  406. if ($match2) {
  407. $i = 0;
  408. $max = count($match2[0]);
  409. for ($i = 0; $i < $max; $i ++) {
  410. if (!empty($match2[0][$i])) {
  411. $result['others']['detail'][] = array(
  412. $match2[0][$i],
  413. $match2[2][$i],
  414. $match2[4][$i],
  415. );
  416. }
  417. }
  418. }
  419. /** Security level */
  420. $security = array(
  421. 'N' => 'no security',
  422. 'U' => 'strong security',
  423. 'I' => 'weak security',
  424. );
  425. if (!empty($result['browser_token'])) {
  426. if (isset($security[$result['browser_token']])) {
  427. $result['security_level'] = $security[$result['browser_token']];
  428. unset($result['browser_token']);
  429. }
  430. }
  431. $product = strtolower($result['browser_name']);
  432. // Mozilla : true && false
  433. $compatibleOrIe = false;
  434. if (isset($result['compatibility_flag']) && isset($result['comment'])) {
  435. $compatibleOrIe = ($result['compatibility_flag'] == 'compatible' || strpos($result['comment']['full'], "MSIE") !== false);
  436. }
  437. if ($product == 'mozilla' && $compatibleOrIe) {
  438. if (!empty($result['browser_token'])) {
  439. // Classic Mozilla chain
  440. preg_match_all('/([^\/\s].*)(\/|\s)(.*)/i', $result['browser_token'], $real);
  441. } else {
  442. // MSIE specific chain with 'Windows' compatibility flag
  443. foreach ($result['comment']['detail'] as $v) {
  444. if (strpos($v, 'MSIE') !== false) {
  445. $real[0][1] = trim($v);
  446. $result['browser_engine'] = "MSIE";
  447. $real[1][0] = "Internet Explorer";
  448. $temp = explode(' ', trim($v));
  449. $real[3][0] = $temp[1];
  450. }
  451. if (strpos($v, 'Win') !== false) {
  452. $result['device_os_token'] = trim($v);
  453. }
  454. }
  455. }
  456. if (!empty($real[0])) {
  457. $result['browser_name'] = $real[1][0];
  458. $result['browser_version'] = $real[3][0];
  459. } else {
  460. $result['browser_name'] = $result['browser_token'];
  461. $result['browser_version'] = '??';
  462. }
  463. } elseif ($product == 'mozilla' && $result['browser_version'] < 5.0) {
  464. // handles the real Mozilla (or old Netscape if version < 5.0)
  465. $result['browser_name'] = 'Netscape';
  466. }
  467. /** windows */
  468. if ($result['browser_name'] == 'MSIE') {
  469. $result['browser_engine'] = 'MSIE';
  470. $result['browser_name'] = 'Internet Explorer';
  471. }
  472. if (isset($result['device_os_token'])) {
  473. if (strpos($result['device_os_token'], 'Win') !== false) {
  474. $windows = array(
  475. 'Windows NT 6.1' => 'Windows 7',
  476. 'Windows NT 6.0' => 'Windows Vista',
  477. 'Windows NT 5.2' => 'Windows Server 2003',
  478. 'Windows NT 5.1' => 'Windows XP',
  479. 'Windows NT 5.01' => 'Windows 2000 SP1',
  480. 'Windows NT 5.0' => 'Windows 2000',
  481. 'Windows NT 4.0' => 'Microsoft Windows NT 4.0',
  482. 'WinNT' => 'Microsoft Windows NT 4.0',
  483. 'Windows 98; Win 9x 4.90' => 'Windows Me',
  484. 'Windows 98' => 'Windows 98',
  485. 'Win98' => 'Windows 98',
  486. 'Windows 95' => 'Windows 95',
  487. 'Win95' => 'Windows 95',
  488. 'Windows CE' => 'Windows CE',
  489. );
  490. if (isset($windows[$result['device_os_token']])) {
  491. $result['device_os_name'] = $windows[$result['device_os_token']];
  492. } else {
  493. $result['device_os_name'] = $result['device_os_token'];
  494. }
  495. }
  496. }
  497. // iphone
  498. $apple_device = array(
  499. 'iPhone',
  500. 'iPod',
  501. 'iPad',
  502. );
  503. if (isset($result['compatibility_flag'])) {
  504. if (in_array($result['compatibility_flag'], $apple_device)) {
  505. $result['device'] = strtolower($result['compatibility_flag']);
  506. $result['device_os_token'] = 'iPhone OS';
  507. if (isset($comment[3])) {
  508. $result['browser_language'] = trim($comment[3]);
  509. }
  510. if (isset($result['others']['detail'][1])) {
  511. $result['browser_version'] = $result['others']['detail'][1][2];
  512. } elseif (isset($result['others']['detail']) && count($result['others']['detail'])) {
  513. $result['browser_version'] = $result['others']['detail'][0][2];
  514. }
  515. if (!empty($result['others']['detail'][2])) {
  516. $result['firmware'] = $result['others']['detail'][2][2];
  517. }
  518. if (!empty($result['others']['detail'][3])) {
  519. $result['browser_name'] = $result['others']['detail'][3][1];
  520. $result['browser_build'] = $result['others']['detail'][3][2];
  521. }
  522. }
  523. }
  524. // Safari
  525. if (isset($result['others'])) {
  526. if ($result['others']['detail'][0][1] == 'AppleWebKit') {
  527. $result['browser_engine'] = 'AppleWebKit';
  528. if (isset($result['others']['detail'][1]) && $result['others']['detail'][1][1] == 'Version') {
  529. $result['browser_version'] = $result['others']['detail'][1][2];
  530. } else {
  531. $result['browser_version'] = $result['others']['detail'][count($result['others']['detail']) - 1][2];
  532. }
  533. if (isset($comment[3])) {
  534. $result['browser_language'] = trim($comment[3]);
  535. }
  536. $last = $result['others']['detail'][count($result['others']['detail']) - 1][1];
  537. if (empty($result['others']['detail'][2][1]) || $result['others']['detail'][2][1] == 'Safari') {
  538. if (isset($result['others']['detail'][1])) {
  539. $result['browser_name'] = ($result['others']['detail'][1][1] && $result['others']['detail'][1][1] != 'Version' ? $result['others']['detail'][1][1] : 'Safari');
  540. $result['browser_version'] = ($result['others']['detail'][1][2] ? $result['others']['detail'][1][2] : $result['others']['detail'][0][2]);
  541. } else {
  542. $result['browser_name'] = ($result['others']['detail'][0][1] && $result['others']['detail'][0][1] != 'Version' ? $result['others']['detail'][0][1] : 'Safari');
  543. $result['browser_version'] = $result['others']['detail'][0][2];
  544. }
  545. } else {
  546. $result['browser_name'] = $result['others']['detail'][2][1];
  547. $result['browser_version'] = $result['others']['detail'][2][2];
  548. // mobile version
  549. if ($result['browser_name'] == 'Mobile') {
  550. $result['browser_name'] = 'Safari ' . $result['browser_name'];
  551. if ($result['others']['detail'][1][1] == 'Version') {
  552. $result['browser_version'] = $result['others']['detail'][1][2];
  553. }
  554. }
  555. }
  556. // For Safari < 2.2, AppleWebKit version gives the Safari version
  557. if (strpos($result['browser_version'], '.') > 2 || (int) $result['browser_version'] > 20) {
  558. $temp = explode('.', $result['browser_version']);
  559. $build = (int) $temp[0];
  560. $awkVersion = array(
  561. 48 => '0.8',
  562. 73 => '0.9',
  563. 85 => '1.0',
  564. 103 => '1.1',
  565. 124 => '1.2',
  566. 300 => '1.3',
  567. 400 => '2.0',
  568. );
  569. foreach ($awkVersion as $k => $v) {
  570. if ($build >= $k) {
  571. $result['browser_version'] = $v;
  572. }
  573. }
  574. }
  575. }
  576. // Gecko (Firefox or compatible)
  577. if ($result['others']['detail'][0][1] == 'Gecko') {
  578. $searchRV = true;
  579. if (!empty($result['others']['detail'][1][1]) && !empty($result['others']['detail'][count($result['others']['detail']) - 1][2]) || strpos(strtolower($result['others']['full']), 'opera') !== false) {
  580. $searchRV = false;
  581. $result['browser_engine'] = $result['others']['detail'][0][1];
  582. // the name of the application is at the end indepenently
  583. // of quantity of information in $result['others']['detail']
  584. $last = count($result['others']['detail']) - 1;
  585. // exception : if the version of the last information is
  586. // empty we take the previous one
  587. if (empty($result['others']['detail'][$last][2])) {
  588. $last --;
  589. }
  590. // exception : if the last one is 'Red Hat' or 'Debian' =>
  591. // use rv: to find browser_version */
  592. if (in_array($result['others']['detail'][$last][1], array(
  593. 'Debian',
  594. 'Hat',
  595. ))) {
  596. $searchRV = true;
  597. }
  598. $result['browser_name'] = $result['others']['detail'][$last][1];
  599. $result['browser_version'] = $result['others']['detail'][$last][2];
  600. if (isset($comment[4])) {
  601. $result['browser_build'] = trim($comment[4]);
  602. }
  603. if (isset($comment[3])) {
  604. $result['browser_language'] = trim($comment[3]);
  605. }
  606. // Netscape
  607. if ($result['browser_name'] == 'Navigator' || $result['browser_name'] == 'Netscape6') {
  608. $result['browser_name'] = 'Netscape';
  609. }
  610. }
  611. if ($searchRV) {
  612. // Mozilla alone : the version is identified by rv:
  613. $result['browser_name'] = 'Mozilla';
  614. if (isset($result['comment']['detail'])) {
  615. foreach ($result['comment']['detail'] as $rv) {
  616. if (strpos($rv, 'rv:') !== false) {
  617. $result['browser_version'] = trim(str_replace('rv:', '', $rv));
  618. }
  619. }
  620. }
  621. }
  622. }
  623. // Netscape
  624. if ($result['others']['detail'][0][1] == 'Netscape') {
  625. $result['browser_name'] = 'Netscape';
  626. $result['browser_version'] = $result['others']['detail'][0][2];
  627. }
  628. // Opera
  629. // Opera: engine Presto
  630. if ($result['others']['detail'][0][1] == 'Presto') {
  631. $result['browser_engine'] = 'Presto';
  632. if (!empty($result['others']['detail'][1][2])) {
  633. $result['browser_version'] = $result['others']['detail'][1][2];
  634. }
  635. }
  636. // UA ends with 'Opera X.XX'
  637. if ($result['others']['detail'][0][1] == 'Opera') {
  638. $result['browser_name'] = $result['others']['detail'][0][1];
  639. $result['browser_version'] = $result['others']['detail'][1][1];
  640. }
  641. // Opera Mini
  642. if (isset($result["browser_token"])) {
  643. if (strpos($result["browser_token"], 'Opera Mini') !== false) {
  644. $result['browser_name'] = 'Opera Mini';
  645. }
  646. }
  647. // Symbian
  648. if ($result['others']['detail'][0][1] == 'SymbianOS') {
  649. $result['device_os_token'] = 'SymbianOS';
  650. }
  651. }
  652. // UA ends with 'Opera X.XX'
  653. if (isset($result['browser_name']) && isset($result['browser_engine'])) {
  654. if ($result['browser_name'] == 'Opera' && $result['browser_engine'] == 'Gecko' && empty($result['browser_version'])) {
  655. $result['browser_version'] = $result['others']['detail'][count($result['others']['detail']) - 1][1];
  656. }
  657. }
  658. // cleanup
  659. if (isset($result['browser_version']) && isset($result['browser_build'])) {
  660. if ($result['browser_version'] == $result['browser_build']) {
  661. unset($result['browser_build']);
  662. }
  663. }
  664. // compatibility
  665. $compatibility['AppleWebKit'] = 'Safari';
  666. $compatibility['Gecko'] = 'Firefox';
  667. $compatibility['MSIE'] = 'Internet Explorer';
  668. $compatibility['Presto'] = 'Opera';
  669. if (!empty($result['browser_engine'])) {
  670. if (isset($compatibility[$result['browser_engine']])) {
  671. $result['browser_compatibility'] = $compatibility[$result['browser_engine']];
  672. }
  673. }
  674. ksort($result);
  675. return $result;
  676. }
  677. /**
  678. * Loads the Features Adapter if it's defined in the $config array
  679. * Otherwise, nothing is done
  680. *
  681. * @param string $browserType Browser type
  682. * @return array
  683. */
  684. protected function _loadFeaturesAdapter()
  685. {
  686. $config = $this->_config;
  687. $browserType = $this->getType();
  688. if (!isset($config[$browserType]) || !isset($config[$browserType]['features'])) {
  689. return array();
  690. }
  691. $config = $config[$browserType]['features'];
  692. if (empty($config['classname'])) {
  693. require_once 'Zend/Http/UserAgent/Exception.php';
  694. throw new Zend_Http_UserAgent_Exception('The ' . $this->getType() . ' features adapter must have a "classname" config parameter defined');
  695. }
  696. $className = $config['classname'];
  697. if (!class_exists($className)) {
  698. if (isset($config['path'])) {
  699. $path = $config['path'];
  700. } else {
  701. require_once 'Zend/Http/UserAgent/Exception.php';
  702. throw new Zend_Http_UserAgent_Exception('The ' . $this->getType() . ' features adapter must have a "path" config parameter defined');
  703. }
  704. if (false === include_once ($path)) {
  705. require_once 'Zend/Http/UserAgent/Exception.php';
  706. throw new Zend_Http_UserAgent_Exception('The ' . $this->getType() . ' features adapter path that does not exist');
  707. }
  708. }
  709. return call_user_func(array($className, 'getFromRequest'), $this->_server, $this->_config);
  710. }
  711. /**
  712. * Retrieve image format support
  713. *
  714. * @return array
  715. */
  716. public function getImageFormatSupport()
  717. {
  718. return $this->_images;
  719. }
  720. /**
  721. * Get maximum image height supported by this device
  722. *
  723. * @return int
  724. */
  725. public function getMaxImageHeight()
  726. {
  727. return null;
  728. }
  729. /**
  730. * Get maximum image width supported by this device
  731. *
  732. * @return int
  733. */
  734. public function getMaxImageWidth()
  735. {
  736. return null;
  737. }
  738. /**
  739. * Get physical screen height of this device
  740. *
  741. * @return int
  742. */
  743. public function getPhysicalScreenHeight()
  744. {
  745. return null;
  746. }
  747. /**
  748. * Get physical screen width of this device
  749. *
  750. * @return int
  751. */
  752. public function getPhysicalScreenWidth()
  753. {
  754. return null;
  755. }
  756. /**
  757. * Get preferred markup type
  758. *
  759. * @return string
  760. */
  761. public function getPreferredMarkup()
  762. {
  763. return 'xhtml';
  764. }
  765. /**
  766. * Get supported X/HTML version
  767. *
  768. * @return int
  769. */
  770. public function getXhtmlSupportLevel()
  771. {
  772. return 4;
  773. }
  774. /**
  775. * Does the device support Flash?
  776. *
  777. * @return bool
  778. */
  779. public function hasFlashSupport()
  780. {
  781. return true;
  782. }
  783. /**
  784. * Does the device support PDF?
  785. *
  786. * @return bool
  787. */
  788. public function hasPdfSupport()
  789. {
  790. return true;
  791. }
  792. /**
  793. * Does the device have a phone number associated with it?
  794. *
  795. * @return bool
  796. */
  797. public function hasPhoneNumber()
  798. {
  799. return false;
  800. }
  801. /**
  802. * Does the device support HTTPS?
  803. *
  804. * @return bool
  805. */
  806. public function httpsSupport()
  807. {
  808. return true;
  809. }
  810. /**
  811. * Get the browser type
  812. *
  813. * @return string
  814. */
  815. public function getBrowser()
  816. {
  817. return $this->_browser;
  818. }
  819. /**
  820. * Get the browser version
  821. *
  822. * @return string
  823. */
  824. public function getBrowserVersion()
  825. {
  826. return $this->_browserVersion;
  827. }
  828. /**
  829. * Get the user agent string
  830. *
  831. * @return string
  832. */
  833. public function getUserAgent()
  834. {
  835. return $this->_userAgent;
  836. }
  837. /**
  838. * @return the $_images
  839. */
  840. public function getImages()
  841. {
  842. return $this->_images;
  843. }
  844. /**
  845. * @param string $browser
  846. */
  847. public function setBrowser($browser)
  848. {
  849. $this->_browser = $browser;
  850. }
  851. /**
  852. * @param string $browserVersion
  853. */
  854. public function setBrowserVersion($browserVersion)
  855. {
  856. $this->_browserVersion = $browserVersion;
  857. }
  858. /**
  859. * @param string $userAgent
  860. */
  861. public function setUserAgent($userAgent)
  862. {
  863. $this->_userAgent = $userAgent;
  864. return $this;
  865. }
  866. /**
  867. * @param array $_images
  868. */
  869. public function setImages($_images)
  870. {
  871. $this->_images = $_images;
  872. }
  873. /**
  874. * Match a user agent string against a list of signatures
  875. *
  876. * @param string $userAgent
  877. * @param array $signatures
  878. * @return bool
  879. */
  880. protected static function _matchAgentAgainstSignatures($userAgent, $signatures)
  881. {
  882. $userAgent = strtolower($userAgent);
  883. foreach ($signatures as $signature) {
  884. if (!empty($signature)) {
  885. if (strpos($userAgent, $signature) !== false) {
  886. // Browser signature was found in user agent string
  887. return true;
  888. }
  889. }
  890. }
  891. return false;
  892. }
  893. }