File: /home/jairicem/4pfxclusive.ng/app/models/admin/Auth_model.php
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class Auth_model extends CI_Model
{
public $_cache_user_in_group = [];
public $_ion_like = [];
public $_ion_limit = null;
public $_ion_offset = null;
public $_ion_order = null;
public $_ion_order_by = null;
public $_ion_select = [];
public $_ion_where = [];
public $activation_code;
public $forgotten_password_code;
public $identity;
public $new_password;
public $tables = [];
protected $_cache_groups = [];
protected $_ion_hooks;
protected $error_end_delimiter;
protected $error_start_delimiter;
protected $errors;
protected $messages;
protected $response = null;
public function __construct()
{
parent::__construct();
$this->load->config('ion_auth', true);
//initialize db tables data
$this->tables = $this->config->item('tables', 'ion_auth');
//initialize data
$this->identity_column = $this->config->item('identity', 'ion_auth');
$this->store_salt = $this->config->item('store_salt', 'ion_auth');
$this->salt_length = $this->config->item('salt_length', 'ion_auth');
$this->join = $this->config->item('join', 'ion_auth');
//initialize hash method options (Bcrypt)
$this->hash_method = $this->config->item('hash_method', 'ion_auth');
$this->default_rounds = $this->config->item('default_rounds', 'ion_auth');
$this->random_rounds = $this->config->item('random_rounds', 'ion_auth');
$this->min_rounds = $this->config->item('min_rounds', 'ion_auth');
$this->max_rounds = $this->config->item('max_rounds', 'ion_auth');
//initialize messages and error
$this->messages = [];
$this->errors = [];
$delimiters_source = $this->config->item('delimiters_source', 'ion_auth');
//load the error delimeters either from the config file or use what's been supplied to form validation
if ($delimiters_source === 'form_validation') {
//load in delimiters from form_validation
//to keep this simple we'll load the value using reflection since these properties are protected
$this->load->library('form_validation');
$form_validation_class = new ReflectionClass('CI_Form_validation');
$error_prefix = $form_validation_class->getProperty('_error_prefix');
$error_prefix->setAccessible(true);
$this->error_start_delimiter = $error_prefix->getValue($this->form_validation);
$this->message_start_delimiter = $this->error_start_delimiter;
$error_suffix = $form_validation_class->getProperty('_error_suffix');
$error_suffix->setAccessible(true);
$this->error_end_delimiter = $error_suffix->getValue($this->form_validation);
$this->message_end_delimiter = $this->error_end_delimiter;
} else {
//use delimiters from config
$this->message_start_delimiter = $this->config->item('message_start_delimiter', 'ion_auth');
$this->message_end_delimiter = $this->config->item('message_end_delimiter', 'ion_auth');
$this->error_start_delimiter = $this->config->item('error_start_delimiter', 'ion_auth');
$this->error_end_delimiter = $this->config->item('error_end_delimiter', 'ion_auth');
}
//initialize our hooks object
$this->_ion_hooks = new stdClass;
//load the bcrypt class if needed
if ($this->hash_method == 'bcrypt') {
if ($this->random_rounds) {
$rand = rand($this->min_rounds, $this->max_rounds);
$rounds = ['rounds' => $rand];
} else {
$rounds = ['rounds' => $this->default_rounds];
}
$this->load->library('bcrypt', $rounds);
}
$this->trigger_events('model_constructor');
}
protected function _call_hook($event, $name)
{
if (isset($this->_ion_hooks->{$event}[$name]) && method_exists($this->_ion_hooks->{$event}[$name]->class, $this->_ion_hooks->{$event}[$name]->method)) {
$hook = $this->_ion_hooks->{$event}[$name];
return call_user_func_array([$hook->class, $hook->method], $hook->arguments);
}
return false;
}
protected function _filter_data($table, $data)
{
$filtered_data = [];
$columns = $this->db->list_fields($table);
if (is_array($data)) {
foreach ($columns as $column) {
if (array_key_exists($column, $data)) {
$filtered_data[$column] = $data[$column];
}
}
}
return $filtered_data;
}
protected function _prepare_ip($ip_address)
{
if ($this->db->platform() === 'postgre' || $this->db->platform() === 'sqlsrv' || $this->db->platform() === 'mssql' || $this->db->platform() === 'mysqli' || $this->db->platform() === 'mysql') {
return $ip_address;
}
return inet_pton($ip_address);
}
public function activate($id, $code = false)
{
$this->trigger_events('pre_activate');
if ($code !== false) {
$query = $this->db->select($this->identity_column)
->where('activation_code', $code)
->limit(1)
->get($this->tables['users']);
$result = $query->row();
if ($query->num_rows() !== 1) {
$this->trigger_events(['post_activate', 'post_activate_unsuccessful']);
$this->set_error('activate_unsuccessful');
return false;
}
$identity = $result->{$this->identity_column};
$data = ['activation_code' => null, 'active' => '1'];
$this->trigger_events('extra_where');
if ($this->db->update($this->tables['users'], $data, [$this->identity_column => $identity])) {
$this->trigger_events(['post_activate', 'post_activate_successful']);
$this->set_message('activate_successful');
return true;
}
$this->trigger_events(['post_activate', 'post_activate_unsuccessful']);
$this->set_error('activate_unsuccessful');
return false;
}
$user = $this->user($id)->row();
$data = ['activation_code' => null, 'active' => '1'];
$this->trigger_events('extra_where');
return $this->db->update($this->tables['users'], $data, ['id' => $id]);
return false;
}
public function change_password($identity, $old, $new)
{
$this->trigger_events('pre_change_password');
$this->trigger_events('extra_where');
$query = $this->db->select('id, password, salt')
->where($this->identity_column, $identity)
->limit(1)
->get($this->tables['users']);
if ($query->num_rows() !== 1) {
$this->trigger_events(['post_change_password', 'post_change_password_unsuccessful']);
$this->set_error('password_change_unsuccessful');
return false;
}
$user = $query->row();
$old_password_matches = $this->hash_password_db($user->id, $old);
if ($old_password_matches === true) {
//store the new password and reset the remember code so all remembered instances have to re-login
$hashed_new_password = $this->hash_password($new, $user->salt);
$data = [
'password' => $hashed_new_password,
'remember_code' => null,
];
$this->trigger_events('extra_where');
$successfully_changed_password_in_db = $this->db->update($this->tables['users'], $data, [$this->identity_column => $identity]);
if ($successfully_changed_password_in_db) {
$this->trigger_events(['post_change_password', 'post_change_password_successful']);
$this->set_message('password_change_successful');
} else {
$this->trigger_events(['post_change_password', 'post_change_password_unsuccessful']);
$this->set_error('password_change_unsuccessful');
}
return $successfully_changed_password_in_db;
}
$this->set_error('old_password_wrong');
$this->set_error('password_change_unsuccessful');
return false;
}
public function clear_forgotten_password_code($code)
{
if (empty($code)) {
return false;
}
$this->db->where('forgotten_password_code', $code);
if ($this->db->count_all_results($this->tables['users']) > 0) {
$data = [
'forgotten_password_code' => null,
'forgotten_password_time' => null,
];
$this->db->update($this->tables['users'], $data, ['forgotten_password_code' => $code]);
return true;
}
return false;
}
public function clear_login_attempts($identity, $expire_period = 86400)
{
if ($this->config->item('track_login_attempts', 'ion_auth')) {
$ip_address = $this->_prepare_ip($this->input->ip_address());
$this->db->where(['ip_address' => $ip_address, 'login' => $identity]);
// Purge obsolete login attempts
$this->db->or_where('time <', time() - $expire_period, false);
return $this->db->delete($this->tables['login_attempts']);
}
return false;
}
public function create_group($group_name = false, $group_description = '', $additional_data = [])
{
// bail if the group name was not passed
if (!$group_name) {
$this->set_error('group_name_required');
return false;
}
// bail if the group name already exists
$existing_group = $this->db->get_where($this->tables['groups'], ['name' => $group_name])->num_rows();
if ($existing_group !== 0) {
$this->set_error('group_already_exists');
return false;
}
$data = ['name' => $group_name, 'description' => $group_description];
//filter out any data passed that doesnt have a matching column in the groups table
//and merge the set group data and the additional data
if (!empty($additional_data)) {
$data = array_merge($this->_filter_data($this->tables['groups'], $additional_data), $data);
}
$this->trigger_events('extra_group_set');
// insert the new group
$this->db->insert($this->tables['groups'], $data);
$group_id = $this->db->insert_id();
// report success
$this->set_message('group_creation_successful');
// return the brand new group id
return $group_id;
}
public function deactivate($id = null)
{
$this->trigger_events('deactivate');
if (!isset($id)) {
$this->set_error('deactivate_unsuccessful');
return false;
}
$activation_code = sha1(md5(microtime()));
$this->activation_code = $activation_code;
$data = [
'activation_code' => $activation_code,
'active' => 0,
];
$this->trigger_events('extra_where');
$this->db->update($this->tables['users'], $data, ['id' => $id]);
$return = $this->db->affected_rows() == 1;
if ($return) {
$this->set_message('deactivate_successful');
} else {
$this->set_error('deactivate_unsuccessful');
}
return $return;
}
public function delete_group($group_id = false)
{
// bail if mandatory param not set
if (!$group_id || empty($group_id)) {
return false;
}
$this->trigger_events('pre_delete_group');
$this->db->trans_begin();
// remove all users from this group
//$this->db->delete($this->tables['users_groups'], array($this->join['groups'] => $group_id));
// remove the group itself
$this->db->delete($this->tables['groups'], ['id' => $group_id]);
if ($this->db->trans_status() === false) {
$this->db->trans_rollback();
$this->trigger_events(['post_delete_group', 'post_delete_group_unsuccessful']);
$this->set_error('group_delete_unsuccessful');
return false;
}
$this->db->trans_commit();
$this->trigger_events(['post_delete_group', 'post_delete_group_successful']);
$this->set_message('group_delete_successful');
return true;
}
public function delete_user($id)
{
$this->trigger_events('pre_delete_user');
$this->db->trans_begin();
// remove user from groups
//$this->remove_from_group(NULL, $id);
// delete user from users table should be placed after remove from group
$this->db->delete($this->tables['users'], ['id' => $id]);
// if user does not exist in database then it returns FALSE else removes the user from groups
if ($this->db->affected_rows() == 0) {
return false;
}
if ($this->db->trans_status() === false) {
$this->db->trans_rollback();
$this->trigger_events(['post_delete_user', 'post_delete_user_unsuccessful']);
$this->set_error('delete_unsuccessful');
return false;
}
$this->db->trans_commit();
$this->trigger_events(['post_delete_user', 'post_delete_user_successful']);
$this->set_message('delete_successful');
return true;
}
public function email_check($email = '')
{
$this->trigger_events('email_check');
if (empty($email)) {
return false;
}
$this->trigger_events('extra_where');
return $this->db->where('email', $email)
->count_all_results($this->tables['users']) > 0;
}
public function errors()
{
$_output = '';
foreach ($this->errors as $error) {
$errorLang = $this->lang->line($error) ? $this->lang->line($error) : '##' . $error . '##';
$_output .= $this->error_start_delimiter . $errorLang . $this->error_end_delimiter;
}
return $_output;
}
public function errors_array($langify = true)
{
if ($langify) {
$_output = [];
foreach ($this->errors as $error) {
$errorLang = $this->lang->line($error) ? $this->lang->line($error) : '##' . $error . '##';
$_output[] = $this->error_start_delimiter . $errorLang . $this->error_end_delimiter;
}
return $_output;
}
return $this->errors;
}
public function forgotten_password($identity)
{
if (empty($identity)) {
$this->trigger_events(['post_forgotten_password', 'post_forgotten_password_unsuccessful']);
return false;
}
//All some more randomness
$activation_code_part = '';
if (function_exists('openssl_random_pseudo_bytes')) {
$activation_code_part = openssl_random_pseudo_bytes(128);
}
for ($i = 0; $i < 1024; $i++) {
$activation_code_part = sha1($activation_code_part . mt_rand() . microtime());
}
$key = $this->hash_code($activation_code_part . $identity);
$this->forgotten_password_code = $key;
$this->trigger_events('extra_where');
$update = [
'forgotten_password_code' => $key,
'forgotten_password_time' => time(),
];
$this->db->update($this->tables['users'], $update, [$this->identity_column => $identity]);
$return = $this->db->affected_rows() == 1;
if ($return) {
$this->trigger_events(['post_forgotten_password', 'post_forgotten_password_successful']);
} else {
$this->trigger_events(['post_forgotten_password', 'post_forgotten_password_unsuccessful']);
}
return $return;
}
public function forgotten_password_complete($code, $salt = false)
{
$this->trigger_events('pre_forgotten_password_complete');
if (empty($code)) {
$this->trigger_events(['post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful']);
return false;
}
$profile = $this->where('forgotten_password_code', $code)->users()->row(); //pass the code to profile
if ($profile) {
if ($this->config->item('forgot_password_expiration', 'ion_auth') > 0) {
//Make sure it isn't expired
$expiration = $this->config->item('forgot_password_expiration', 'ion_auth');
if (time() - $profile->forgotten_password_time > $expiration) {
//it has expired
$this->set_error('forgot_password_expired');
$this->trigger_events(['post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful']);
return false;
}
}
$password = $this->salt();
$data = [
'password' => $this->hash_password($password, $salt),
'forgotten_password_code' => null,
'active' => 1,
];
$this->db->update($this->tables['users'], $data, ['forgotten_password_code' => $code]);
$this->trigger_events(['post_forgotten_password_complete', 'post_forgotten_password_complete_successful']);
return $password;
}
$this->trigger_events(['post_forgotten_password_complete', 'post_forgotten_password_complete_unsuccessful']);
return false;
}
public function get_attempts_num($identity)
{
if ($this->config->item('track_login_attempts', 'ion_auth')) {
$ip_address = $this->_prepare_ip($this->input->ip_address());
$this->db->select('1', false);
if ($this->config->item('track_login_ip_address', 'ion_auth')) {
$this->db->where('ip_address', $ip_address);
} elseif (strlen($identity) > 0) {
$this->db->or_where('login', $identity);
}
$qres = $this->db->get($this->tables['login_attempts']);
return $qres->num_rows();
}
return 0;
}
public function get_last_attempt_time($identity)
{
if ($this->config->item('track_login_attempts', 'ion_auth')) {
$ip_address = $this->_prepare_ip($this->input->ip_address());
$this->db->select_max('time');
if ($this->config->item('track_login_ip_address', 'ion_auth')) {
$this->db->where('ip_address', $ip_address);
} elseif (strlen($identity) > 0) {
$this->db->or_where('login', $identity);
}
$qres = $this->db->get($this->tables['login_attempts'], 1);
if ($qres->num_rows() > 0) {
return $qres->row()->time;
}
}
return 0;
}
/**
* get_users_groups
*
* @return array
* @author Ben Edmunds
* */
public function get_users_group($id = false)
{
$this->trigger_events('get_users_group');
//if no id was passed use the current users id
$id || $id = $this->session->userdata('user_id');
return $this->db->select($this->tables['groups'] . '.id as id, ' . $this->tables['groups'] . '.name, ' . $this->tables['groups'] . '.description')
->where($this->tables['groups'] . '.id', $id)
//->join($this->tables['groups'], $this->tables['users_groups'] . '.' . $this->join['groups'] . '=' . $this->tables['groups'] . '.id')
->get($this->tables['groups']);
}
public function getBillingAddress($id)
{
$q = $this->db->get_where('addresses', ['user_id' => $id, 'type' => 'billing'], 1);
if ($q->num_rows() > 0) {
return $q->row();
}
return false;
}
public function getDeliveryAddress($id)
{
$q = $this->db->get_where('addresses', ['user_id' => $id, 'type' => 'delivery'], 1);
if ($q->num_rows() > 0) {
return $q->row();
}
return false;
}
public function group($id = null)
{
$this->trigger_events('group');
if (isset($id)) {
$this->db->where($this->tables['groups'] . '.id', $id);
}
$this->limit(1);
return $this->groups();
}
/**
* groups
*
* @return object
* @author Ben Edmunds
* */
public function groups()
{
$this->trigger_events('groups');
//run each where that was passed
if (isset($this->_ion_where) && !empty($this->_ion_where)) {
foreach ($this->_ion_where as $where) {
$this->db->where($where);
}
$this->_ion_where = [];
}
if (isset($this->_ion_limit) && isset($this->_ion_offset)) {
$this->db->limit($this->_ion_limit, $this->_ion_offset);
$this->_ion_limit = null;
$this->_ion_offset = null;
} elseif (isset($this->_ion_limit)) {
$this->db->limit($this->_ion_limit);
$this->_ion_limit = null;
}
//set the order
if (isset($this->_ion_order_by) && isset($this->_ion_order)) {
$this->db->order_by($this->_ion_order_by, $this->_ion_order);
}
$this->response = $this->db->get($this->tables['groups']);
return $this;
}
public function hash_code($password)
{
return $this->hash_password($password, false, true);
}
public function hash_password($password, $salt = false, $use_sha1_override = false)
{
if (empty($password)) {
return false;
}
//bcrypt
if ($use_sha1_override === false && $this->hash_method == 'bcrypt') {
return $this->bcrypt->hash($password);
}
if ($this->store_salt && $salt) {
return sha1($password . $salt);
}
$salt = $this->salt();
return $salt . substr(sha1($salt . $password), 0, -$this->salt_length);
}
public function hash_password_db($id, $password, $use_sha1_override = false)
{
if (empty($id) || empty($password)) {
return false;
}
$this->trigger_events('extra_where');
$query = $this->db->select('password, salt')
->where('id', $id)
->limit(1)
->get($this->tables['users']);
$hash_password_db = $query->row();
if ($query->num_rows() !== 1) {
return false;
}
// bcrypt
if ($use_sha1_override === false && $this->hash_method == 'bcrypt') {
if ($this->bcrypt->verify($password, $hash_password_db->password)) {
return true;
}
return false;
}
// sha1
if ($this->store_salt) {
$db_password = sha1($password . $hash_password_db->salt);
} else {
$salt = substr($hash_password_db->password, 0, $this->salt_length);
$db_password = $salt . substr(sha1($salt . $password), 0, -$this->salt_length);
}
if ($db_password == $hash_password_db->password) {
return true;
}
return false;
}
public function identity_check($identity = '')
{
$this->trigger_events('identity_check');
if (empty($identity)) {
return false;
}
return $this->db->where($this->identity_column, $identity)
->count_all_results($this->tables['users']) > 0;
}
public function increase_login_attempts($identity)
{
if ($this->config->item('track_login_attempts', 'ion_auth')) {
$ip_address = $this->_prepare_ip($this->input->ip_address());
return $this->db->insert($this->tables['login_attempts'], ['ip_address' => $ip_address, 'login' => $identity, 'time' => time()]);
}
return false;
}
public function is_max_login_attempts_exceeded($identity)
{
if ($this->config->item('track_login_attempts', 'ion_auth')) {
$max_attempts = $this->config->item('maximum_login_attempts', 'ion_auth');
if ($max_attempts > 0) {
$attempts = $this->get_attempts_num($identity);
return $attempts >= $max_attempts;
}
}
return false;
}
public function is_time_locked_out($identity)
{
return $this->is_max_login_attempts_exceeded($identity) && $this->get_last_attempt_time($identity) > time() - $this->config->item('lockout_time', 'ion_auth');
}
public function like($like, $value = null, $position = 'both')
{
$this->trigger_events('like');
if (!is_array($like)) {
$like = [$like => [
'value' => $value,
'position' => $position,
]];
}
array_push($this->_ion_like, $like);
return $this;
}
public function limit($limit)
{
$this->trigger_events('limit');
$this->_ion_limit = $limit;
return $this;
}
public function login($identity, $password, $remember = false)
{
$this->trigger_events('pre_login');
if (empty($identity) || empty($password)) {
$this->set_error('login_unsuccessful');
return false;
}
$this->trigger_events('extra_where');
$this->load->helper('email');
$this->identity_column = valid_email($identity) ? 'email' : 'username';
$query = $this->db->select($this->identity_column . ', username, email, id, password, active, last_login, last_ip_address, avatar, gender, group_id, warehouse_id, biller_id, company_id, view_right, edit_right, allow_discount, show_cost, show_price')
->where($this->identity_column, $this->db->escape_str($identity))
->limit(1)
->get($this->tables['users']);
if ($this->is_time_locked_out($identity)) {
//Hash something anyway, just to take up time
$this->hash_password($password);
$this->trigger_events('post_login_unsuccessful');
$this->set_error('login_timeout');
return false;
}
if ($query->num_rows() === 1) {
$user = $query->row();
$password = $this->hash_password_db($user->id, $password);
if ($password === true) {
if ($user->active != 1) {
$this->trigger_events('post_login_unsuccessful');
$this->set_error('login_unsuccessful_not_active');
return false;
}
$this->set_session($user);
$this->update_last_login($user->id);
$this->update_last_login_ip($user->id);
$ldata = ['user_id' => $user->id, 'ip_address' => $this->input->ip_address(), 'login' => $identity, 'time' => date('Y-m-d H:i:s')];
$this->db->insert('user_logins', $ldata);
$this->clear_login_attempts($identity);
if ($remember && $this->config->item('remember_users', 'ion_auth')) {
$this->remember_user($user->id);
}
$this->trigger_events(['post_login', 'post_login_successful']);
$this->set_message('login_successful');
return true;
}
}
//Hash something anyway, just to take up time
$this->hash_password($password);
$this->increase_login_attempts($identity);
$this->trigger_events('post_login_unsuccessful');
$this->set_error('login_unsuccessful');
return false;
}
public function login_remembered_user()
{
$this->trigger_events('pre_login_remembered_user');
//check for valid data
if (!get_cookie('identity') || !get_cookie('remember_code') || !$this->identity_check(get_cookie('identity'))) {
$this->trigger_events(['post_login_remembered_user', 'post_login_remembered_user_unsuccessful']);
return false;
}
//get the user
$this->trigger_events('extra_where');
$query = $this->db->select($this->identity_column . ', id, username, email, last_login, last_ip_address, avatar, gender, group_id, warehouse_id, biller_id, company_id, view_right, allow_discount, edit_right, show_cost, show_price')
->where($this->identity_column, get_cookie('identity'))
->where('remember_code', get_cookie('remember_code'))
->limit(1)
->get($this->tables['users']);
//if the user was found, sign them in
if ($query->num_rows() == 1) {
$user = $query->row();
$this->update_last_login($user->id);
$this->update_last_login_ip($user->id);
$this->set_session($user);
//extend the users cookies if the option is enabled
if ($this->config->item('user_extend_on_login', 'ion_auth')) {
$this->remember_user($user->id);
}
$this->trigger_events(['post_login_remembered_user', 'post_login_remembered_user_successful']);
return true;
}
$this->trigger_events(['post_login_remembered_user', 'post_login_remembered_user_unsuccessful']);
return false;
}
public function messages()
{
$_output = '';
foreach ($this->messages as $message) {
$messageLang = $this->lang->line($message) ? $this->lang->line($message) : '##' . $message . '##';
$_output .= $this->message_start_delimiter . $messageLang . $this->message_end_delimiter;
}
return $_output;
}
public function messages_array($langify = true)
{
if ($langify) {
$_output = [];
foreach ($this->messages as $message) {
$messageLang = $this->lang->line($message) ? $this->lang->line($message) : '##' . $message . '##';
$_output[] = $this->message_start_delimiter . $messageLang . $this->message_end_delimiter;
}
return $_output;
}
return $this->messages;
}
public function num_rows()
{
$this->trigger_events(['num_rows']);
$result = $this->response->num_rows();
$this->response->free_result();
return $result;
}
public function offset($offset)
{
$this->trigger_events('offset');
$this->_ion_offset = $offset;
return $this;
}
public function order_by($by, $order = 'desc')
{
$this->trigger_events('order_by');
$this->_ion_order_by = $by;
$this->_ion_order = $order;
return $this;
}
public function register($username, $password, $email, $additional_data = [], $active = false)
{
$this->trigger_events('pre_register');
$manual_activation = $this->config->item('manual_activation', 'ion_auth');
if ($this->identity_column == 'email' && $this->email_check($email)) {
$this->set_error('account_creation_duplicate_email');
return false;
} elseif ($this->identity_column == 'username' && $this->username_check($username)) {
$this->set_error('account_creation_duplicate_username');
return false;
}
// If username is taken, use username1 or username2, etc.
if ($this->identity_column != 'username') {
$original_username = $username;
for ($i = 0; $this->username_check($username); $i++) {
if ($i > 0) {
$username = $original_username . $i;
}
}
}
// IP Address
$ip_address = $this->_prepare_ip($this->input->ip_address());
$salt = $this->store_salt ? $this->salt() : false;
$password = $this->hash_password($password, $salt);
// Users table.
$data = [
'username' => $username,
'password' => $password,
'email' => $email,
'ip_address' => $ip_address,
'created_on' => time(),
'last_login' => time(),
'active' => ($active ? 1 : (($manual_activation === false) ? 1 : 0)),
];
if ($this->store_salt) {
$data['salt'] = $salt;
}
if (!isset($additional_data['group_id'])) {
$additional_data['group_id'] = 3;
}
//filter out any data passed that doesnt have a matching column in the users table
//and merge the set user data and the additional data
$user_data = array_merge($this->_filter_data($this->tables['users'], $additional_data), $data);
$this->trigger_events('extra_set');
$this->db->insert($this->tables['users'], $user_data);
$id = $this->db->insert_id();
/*if(!empty($groups)) {
//add to groups
foreach ($groups as $group) {
$this->add_to_group($group, $id);
}
}
//add to default group if not already set
$default_group = $this->where('name', $this->config->item('default_group', 'ion_auth'))->group()->row();
if((isset($default_group->id) && !isset($groups)) || (empty($groups) && !in_array($default_group->id, $groups))) {
$this->add_to_group($default_group->id, $id);
}*/
$this->trigger_events('post_register');
return (isset($id)) ? $id : false;
}
public function remember_user($id)
{
$this->trigger_events('pre_remember_user');
if (!$id) {
return false;
}
$user = $this->user($id)->row();
$salt = sha1($user->password);
$this->db->update($this->tables['users'], ['remember_code' => $salt], ['id' => $id]);
if ($this->db->affected_rows() > -1) {
// if the user_expire is set to zero we'll set the expiration two years from now.
if ($this->config->item('user_expire', 'ion_auth') === 0) {
$expire = (60 * 60 * 24 * 365 * 2);
} // otherwise use what is set
else {
$expire = $this->config->item('user_expire', 'ion_auth');
}
set_cookie([
'name' => 'identity',
'value' => $user->{$this->identity_column},
'expire' => $expire,
]);
set_cookie([
'name' => 'remember_code',
'value' => $salt,
'expire' => $expire,
]);
$this->trigger_events(['post_remember_user', 'remember_user_successful']);
return true;
}
$this->trigger_events(['post_remember_user', 'remember_user_unsuccessful']);
return false;
}
public function remove_hook($event, $name)
{
if (isset($this->_ion_hooks->{$event}[$name])) {
unset($this->_ion_hooks->{$event}[$name]);
}
}
public function remove_hooks($event)
{
if (isset($this->_ion_hooks->$event)) {
unset($this->_ion_hooks->$event);
}
}
public function reset_password($identity, $new)
{
$this->trigger_events('pre_change_password');
if (!$this->identity_check($identity)) {
$this->trigger_events(['post_change_password', 'post_change_password_unsuccessful']);
return false;
}
$this->trigger_events('extra_where');
$query = $this->db->select('id, password, salt')
->where($this->identity_column, $identity)
->limit(1)
->get($this->tables['users']);
if ($query->num_rows() !== 1) {
$this->trigger_events(['post_change_password', 'post_change_password_unsuccessful']);
$this->set_error('password_change_unsuccessful');
return false;
}
$result = $query->row();
$new = $this->hash_password($new, $result->salt);
//store the new password and reset the remember code so all remembered instances have to re-login
//also clear the forgotten password code
$data = [
'password' => $new,
'remember_code' => null,
'forgotten_password_code' => null,
'forgotten_password_time' => null,
];
$this->trigger_events('extra_where');
$this->db->update($this->tables['users'], $data, [$this->identity_column => $identity]);
$return = $this->db->affected_rows() == 1;
if ($return) {
$this->trigger_events(['post_change_password', 'post_change_password_successful']);
$this->set_message('password_change_successful');
} else {
$this->trigger_events(['post_change_password', 'post_change_password_unsuccessful']);
$this->set_error('password_change_unsuccessful');
}
return $return;
}
public function result()
{
$this->trigger_events('result');
$result = $this->response->result();
$this->response->free_result();
return $result;
}
public function result_array()
{
$this->trigger_events(['result', 'result_array']);
$result = $this->response->result_array();
$this->response->free_result();
return $result;
}
public function row()
{
$this->trigger_events('row');
$row = $this->response->row();
$this->response->free_result();
return $row;
}
public function row_array()
{
$this->trigger_events(['row', 'row_array']);
$row = $this->response->row_array();
$this->response->free_result();
return $row;
}
public function salt()
{
return substr(md5(uniqid(rand(), true)), 0, $this->salt_length);
}
public function select($select)
{
$this->trigger_events('select');
$this->_ion_select[] = $select;
return $this;
}
public function set_error($error)
{
$this->errors[] = $error;
return $error;
}
public function set_error_delimiters($start_delimiter, $end_delimiter)
{
$this->error_start_delimiter = $start_delimiter;
$this->error_end_delimiter = $end_delimiter;
return true;
}
public function set_hook($event, $name, $class, $method, $arguments)
{
$this->_ion_hooks->{$event}[$name] = new stdClass;
$this->_ion_hooks->{$event}[$name]->class = $class;
$this->_ion_hooks->{$event}[$name]->method = $method;
$this->_ion_hooks->{$event}[$name]->arguments = $arguments;
}
public function set_lang($lang = 'en')
{
$this->trigger_events('set_lang');
// if the user_expire is set to zero we'll set the expiration two years from now.
if ($this->config->item('user_expire', 'ion_auth') === 0) {
$expire = (60 * 60 * 24 * 365 * 2);
} // otherwise use what is set
else {
$expire = $this->config->item('user_expire', 'ion_auth');
}
set_cookie([
'name' => 'lang_code',
'value' => $lang,
'expire' => $expire,
]);
return true;
}
public function set_message($message)
{
$this->messages[] = $message;
return $message;
}
public function set_message_delimiters($start_delimiter, $end_delimiter)
{
$this->message_start_delimiter = $start_delimiter;
$this->message_end_delimiter = $end_delimiter;
return true;
}
public function set_session($user)
{
$this->trigger_events('pre_set_session');
$session_data = [
'identity' => $user->{$this->identity_column},
'username' => $user->username,
'email' => $user->email,
'user_id' => $user->id, //everyone likes to overwrite id so we'll use user_id
'old_last_login' => $user->last_login,
'last_ip' => $user->last_ip_address,
'avatar' => $user->avatar,
'gender' => $user->gender,
'group_id' => $user->group_id,
'warehouse_id' => $user->warehouse_id,
'view_right' => $user->view_right,
'edit_right' => $user->edit_right,
'allow_discount' => $user->allow_discount,
'biller_id' => $user->biller_id,
'company_id' => $user->company_id,
'show_cost' => $user->show_cost,
'show_price' => $user->show_price,
];
$this->session->set_userdata($session_data);
$this->trigger_events('post_set_session');
return true;
}
public function trigger_events($events)
{
if (is_array($events) && !empty($events)) {
foreach ($events as $event) {
$this->trigger_events($event);
}
} else {
if (isset($this->_ion_hooks->$events) && !empty($this->_ion_hooks->$events)) {
foreach ($this->_ion_hooks->$events as $name => $hook) {
$this->_call_hook($events, $name);
}
}
}
}
public function update($id, array $data, $upgs = [])
{
$this->trigger_events('pre_update_user');
$user = $this->user($id)->row();
$this->db->trans_begin();
if (array_key_exists($this->identity_column, $data) && $this->identity_check($data[$this->identity_column]) && $user->{$this->identity_column} !== $data[$this->identity_column]) {
$this->db->trans_rollback();
$this->set_error('account_creation_duplicate_' . $this->identity_column);
$this->trigger_events(['post_update_user', 'post_update_user_unsuccessful']);
$this->set_error('update_unsuccessful');
return false;
}
// Filter the data passed
$data = $this->_filter_data($this->tables['users'], $data);
if (array_key_exists('username', $data) || array_key_exists('password', $data) || array_key_exists('email', $data)) {
if (array_key_exists('password', $data)) {
if (!empty($data['password'])) {
$data['password'] = $this->hash_password($data['password'], $user->salt);
} else {
// unset password so it doesn't effect database entry if no password passed
unset($data['password']);
}
}
}
$this->trigger_events('extra_where');
$this->db->update($this->tables['users'], $data, ['id' => $user->id]);
if ($this->db->trans_status() === false) {
$this->db->trans_rollback();
$this->trigger_events(['post_update_user', 'post_update_user_unsuccessful']);
$this->set_error('update_unsuccessful');
return false;
}
$this->db->trans_commit();
$this->trigger_events(['post_update_user', 'post_update_user_successful']);
$this->set_message('update_successful');
return true;
}
public function update_group($group_id = false, $group_name = false, $additional_data = [])
{
if (empty($group_id)) {
return false;
}
$data = [];
if (!empty($group_name)) {
// we are changing the name, so do some checks
// bail if the group name already exists
$existing_group = $this->db->get_where($this->tables['groups'], ['name' => $group_name])->row();
if (isset($existing_group->id) && $existing_group->id != $group_id) {
$this->set_error('group_already_exists');
return false;
}
$data['name'] = $group_name;
}
// IMPORTANT!! Third parameter was string type $description; this following code is to maintain backward compatibility
// New projects should work with 3rd param as array
if (is_string($additional_data)) {
$additional_data = ['description' => $additional_data];
}
//filter out any data passed that doesnt have a matching column in the groups table
//and merge the set group data and the additional data
if (!empty($additional_data)) {
$data = array_merge($this->_filter_data($this->tables['groups'], $additional_data), $data);
}
$this->db->update($this->tables['groups'], $data, ['id' => $group_id]);
$this->set_message('group_update_successful');
return true;
}
public function update_last_login($id)
{
$this->trigger_events('update_last_login');
$this->load->helper('date');
$this->trigger_events('extra_where');
$this->db->update($this->tables['users'], ['last_login' => time()], ['id' => $id]);
return $this->db->affected_rows() == 1;
}
public function update_last_login_ip($id)
{
$this->trigger_events('update_last_login_ip');
$this->trigger_events('extra_where');
$this->db->update($this->tables['users'], ['last_ip_address' => $this->input->ip_address()], ['id' => $id]);
return $this->db->affected_rows() == 1;
}
public function updateAvatar($id, $avatar)
{
if ($this->db->update($this->tables['users'], ['avatar' => $avatar], ['id' => $id])) {
$this->set_message('avatar_updated');
return true;
}
return false;
}
public function updateUser($id, $admin)
{
if ($this->db->update('users', ['admin_id' => $admin], ['id' => $id])) {
$this->db->update('orders', ['admin_id' => $admin], ['customer_id' => $id]);
$this->db->update('drafts', ['admin_id' => $admin], ['customer_id' => $id]);
return true;
}
return false;
}
public function user($id = null)
{
$this->trigger_events('user');
//if no id was passed use the current users id
$id || $id = $this->session->userdata('user_id');
$this->limit(1);
$this->where($this->tables['users'] . '.id', $id);
$this->users();
return $this;
}
public function username_check($username = '')
{
$this->trigger_events('username_check');
if (empty($username)) {
return false;
}
$this->trigger_events('extra_where');
return $this->db->where('username', $username)
->count_all_results($this->tables['users']) > 0;
}
public function users($groups = null)
{
$this->trigger_events('users');
if (isset($this->_ion_select) && !empty($this->_ion_select)) {
foreach ($this->_ion_select as $select) {
$this->db->select($select);
}
$this->_ion_select = [];
} else {
//default selects
$this->db->select([
$this->tables['users'] . '.*',
$this->tables['users'] . '.id as id',
$this->tables['users'] . '.id as user_id',
]);
}
//filter by group id(s) if passed
/*if(isset($groups)) {
//build an array if only one group was passed
if(is_numeric($groups)) {
$groups = Array($groups);
}
//join and then run a where_in against the group ids
if(isset($groups) && !empty($groups)) {
$this->db->distinct();
$this->db->join(
$this->tables['users_groups'], $this->tables['users_groups'] . '.' . $this->join['users'] . '=' . $this->tables['users'] . '.id', 'inner'
);
$this->db->where_in($this->tables['users_groups'] . '.' . $this->join['groups'], $groups);
}
}*/
$this->trigger_events('extra_where');
//run each where that was passed
if (isset($this->_ion_where) && !empty($this->_ion_where)) {
foreach ($this->_ion_where as $where) {
$this->db->where($where);
}
$this->_ion_where = [];
}
if (isset($this->_ion_like) && !empty($this->_ion_like)) {
foreach ($this->_ion_like as $like) {
$this->db->or_like($like);
}
$this->_ion_like = [];
}
if (isset($this->_ion_limit) && isset($this->_ion_offset)) {
$this->db->limit($this->_ion_limit, $this->_ion_offset);
$this->_ion_limit = null;
$this->_ion_offset = null;
} elseif (isset($this->_ion_limit)) {
$this->db->limit($this->_ion_limit);
$this->_ion_limit = null;
}
//set the order
if (isset($this->_ion_order_by) && isset($this->_ion_order)) {
$this->db->order_by($this->_ion_order_by, $this->_ion_order);
$this->_ion_order = null;
$this->_ion_order_by = null;
}
$this->response = $this->db->get($this->tables['users']);
return $this;
}
public function where($where, $value = null)
{
$this->trigger_events('where');
if (!is_array($where)) {
$where = [$where => $value];
}
array_push($this->_ion_where, $where);
return $this;
}
}