4 * Class Users_model models user information from DB
10 class Users_model extends CI_Model {
13 public function __construct()
15 parent::__construct();
17 if ($this->db === NULL)
19 $this->load->library('singleton_db');
20 $this->db = $this->singleton_db->connect();
25 * Check authentication credentials. $username can be username or e-mail.
27 * @param string $username
28 * @param string $password
29 * @return mixed can return FALSE if authentication failed, a `users`DB row
30 * as an associative array if authentication was successful
32 public function login($username, $password)
34 $this->load->helper('email');
36 // User logs with e-mail address.
37 if (! valid_email($username))
38 $cond_user = "username = '$username'";
40 $cond_user = "email = '$username'";
42 $enc_password = sha1($password);
44 $query = $this->db->query("SELECT u.*, a.activation_code
45 FROM `users` u LEFT JOIN `users_unactivated` a ON (u.id = a.user_id)
47 AND (auth_src = 'ldap' OR password = '$enc_password')");
49 // It is possible that the user has a LDAP account but he's
50 // authenticating here for the first time so it does not have an entry
52 if ($query->num_rows() === 0)
54 $ldap_userdata = $this->ldap_login($username, $password);
55 if ($ldap_userdata === FALSE)
57 $userdata = $this->convert_ldap_userdata($ldap_userdata);
58 $this->register($userdata);
60 $user = $this->login($username, $password);
61 $user['import'] = TRUE;
65 $user = $query->row_array();
67 // Authenticate with LDAP.
68 if ($user['auth_src'] == 'ldap'
69 && ! $this->ldap_login($username, $password))
72 if (empty($user['username']) || empty($user['email'])
73 || empty($user['first_name']) || empty($user['last_name'])
74 || empty($user['country']))
75 $user['import'] = TRUE;
77 // Update last login time.
78 $this->db->query("UPDATE `users`
79 SET last_login = UTC_TIMESTAMP()
80 WHERE username = '$username'");
82 // If we are here internal authentication has successful.
87 * Begin the OpenID login by redirecting user to the OP to authenticate.
89 * @param string $openid
91 public function openid_begin_login($openid)
93 $this->lang->load('openid');
94 $this->load->library('openid');
96 $request_to = site_url('user/check_openid_login');
98 $req = array('nickname');
99 $opt = array('fullname', 'email', 'dob', 'country');
100 $policy = site_url('user/openid_policy');
102 $ax_attributes[] = Auth_OpenID_AX_AttrInfo::make(
103 'http://axschema.org/contact/email', 1, TRUE);
104 $ax_attributes[] = Auth_OpenID_AX_AttrInfo::make(
105 'http://axschema.org/namePerson/first', 1, TRUE);
106 $ax_attributes[] = Auth_OpenID_AX_AttrInfo::make(
107 'http://axschema.org/namePerson/last', 1, TRUE);
108 $ax_attributes[] = Auth_OpenID_AX_AttrInfo::make(
109 'http://axschema.org/contact/country', 1, TRUE);
111 $this->openid->set_request_to($request_to);
112 $this->openid->set_trust_root(base_url());
113 $this->openid->set_sreg(TRUE, $req, $opt, $policy);
114 $this->openid->set_ax(TRUE, $ax_attributes);
116 // Redirection to OP site will follow.
117 $this->openid->authenticate($openid);
121 * Finalize the OpenID login. Register user if is here for the first time.
123 * @return mixed returns a `users` DB row as an associative array if
124 * authentication was successful or Auth_OpenID_CANCEL/_FAILURE if it was
127 public function openid_complete_login()
129 $this->lang->load('openid');
130 $this->load->library('openid');
132 $request_to = site_url('user/check_openid_login');
133 $this->openid->set_request_to($request_to);
135 $response = $this->openid->get_response();
137 if ($response->status === Auth_OpenID_CANCEL
138 || $response->status === Auth_OpenID_FAILURE)
139 return $response->status;
141 // Auth_OpenID_SUCCESS
142 $openid = $response->getDisplayIdentifier();
143 //$esc_openid = htmlspecialchars($openid, ENT_QUOTES);
145 // Get user_id to see if it's the first time the user logs in with
147 $query = $this->db->query("SELECT * from `users_openid`
148 WHERE openid_url = '$openid'");
151 // First time with OpenID => register user
152 if ($query->num_rows() === 0)
154 $user_id = $this->openid_register($response);
157 // Not first time with OpenID.
159 $user_id = $query->row()->user_id;
162 $query = $this->db->query("SELECT * FROM `users`
163 WHERE id = $user_id");
164 $userdata = $query->row_array();
165 $userdata['import'] = $import;
167 if (empty($userdata['username']) || empty($userdata['email'])
168 || empty($userdata['first_name'])
169 || empty($userdata['last_name'])
170 || empty($userdata['country']))
171 $userdata['import'] = TRUE;
173 // Update last login time.
174 $this->db->query("UPDATE `users`
175 SET last_login = UTC_TIMESTAMP()
176 WHERE id = $user_id");
182 * Register an user that logged in with OpenID for the first time.
184 * @param object $op_response object returned by Janrain
185 * Consumer::complete method.
186 * @return mixed the user_id inserted or FALSE on error
188 public function openid_register($op_response)
190 $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($op_response);
191 $ax_resp = Auth_OpenID_AX_FetchResponse::fromSuccessResponse($op_response);
195 $ax_email = $ax_resp->get('http://axschema.org/contact/email');
196 $ax_first_name = $ax_resp->get(
197 'http://axschema.org/namePerson/first');
198 $ax_last_name = $ax_resp->get('http://axschema.org/namePerson/last');
199 $ax_country = $ax_resp->get('http://axschema.org/contact/country');
211 $sreg_email = $sreg_resp->get('email', '');
212 $sreg_fullname = $sreg_resp->get('fullname', '');
213 $sreg_nickname = $sreg_resp->get('nickname', '');
214 $sreg_country = $sreg_resp->get('country', '');
215 $sreg_dob = $sreg_resp->get('dob', NULL);
219 $sreg_email = $sreg_fullname = $sreg_nickname = $sreg_country = '';
224 if (empty($ax_email) || is_a($ax_email, 'Auth_OpenID_AX_Error'))
225 $data['email'] = $sreg_email;
227 $data['email'] = $ax_email[0];
228 $data['email'] = strtolower($data['email']);
231 if (empty($ax_first_name)
232 || is_a($ax_first_name, 'Auth_OpenID_AX_Error'))
233 $data['first_name'] = '';
235 $data['first_name'] = $ax_first_name[0];
238 if (empty($ax_last_name) || is_a($ax_last_name, 'Auth_OpenID_AX_Error'))
239 $data['last_name'] = '';
241 $data['last_name'] = $ax_last_name[0];
243 // First Name and Last Name
244 if (empty($data['first_name']) || empty($data['last_name']))
248 if (empty($data['first_name']))
249 $data['first_name'] = substr(
250 $sreg_fullname, 0, strrpos($sreg_fullname, ' '));
251 if (empty($data['last_name']))
252 $data['last_name'] = substr(
253 $sreg_fullname, strrpos($sreg_fullname, ' ') + 1);
258 $data['username'] = $sreg_nickname;
259 if (!$data['username'])
261 // Generate username from email
262 if (!empty($data['email']))
264 $data['username'] = substr($data['email'],
265 0, strpos($data['email'], '@'));
266 $data['username'] = preg_replace(array('/[^a-z0-9\._]*/'),
267 array(''), $data['username']);
269 // Generate username from first name and sur name
270 else if(!empty($data['first_name']) || !empty($data['last_name']))
272 $data['username'] = $data['first_name'] . '_'
273 . $data['last_name'];
275 // Generate a random username
277 $data['username'] = $this->gen_username();
279 // Limit username to 24 characters because a prefix of 8 characters
280 // will be added: 'autogen_'.
281 $data['username'] = substr($data['username'], 0, 24);
282 // Append a random character to the username each time it still exists.
283 if ($this->get_userdata($data['username']))
285 $chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
286 $len_chars = strlen($chars);
287 $data['username'] .= '_';
290 $data['username'] .= $chars[ mt_rand(0, $len_chars - 1) ];
291 } while($this->get_userdata($data['username']));
293 // Usernames autogenerated have 'autogen_' prefix and can be changed
294 // by the user from the account section. After this process it cannot
295 // be changed anymore.
296 $data['username'] = 'autogen_' . $data['username'];
299 if (empty($ax_country) || is_a($ax_country, 'Auth_OpenID_AX_Error'))
300 $data['country'] = $sreg_country;
302 $data['country'] = $ax_country[0];
305 $data['birth_date'] = $sreg_dob;
308 $data['auth_src'] = 'openid';
310 if (!$this->register($data, $op_response->getDisplayIdentifier()))
313 $query = $this->db->query("SELECT id from `users`
314 WHERE username = '{$data['username']}'");
315 return $query->row()->id;
319 * Converts an array returned by LDAP login to an array which contains
320 * user data ready to be used in `users` DB.
322 * @param array $ldap_userdata
325 public function convert_ldap_userdata($ldap_userdata)
327 $userdata['username'] = $ldap_userdata['uid'][0];
328 $userdata['email'] = $ldap_userdata['mail'][0];
329 $userdata['first_name'] = $ldap_userdata['givenname'][0];
330 $userdata['last_name'] = $ldap_userdata['sn'][0];
332 $userdata['auth_src'] = 'ldap';
340 * @param string $username
341 * @param string $password
343 * @author Alex Herișanu, Răzvan Deaconescu, Călin-Andrei Burloiu
345 public function ldap_login($username, $password)
347 $this->config->load('ldap');
349 // First connection: binding.
351 $ds = ldap_connect($this->config->item('ldap_server')) or die("Can't connect to ldap server.\n");
352 if (!@ldap_bind($ds, $this->config->item('ldap_bind_user'),
353 $this->config->item('ldap_bind_password')))
356 die("Can't connect to ".$this->config->item('ldap_server')."\n");
359 $sr = ldap_search($ds, "dc=cs,dc=curs,dc=pub,dc=ro", "(uid=" . $username . ")");
360 if (ldap_count_entries($ds, $sr) > 1)
361 die("Multiple entries with the same uid in LDAP database??");
362 if (ldap_count_entries($ds, $sr) < 1) {
367 $info = ldap_get_entries($ds, $sr);
368 $dn = $info[0]["dn"];
371 // Second connection: connect with user's credentials.
372 $ds = ldap_connect($this->config->item('ldap_server')) or die("Can't connect to ldap server\n");
373 if (!@ldap_bind($ds, $dn, $password) or $password == '') {
378 // Verifify if DN belongs to the requested OU.
379 $info[0]['ou_ok'] = $this->ldap_dn_belongs_ou( $dn, $this->config->item('ldap_req_ou') );
381 // Set authentication source.
382 $info[0]['auth_src'] = 'ldap_first_time';
388 * Verify if a user belongs to a group.
390 * @param string $dn = "ou=Student,ou=People..."
391 * @param array $ou = array ("Student", etc
392 * @return TRUE or FALSE
393 * @author Răzvan Herișanu, Răzvan Deaconescu, Călin-Andrei Burloiu
395 public function ldap_dn_belongs_ou($dn, $ou)
401 $words = explode(',', $dn);
402 foreach ($words as $c) {
403 $parts = explode("=", $c);
407 if (strtolower($key) == "ou" && in_array($value, $ou) )
415 * Adds a new user to DB.
416 * Do not add join_date and last_login column, they will be automatically
418 * Provide an 'openid' with the OpenID as value in order to register users
419 * logging in this way.
421 * @param array $data corresponds to DB columns
423 public function register($data, $openid = NULL)
425 $this->load->helper('array');
427 // TODO verify mandatory data existance
430 if (isset($data['password']))
431 $data['password'] = sha1($data['password']);
433 if (empty($data['birth_date']))
434 $data['birth_date'] = NULL;
438 foreach ($data as $col=> $val)
450 else if (is_string($val))
453 $cols = substr($cols, 0, -2);
454 $vals = substr($vals, 0, -2);
456 $query = $this->db->query("INSERT INTO `users`
457 ($cols, registration_date, last_login)
458 VALUES ($vals, utc_timestamp(), utc_timestamp())");
459 if ($query === FALSE)
462 // If registered with OpenID insert a row in `users_openid`.
466 $query = $this->db->query("SELECT id from `users`
467 WHERE username = '{$data['username']}'");
468 if ($query->num_rows() === 0)
470 $user_id = $query->row()->id;
472 // Insert row in `users_openid`.
473 $query = $this->db->query("INSERT INTO `users_openid`
474 (openid_url, user_id)
475 VALUES ('$openid', $user_id)");
480 // If registered with internal authentication it needs to activate
482 if ($data['auth_src'] == 'internal')
484 $activation_code = Users_model::gen_activation_code($data['username']);
485 $user_id = $this->get_user_id($data['username']);
486 $query = $this->db->query("INSERT INTO `users_unactivated`
487 (user_id, activation_code)
488 VALUES ($user_id, '$activation_code')");
489 $this->send_activation_email($user_id, $data['email'],
490 $activation_code, $data['username']);
493 // TODO exception on failure
497 public function get_user_id($username)
499 $query = $this->db->query("SELECT id FROM `users`
500 WHERE username = '$username'");
502 if ($query->num_rows() === 0)
505 return $query->row()->id;
508 // TODO cleanup account activation
509 public function cleanup_account_activation()
515 * Activated an account for an user having $user_id with $activation_code.
517 * @param int $user_id
518 * @param string $activation_code hexa 16 characters string
519 * @return returns TRUE if activation was successful and FALSE otherwise
521 public function activate_account($user_id, $activation_code)
523 $query = $this->db->query("SELECT * FROM `users_unactivated`
524 WHERE user_id = $user_id
525 AND activation_code = '$activation_code'");
527 if ($query->num_rows() === 0)
530 $this->db->query("DELETE FROM `users_unactivated`
531 WHERE user_id = $user_id");
536 public function send_activation_email($user_id, $email = NULL,
537 $activation_code = NULL, $username = NULL)
539 if (!$activation_code || !$email || !$username)
546 $userdata = $this->get_userdata($user_id,
547 $cols. "a.activation_code, username");
548 $activation_code =& $userdata['activation_code'];
551 $email =& $userdata['email'];
552 $username =& $userdata['username'];
555 if ($activation_code === NULL)
558 $subject = '['. $this->config->item('site_name')
559 . '] Account Activation';
561 site_url("user/activate/$user_id/code/$activation_code");
562 $msg = sprintf($this->lang->line('user_activation_email_content'),
563 $username, $this->config->item('site_name'), site_url(),
564 $activation_url, $activation_code);
565 $headers = "From: ". $this->config->item('noreply_email');
567 return mail($email, $subject, $msg, $headers);
570 public function recover_password($username, $email)
572 $userdata = $this->get_userdata($username, 'email, username, id');
574 if (strcmp($userdata['email'], $email) !== 0)
577 $recovered_password = Users_model::gen_password();
579 $this->set_userdata(intval($userdata['id']), array('password'=>
580 $recovered_password));
582 $subject = '['. $this->config->item('site_name')
583 . '] Password Recovery';
584 $msg = sprintf($this->lang->line('user_password_recovery_email_content'),
585 $username, $this->config->item('site_name'), site_url(),
586 $recovered_password);
587 $headers = "From: ". $this->config->item('noreply_email');
589 mail($email, $subject, $msg, $headers);
595 * Returns data from `users` table. If $user is int it is used as an
596 * id, if it is string it is used as an username.
599 * @param string $table_cols (optional) string with comma separated
600 * `users` table column names. Use a.activation_code to check user's
601 * account activation_code. If this value is NULL than the account is
603 * @return array associative array with userdata from DB
605 public function get_userdata($user, $table_cols = '*')
608 $cond = "id = $user";
610 $cond = "username = '$user'";
612 $query = $this->db->query("SELECT $table_cols
613 FROM `users` u LEFT JOIN `users_unactivated` a
614 ON (u.id = a.user_id)
617 if ($query->num_rows() === 0)
620 $userdata = $query->row_array();
622 // Post process userdata.
623 if (isset($userdata['picture']))
625 $userdata['picture_thumb'] = site_url(
626 "data/user_pictures/{$userdata['picture']}-thumb.jpg");
627 $userdata['picture'] = site_url(
628 "data/user_pictures/{$userdata['picture']}");
635 * Modifies data from `users` table for user with $user_id.
637 * @param int $user_id
638 * @param array $data key-value pairs with columns and new values to be
640 * @return boolean returns TRUE on success and FALSE otherwise
642 public function set_userdata($user_id, $data)
644 // TODO verify mandatory data existance
647 if (isset($data['password']))
648 $data['password'] = sha1($data['password']);
649 // TODO picture data: save, convert, make it thumbnail
651 if (empty($data['birth_date']))
652 $data['birth_date'] = NULL;
655 foreach ($data as $col => $val)
659 $set .= "$col = NULL, ";
664 $set .= "$col = $val, ";
665 else if (is_string($val))
666 $set .= "$col = '$val', ";
668 $set = substr($set, 0, -2);
670 $query_str = "UPDATE `users`
671 SET $set WHERE id = $user_id";
672 //echo "<p>$query_str</p>";
673 $query = $this->db->query($query_str);
679 public static function gen_activation_code($str = '')
681 $ci =& get_instance();
683 $activation_code = substr(
684 sha1(''. $str. $ci->config->item('encryption_key')
689 return $activation_code;
692 public static function gen_password()
694 $ci =& get_instance();
696 $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,.?!_-';
697 $len_chars = strlen($chars);
698 $enc_key = $ci->config->item('encryption_key');
699 $len_enc_key = strlen($enc_key);
702 for ($p = 0; $p < $length; $p++)
704 $i = (mt_rand(1, 100) * ord($enc_key[ mt_rand(0, $len_enc_key-1) ]))
706 $password .= $chars[$i];
712 public static function gen_username()
714 $chars = 'abcdefghijklmnopqrstuvwxyz0123456789._';
715 $len_chars = strlen($chars);
719 for ($i = 0; $i < $len; $i++)
720 $username .= $chars[ mt_rand(0, $len_chars - 1) ];
725 public static function roles_to_string($roles)
727 $ci =& get_instance();
728 $ci->lang->load('user');
730 if ($roles == USER_ROLE_STANDARD)
731 return $ci->lang->line('user_role_standard');
736 if ($roles & USER_ROLE_ADMIN)
737 $str_roles .= $ci->lang->line('user_role_admin') . '; ';
744 /* End of file users_model.php */
745 /* Location: ./application/models/users_model.php */