You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

681 lines
13 KiB

7 years ago
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2017, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2017, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://opensource.org/licenses/MIT MIT License
  34. * @link https://codeigniter.com
  35. * @since Version 1.0.0
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * User Agent Class
  41. *
  42. * Identifies the platform, browser, robot, or mobile device of the browsing agent
  43. *
  44. * @package CodeIgniter
  45. * @subpackage Libraries
  46. * @category User Agent
  47. * @author EllisLab Dev Team
  48. * @link https://codeigniter.com/user_guide/libraries/user_agent.html
  49. */
  50. class CI_User_agent {
  51. /**
  52. * Current user-agent
  53. *
  54. * @var string
  55. */
  56. public $agent = NULL;
  57. /**
  58. * Flag for if the user-agent belongs to a browser
  59. *
  60. * @var bool
  61. */
  62. public $is_browser = FALSE;
  63. /**
  64. * Flag for if the user-agent is a robot
  65. *
  66. * @var bool
  67. */
  68. public $is_robot = FALSE;
  69. /**
  70. * Flag for if the user-agent is a mobile browser
  71. *
  72. * @var bool
  73. */
  74. public $is_mobile = FALSE;
  75. /**
  76. * Languages accepted by the current user agent
  77. *
  78. * @var array
  79. */
  80. public $languages = array();
  81. /**
  82. * Character sets accepted by the current user agent
  83. *
  84. * @var array
  85. */
  86. public $charsets = array();
  87. /**
  88. * List of platforms to compare against current user agent
  89. *
  90. * @var array
  91. */
  92. public $platforms = array();
  93. /**
  94. * List of browsers to compare against current user agent
  95. *
  96. * @var array
  97. */
  98. public $browsers = array();
  99. /**
  100. * List of mobile browsers to compare against current user agent
  101. *
  102. * @var array
  103. */
  104. public $mobiles = array();
  105. /**
  106. * List of robots to compare against current user agent
  107. *
  108. * @var array
  109. */
  110. public $robots = array();
  111. /**
  112. * Current user-agent platform
  113. *
  114. * @var string
  115. */
  116. public $platform = '';
  117. /**
  118. * Current user-agent browser
  119. *
  120. * @var string
  121. */
  122. public $browser = '';
  123. /**
  124. * Current user-agent version
  125. *
  126. * @var string
  127. */
  128. public $version = '';
  129. /**
  130. * Current user-agent mobile name
  131. *
  132. * @var string
  133. */
  134. public $mobile = '';
  135. /**
  136. * Current user-agent robot name
  137. *
  138. * @var string
  139. */
  140. public $robot = '';
  141. /**
  142. * HTTP Referer
  143. *
  144. * @var mixed
  145. */
  146. public $referer;
  147. // --------------------------------------------------------------------
  148. /**
  149. * Constructor
  150. *
  151. * Sets the User Agent and runs the compilation routine
  152. *
  153. * @return void
  154. */
  155. public function __construct()
  156. {
  157. $this->_load_agent_file();
  158. if (isset($_SERVER['HTTP_USER_AGENT']))
  159. {
  160. $this->agent = trim($_SERVER['HTTP_USER_AGENT']);
  161. $this->_compile_data();
  162. }
  163. log_message('info', 'User Agent Class Initialized');
  164. }
  165. // --------------------------------------------------------------------
  166. /**
  167. * Compile the User Agent Data
  168. *
  169. * @return bool
  170. */
  171. protected function _load_agent_file()
  172. {
  173. if (($found = file_exists(APPPATH.'config/user_agents.php')))
  174. {
  175. include(APPPATH.'config/user_agents.php');
  176. }
  177. if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php'))
  178. {
  179. include(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php');
  180. $found = TRUE;
  181. }
  182. if ($found !== TRUE)
  183. {
  184. return FALSE;
  185. }
  186. $return = FALSE;
  187. if (isset($platforms))
  188. {
  189. $this->platforms = $platforms;
  190. unset($platforms);
  191. $return = TRUE;
  192. }
  193. if (isset($browsers))
  194. {
  195. $this->browsers = $browsers;
  196. unset($browsers);
  197. $return = TRUE;
  198. }
  199. if (isset($mobiles))
  200. {
  201. $this->mobiles = $mobiles;
  202. unset($mobiles);
  203. $return = TRUE;
  204. }
  205. if (isset($robots))
  206. {
  207. $this->robots = $robots;
  208. unset($robots);
  209. $return = TRUE;
  210. }
  211. return $return;
  212. }
  213. // --------------------------------------------------------------------
  214. /**
  215. * Compile the User Agent Data
  216. *
  217. * @return bool
  218. */
  219. protected function _compile_data()
  220. {
  221. $this->_set_platform();
  222. foreach (array('_set_robot', '_set_browser', '_set_mobile') as $function)
  223. {
  224. if ($this->$function() === TRUE)
  225. {
  226. break;
  227. }
  228. }
  229. }
  230. // --------------------------------------------------------------------
  231. /**
  232. * Set the Platform
  233. *
  234. * @return bool
  235. */
  236. protected function _set_platform()
  237. {
  238. if (is_array($this->platforms) && count($this->platforms) > 0)
  239. {
  240. foreach ($this->platforms as $key => $val)
  241. {
  242. if (preg_match('|'.preg_quote($key).'|i', $this->agent))
  243. {
  244. $this->platform = $val;
  245. return TRUE;
  246. }
  247. }
  248. }
  249. $this->platform = 'Unknown Platform';
  250. return FALSE;
  251. }
  252. // --------------------------------------------------------------------
  253. /**
  254. * Set the Browser
  255. *
  256. * @return bool
  257. */
  258. protected function _set_browser()
  259. {
  260. if (is_array($this->browsers) && count($this->browsers) > 0)
  261. {
  262. foreach ($this->browsers as $key => $val)
  263. {
  264. if (preg_match('|'.$key.'.*?([0-9\.]+)|i', $this->agent, $match))
  265. {
  266. $this->is_browser = TRUE;
  267. $this->version = $match[1];
  268. $this->browser = $val;
  269. $this->_set_mobile();
  270. return TRUE;
  271. }
  272. }
  273. }
  274. return FALSE;
  275. }
  276. // --------------------------------------------------------------------
  277. /**
  278. * Set the Robot
  279. *
  280. * @return bool
  281. */
  282. protected function _set_robot()
  283. {
  284. if (is_array($this->robots) && count($this->robots) > 0)
  285. {
  286. foreach ($this->robots as $key => $val)
  287. {
  288. if (preg_match('|'.preg_quote($key).'|i', $this->agent))
  289. {
  290. $this->is_robot = TRUE;
  291. $this->robot = $val;
  292. $this->_set_mobile();
  293. return TRUE;
  294. }
  295. }
  296. }
  297. return FALSE;
  298. }
  299. // --------------------------------------------------------------------
  300. /**
  301. * Set the Mobile Device
  302. *
  303. * @return bool
  304. */
  305. protected function _set_mobile()
  306. {
  307. if (is_array($this->mobiles) && count($this->mobiles) > 0)
  308. {
  309. foreach ($this->mobiles as $key => $val)
  310. {
  311. if (FALSE !== (stripos($this->agent, $key)))
  312. {
  313. $this->is_mobile = TRUE;
  314. $this->mobile = $val;
  315. return TRUE;
  316. }
  317. }
  318. }
  319. return FALSE;
  320. }
  321. // --------------------------------------------------------------------
  322. /**
  323. * Set the accepted languages
  324. *
  325. * @return void
  326. */
  327. protected function _set_languages()
  328. {
  329. if ((count($this->languages) === 0) && ! empty($_SERVER['HTTP_ACCEPT_LANGUAGE']))
  330. {
  331. $this->languages = explode(',', preg_replace('/(;\s?q=[0-9\.]+)|\s/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_LANGUAGE']))));
  332. }
  333. if (count($this->languages) === 0)
  334. {
  335. $this->languages = array('Undefined');
  336. }
  337. }
  338. // --------------------------------------------------------------------
  339. /**
  340. * Set the accepted character sets
  341. *
  342. * @return void
  343. */
  344. protected function _set_charsets()
  345. {
  346. if ((count($this->charsets) === 0) && ! empty($_SERVER['HTTP_ACCEPT_CHARSET']))
  347. {
  348. $this->charsets = explode(',', preg_replace('/(;\s?q=.+)|\s/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_CHARSET']))));
  349. }
  350. if (count($this->charsets) === 0)
  351. {
  352. $this->charsets = array('Undefined');
  353. }
  354. }
  355. // --------------------------------------------------------------------
  356. /**
  357. * Is Browser
  358. *
  359. * @param string $key
  360. * @return bool
  361. */
  362. public function is_browser($key = NULL)
  363. {
  364. if ( ! $this->is_browser)
  365. {
  366. return FALSE;
  367. }
  368. // No need to be specific, it's a browser
  369. if ($key === NULL)
  370. {
  371. return TRUE;
  372. }
  373. // Check for a specific browser
  374. return (isset($this->browsers[$key]) && $this->browser === $this->browsers[$key]);
  375. }
  376. // --------------------------------------------------------------------
  377. /**
  378. * Is Robot
  379. *
  380. * @param string $key
  381. * @return bool
  382. */
  383. public function is_robot($key = NULL)
  384. {
  385. if ( ! $this->is_robot)
  386. {
  387. return FALSE;
  388. }
  389. // No need to be specific, it's a robot
  390. if ($key === NULL)
  391. {
  392. return TRUE;
  393. }
  394. // Check for a specific robot
  395. return (isset($this->robots[$key]) && $this->robot === $this->robots[$key]);
  396. }
  397. // --------------------------------------------------------------------
  398. /**
  399. * Is Mobile
  400. *
  401. * @param string $key
  402. * @return bool
  403. */
  404. public function is_mobile($key = NULL)
  405. {
  406. if ( ! $this->is_mobile)
  407. {
  408. return FALSE;
  409. }
  410. // No need to be specific, it's a mobile
  411. if ($key === NULL)
  412. {
  413. return TRUE;
  414. }
  415. // Check for a specific robot
  416. return (isset($this->mobiles[$key]) && $this->mobile === $this->mobiles[$key]);
  417. }
  418. // --------------------------------------------------------------------
  419. /**
  420. * Is this a referral from another site?
  421. *
  422. * @return bool
  423. */
  424. public function is_referral()
  425. {
  426. if ( ! isset($this->referer))
  427. {
  428. if (empty($_SERVER['HTTP_REFERER']))
  429. {
  430. $this->referer = FALSE;
  431. }
  432. else
  433. {
  434. $referer_host = @parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
  435. $own_host = parse_url(config_item('base_url'), PHP_URL_HOST);
  436. $this->referer = ($referer_host && $referer_host !== $own_host);
  437. }
  438. }
  439. return $this->referer;
  440. }
  441. // --------------------------------------------------------------------
  442. /**
  443. * Agent String
  444. *
  445. * @return string
  446. */
  447. public function agent_string()
  448. {
  449. return $this->agent;
  450. }
  451. // --------------------------------------------------------------------
  452. /**
  453. * Get Platform
  454. *
  455. * @return string
  456. */
  457. public function platform()
  458. {
  459. return $this->platform;
  460. }
  461. // --------------------------------------------------------------------
  462. /**
  463. * Get Browser Name
  464. *
  465. * @return string
  466. */
  467. public function browser()
  468. {
  469. return $this->browser;
  470. }
  471. // --------------------------------------------------------------------
  472. /**
  473. * Get the Browser Version
  474. *
  475. * @return string
  476. */
  477. public function version()
  478. {
  479. return $this->version;
  480. }
  481. // --------------------------------------------------------------------
  482. /**
  483. * Get The Robot Name
  484. *
  485. * @return string
  486. */
  487. public function robot()
  488. {
  489. return $this->robot;
  490. }
  491. // --------------------------------------------------------------------
  492. /**
  493. * Get the Mobile Device
  494. *
  495. * @return string
  496. */
  497. public function mobile()
  498. {
  499. return $this->mobile;
  500. }
  501. // --------------------------------------------------------------------
  502. /**
  503. * Get the referrer
  504. *
  505. * @return bool
  506. */
  507. public function referrer()
  508. {
  509. return empty($_SERVER['HTTP_REFERER']) ? '' : trim($_SERVER['HTTP_REFERER']);
  510. }
  511. // --------------------------------------------------------------------
  512. /**
  513. * Get the accepted languages
  514. *
  515. * @return array
  516. */
  517. public function languages()
  518. {
  519. if (count($this->languages) === 0)
  520. {
  521. $this->_set_languages();
  522. }
  523. return $this->languages;
  524. }
  525. // --------------------------------------------------------------------
  526. /**
  527. * Get the accepted Character Sets
  528. *
  529. * @return array
  530. */
  531. public function charsets()
  532. {
  533. if (count($this->charsets) === 0)
  534. {
  535. $this->_set_charsets();
  536. }
  537. return $this->charsets;
  538. }
  539. // --------------------------------------------------------------------
  540. /**
  541. * Test for a particular language
  542. *
  543. * @param string $lang
  544. * @return bool
  545. */
  546. public function accept_lang($lang = 'en')
  547. {
  548. return in_array(strtolower($lang), $this->languages(), TRUE);
  549. }
  550. // --------------------------------------------------------------------
  551. /**
  552. * Test for a particular character set
  553. *
  554. * @param string $charset
  555. * @return bool
  556. */
  557. public function accept_charset($charset = 'utf-8')
  558. {
  559. return in_array(strtolower($charset), $this->charsets(), TRUE);
  560. }
  561. // --------------------------------------------------------------------
  562. /**
  563. * Parse a custom user-agent string
  564. *
  565. * @param string $string
  566. * @return void
  567. */
  568. public function parse($string)
  569. {
  570. // Reset values
  571. $this->is_browser = FALSE;
  572. $this->is_robot = FALSE;
  573. $this->is_mobile = FALSE;
  574. $this->browser = '';
  575. $this->version = '';
  576. $this->mobile = '';
  577. $this->robot = '';
  578. // Set the new user-agent string and parse it, unless empty
  579. $this->agent = $string;
  580. if ( ! empty($string))
  581. {
  582. $this->_compile_data();
  583. }
  584. }
  585. }