PageRenderTime 61ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/application/models/ion_auth_model.php

https://bitbucket.org/alexdeoliveira/ignitercms
PHP | 2028 lines | 1187 code | 355 blank | 486 comment | 162 complexity | ee6ae6bb2d98e9e1a673fcbfd7c5c1dc MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * Name: Ion Auth Model
  4. *
  5. * Author: Ben Edmunds
  6. * ben.edmunds@gmail.com
  7. * @benedmunds
  8. *
  9. * Added Awesomeness: Phil Sturgeon
  10. *
  11. * Location: http://github.com/benedmunds/CodeIgniter-Ion-Auth
  12. *
  13. * Created: 10.01.2009
  14. *
  15. * Description: Modified auth system based on redux_auth with extensive customization. This is basically what Redux Auth 2 should be.
  16. * Original Author name has been kept but that does not mean that the method has not been modified.
  17. *
  18. * Requirements: PHP5 or above
  19. *
  20. */
  21. class Ion_auth_model extends CI_Model
  22. {
  23. /**
  24. * Holds an array of tables used
  25. *
  26. * @var string
  27. **/
  28. public $tables = array();
  29. /**
  30. * activation code
  31. *
  32. * @var string
  33. **/
  34. public $activation_code;
  35. /**
  36. * forgotten password key
  37. *
  38. * @var string
  39. **/
  40. public $forgotten_password_code;
  41. /**
  42. * new password
  43. *
  44. * @var string
  45. **/
  46. public $new_password;
  47. /**
  48. * Identity
  49. *
  50. * @var string
  51. **/
  52. public $identity;
  53. /**
  54. * Where
  55. *
  56. * @var array
  57. **/
  58. public $_ion_where = array();
  59. /**
  60. * Select
  61. *
  62. * @var string
  63. **/
  64. public $_ion_select = array();
  65. /**
  66. * Like
  67. *
  68. * @var string
  69. **/
  70. public $_ion_like = array();
  71. /**
  72. * Limit
  73. *
  74. * @var string
  75. **/
  76. public $_ion_limit = NULL;
  77. /**
  78. * Offset
  79. *
  80. * @var string
  81. **/
  82. public $_ion_offset = NULL;
  83. /**
  84. * Order By
  85. *
  86. * @var string
  87. **/
  88. public $_ion_order_by = NULL;
  89. /**
  90. * Order
  91. *
  92. * @var string
  93. **/
  94. public $_ion_order = NULL;
  95. /**
  96. * Hooks
  97. *
  98. * @var object
  99. **/
  100. protected $_ion_hooks;
  101. /**
  102. * Response
  103. *
  104. * @var string
  105. **/
  106. protected $response = NULL;
  107. /**
  108. * message (uses lang file)
  109. *
  110. * @var string
  111. **/
  112. protected $messages;
  113. /**
  114. * error message (uses lang file)
  115. *
  116. * @var string
  117. **/
  118. protected $errors;
  119. /**
  120. * error start delimiter
  121. *
  122. * @var string
  123. **/
  124. protected $error_start_delimiter;
  125. /**
  126. * error end delimiter
  127. *
  128. * @var string
  129. **/
  130. protected $error_end_delimiter;
  131. /**
  132. * caching of users and their groups
  133. *
  134. * @var array
  135. **/
  136. public $_cache_user_in_group = array();
  137. /**
  138. * caching of groups
  139. *
  140. * @var array
  141. **/
  142. protected $_cache_groups = array();
  143. public function __construct()
  144. {
  145. parent::__construct();
  146. $this->load->database();
  147. $this->load->config('ion_auth', TRUE);
  148. $this->load->helper('cookie');
  149. $this->load->helper('date');
  150. $this->load->library('session');
  151. $this->lang->load('ion_auth');
  152. //initialize db tables data
  153. $this->tables = $this->config->item('tables', 'ion_auth');
  154. //initialize data
  155. $this->identity_column = $this->config->item('identity', 'ion_auth');
  156. $this->store_salt = $this->config->item('store_salt', 'ion_auth');
  157. $this->salt_length = $this->config->item('salt_length', 'ion_auth');
  158. $this->join = $this->config->item('join', 'ion_auth');
  159. //initialize hash method options (Bcrypt)
  160. $this->hash_method = $this->config->item('hash_method', 'ion_auth');
  161. $this->default_rounds = $this->config->item('default_rounds', 'ion_auth');
  162. $this->random_rounds = $this->config->item('random_rounds', 'ion_auth');
  163. $this->min_rounds = $this->config->item('min_rounds', 'ion_auth');
  164. $this->max_rounds = $this->config->item('max_rounds', 'ion_auth');
  165. //initialize messages and error
  166. $this->messages = array();
  167. $this->errors = array();
  168. $this->message_start_delimiter = $this->config->item('message_start_delimiter', 'ion_auth');
  169. $this->message_end_delimiter = $this->config->item('message_end_delimiter', 'ion_auth');
  170. $this->error_start_delimiter = $this->config->item('error_start_delimiter', 'ion_auth');
  171. $this->error_end_delimiter = $this->config->item('error_end_delimiter', 'ion_auth');
  172. //initialize our hooks object
  173. $this->_ion_hooks = new stdClass;
  174. //load the bcrypt class if needed
  175. if ($this->hash_method == 'bcrypt') {
  176. if ($this->random_rounds)
  177. {
  178. $rand = rand($this->min_rounds,$this->max_rounds);
  179. $rounds = array('rounds' => $rand);
  180. }
  181. else
  182. {
  183. $rounds = array('rounds' => $this->default_rounds);
  184. }
  185. $this->load->library('bcrypt',$rounds);
  186. }
  187. $this->trigger_events('model_constructor');
  188. }
  189. /**
  190. * Misc functions
  191. *
  192. * Hash password : Hashes the password to be stored in the database.
  193. * Hash password db : This function takes a password and validates it
  194. * against an entry in the users table.
  195. * Salt : Generates a random salt value.
  196. *
  197. * @author Mathew
  198. */
  199. /**
  200. * Hashes the password to be stored in the database.
  201. *
  202. * @return void
  203. * @author Mathew
  204. **/
  205. public function hash_password($password, $salt=false, $use_sha1_override=FALSE)
  206. {
  207. if (empty($password))
  208. {
  209. return FALSE;
  210. }
  211. //bcrypt
  212. if ($use_sha1_override === FALSE && $this->hash_method == 'bcrypt')
  213. {
  214. return $this->bcrypt->hash($password);
  215. }
  216. if ($this->store_salt && $salt)
  217. {
  218. return sha1($password . $salt);
  219. }
  220. else
  221. {
  222. $salt = $this->salt();
  223. return $salt . substr(sha1($salt . $password), 0, -$this->salt_length);
  224. }
  225. }
  226. /**
  227. * This function takes a password and validates it
  228. * against an entry in the users table.
  229. *
  230. * @return void
  231. * @author Mathew
  232. **/
  233. public function hash_password_db($id, $password, $use_sha1_override=FALSE)
  234. {
  235. if (empty($id) || empty($password))
  236. {
  237. return FALSE;
  238. }
  239. $this->trigger_events('extra_where');
  240. $query = $this->db->select('password, salt')
  241. ->where('id', $id)
  242. ->limit(1)
  243. ->get($this->tables['users']);
  244. $hash_password_db = $query->row();
  245. if ($query->num_rows() !== 1)
  246. {
  247. return FALSE;
  248. }
  249. // bcrypt
  250. if ($use_sha1_override === FALSE && $this->hash_method == 'bcrypt')
  251. {
  252. if ($this->bcrypt->verify($password,$hash_password_db->password))
  253. {
  254. return TRUE;
  255. }
  256. return FALSE;
  257. }
  258. // sha1
  259. if ($this->store_salt)
  260. {
  261. $db_password = sha1($password . $hash_password_db->salt);
  262. }
  263. else
  264. {
  265. $salt = substr($hash_password_db->password, 0, $this->salt_length);
  266. $db_password = $salt . substr(sha1($salt . $password), 0, -$this->salt_length);
  267. }
  268. if($db_password == $hash_password_db->password)
  269. {
  270. return TRUE;
  271. }
  272. else
  273. {
  274. return FALSE;
  275. }
  276. }
  277. /**
  278. * Generates a random salt value for forgotten passwords or any other keys. Uses SHA1.
  279. *
  280. * @return void
  281. * @author Mathew
  282. **/
  283. public function hash_code($password)
  284. {
  285. return $this->hash_password($password, FALSE, TRUE);
  286. }
  287. /**
  288. * Generates a random salt value.
  289. *
  290. * @return void
  291. * @author Mathew
  292. **/
  293. public function salt()
  294. {
  295. return substr(md5(uniqid(rand(), true)), 0, $this->salt_length);
  296. }
  297. /**
  298. * Activation functions
  299. *
  300. * Activate : Validates and removes activation code.
  301. * Deactivae : Updates a users row with an activation code.
  302. *
  303. * @author Mathew
  304. */
  305. /**
  306. * activate
  307. *
  308. * @return void
  309. * @author Mathew
  310. **/
  311. public function activate($id, $code = false)
  312. {
  313. $this->trigger_events('pre_activate');
  314. if ($code !== FALSE)
  315. {
  316. $query = $this->db->select($this->identity_column)
  317. ->where('activation_code', $code)
  318. ->limit(1)
  319. ->get($this->tables['users']);
  320. $result = $query->row();
  321. if ($query->num_rows() !== 1)
  322. {
  323. $this->trigger_events(array('post_activate', 'post_activate_unsuccessful'));
  324. $this->set_error('activate_unsuccessful');
  325. return FALSE;
  326. }
  327. $identity = $result->{$this->identity_column};
  328. $data = array(
  329. 'activation_code' => NULL,
  330. 'active' => 1
  331. );
  332. $this->trigger_events('extra_where');
  333. $this->db->update($this->tables['users'], $data, array($this->identity_column => $identity));
  334. }
  335. else
  336. {
  337. $data = array(
  338. 'activation_code' => NULL,
  339. 'active' => 1
  340. );
  341. $this->trigger_events('extra_where');
  342. $this->db->update($this->tables['users'], $data, array('id' => $id));
  343. }
  344. $return = $this->db->affected_rows() == 1;
  345. if ($return)
  346. {
  347. $this->trigger_events(array('post_activate', 'post_activate_successful'));
  348. $this->set_message('activate_successful');
  349. }
  350. else
  351. {
  352. $this->trigger_events(array('post_activate', 'post_activate_unsuccessful'));
  353. $this->set_error('activate_unsuccessful');
  354. }
  355. return $return;
  356. }
  357. /**
  358. * Deactivate
  359. *
  360. * @return void
  361. * @author Mathew
  362. **/
  363. public function deactivate($id = NULL)
  364. {
  365. $this->trigger_events('deactivate');
  366. if (!isset($id))
  367. {
  368. $this->set_error('deactivate_unsuccessful');
  369. return FALSE;
  370. }
  371. $activation_code = sha1(md5(microtime()));
  372. $this->activation_code = $activation_code;
  373. $data = array(
  374. 'activation_code' => $activation_code,
  375. 'active' => 0
  376. );
  377. $this->trigger_events('extra_where');
  378. $this->db->update($this->tables['users'], $data, array('id' => $id));
  379. $return = $this->db->affected_rows() == 1;
  380. if ($return)
  381. $this->set_message('deactivate_successful');
  382. else
  383. $this->set_error('deactivate_unsuccessful');
  384. return $return;
  385. }
  386. public function clear_forgotten_password_code($code) {
  387. if (empty($code))
  388. {
  389. return FALSE;
  390. }
  391. $this->db->where('forgotten_password_code', $code);
  392. if ($this->db->count_all_results($this->tables['users']) > 0)
  393. {
  394. $data = array(
  395. 'forgotten_password_code' => NULL,
  396. 'forgotten_password_time' => NULL
  397. );
  398. $this->db->update($this->tables['users'], $data, array('forgotten_password_code' => $code));
  399. return TRUE;
  400. }
  401. return FALSE;
  402. }
  403. /**
  404. * reset password
  405. *
  406. * @return bool
  407. * @author Mathew
  408. **/
  409. public function reset_password($identity, $new) {
  410. $this->trigger_events('pre_change_password');
  411. if (!$this->identity_check($identity)) {
  412. $this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful'));
  413. return FALSE;
  414. }
  415. $this->trigger_events('extra_where');
  416. $query = $this->db->select('id, password, salt')
  417. ->where($this->identity_column, $identity)
  418. ->limit(1)
  419. ->get($this->tables['users']);
  420. if ($query->num_rows() !== 1)
  421. {
  422. $this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful'));
  423. $this->set_error('password_change_unsuccessful');
  424. return FALSE;
  425. }
  426. $result = $query->row();
  427. $new = $this->hash_password($new, $result->salt);
  428. //store the new password and reset the remember code so all remembered instances have to re-login
  429. //also clear the forgotten password code
  430. $data = array(
  431. 'password' => $new,
  432. 'remember_code' => NULL,
  433. 'forgotten_password_code' => NULL,
  434. 'forgotten_password_time' => NULL,
  435. );
  436. $this->trigger_events('extra_where');
  437. $this->db->update($this->tables['users'], $data, array($this->identity_column => $identity));
  438. $return = $this->db->affected_rows() == 1;
  439. if ($return)
  440. {
  441. $this->trigger_events(array('post_change_password', 'post_change_password_successful'));
  442. $this->set_message('password_change_successful');
  443. }
  444. else
  445. {
  446. $this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful'));
  447. $this->set_error('password_change_unsuccessful');
  448. }
  449. return $return;
  450. }
  451. /**
  452. * change password
  453. *
  454. * @return bool
  455. * @author Mathew
  456. **/
  457. public function change_password($identity, $old, $new)
  458. {
  459. $this->trigger_events('pre_change_password');
  460. $this->trigger_events('extra_where');
  461. $query = $this->db->select('id, password, salt')
  462. ->where($this->identity_column, $identity)
  463. ->limit(1)
  464. ->get($this->tables['users']);
  465. if ($query->num_rows() !== 1)
  466. {
  467. $this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful'));
  468. $this->set_error('password_change_unsuccessful');
  469. return FALSE;
  470. }
  471. $result = $query->row();
  472. $db_password = $result->password;
  473. $old = $this->hash_password_db($result->id, $old);
  474. $new = $this->hash_password($new, $result->salt);
  475. if ($old === TRUE)
  476. {
  477. //store the new password and reset the remember code so all remembered instances have to re-login
  478. $data = array(
  479. 'password' => $new,
  480. 'remember_code' => NULL,
  481. );
  482. $this->trigger_events('extra_where');
  483. $this->db->update($this->tables['users'], $data, array($this->identity_column => $identity));
  484. $return = $this->db->affected_rows() == 1;
  485. if ($return)
  486. {
  487. $this->trigger_events(array('post_change_password', 'post_change_password_successful'));
  488. $this->set_message('password_change_successful');
  489. }
  490. else
  491. {
  492. $this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful'));
  493. $this->set_error('password_change_unsuccessful');
  494. }
  495. return $return;
  496. }
  497. $this->set_error('password_change_unsuccessful');
  498. return FALSE;
  499. }
  500. /**
  501. * Checks username
  502. *
  503. * @return bool
  504. * @author Mathew
  505. **/
  506. public function username_check($username = '')
  507. {
  508. $this->trigger_events('username_check');
  509. if (empty($username))
  510. {
  511. return FALSE;
  512. }
  513. $this->trigger_events('extra_where');
  514. return $this->db->where('username', $username)
  515. ->count_all_results($this->tables['users']) > 0;
  516. }
  517. /**
  518. * Checks email
  519. *
  520. * @return bool
  521. * @author Mathew
  522. **/
  523. public function email_check($email = '')
  524. {
  525. $this->trigger_events('email_check');
  526. if (empty($email))
  527. {
  528. return FALSE;
  529. }
  530. $this->trigger_events('extra_where');
  531. return $this->db->where('email', $email)
  532. ->count_all_results($this->tables['users']) > 0;
  533. }
  534. /**
  535. * Identity check
  536. *
  537. * @return bool
  538. * @author Mathew
  539. **/
  540. public function identity_check($identity = '')
  541. {
  542. $this->trigger_events('identity_check');
  543. if (empty($identity))
  544. {
  545. return FALSE;
  546. }
  547. return $this->db->where($this->identity_column, $identity)
  548. ->count_all_results($this->tables['users']) > 0;
  549. }
  550. /**
  551. * Insert a forgotten password key.
  552. *
  553. * @return bool
  554. * @author Mathew
  555. * @updated Ryan
  556. **/
  557. public function forgotten_password($identity)
  558. {
  559. if (empty($identity))
  560. {
  561. $this->trigger_events(array('post_forgotten_password', 'post_forgotten_password_unsuccessful'));
  562. return FALSE;
  563. }
  564. $key = $this->hash_code(microtime().$identity);
  565. $this->forgotten_password_code = $key;
  566. $this->trigger_events('extra_where');
  567. $update = array(
  568. 'forgotten_password_code' => $key,
  569. 'forgotten_password_time' => time()
  570. );
  571. $this->db->update($this->tables['users'], $update, array($this->identity_column => $identity));
  572. $return = $this->db->affected_rows() == 1;
  573. if ($return)
  574. $this->trigger_events(array('post_forgotten_password', 'post_forgotten_password_successful'));
  575. else
  576. $this->trigger_events(array('post_forgotten_password', 'post_forgotten_password_unsuccessful'));
  577. return $return;
  578. }
  579. /**
  580. * Forgotten Password Complete
  581. *
  582. * @return string
  583. * @author Mathew
  584. **/
  585. public function forgotten_password_complete($code, $salt=FALSE)
  586. {
  587. $this->trigger_events('pre_forgotten_password_complete');
  588. if (empty($code))
  589. {
  590. $this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful'));
  591. return FALSE;
  592. }
  593. $profile = $this->where('forgotten_password_code', $code)->users()->row(); //pass the code to profile
  594. if ($profile) {
  595. if ($this->config->item('forgot_password_expiration', 'ion_auth') > 0) {
  596. //Make sure it isn't expired
  597. $expiration = $this->config->item('forgot_password_expiration', 'ion_auth');
  598. if (time() - $profile->forgotten_password_time > $expiration) {
  599. //it has expired
  600. $this->set_error('forgot_password_expired');
  601. $this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful'));
  602. return FALSE;
  603. }
  604. }
  605. $password = $this->salt();
  606. $data = array(
  607. 'password' => $this->hash_password($password, $salt),
  608. 'forgotten_password_code' => NULL,
  609. 'active' => 1,
  610. );
  611. $this->db->update($this->tables['users'], $data, array('forgotten_password_code' => $code));
  612. $this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_successful'));
  613. return $password;
  614. }
  615. $this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful'));
  616. return FALSE;
  617. }
  618. /**
  619. * register
  620. *
  621. * @return bool
  622. * @author Mathew
  623. **/
  624. public function register($username, $password, $email, $additional_data = array(), $groups = array())
  625. {
  626. $this->trigger_events('pre_register');
  627. $manual_activation = $this->config->item('manual_activation', 'ion_auth');
  628. if ($this->identity_column == 'email' && $this->email_check($email))
  629. {
  630. $this->set_error('account_creation_duplicate_email');
  631. return FALSE;
  632. }
  633. elseif ($this->identity_column == 'username' && $this->username_check($username))
  634. {
  635. $this->set_error('account_creation_duplicate_username');
  636. return FALSE;
  637. }
  638. // If username is taken, use username1 or username2, etc.
  639. if ($this->identity_column != 'username')
  640. {
  641. $original_username = $username;
  642. for($i = 0; $this->username_check($username); $i++)
  643. {
  644. if($i > 0)
  645. {
  646. $username = $original_username . $i;
  647. }
  648. }
  649. }
  650. // IP Address
  651. $ip_address = $this->_prepare_ip($this->input->ip_address());
  652. $salt = $this->store_salt ? $this->salt() : FALSE;
  653. $password = $this->hash_password($password, $salt);
  654. // Users table.
  655. $data = array(
  656. 'username' => $username,
  657. 'password' => $password,
  658. 'email' => $email,
  659. 'ip_address' => $ip_address,
  660. 'created_on' => time(),
  661. 'last_login' => time(),
  662. 'active' => ($manual_activation === false ? 1 : 0)
  663. );
  664. if ($this->store_salt)
  665. {
  666. $data['salt'] = $salt;
  667. }
  668. //filter out any data passed that doesnt have a matching column in the users table
  669. //and merge the set user data and the additional data
  670. $user_data = array_merge($this->_filter_data($this->tables['users'], $additional_data), $data);
  671. $this->trigger_events('extra_set');
  672. $this->db->insert($this->tables['users'], $user_data);
  673. $id = $this->db->insert_id();
  674. if (!empty($groups))
  675. {
  676. //add to groups
  677. foreach ($groups as $group)
  678. {
  679. $this->add_to_group($group, $id);
  680. }
  681. }
  682. //add to default group if not already set
  683. $default_group = $this->where('name', $this->config->item('default_group', 'ion_auth'))->group()->row();
  684. if ((isset($default_group->id) && !isset($groups)) || (empty($groups) && !in_array($default_group->id, $groups)))
  685. {
  686. $this->add_to_group($default_group->id, $id);
  687. }
  688. $this->trigger_events('post_register');
  689. return (isset($id)) ? $id : FALSE;
  690. }
  691. /**
  692. * login
  693. *
  694. * @return bool
  695. * @author Mathew
  696. **/
  697. public function login($identity, $password, $remember=FALSE)
  698. {
  699. $this->trigger_events('pre_login');
  700. if (empty($identity) || empty($password))
  701. {
  702. $this->set_error('login_unsuccessful');
  703. return FALSE;
  704. }
  705. $this->trigger_events('extra_where');
  706. $query = $this->db->select($this->identity_column . ', username, email, id, password, active, last_login, first_name, last_name')
  707. ->where($this->identity_column, $this->db->escape_str($identity))
  708. ->limit(1)
  709. ->get($this->tables['users']);
  710. if($this->is_time_locked_out($identity))
  711. {
  712. //Hash something anyway, just to take up time
  713. $this->hash_password($password);
  714. $this->trigger_events('post_login_unsuccessful');
  715. $this->set_error('login_timeout');
  716. return FALSE;
  717. }
  718. if ($query->num_rows() === 1)
  719. {
  720. $user = $query->row();
  721. $password = $this->hash_password_db($user->id, $password);
  722. if ($password === TRUE)
  723. {
  724. if ($user->active == 0)
  725. {
  726. $this->trigger_events('post_login_unsuccessful');
  727. $this->set_error('login_unsuccessful_not_active');
  728. return FALSE;
  729. }
  730. $session_data = array(
  731. 'identity' => $user->{$this->identity_column},
  732. 'username' => $user->username,
  733. 'email' => $user->email,
  734. 'user_id' => $user->id, //everyone likes to overwrite id so we'll use user_id
  735. 'old_last_login' => $user->last_login,
  736. 'first_name' => $user->first_name,
  737. 'last_name' => $user->last_name,
  738. );
  739. $this->update_last_login($user->id);
  740. $this->clear_login_attempts($identity);
  741. $this->session->set_userdata($session_data);
  742. if ($remember && $this->config->item('remember_users', 'ion_auth'))
  743. {
  744. $this->remember_user($user->id);
  745. }
  746. $this->trigger_events(array('post_login', 'post_login_successful'));
  747. $this->set_message('login_successful');
  748. return TRUE;
  749. }
  750. }
  751. //Hash something anyway, just to take up time
  752. $this->hash_password($password);
  753. $this->increase_login_attempts($identity);
  754. $this->trigger_events('post_login_unsuccessful');
  755. $this->set_error('login_unsuccessful');
  756. return FALSE;
  757. }
  758. /**
  759. * is_max_login_attempts_exceeded
  760. * Based on code from Tank Auth, by Ilya Konyukhov (https://github.com/ilkon/Tank-Auth)
  761. *
  762. * @param string $identity
  763. * @return boolean
  764. **/
  765. public function is_max_login_attempts_exceeded($identity) {
  766. if ($this->config->item('track_login_attempts', 'ion_auth')) {
  767. $max_attempts = $this->config->item('maximum_login_attempts', 'ion_auth');
  768. if ($max_attempts > 0) {
  769. $attempts = $this->get_attempts_num($identity);
  770. return $attempts >= $max_attempts;
  771. }
  772. }
  773. return FALSE;
  774. }
  775. /**
  776. * Get number of attempts to login occured from given IP-address or identity
  777. * Based on code from Tank Auth, by Ilya Konyukhov (https://github.com/ilkon/Tank-Auth)
  778. *
  779. * @param string $identity
  780. * @return int
  781. */
  782. function get_attempts_num($identity)
  783. {
  784. if ($this->config->item('track_login_attempts', 'ion_auth')) {
  785. $ip_address = $this->_prepare_ip($this->input->ip_address());
  786. $this->db->select('1', FALSE);
  787. $this->db->where('ip_address', $ip_address);
  788. if (strlen($identity) > 0) $this->db->or_where('login', $identity);
  789. $qres = $this->db->get($this->tables['login_attempts']);
  790. return $qres->num_rows();
  791. }
  792. return 0;
  793. }
  794. /**
  795. * Get a boolean to determine if an account should be locked out due to
  796. * exceeded login attempts within a given period
  797. *
  798. * @return boolean
  799. */
  800. public function is_time_locked_out($identity) {
  801. return $this->is_max_login_attempts_exceeded($identity) && $this->get_last_attempt_time($identity) > time() - $this->config->item('lockout_time', 'ion_auth');
  802. }
  803. /**
  804. * Get the time of the last time a login attempt occured from given IP-address or identity
  805. *
  806. * @param string $identity
  807. * @return int
  808. */
  809. public function get_last_attempt_time($identity) {
  810. if ($this->config->item('track_login_attempts', 'ion_auth')) {
  811. $ip_address = $this->_prepare_ip($this->input->ip_address());
  812. $this->db->select_max('time');
  813. $this->db->where('ip_address', $ip_address);
  814. if (strlen($identity) > 0) $this->db->or_where('login', $identity);
  815. $qres = $this->db->get($this->tables['login_attempts'], 1);
  816. if($qres->num_rows() > 0) {
  817. return $qres->row()->time;
  818. }
  819. }
  820. return 0;
  821. }
  822. /**
  823. * increase_login_attempts
  824. * Based on code from Tank Auth, by Ilya Konyukhov (https://github.com/ilkon/Tank-Auth)
  825. *
  826. * @param string $identity
  827. **/
  828. public function increase_login_attempts($identity) {
  829. if ($this->config->item('track_login_attempts', 'ion_auth')) {
  830. $ip_address = $this->_prepare_ip($this->input->ip_address());
  831. return $this->db->insert($this->tables['login_attempts'], array('ip_address' => $ip_address, 'login' => $identity, 'time' => time()));
  832. }
  833. return FALSE;
  834. }
  835. /**
  836. * clear_login_attempts
  837. * Based on code from Tank Auth, by Ilya Konyukhov (https://github.com/ilkon/Tank-Auth)
  838. *
  839. * @param string $identity
  840. **/
  841. public function clear_login_attempts($identity, $expire_period = 86400) {
  842. if ($this->config->item('track_login_attempts', 'ion_auth')) {
  843. $ip_address = $this->_prepare_ip($this->input->ip_address());
  844. $this->db->where(array('ip_address' => $ip_address, 'login' => $identity));
  845. // Purge obsolete login attempts
  846. $this->db->or_where('time <', time() - $expire_period, FALSE);
  847. return $this->db->delete($this->tables['login_attempts']);
  848. }
  849. return FALSE;
  850. }
  851. public function limit($limit)
  852. {
  853. $this->trigger_events('limit');
  854. $this->_ion_limit = $limit;
  855. return $this;
  856. }
  857. public function offset($offset)
  858. {
  859. $this->trigger_events('offset');
  860. $this->_ion_offset = $offset;
  861. return $this;
  862. }
  863. public function where($where, $value = NULL)
  864. {
  865. $this->trigger_events('where');
  866. if (!is_array($where))
  867. {
  868. $where = array($where => $value);
  869. }
  870. array_push($this->_ion_where, $where);
  871. return $this;
  872. }
  873. public function like($like, $value = NULL)
  874. {
  875. $this->trigger_events('like');
  876. if (!is_array($like))
  877. {
  878. $like = array($like => $value);
  879. }
  880. array_push($this->_ion_like, $like);
  881. return $this;
  882. }
  883. public function select($select)
  884. {
  885. $this->trigger_events('select');
  886. $this->_ion_select[] = $select;
  887. return $this;
  888. }
  889. public function order_by($by, $order='desc')
  890. {
  891. $this->trigger_events('order_by');
  892. $this->_ion_order_by = $by;
  893. $this->_ion_order = $order;
  894. return $this;
  895. }
  896. public function row()
  897. {
  898. $this->trigger_events('row');
  899. $row = $this->response->row();
  900. $this->response->free_result();
  901. return $row;
  902. }
  903. public function row_array()
  904. {
  905. $this->trigger_events(array('row', 'row_array'));
  906. $row = $this->response->row_array();
  907. $this->response->free_result();
  908. return $row;
  909. }
  910. public function result()
  911. {
  912. $this->trigger_events('result');
  913. $result = $this->response->result();
  914. $this->response->free_result();
  915. return $result;
  916. }
  917. public function result_array()
  918. {
  919. $this->trigger_events(array('result', 'result_array'));
  920. $result = $this->response->result_array();
  921. $this->response->free_result();
  922. return $result;
  923. }
  924. public function num_rows()
  925. {
  926. $this->trigger_events(array('num_rows'));
  927. $result = $this->response->num_rows();
  928. $this->response->free_result();
  929. return $result;
  930. }
  931. /**
  932. * users
  933. *
  934. * @return object Users
  935. * @author Ben Edmunds
  936. **/
  937. public function users($groups = NULL)
  938. {
  939. $this->trigger_events('users');
  940. if (isset($this->_ion_select))
  941. {
  942. foreach ($this->_ion_select as $select)
  943. {
  944. $this->db->select($select);
  945. }
  946. $this->_ion_select = array();
  947. }
  948. else
  949. {
  950. //default selects
  951. $this->db->select(array(
  952. $this->tables['users'].'.*',
  953. $this->tables['users'].'.id as id',
  954. $this->tables['users'].'.id as user_id'
  955. ));
  956. }
  957. //filter by group id(s) if passed
  958. if (isset($groups))
  959. {
  960. //build an array if only one group was passed
  961. if (is_numeric($groups))
  962. {
  963. $groups = Array($groups);
  964. }
  965. //join and then run a where_in against the group ids
  966. if (isset($groups) && !empty($groups))
  967. {
  968. $this->db->distinct();
  969. $this->db->join(
  970. $this->tables['users_groups'],
  971. $this->tables['users_groups'].'.user_id = ' . $this->tables['users'].'.id',
  972. 'inner'
  973. );
  974. $this->db->where_in($this->tables['users_groups'].'.group_id', $groups);
  975. }
  976. }
  977. $this->trigger_events('extra_where');
  978. //run each where that was passed
  979. if (isset($this->_ion_where))
  980. {
  981. foreach ($this->_ion_where as $where)
  982. {
  983. $this->db->where($where);
  984. }
  985. $this->_ion_where = array();
  986. }
  987. if (isset($this->_ion_like))
  988. {
  989. foreach ($this->_ion_like as $like)
  990. {
  991. $this->db->or_like($like);
  992. }
  993. $this->_ion_like = array();
  994. }
  995. if (isset($this->_ion_limit) && isset($this->_ion_offset))
  996. {
  997. $this->db->limit($this->_ion_limit, $this->_ion_offset);
  998. $this->_ion_limit = NULL;
  999. $this->_ion_offset = NULL;
  1000. }
  1001. else if (isset($this->_ion_limit))
  1002. {
  1003. $this->db->limit($this->_ion_limit);
  1004. $this->_ion_limit = NULL;
  1005. }
  1006. //set the order
  1007. if (isset($this->_ion_order_by) && isset($this->_ion_order))
  1008. {
  1009. $this->db->order_by($this->_ion_order_by, $this->_ion_order);
  1010. $this->_ion_order = NULL;
  1011. $this->_ion_order_by = NULL;
  1012. }
  1013. $this->response = $this->db->get($this->tables['users']);
  1014. return $this;
  1015. }
  1016. /**
  1017. * user
  1018. *
  1019. * @return object
  1020. * @author Ben Edmunds
  1021. **/
  1022. public function user($id = NULL)
  1023. {
  1024. $this->trigger_events('user');
  1025. //if no id was passed use the current users id
  1026. $id || $id = $this->session->userdata('user_id');
  1027. $this->limit(1);
  1028. $this->where($this->tables['users'].'.id', $id);
  1029. $this->users();
  1030. return $this;
  1031. }
  1032. /**
  1033. * get_users_groups
  1034. *
  1035. * @return array
  1036. * @author Ben Edmunds
  1037. **/
  1038. public function get_users_groups($id=FALSE)
  1039. {
  1040. $this->trigger_events('get_users_group');
  1041. //if no id was passed use the current users id
  1042. $id || $id = $this->session->userdata('user_id');
  1043. return $this->db->select($this->tables['users_groups'].'.'.$this->join['groups'].' as id, '.$this->tables['groups'].'.name, '.$this->tables['groups'].'.description')
  1044. ->where($this->tables['users_groups'].'.'.$this->join['users'], $id)
  1045. ->join($this->tables['groups'], $this->tables['users_groups'].'.'.$this->join['groups'].'='.$this->tables['groups'].'.id')
  1046. ->get($this->tables['users_groups']);
  1047. }
  1048. /**
  1049. * add_to_group
  1050. *
  1051. * @return bool
  1052. * @author Ben Edmunds
  1053. **/
  1054. public function add_to_group($group_id, $user_id=false)
  1055. {
  1056. $this->trigger_events('add_to_group');
  1057. //if no id was passed use the current users id
  1058. $user_id || $user_id = $this->session->userdata('user_id');
  1059. if ($return = $this->db->insert($this->tables['users_groups'], array( $this->join['groups'] => (int)$group_id, $this->join['users'] => (int)$user_id)))
  1060. {
  1061. if (isset($this->_cache_groups[$group_id])) {
  1062. $group_name = $this->_cache_groups[$group_id];
  1063. }
  1064. else {
  1065. $group = $this->group($group_id)->result();
  1066. $group_name = $group[0]->name;
  1067. $this->_cache_groups[$group_id] = $group_name;
  1068. }
  1069. $this->_cache_user_in_group[$user_id][$group_id] = $group_name;
  1070. }
  1071. return $return;
  1072. }
  1073. /**
  1074. * remove_from_group
  1075. *
  1076. * @return bool
  1077. * @author Ben Edmunds
  1078. **/
  1079. public function remove_from_group($group_ids=false, $user_id=false)
  1080. {
  1081. $this->trigger_events('remove_from_group');
  1082. // user id is required
  1083. if(empty($user_id))
  1084. {
  1085. return FALSE;
  1086. }
  1087. // if group id(s) are passed remove user from the group(s)
  1088. if( ! empty($group_ids))
  1089. {
  1090. if(!is_array($group_ids))
  1091. {
  1092. $group_ids = array($group_ids);
  1093. }
  1094. foreach($group_ids as $group_id)
  1095. {
  1096. $this->db->delete($this->tables['users_groups'], array($this->join['groups'] => (int)$group_id, $this->join['users'] => (int)$user_id));
  1097. if (isset($this->_cache_user_in_group[$user_id]) && isset($this->_cache_user_in_group[$user_id][$group_id]))
  1098. {
  1099. unset($this->_cache_user_in_group[$user_id][$group_id]);
  1100. }
  1101. }
  1102. $return = TRUE;
  1103. }
  1104. // otherwise remove user from all groups
  1105. else
  1106. {
  1107. if ($return = $this->db->delete($this->tables['users_groups'], array($this->join['users'] => (int)$user_id))) {
  1108. $this->_cache_user_in_group[$user_id] = array();
  1109. }
  1110. }
  1111. return $return;
  1112. }
  1113. /**
  1114. * groups
  1115. *
  1116. * @return object
  1117. * @author Ben Edmunds
  1118. **/
  1119. public function groups()
  1120. {
  1121. $this->trigger_events('groups');
  1122. //run each where that was passed
  1123. if (isset($this->_ion_where))
  1124. {
  1125. foreach ($this->_ion_where as $where)
  1126. {
  1127. $this->db->where($where);
  1128. }
  1129. $this->_ion_where = array();
  1130. }
  1131. if (isset($this->_ion_limit) && isset($this->_ion_offset))
  1132. {
  1133. $this->db->limit($this->_ion_limit, $this->_ion_offset);
  1134. $this->_ion_limit = NULL;
  1135. $this->_ion_offset = NULL;
  1136. }
  1137. else if (isset($this->_ion_limit))
  1138. {
  1139. $this->db->limit($this->_ion_limit);
  1140. $this->_ion_limit = NULL;
  1141. }
  1142. //set the order
  1143. if (isset($this->_ion_order_by) && isset($this->_ion_order))
  1144. {
  1145. $this->db->order_by($this->_ion_order_by, $this->_ion_order);
  1146. }
  1147. $this->response = $this->db->get($this->tables['groups']);
  1148. return $this;
  1149. }
  1150. /**
  1151. * group
  1152. *
  1153. * @return object
  1154. * @author Ben Edmunds
  1155. **/
  1156. public function group($id = NULL)
  1157. {
  1158. $this->trigger_events('group');
  1159. if (isset($id))
  1160. {
  1161. $this->db->where($this->tables['groups'].'.id', $id);
  1162. }
  1163. $this->limit(1);
  1164. return $this->groups();
  1165. }
  1166. /**
  1167. * update
  1168. *
  1169. * @return bool
  1170. * @author Phil Sturgeon
  1171. **/
  1172. public function update($id, array $data)
  1173. {
  1174. $this->trigger_events('pre_update_user');
  1175. $user = $this->user($id)->row();
  1176. $this->db->trans_begin();
  1177. if (array_key_exists($this->identity_column, $data) && $this->identity_check($data[$this->identity_column]) && $user->{$this->identity_column} !== $data[$this->identity_column])
  1178. {
  1179. $this->db->trans_rollback();
  1180. $this->set_error('account_creation_duplicate_'.$this->identity_column);
  1181. $this->trigger_events(array('post_update_user', 'post_update_user_unsuccessful'));
  1182. $this->set_error('update_unsuccessful');
  1183. return FALSE;
  1184. }
  1185. // Filter the data passed
  1186. $data = $this->_filter_data($this->tables['users'], $data);
  1187. if (array_key_exists('username', $data) || array_key_exists('password', $data) || array_key_exists('email', $data))
  1188. {
  1189. if (array_key_exists('password', $data))
  1190. {
  1191. if( ! empty($data['password']))
  1192. {
  1193. $data['password'] = $this->hash_password($data['password'], $user->salt);
  1194. }
  1195. else
  1196. {
  1197. // unset password so it doesn't effect database entry if no password passed
  1198. unset($data['password']);
  1199. }
  1200. }
  1201. }
  1202. $this->trigger_events('extra_where');
  1203. $this->db->update($this->tables['users'], $data, array('id' => $user->id));
  1204. if ($this->db->trans_status() === FALSE)
  1205. {
  1206. $this->db->trans_rollback();
  1207. $this->trigger_events(array('post_update_user', 'post_update_user_unsuccessful'));
  1208. $this->set_error('update_unsuccessful');
  1209. return FALSE;
  1210. }
  1211. $this->db->trans_commit();
  1212. $this->trigger_events(array('post_update_user', 'post_update_user_successful'));
  1213. $this->set_message('update_successful');
  1214. return TRUE;
  1215. }
  1216. /**
  1217. * delete_user
  1218. *
  1219. * @return bool
  1220. * @author Phil Sturgeon
  1221. **/
  1222. public function delete_user($id)
  1223. {
  1224. $this->trigger_events('pre_delete_user');
  1225. $this->db->trans_begin();
  1226. // remove user from groups
  1227. $this->remove_from_group(NULL, $id);
  1228. // delete user from users table
  1229. $this->db->delete($this->tables['users'], array('id' => $id));
  1230. if ($this->db->trans_status() === FALSE)
  1231. {
  1232. $this->db->trans_rollback();
  1233. $this->trigger_events(array('post_delete_user', 'post_delete_user_unsuccessful'));
  1234. $this->set_error('delete_unsuccessful');
  1235. return FALSE;
  1236. }
  1237. $this->db->trans_commit();
  1238. $this->trigger_events(array('post_delete_user', 'post_delete_user_successful'));
  1239. $this->set_message('delete_successful');
  1240. return TRUE;
  1241. }
  1242. /**
  1243. * update_last_login
  1244. *
  1245. * @return bool
  1246. * @author Ben Edmunds
  1247. **/
  1248. public function update_last_login($id)
  1249. {
  1250. $this->trigger_events('update_last_login');
  1251. $this->load->helper('date');
  1252. $this->trigger_events('extra_where');
  1253. $this->db->update($this->tables['users'], array('last_login' => time()), array('id' => $id));
  1254. return $this->db->affected_rows() == 1;
  1255. }
  1256. /**
  1257. * set_lang
  1258. *
  1259. * @return bool
  1260. * @author Ben Edmunds
  1261. **/
  1262. public function set_lang($lang = 'en')
  1263. {
  1264. $this->trigger_events('set_lang');
  1265. // if the user_expire is set to zero we'll set the expiration two years from now.
  1266. if($this->config->item('user_expire', 'ion_auth') === 0)
  1267. {
  1268. $expire = (60*60*24*365*2);
  1269. }
  1270. // otherwise use what is set
  1271. else
  1272. {
  1273. $expire = $this->config->item('user_expire', 'ion_auth');
  1274. }
  1275. set_cookie(array(
  1276. 'name' => 'lang_code',
  1277. 'value' => $lang,
  1278. 'expire' => $expire
  1279. ));
  1280. return TRUE;
  1281. }
  1282. /**
  1283. * remember_user
  1284. *
  1285. * @return bool
  1286. * @author Ben Edmunds
  1287. **/
  1288. public function remember_user($id)
  1289. {
  1290. $this->trigger_events('pre_remember_user');
  1291. if (!$id)
  1292. {
  1293. return FALSE;
  1294. }
  1295. $user = $this->user($id)->row();
  1296. $salt = sha1($user->password);
  1297. $this->db->update($this->tables['users'], array('remember_code' => $salt), array('id' => $id));
  1298. if ($this->db->affected_rows() > -1)
  1299. {
  1300. // if the user_expire is set to zero we'll set the expiration two years from now.
  1301. if($this->config->item('user_expire', 'ion_auth') === 0)
  1302. {
  1303. $expire = (60*60*24*365*2);
  1304. }
  1305. // otherwise use what is set
  1306. else
  1307. {
  1308. $expire = $this->config->item('user_expire', 'ion_auth');
  1309. }
  1310. set_cookie(array(
  1311. 'name' => 'identity',
  1312. 'value' => $user->{$this->identity_column},
  1313. 'expire' => $expire
  1314. ));
  1315. set_cookie(array(
  1316. 'name' => 'remember_code',
  1317. 'value' => $salt,
  1318. 'expire' => $expire
  1319. ));
  1320. $this->trigger_events(array('post_remember_user', 'remember_user_successful'));
  1321. return TRUE;
  1322. }
  1323. $this->trigger_events(array('post_remember_user', 'remember_user_unsuccessful'));
  1324. return FALSE;
  1325. }
  1326. /**
  1327. * login_remembed_user
  1328. *
  1329. * @return bool
  1330. * @author Ben Edmunds
  1331. **/
  1332. public function login_remembered_user()
  1333. {
  1334. $this->trigger_events('pre_login_remembered_user');
  1335. //check for valid data
  1336. if (!get_cookie('identity') || !get_cookie('remember_code') || !$this->identity_check(get_cookie('identity')))
  1337. {
  1338. $this->trigger_events(array('post_login_remembered_user', 'post_login_remembered_user_unsuccessful'));
  1339. return FALSE;
  1340. }
  1341. //get the user
  1342. $this->trigger_events('extra_where');
  1343. $query = $this->db->select($this->identity_column.', id')
  1344. ->where($this->identity_column, get_cookie('identity'))
  1345. ->where('remember_code', get_cookie('remember_code'))
  1346. ->limit(1)
  1347. ->get($this->tables['users']);
  1348. //if the user was found, sign them in
  1349. if ($query->num_rows() == 1)
  1350. {
  1351. $user = $query->row();
  1352. $this->update_last_login($user->id);
  1353. $session_data = array(
  1354. $this->identity_column => $user->{$this->identity_column},
  1355. 'id' => $user->id, //kept for backwards compatibility
  1356. 'user_id' => $user->id, //everyone likes to overwrite id so we'll use user_id
  1357. );
  1358. $this->session->set_userdata($session_data);
  1359. //extend the users cookies if the option is enabled
  1360. if ($this->config->item('user_extend_on_login', 'ion_auth'))
  1361. {
  1362. $this->remember_user($user->id);
  1363. }
  1364. $this->trigger_events(array('post_login_remembered_user', 'post_login_remembered_user_successful'));
  1365. return TRUE;
  1366. }
  1367. $this->trigger_events(array('post_login_remembered_user', 'post_login_remembered_user_unsuccessful'));
  1368. return FALSE;
  1369. }
  1370. /**
  1371. * create_group
  1372. *
  1373. * @author aditya menon
  1374. */
  1375. public function create_group($group_name = FALSE, $group_description = NULL)
  1376. {
  1377. // bail if the group name was not passed
  1378. if(!$group_name)
  1379. {
  1380. return FALSE;
  1381. }
  1382. // bail if the group name already exists
  1383. $existing_group = $this->db->get_where('groups', array('name' => $group_name))->row();
  1384. if(!is_null($existing_group->id))
  1385. {
  1386. $this->set_error('group_already_exists');
  1387. return FALSE;
  1388. }
  1389. // insert the new group
  1390. $this->db->insert($this->tables['groups'], array('name' => $group_name, 'description' => $group_description));
  1391. $group_id = $this->db->insert_id();
  1392. // report success
  1393. $this->set_message('group_creation_successful');
  1394. // return the brand new group id
  1395. return $group_id;
  1396. }
  1397. /**
  1398. * update_group
  1399. *
  1400. * @return bool
  1401. * @author aditya menon
  1402. **/
  1403. public function update_group($group_id = FALSE, $group_name = FALSE, $group_description = NULL)
  1404. {
  1405. $mandatory = array($group_id, $group_name);
  1406. // bail if no group id or name given
  1407. foreach ($mandatory as $mandatory_param) {
  1408. if(!$mandatory_param || empty($mandatory_param))
  1409. {
  1410. return FALSE;
  1411. }
  1412. }
  1413. // bail if the group name already exists
  1414. $existing_group = $this->db->get_where('groups', array('name' => $group_name))->row();
  1415. if(isset($existing_group->id) && $existing_group->id != $group_id)
  1416. {
  1417. $this->set_error('group_already_exists');
  1418. return FALSE;
  1419. }
  1420. $query_data = array(
  1421. 'name' => $group_name,
  1422. 'description' => $group_description,
  1423. );
  1424. $this->db->update($this->tables['groups'], $query_data, array('id' => $group_id));
  1425. $this->set_message('group_update_successful');
  1426. return TRUE;
  1427. }
  1428. /**
  1429. * delete_group
  1430. *
  1431. * @return bool
  1432. * @author aditya menon
  1433. **/
  1434. public function delete_group($group_id = FALSE)
  1435. {
  1436. // bail if mandatory param not set
  1437. if(!$group_id || empty($group_id))
  1438. {
  1439. return FALSE;
  1440. }
  1441. $this->trigger_events('pre_delete_group');
  1442. $this->db->trans_begin();
  1443. // remove all users from this group
  1444. $this->db->delete($this->tables['users_groups'], array('group_id' => $group_id));
  1445. // remove the group itself
  1446. $this->db->delete($this->tables['groups'], array('id' => $group_id));
  1447. if ($this->db->trans_status() === FALSE)
  1448. {
  1449. $this->db->trans_rollback();
  1450. $this->trigger_events(array('post_delete_group', 'post_delete_group_unsuccessful'));
  1451. $this->set_error('group_delete_unsuccessful');
  1452. return FALSE;
  1453. }
  1454. $this->db->trans_commit();
  1455. $this->trigger_events(array('post_delete_group', 'post_delete_group_successful'));
  1456. $this->set_message('group_delete_successful');
  1457. return TRUE;
  1458. }
  1459. public function set_hook($event, $name, $class, $method, $arguments)
  1460. {
  1461. $this->_ion_hooks->{$event}[$name] = new stdClass;
  1462. $this->_ion_hooks->{$event}[$name]->class = $class;
  1463. $this->_ion_hooks->{$event}[$name]->method = $method;
  1464. $this->_ion_hooks->{$event}[$name]->arguments = $arguments;
  1465. }
  1466. public function remove_hook($event, $name)
  1467. {
  1468. if (isset($this->_ion_hooks->{$event}[$name]))
  1469. {
  1470. unset($this->_ion_hooks->{$event}[$name]);
  1471. }
  1472. }
  1473. public function remove_hooks($event)
  1474. {
  1475. if (isset($this->_ion_hooks->$event))
  1476. {
  1477. unset($this->_ion_hooks->$event);
  1478. }
  1479. }
  1480. protected function _call_hook($event, $name)
  1481. {
  1482. if (isset($this->_ion_hooks->{$event}[$name]) && method_exists($this->_ion_hooks->{$event}[$name]->class, $this->_ion_hooks->{$event}[$name]->method))
  1483. {
  1484. $hook = $this->_ion_hooks->{$event}[$name];
  1485. return call_user_func_array(array($hook->class, $hook->method), $hook->arguments);
  1486. }
  1487. return FALSE;
  1488. }
  1489. public function trigger_events($events)
  1490. {
  1491. if (is_array($events) && !empty($events))
  1492. {
  1493. foreach ($events as $event)
  1494. {
  1495. $this->trigger_events($event);
  1496. }
  1497. }
  1498. else
  1499. {
  1500. if (isset($this->_ion_hooks->$events) && !empty($this->_ion_hooks->$events))
  1501. {
  1502. foreach ($this->_ion_hooks->$events as $name => $hook)
  1503. {
  1504. $this->_call_hook($events, $name);
  1505. }
  1506. }
  1507. }
  1508. }
  1509. /**
  1510. * set_message_delimiters
  1511. *
  1512. * Set the message delimiters
  1513. *
  1514. * @return void
  1515. * @author Ben Edmunds
  1516. **/
  1517. public function set_message_delimiters($start_delimiter, $end_delimiter)
  1518. {
  1519. $this->message_start_delimiter = $start_delimiter;
  1520. $this->message_end_delimiter = $end_delimiter;
  1521. return TRUE;
  1522. }
  1523. /**
  1524. * set_error_delimiters
  1525. *
  1526. * Set the error delimiters
  1527. *
  1528. * @return void
  1529. * @author Ben Edmunds
  1530. **/
  1531. public function set_error_delimiters($start_delimiter, $end_delimiter)
  1532. {
  1533. $this->error_start_delimiter = $start_delimiter;
  1534. $this->error_end_delimiter = $end_delimiter;
  1535. return TRUE;
  1536. }
  1537. /**
  1538. * set_message
  1539. *
  1540. * Set a message
  1541. *
  1542. * @return void
  1543. * @author Ben Edmunds
  1544. **/
  1545. public function set_message($message)
  1546. {
  1547. $this->messages[] = $message;
  1548. return $message;
  1549. }
  1550. /**
  1551. * messages
  1552. *
  1553. * Get the messages
  1554. *
  1555. * @return void
  1556. * @author Ben Edmunds
  1557. **/
  1558. public function messages()
  1559. {
  1560. $_output = '';
  1561. foreach ($this->messages as $message)
  1562. {
  1563. $messageLang = $this->lang->line($message) ? $this->lang->line($message) : '##' . $message . '##';
  1564. $_output .= $this->message_start_delimiter . $messageLang . $this->message_end_delimiter;
  1565. }
  1566. return $_output;
  1567. }
  1568. /**
  1569. * messages as array
  1570. *
  1571. * Get the messages as an array
  1572. *
  1573. * @return array
  1574. * @author Raul Baldner Junior
  1575. **/
  1576. public function messages_array($langify = TRUE)
  1577. {
  1578. if ($langify)
  1579. {
  1580. $_output = array();
  1581. foreach ($this->messages as $message)
  1582. {
  1583. $messageLang = $this->lang->line($message) ? $this->lang->line($message) : '##' . $message . '##';
  1584. $_output[] = $this->message_start_delimiter . $messageLang . $this->message_end_delimiter;
  1585. }
  1586. return $_output;
  1587. }
  1588. else
  1589. {
  1590. return $this->messages;
  1591. }
  1592. }
  1593. /**
  1594. * set_error
  1595. *
  1596. * Set an error message
  1597. *
  1598. * @return void
  1599. * @author Ben Edmunds
  1600. **/
  1601. public function set_error($error)
  1602. {
  1603. $this->errors[] = $error;
  1604. return $error;
  1605. }
  1606. /**
  1607. * errors
  1608. *
  1609. * Get the error message
  1610. *
  1611. * @return void
  1612. * @author Ben Edmunds
  1613. **/
  1614. public function errors()
  1615. {
  1616. $_output = '';
  1617. foreach ($this->errors as $error)
  1618. {
  1619. $errorLang = $this->lang->line($error) ? $this->lang->line($error) : '##' . $error . '##';
  1620. $_output .= $this->error_start_delimiter . $errorLang . $this->error_end_delimiter;
  1621. }
  1622. return $_output;
  1623. }
  1624. /**
  1625. * errors as array
  1626. *
  1627. * Get the error messages as an array
  1628. *
  1629. * @return array
  1630. * @author Raul Baldner Junior
  1631. **/
  1632. public function errors_array($langify = TRUE)
  1633. {
  1634. if ($langify)
  1635. {
  1636. $_output = array();
  1637. foreach ($this->errors as $error)
  1638. {
  1639. $errorLang = $this->lang->line($error) ? $this->lang->line($error) : '##' . $error . '##';
  1640. $_output[] = $this->error_start_delimiter . $errorLang . $this->error_end_delimiter;
  1641. }
  1642. return $_output;
  1643. }
  1644. else
  1645. {
  1646. return $this->errors;
  1647. }
  1648. }
  1649. protected function _filter_data($table, $data)
  1650. {
  1651. $filtered_data = array();
  1652. $columns = $this->db->list_fields($table);
  1653. if (is_array($data))
  1654. {
  1655. foreach ($columns as $column)
  1656. {
  1657. if (array_key_exists($column, $data))
  1658. $filtered_data[$column] = $data[$column];
  1659. }
  1660. }
  1661. return $filtered_data;
  1662. }
  1663. protected function _prepare_ip($ip_address) {
  1664. if ($this->db->platform() === 'postgre' || $this->db->platform() === 'sqlsrv' || $this->db->platform() === 'mssql')
  1665. {
  1666. return $ip_address;
  1667. }
  1668. else
  1669. {
  1670. return inet_pton($ip_address);
  1671. }
  1672. }
  1673. }