PageRenderTime 67ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/manager/application/models/ion_auth_model.php

https://bitbucket.org/jerwinse/iagh-cms
PHP | 1428 lines | 801 code | 260 blank | 367 comment | 93 complexity | a6e0a73d40991d67d422c48944744ceb MD5 | raw file
  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. * Limit
  67. *
  68. * @var string
  69. **/
  70. public $_ion_limit = NULL;
  71. /**
  72. * Offset
  73. *
  74. * @var string
  75. **/
  76. public $_ion_offset = NULL;
  77. /**
  78. * Order By
  79. *
  80. * @var string
  81. **/
  82. public $_ion_order_by = NULL;
  83. /**
  84. * Order
  85. *
  86. * @var string
  87. **/
  88. public $_ion_order = NULL;
  89. /**
  90. * Hooks
  91. *
  92. * @var object
  93. **/
  94. protected $_ion_hooks;
  95. /**
  96. * Response
  97. *
  98. * @var string
  99. **/
  100. protected $response = NULL;
  101. /**
  102. * message (uses lang file)
  103. *
  104. * @var string
  105. **/
  106. protected $messages;
  107. /**
  108. * error message (uses lang file)
  109. *
  110. * @var string
  111. **/
  112. protected $errors;
  113. /**
  114. * error start delimiter
  115. *
  116. * @var string
  117. **/
  118. protected $error_start_delimiter;
  119. /**
  120. * error end delimiter
  121. *
  122. * @var string
  123. **/
  124. protected $error_end_delimiter;
  125. public function __construct()
  126. {
  127. parent::__construct();
  128. $this->load->database();
  129. $this->load->config('ion_auth', TRUE);
  130. $this->load->helper('cookie');
  131. $this->load->helper('date');
  132. $this->load->library('session');
  133. $this->lang->load('ion_auth');
  134. //initialize db tables data
  135. $this->tables = $this->config->item('tables', 'ion_auth');
  136. //initialize data
  137. $this->identity_column = $this->config->item('identity', 'ion_auth');
  138. $this->store_salt = $this->config->item('store_salt', 'ion_auth');
  139. $this->salt_length = $this->config->item('salt_length', 'ion_auth');
  140. $this->join = $this->config->item('join', 'ion_auth');
  141. //initialize messages and error
  142. $this->messages = array();
  143. $this->errors = array();
  144. $this->message_start_delimiter = $this->config->item('message_start_delimiter', 'ion_auth');
  145. $this->message_end_delimiter = $this->config->item('message_end_delimiter', 'ion_auth');
  146. $this->error_start_delimiter = $this->config->item('error_start_delimiter', 'ion_auth');
  147. $this->error_end_delimiter = $this->config->item('error_end_delimiter', 'ion_auth');
  148. //initialize our hooks object
  149. $this->_ion_hooks = new stdClass;
  150. $this->trigger_events('model_constructor');
  151. }
  152. /**
  153. * Misc functions
  154. *
  155. * Hash password : Hashes the password to be stored in the database.
  156. * Hash password db : This function takes a password and validates it
  157. * against an entry in the users table.
  158. * Salt : Generates a random salt value.
  159. *
  160. * @author Mathew
  161. */
  162. /**
  163. * Hashes the password to be stored in the database.
  164. *
  165. * @return void
  166. * @author Mathew
  167. **/
  168. public function hash_password($password, $salt=false)
  169. {
  170. if (empty($password))
  171. {
  172. return FALSE;
  173. }
  174. if ($this->store_salt && $salt)
  175. {
  176. return sha1($password . $salt);
  177. }
  178. else
  179. {
  180. $salt = $this->salt();
  181. return $salt . substr(sha1($salt . $password), 0, -$this->salt_length);
  182. }
  183. }
  184. /**
  185. * This function takes a password and validates it
  186. * against an entry in the users table.
  187. *
  188. * @return void
  189. * @author Mathew
  190. **/
  191. public function hash_password_db($id, $password)
  192. {
  193. if (empty($id) || empty($password))
  194. {
  195. return FALSE;
  196. }
  197. $this->trigger_events('extra_where');
  198. $query = $this->db->select('password, salt')
  199. ->where('id', $id)
  200. ->limit(1)
  201. ->get($this->tables['users']);
  202. $hash_password_db = $query->row();
  203. if ($query->num_rows() !== 1)
  204. {
  205. return FALSE;
  206. }
  207. if ($this->store_salt)
  208. {
  209. return sha1($password . $hash_password_db->salt);
  210. }
  211. else
  212. {
  213. $salt = substr($hash_password_db->password, 0, $this->salt_length);
  214. return $salt . substr(sha1($salt . $password), 0, -$this->salt_length);
  215. }
  216. }
  217. /**
  218. * Generates a random salt value.
  219. *
  220. * @return void
  221. * @author Mathew
  222. **/
  223. public function salt()
  224. {
  225. return substr(md5(uniqid(rand(), true)), 0, $this->salt_length);
  226. }
  227. /**
  228. * Activation functions
  229. *
  230. * Activate : Validates and removes activation code.
  231. * Deactivae : Updates a users row with an activation code.
  232. *
  233. * @author Mathew
  234. */
  235. /**
  236. * activate
  237. *
  238. * @return void
  239. * @author Mathew
  240. **/
  241. public function activate($id, $code = false)
  242. {
  243. $this->trigger_events('pre_activate');
  244. if ($code !== FALSE)
  245. {
  246. $query = $this->db->select($this->identity_column)
  247. ->where('activation_code', $code)
  248. ->limit(1)
  249. ->get($this->tables['users']);
  250. $result = $query->row();
  251. if ($query->num_rows() !== 1)
  252. {
  253. $this->trigger_events(array('post_activate', 'post_activate_unsuccessful'));
  254. $this->set_error('activate_unsuccessful');
  255. return FALSE;
  256. }
  257. $identity = $result->{$this->identity_column};
  258. $data = array(
  259. 'activation_code' => NULL,
  260. 'active' => 1
  261. );
  262. $this->trigger_events('extra_where');
  263. $this->db->update($this->tables['users'], $data, array($this->identity_column => $identity));
  264. }
  265. else
  266. {
  267. $data = array(
  268. 'activation_code' => NULL,
  269. 'active' => 1
  270. );
  271. $this->trigger_events('extra_where');
  272. $this->db->update($this->tables['users'], $data, array('id' => $id));
  273. }
  274. $return = $this->db->affected_rows() == 1;
  275. if ($return)
  276. {
  277. $this->trigger_events(array('post_activate', 'post_activate_successful'));
  278. $this->set_message('activate_successful');
  279. }
  280. else
  281. {
  282. $this->trigger_events(array('post_activate', 'post_activate_unsuccessful'));
  283. $this->set_error('activate_unsuccessful');
  284. }
  285. return $return;
  286. }
  287. /**
  288. * Deactivate
  289. *
  290. * @return void
  291. * @author Mathew
  292. **/
  293. public function deactivate($id = NULL)
  294. {
  295. $this->trigger_events('deactivate');
  296. if (!isset($id))
  297. {
  298. $this->set_error('deactivate_unsuccessful');
  299. return FALSE;
  300. }
  301. $activation_code = sha1(md5(microtime()));
  302. $this->activation_code = $activation_code;
  303. $data = array(
  304. 'activation_code' => $activation_code,
  305. 'active' => 0
  306. );
  307. $this->trigger_events('extra_where');
  308. $this->db->update($this->tables['users'], $data, array('id' => $id));
  309. $return = $this->db->affected_rows() == 1;
  310. if ($return)
  311. $this->set_message('deactivate_successful');
  312. else
  313. $this->set_error('deactivate_unsuccessful');
  314. return $return;
  315. }
  316. /**
  317. * change password
  318. *
  319. * @return bool
  320. * @author Mathew
  321. **/
  322. public function change_password($identity, $old, $new)
  323. {
  324. $this->trigger_events('pre_change_password');
  325. $this->trigger_events('extra_where');
  326. $query = $this->db->select('id, password, salt')
  327. ->where($this->identity_column, $identity)
  328. ->limit(1)
  329. ->get($this->tables['users']);
  330. $result = $query->row();
  331. $db_password = $result->password;
  332. $old = $this->hash_password_db($result->id, $old);
  333. $new = $this->hash_password($new, $result->salt);
  334. if ($db_password === $old)
  335. {
  336. //store the new password and reset the remember code so all remembered instances have to re-login
  337. $data = array(
  338. 'password' => $new,
  339. 'remember_code' => NULL,
  340. );
  341. $this->trigger_events('extra_where');
  342. $this->db->update($this->tables['users'], $data, array($this->identity_column => $identity));
  343. $return = $this->db->affected_rows() == 1;
  344. if ($return)
  345. {
  346. $this->trigger_events(array('post_change_password', 'post_change_password_successful'));
  347. $this->set_message('password_change_successful');
  348. }
  349. else
  350. {
  351. $this->trigger_events(array('post_change_password', 'post_change_password_unsuccessful'));
  352. $this->set_error('password_change_unsuccessful');
  353. }
  354. return $return;
  355. }
  356. $this->set_error('password_change_unsuccessful');
  357. return FALSE;
  358. }
  359. /**
  360. * Checks username
  361. *
  362. * @return bool
  363. * @author Mathew
  364. **/
  365. public function username_check($username = '')
  366. {
  367. $this->trigger_events('username_check');
  368. if (empty($username))
  369. {
  370. return FALSE;
  371. }
  372. $this->trigger_events('extra_where');
  373. return $this->db->where('username', $username)
  374. ->count_all_results($this->tables['users']) > 0;
  375. }
  376. /**
  377. * Checks email
  378. *
  379. * @return bool
  380. * @author Mathew
  381. **/
  382. public function email_check($email = '')
  383. {
  384. $this->trigger_events('email_check');
  385. if (empty($email))
  386. {
  387. return FALSE;
  388. }
  389. $this->trigger_events('extra_where');
  390. return $this->db->where('email', $email)
  391. ->count_all_results($this->tables['users']) > 0;
  392. }
  393. /**
  394. * Identity check
  395. *
  396. * @return bool
  397. * @author Mathew
  398. **/
  399. protected function identity_check($identity = '')
  400. {
  401. $this->trigger_events('identity_check');
  402. if (empty($identity))
  403. {
  404. return FALSE;
  405. }
  406. return $this->db->where($this->identity_column, $identity)
  407. ->count_all_results($this->tables['users']) > 0;
  408. }
  409. /**
  410. * Insert a forgotten password key.
  411. *
  412. * @return bool
  413. * @author Mathew
  414. * @updated Ryan
  415. **/
  416. public function forgotten_password($identity)
  417. {
  418. if (empty($identity))
  419. {
  420. $this->trigger_events(array('post_forgotten_password', 'post_forgotten_password_unsuccessful'));
  421. return FALSE;
  422. }
  423. $key = $this->hash_password(microtime().$identity);
  424. $this->forgotten_password_code = $key;
  425. $this->trigger_events('extra_where');
  426. $this->db->update($this->tables['users'], array('forgotten_password_code' => $key), array($this->identity_column => $identity));
  427. $return = $this->db->affected_rows() == 1;
  428. if ($return)
  429. $this->trigger_events(array('post_forgotten_password', 'post_forgotten_password_successful'));
  430. else
  431. $this->trigger_events(array('post_forgotten_password', 'post_forgotten_password_unsuccessful'));
  432. return $return;
  433. }
  434. /**
  435. * Forgotten Password Complete
  436. *
  437. * @return string
  438. * @author Mathew
  439. **/
  440. public function forgotten_password_complete($code, $salt=FALSE)
  441. {
  442. $this->trigger_events('pre_forgotten_password_complete');
  443. if (empty($code))
  444. {
  445. $this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful'));
  446. return FALSE;
  447. }
  448. $this->db->where('forgotten_password_code', $code);
  449. if ($this->db->count_all_results($this->tables['users']) > 0)
  450. {
  451. $password = $this->salt();
  452. $data = array(
  453. 'password' => $this->hash_password($password, $salt),
  454. 'forgotten_password_code' => NULL,
  455. 'active' => 1,
  456. );
  457. $this->db->update($this->tables['users'], $data, array('forgotten_password_code' => $code));
  458. $this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_successful'));
  459. return $password;
  460. }
  461. $this->trigger_events(array('post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful'));
  462. return FALSE;
  463. }
  464. /**
  465. * register
  466. *
  467. * @return bool
  468. * @author Mathew
  469. **/
  470. public function register($username, $password, $email, $additional_data = array(), $groups = array())
  471. {
  472. $this->trigger_events('pre_register');
  473. if ($this->identity_column == 'email' && $this->email_check($email))
  474. {
  475. $this->set_error('account_creation_duplicate_email');
  476. return FALSE;
  477. }
  478. elseif ($this->identity_column == 'username' && $this->username_check($username))
  479. {
  480. $this->set_error('account_creation_duplicate_username');
  481. return FALSE;
  482. }
  483. // If username is taken, use username1 or username2, etc.
  484. if ($this->identity_column != 'username')
  485. {
  486. $original_username = $username;
  487. for($i = 0; $this->username_check($username); $i++)
  488. {
  489. if($i > 0)
  490. {
  491. $username = $original_username . $i;
  492. }
  493. }
  494. }
  495. // IP Address
  496. $ip_address = $this->input->ip_address();
  497. $salt = $this->store_salt ? $this->salt() : FALSE;
  498. $password = $this->hash_password($password, $salt);
  499. // Users table.
  500. $data = array(
  501. 'username' => $username,
  502. 'password' => $password,
  503. 'email' => $email,
  504. 'ip_address' => sprintf('%u', ip2long($ip_address)),
  505. 'created_on' => time(),
  506. 'last_login' => time(),
  507. 'active' => 1
  508. );
  509. if ($this->store_salt){
  510. $data['salt'] = $salt;
  511. }
  512. //filter out any data passed that doesnt have a matching column in the users table
  513. //and merge the set user data and the additional data
  514. $user_data = array_merge($this->_filter_data($this->tables['users'], $additional_data), $data);
  515. $this->trigger_events('extra_set');
  516. $this->db->insert($this->tables['users'], $user_data);
  517. $id = $this->db->insert_id();
  518. if (!empty($groups))
  519. {
  520. //add to groups
  521. foreach ($groups as $group)
  522. {
  523. $this->add_to_group($group, $id);
  524. }
  525. }
  526. //add to default group if not already set
  527. $default_group = $this->where('roleName', $this->config->item('default_group', 'ion_auth'))->group()->row();
  528. error_log(print_r($default_group, true));
  529. if (isset($default_group->ID))// && isset($groups) && !empty($groups) && !in_array($default_group->ID, $groups) || !isset($groups) || empty($groups))
  530. {
  531. $this->add_to_group($default_group->ID, $id);
  532. }
  533. $this->trigger_events('post_register');
  534. return (isset($id)) ? $id : FALSE;
  535. }
  536. /**
  537. * Update User
  538. *
  539. * @return bool
  540. * @author Jerwin
  541. **/
  542. public function updateUser($userId, $newData){
  543. // IP Address
  544. $ip_address = $this->input->ip_address();
  545. $salt = $this->store_salt ? $this->salt() : FALSE;
  546. $password = $this->hash_password($newData['password'], $salt);
  547. // Users table.
  548. $data = array(
  549. 'username' => $newData['username'],
  550. 'password' => $password,
  551. 'email' => $newData['email'],
  552. 'ip_address' => sprintf('%u', ip2long($ip_address)),
  553. 'created_on' => time(),
  554. 'last_login' => time(),
  555. 'active' => 1,
  556. 'first_name' => $newData['first_name'],
  557. 'last_name' => $newData['last_name']
  558. );
  559. if ($this->store_salt){
  560. $data['salt'] = $salt;
  561. }
  562. $this->db->where('id', $userId);
  563. $this->db->update($this->tables['users'], $data);
  564. }
  565. /**
  566. * login
  567. *
  568. * @return bool
  569. * @author Mathew
  570. **/
  571. public function login($identity, $password, $remember=FALSE)
  572. {
  573. $this->trigger_events('pre_login');
  574. if (empty($identity) || empty($password) )
  575. {
  576. $this->set_error('login_unsuccessful');
  577. return FALSE;
  578. }
  579. $this->trigger_events('extra_where');
  580. $query = $this->db->select('username, email, id, password, active, last_login, account_num')
  581. ->where(sprintf("(username = '%1\$s' OR email = '%1\$s')", $this->db->escape_str($identity)))
  582. // ->where('account_num', $this->db->escape_str($account_num))
  583. ->limit(1)
  584. ->get($this->tables['users']);
  585. $user = $query->row();
  586. if ($query->num_rows() == 1)
  587. {
  588. $password = $this->hash_password_db($user->id, $password);
  589. if ($user->password === $password)
  590. {
  591. if ($user->active == 0)
  592. {
  593. $this->trigger_events('post_login_unsuccessful');
  594. $this->set_error('login_unsuccessful_not_active');
  595. return FALSE;
  596. }
  597. $session_data = array(
  598. 'username' => $user->username,
  599. 'email' => $user->email,
  600. 'user_id' => $user->id, //everyone likes to overwrite id so we'll use user_id
  601. 'old_last_login' => $user->last_login
  602. );
  603. $this->update_last_login($user->id);
  604. $this->session->set_userdata($session_data);
  605. if ($remember && $this->config->item('remember_users', 'ion_auth'))
  606. {
  607. $this->remember_user($user->id);
  608. }
  609. $this->trigger_events(array('post_login', 'post_login_successful'));
  610. $this->set_message('login_successful');
  611. return TRUE;
  612. }
  613. }
  614. $this->trigger_events('post_login_unsuccessful');
  615. $this->set_error('login_unsuccessful');
  616. return FALSE;
  617. }
  618. public function limit($limit)
  619. {
  620. $this->trigger_events('limit');
  621. $this->_ion_limit = $limit;
  622. return $this;
  623. }
  624. public function offset($offset)
  625. {
  626. $this->trigger_events('offset');
  627. $this->_ion_offset = $offset;
  628. return $this;
  629. }
  630. public function where($where, $value = NULL)
  631. {
  632. $this->trigger_events('where');
  633. if (!is_array($where))
  634. {
  635. $where = array($where => $value);
  636. }
  637. array_push($this->_ion_where, $where);
  638. return $this;
  639. }
  640. public function select($select)
  641. {
  642. $this->trigger_events('select');
  643. $this->_ion_select[] = $select;
  644. return $this;
  645. }
  646. public function order_by($by, $order='desc')
  647. {
  648. $this->trigger_events('order_by');
  649. $this->_ion_order_by = $by;
  650. $this->_ion_order = $order;
  651. return $this;
  652. }
  653. public function row()
  654. {
  655. $this->trigger_events('row');
  656. $row = $this->response->row();
  657. $this->response->free_result();
  658. return $row;
  659. }
  660. public function row_array()
  661. {
  662. $this->trigger_events(array('row', 'row_array'));
  663. $row = $this->response->row_array();
  664. $this->response->free_result();
  665. return $row;
  666. }
  667. public function result()
  668. {
  669. $this->trigger_events('result');
  670. $result = $this->response->result();
  671. $this->response->free_result();
  672. return $result;
  673. }
  674. public function result_array()
  675. {
  676. $this->trigger_events(array('result', 'result_array'));
  677. $result = $this->response->result_array();
  678. $this->response->free_result();
  679. return $result;
  680. }
  681. /**
  682. * users
  683. *
  684. * @return object Users
  685. * @author Ben Edmunds
  686. **/
  687. public function users()
  688. {
  689. $this->trigger_events('users');
  690. if (isset($this->_ion_select))
  691. {
  692. foreach ($this->_ion_select as $select)
  693. {
  694. $this->db->select($select);
  695. }
  696. $this->_ion_select = array();
  697. }
  698. $this->trigger_events('extra_where');
  699. //run each where that was passed
  700. if (isset($this->_ion_where))
  701. {
  702. foreach ($this->_ion_where as $where)
  703. {
  704. $this->db->where($where);
  705. }
  706. $this->_ion_where = array();
  707. }
  708. if (isset($this->_ion_limit) && isset($this->_ion_offset))
  709. {
  710. $this->db->limit($this->_ion_limit, $this->_ion_offset);
  711. $this->_ion_limit = NULL;
  712. $this->_ion_offset = NULL;
  713. }
  714. //set the order
  715. if (isset($this->_ion_order_by) && isset($this->_ion_order))
  716. {
  717. $this->db->order_by($this->_ion_order_by, $this->_ion_order);
  718. $this->_ion_order = NULL;
  719. $this->_ion_order_by = NULL;
  720. }
  721. $this->response = $this->db->get($this->tables['users']);
  722. return $this;
  723. }
  724. /**
  725. * user
  726. *
  727. * @return object
  728. * @author Ben Edmunds
  729. **/
  730. public function user($id = NULL)
  731. {
  732. $this->trigger_events('user');
  733. //if no id was passed use the current users id
  734. $id || $id = $this->session->userdata('user_id');
  735. $this->limit(1);
  736. $this->where($this->tables['users'].'.id', $id);
  737. $this->users();
  738. return $this;
  739. }
  740. /**
  741. * get_users_groups
  742. *
  743. * @return array
  744. * @author Ben Edmunds
  745. **/
  746. public function get_users_groups($id=FALSE)
  747. {
  748. $this->trigger_events('get_users_group');
  749. //if no id was passed use the current users id
  750. $id || $id = $this->session->userdata('user_id');
  751. // return $this->db->select($this->tables['users_groups'].'.'.$this->join['groups'].' as id, '.$this->tables['groups'].'.name, '.$this->tables['groups'].'.description')
  752. // ->where($this->tables['users_groups'].'.'.$this->join['users'], $id)
  753. // ->join($this->tables['groups'], $this->tables['users_groups'].'.'.$this->join['groups'].'='.$this->tables['groups'].'.id')
  754. // ->get($this->tables['users_groups']);
  755. $res = $this->db->select($this->tables['users_groups'].'.'.$this->join['groups'].' as id, '.$this->tables['groups'].'.roleName as name')
  756. ->where($this->tables['users_groups'].'.'.$this->join['users'], $id)
  757. ->join($this->tables['groups'], $this->tables['users_groups'].'.'.$this->join['groups'].'='.$this->tables['groups'].'.id')
  758. ->get($this->tables['users_groups']);
  759. error_log($this->db->last_query());
  760. return $res;
  761. }
  762. /**
  763. * add_to_group
  764. *
  765. * @return bool
  766. * @author Ben Edmunds
  767. **/
  768. public function add_to_group($group_id, $user_id=false)
  769. {
  770. $this->trigger_events('add_to_group');
  771. //if no id was passed use the current users id
  772. $user_id || $user_id = $this->session->userdata('user_id');
  773. return $this->db->insert($this->tables['users_groups'], array( $this->join['groups'] => (int)$group_id, $this->join['users'] => (int)$user_id));
  774. }
  775. /**
  776. * remove_from_group
  777. *
  778. * @return bool
  779. * @author Ben Edmunds
  780. **/
  781. public function remove_from_group($group_id=false, $user_id=false)
  782. {
  783. $this->trigger_events('remove_from_group');
  784. //if no id was passed use the current users id
  785. $user_id || $user_id = $this->session->userdata('user_id');
  786. // if no group id is passed remove user from all groups
  787. if( ! empty($group_id))
  788. {
  789. return $this->db->delete($this->tables['users_groups'], array($this->join['groups'] => (int)$group_id, $this->join['users'] => (int)$user_id));
  790. }
  791. else
  792. {
  793. return $this->db->delete($this->tables['users_groups'], array($this->join['users'] => (int)$user_id));
  794. }
  795. }
  796. /**
  797. * groups
  798. *
  799. * @return object
  800. * @author Ben Edmunds
  801. **/
  802. public function groups()
  803. {
  804. $this->trigger_events('groups');
  805. //run each where that was passed
  806. if (isset($this->_ion_where))
  807. {
  808. foreach ($this->_ion_where as $where)
  809. {
  810. $this->db->where($where);
  811. }
  812. $this->_ion_where = array();
  813. }
  814. if (isset($this->_ion_limit) && isset($this->_ion_offset))
  815. {
  816. $this->db->limit($this->_ion_limit, $this->_ion_offset);
  817. $this->_ion_limit = NULL;
  818. $this->_ion_offset = NULL;
  819. }
  820. //set the order
  821. if (isset($this->_ion_order_by) && isset($this->_ion_order))
  822. {
  823. $this->db->order_by($this->_ion_order_by, $this->_ion_order);
  824. }
  825. $this->response = $this->db->get($this->tables['groups']);
  826. return $this;
  827. }
  828. /**
  829. * group
  830. *
  831. * @return object
  832. * @author Ben Edmunds
  833. **/
  834. public function group()
  835. {
  836. $this->trigger_events('group');
  837. $this->limit(1);
  838. return $this->groups();
  839. }
  840. /**
  841. * update
  842. *
  843. * @return bool
  844. * @author Phil Sturgeon
  845. **/
  846. public function update($id, array $data)
  847. {
  848. $this->trigger_events('pre_update_user');
  849. $user = $this->user($id)->row();
  850. $this->db->trans_begin();
  851. if (array_key_exists($this->identity_column, $data) && $this->identity_check($data[$this->identity_column]) && $user->{$this->identity_column} !== $data[$this->identity_column])
  852. {
  853. $this->db->trans_rollback();
  854. $this->set_error('account_creation_duplicate_'.$this->identity_column);
  855. $this->trigger_events(array('post_update_user', 'post_update_user_unsuccessful'));
  856. $this->set_error('update_unsuccessful');
  857. return FALSE;
  858. }
  859. // Filter the data passed
  860. $data = $this->_filter_data($this->tables['users'], $data);
  861. if (array_key_exists('username', $data) || array_key_exists('password', $data) || array_key_exists('email', $data))
  862. {
  863. if (array_key_exists('password', $data))
  864. {
  865. $data['password'] = $this->hash_password($data['password'], $user->salt);
  866. }
  867. }
  868. $this->trigger_events('extra_where');
  869. $this->db->update($this->tables['users'], $data, array('id' => $user->id));
  870. if ($this->db->trans_status() === FALSE)
  871. {
  872. $this->db->trans_rollback();
  873. $this->trigger_events(array('post_update_user', 'post_update_user_unsuccessful'));
  874. $this->set_error('update_unsuccessful');
  875. return FALSE;
  876. }
  877. $this->db->trans_commit();
  878. $this->trigger_events(array('post_update_user', 'post_update_user_successful'));
  879. $this->set_message('update_successful');
  880. return TRUE;
  881. }
  882. /**
  883. * delete_user
  884. *
  885. * @return bool
  886. * @author Phil Sturgeon
  887. **/
  888. public function delete_user($id)
  889. {
  890. $this->trigger_events('pre_delete_user');
  891. $this->db->trans_begin();
  892. $this->db->delete($this->tables['users'], array('id' => $id));
  893. $this->remove_from_group(NULL, $id);
  894. if ($this->db->trans_status() === FALSE)
  895. {
  896. $this->db->trans_rollback();
  897. $this->trigger_events(array('post_delete_user', 'post_delete_user_unsuccessful'));
  898. $this->set_error('delete_unsuccessful');
  899. return FALSE;
  900. }
  901. $this->db->trans_commit();
  902. $this->trigger_events(array('post_delete_user', 'post_delete_user_successful'));
  903. $this->set_message('delete_successful');
  904. return TRUE;
  905. }
  906. /**
  907. * update_last_login
  908. *
  909. * @return bool
  910. * @author Ben Edmunds
  911. **/
  912. public function update_last_login($id)
  913. {
  914. $this->trigger_events('update_last_login');
  915. $this->load->helper('date');
  916. $this->trigger_events('extra_where');
  917. $this->db->update($this->tables['users'], array('last_login' => time()), array('id' => $id));
  918. return $this->db->affected_rows() == 1;
  919. }
  920. /**
  921. * set_lang
  922. *
  923. * @return bool
  924. * @author Ben Edmunds
  925. **/
  926. public function set_lang($lang = 'en')
  927. {
  928. $this->trigger_events('set_lang');
  929. set_cookie(array(
  930. 'name' => 'lang_code',
  931. 'value' => $lang,
  932. 'expire' => $this->config->item('user_expire', 'ion_auth') + time()
  933. ));
  934. return TRUE;
  935. }
  936. /**
  937. * remember_user
  938. *
  939. * @return bool
  940. * @author Ben Edmunds
  941. **/
  942. private function remember_user($id)
  943. {
  944. $this->trigger_events('pre_remember_user');
  945. if (!$id)
  946. {
  947. return FALSE;
  948. }
  949. $user = $this->user($id)->row();
  950. $salt = sha1($user->password);
  951. $this->db->update($this->tables['users'], array('remember_code' => $salt), array('id' => $id));
  952. if ($this->db->affected_rows() > -1)
  953. {
  954. set_cookie(array(
  955. 'name' => 'identity',
  956. 'value' => $user->{$this->identity_column},
  957. 'expire' => $this->config->item('user_expire', 'ion_auth'),
  958. ));
  959. set_cookie(array(
  960. 'name' => 'remember_code',
  961. 'value' => $salt,
  962. 'expire' => $this->config->item('user_expire', 'ion_auth'),
  963. ));
  964. $this->trigger_events(array('post_remember_user', 'remember_user_successful'));
  965. return TRUE;
  966. }
  967. $this->trigger_events(array('post_remember_user', 'remember_user_unsuccessful'));
  968. return FALSE;
  969. }
  970. /**
  971. * login_remembed_user
  972. *
  973. * @return bool
  974. * @author Ben Edmunds
  975. **/
  976. public function login_remembered_user()
  977. {
  978. $this->trigger_events('pre_login_remembered_user');
  979. //check for valid data
  980. if (!get_cookie('identity') || !get_cookie('remember_code') || !$this->identity_check(get_cookie('identity')))
  981. {
  982. $this->trigger_events(array('post_login_remembered_user', 'post_login_remembered_user_unsuccessful'));
  983. return FALSE;
  984. }
  985. //get the user
  986. $this->trigger_events('extra_where');
  987. $query = $this->db->select($this->identity_column.', id')
  988. ->where($this->identity_column, get_cookie('identity'))
  989. ->where('remember_code', get_cookie('remember_code'))
  990. ->limit(1)
  991. ->get($this->tables['users']);
  992. //if the user was found, sign them in
  993. if ($query->num_rows() == 1)
  994. {
  995. $user = $query->row();
  996. $this->update_last_login($user->id);
  997. $session_data = array(
  998. $this->identity_column => $user->{$this->identity_column},
  999. 'id' => $user->id, //kept for backwards compatibility
  1000. 'user_id' => $user->id, //everyone likes to overwrite id so we'll use user_id
  1001. );
  1002. $this->session->set_userdata($session_data);
  1003. //extend the users cookies if the option is enabled
  1004. if ($this->config->item('user_extend_on_login', 'ion_auth'))
  1005. {
  1006. $this->remember_user($user->id);
  1007. }
  1008. $this->trigger_events(array('post_login_remembered_user', 'post_login_remembered_user_successful'));
  1009. return TRUE;
  1010. }
  1011. $this->trigger_events(array('post_login_remembered_user', 'post_login_remembered_user_unsuccessful'));
  1012. return FALSE;
  1013. }
  1014. public function set_hook($event, $name, $class, $method, $arguments)
  1015. {
  1016. $this->_ion_hooks->{$event}[$name] = new stdClass;
  1017. $this->_ion_hooks->{$event}[$name]->class = $class;
  1018. $this->_ion_hooks->{$event}[$name]->method = $method;
  1019. $this->_ion_hooks->{$event}[$name]->arguments = $arguments;
  1020. }
  1021. public function remove_hook($event, $name)
  1022. {
  1023. if (isset($this->_ion_hooks->{$event}[$name]))
  1024. {
  1025. unset($this->_ion_hooks->{$event}[$name]);
  1026. }
  1027. }
  1028. public function remove_hooks($event)
  1029. {
  1030. if (isset($this->_ion_hooks->$event))
  1031. {
  1032. unset($this->_ion_hooks->$event);
  1033. }
  1034. }
  1035. protected function _call_hook($event, $name)
  1036. {
  1037. if (isset($this->_ion_hooks->{$event}[$name]) && method_exists($this->_ion_hooks->{$event}[$name]->class, $this->_ion_hooks->{$event}[$name]->method))
  1038. {
  1039. $hook = $this->_ion_hooks->{$event}[$name];
  1040. return call_user_func_array(array($hook->class, $hook->method), $hook->arguments);
  1041. }
  1042. return FALSE;
  1043. }
  1044. public function trigger_events($events)
  1045. {
  1046. if (is_array($events) && !empty($events))
  1047. {
  1048. foreach ($events as $event)
  1049. {
  1050. $this->trigger_events($event);
  1051. }
  1052. }
  1053. else
  1054. {
  1055. if (isset($this->_ion_hooks->$events) && !empty($this->_ion_hooks->$events))
  1056. {
  1057. foreach ($this->_ion_hooks->$events as $name => $hook)
  1058. {
  1059. $this->_call_hook($events, $name);
  1060. }
  1061. }
  1062. }
  1063. }
  1064. /**
  1065. * set_message_delimiters
  1066. *
  1067. * Set the message delimiters
  1068. *
  1069. * @return void
  1070. * @author Ben Edmunds
  1071. **/
  1072. public function set_message_delimiters($start_delimiter, $end_delimiter)
  1073. {
  1074. $this->message_start_delimiter = $start_delimiter;
  1075. $this->message_end_delimiter = $end_delimiter;
  1076. return TRUE;
  1077. }
  1078. /**
  1079. * set_error_delimiters
  1080. *
  1081. * Set the error delimiters
  1082. *
  1083. * @return void
  1084. * @author Ben Edmunds
  1085. **/
  1086. public function set_error_delimiters($start_delimiter, $end_delimiter)
  1087. {
  1088. $this->error_start_delimiter = $start_delimiter;
  1089. $this->error_end_delimiter = $end_delimiter;
  1090. return TRUE;
  1091. }
  1092. /**
  1093. * set_message
  1094. *
  1095. * Set a message
  1096. *
  1097. * @return void
  1098. * @author Ben Edmunds
  1099. **/
  1100. public function set_message($message)
  1101. {
  1102. $this->messages[] = $message;
  1103. return $message;
  1104. }
  1105. /**
  1106. * messages
  1107. *
  1108. * Get the messages
  1109. *
  1110. * @return void
  1111. * @author Ben Edmunds
  1112. **/
  1113. public function messages()
  1114. {
  1115. $_output = '';
  1116. foreach ($this->messages as $message)
  1117. {
  1118. $messageLang = $this->lang->line($message) ? $this->lang->line($message) : '##' . $message . '##';
  1119. $_output .= $this->message_start_delimiter . $messageLang . $this->message_end_delimiter;
  1120. }
  1121. return $_output;
  1122. }
  1123. /**
  1124. * set_error
  1125. *
  1126. * Set an error message
  1127. *
  1128. * @return void
  1129. * @author Ben Edmunds
  1130. **/
  1131. public function set_error($error)
  1132. {
  1133. $this->errors[] = $error;
  1134. return $error;
  1135. }
  1136. /**
  1137. * errors
  1138. *
  1139. * Get the error message
  1140. *
  1141. * @return void
  1142. * @author Ben Edmunds
  1143. **/
  1144. public function errors()
  1145. {
  1146. $_output = '';
  1147. foreach ($this->errors as $error)
  1148. {
  1149. $errorLang = $this->lang->line($error) ? $this->lang->line($error) : '##' . $error . '##';
  1150. $_output .= $this->error_start_delimiter . $errorLang . $this->error_end_delimiter;
  1151. }
  1152. return $_output;
  1153. }
  1154. protected function _filter_data($table, $data)
  1155. {
  1156. $filtered_data = array();
  1157. $columns = $this->db->list_fields($table);
  1158. if (is_array($data))
  1159. {
  1160. foreach ($columns as $column)
  1161. {
  1162. if (array_key_exists($column, $data))
  1163. $filtered_data[$column] = $data[$column];
  1164. }
  1165. }
  1166. return $filtered_data;
  1167. }
  1168. }