<?php //////////////////////////////////////////////////////////////////////////////// // Copyright (C) ReloadCMS Development Team // // http://reloadcms.com // // This product released under GNU General Public License v2 // //////////////////////////////////////////////////////////////////////////////// if (defined('DEBUG')) { //MySQL work! $db =new MySQLDB(); //check for existing table `users` in base $tableExists = simple_query("SHOW TABLES LIKE 'users'") > 0; if ($tableExists) define('USERS_MYSQL',true); else define('USERS_MYSQL',false); } else define('USERS_MYSQL',false); class rcms_access { var $rights_database = array(); var $rights = array(); var $root = false; var $level = 0; function initialiseAccess($rights, $level){ $this->rights = array(); $this->root = false; if($rights !== '*') { preg_match_all('/\|(.*?)\|/', $rights, $rights_r); foreach ($rights_r[1] as $right){ $this->rights[$right] = (empty($this->rights_database[$right])) ? ' ' : $this->rights_database[$right]; } } else { $this->root = true; } $this->level = $level; return true; } /** * @param string $right * @return boolean * @desc Check if user have specified right */ function checkForRight($right = '-any-', $username = ''){ if(empty($username)) { $rights = &$this->rights; $root = &$this->root; } else { if(!$this->getRightsForUser($username, $rights, $root, $level)) { return false; } } return $root || ($right == '-any-' && !empty($rights)) || !empty($rights[$right]); } function getRightsForUser($username, &$rights, &$root, &$level){ if (!($userdata = $this->getUserData($username))) return false; if(!empty($this->config['registered_accesslevel'])){ $level = (int)$this->config['registered_accesslevel']; if(!isset($userdata['accesslevel']) || $level > $userdata['accesslevel']){ $userdata['accesslevel'] = $level; } } $rights = array(); $root = false; if($userdata['admin'] !== '*') { preg_match_all('/\|(.*?)\|/', $userdata['admin'], $rights_r); foreach ($rights_r[1] as $right){ $rights[$right] = (empty($this->rights_database[$right])) ? ' ' : $this->rights_database[$right]; } } else { $root = true; } $level = (int)@$userdata['accesslevel']; return true; } function setRightsForUser($username, $rights, $root = false, $level = 0){ if(empty($rights)) $rights = array(); if(!empty($this->config['registered_accesslevel'])){ $reg_level = (int)$this->config['registered_accesslevel']; if($level === ''){ $userdata['accesslevel'] = $reg_level; } } if($root) { $rights_string = '*'; } else { $rights_string = ''; if(is_array($rights)){ foreach ($rights as $right => $cond){ if($cond) $rights_string .= '|' . $right . '|'; } } } user_change_field($username, 'admin', $rights_string); user_change_field($username, 'accesslevel', $level); return true; } } class rcms_user_cache{ var $cache_filename = 'users.cache.dat'; var $cache = array(); function rcms_user_cache(){ if(!is_file(DATA_PATH . $this->cache_filename)) { $this->cache = array(); } else { if(!($this->cache = @unserialize(@file_get_contents(DATA_PATH . 'users.cache.dat')))){ $this->cache = array(); } } } function save(){ file_write_contents(DATA_PATH . $this->cache_filename, serialize($this->cache)); } function registerUser($username, $usernick, $email){ $this->cache['nicks'][$username] = $usernick; $this->cache['mails'][$username] = $email; $this->save(); return true; } function getUser($field, $value){ return array_search($value, $this->cache[$field]); } function removeUser($username){ if(!empty($this->cache['nicks'][$username])) { $this->cache['nicks'][$username] = ''; unset($this->cache['nicks'][$username]); } if(!empty($this->cache['mails'][$username])) { $this->cache['mails'][$username] = ''; unset($this->cache['mails'][$username]); } $this->save(); return true; } function checkField($field, $value){ if(empty($this->cache[$field])) return true; return !in_array_i($value, $this->cache[$field]); } } define('USERS_ALLOW_CHANGE', 0); define('USERS_ALLOW_SET', 1); define('USERS_DISALLOW_CHANGE', 2); define('USERS_DISALLOW_CHANGE_ALL', 3); class rcms_user extends rcms_access { var $profile_fields = array(); var $profile_defaults = array(); /** * This property indicates if user is registered or just a guest * * @access public * @var boolean */ var $logged_in = false; /** * This array contain data from user's profile * * @access public * @var array */ var $user = array(); /** * Name for user cookie * * @access private * @var string */ var $cookie_user = 'reloadcms_user'; var $users_cache = null; /** * @return boolean * @param string $skipcheck Use this parameter to skip userdata checks * @desc This function is an internal private function for class rcms_system and must not be used externally. This function initialize user and load his profile to object. */ function initializeUser($skipcheck = false){ $this->users_cache = new rcms_user_cache(); $this->data['apf'] = parse_ini_file(CONFIG_PATH . 'users.fields.ini'); // Enter access levels for fields here $this->profile_fields = array( 'hideemail' => USERS_ALLOW_CHANGE, 'admin' => USERS_DISALLOW_CHANGE_ALL, 'tz' => USERS_ALLOW_CHANGE, 'accesslevel' => USERS_DISALLOW_CHANGE_ALL, 'last_prr' => USERS_DISALLOW_CHANGE_ALL, 'blocked' => USERS_DISALLOW_CHANGE ); foreach ($this->data['apf'] as $field => $desc) { $this->profile_fields[$field] = USERS_ALLOW_CHANGE; } $this->profile_defaults = array('hideemail' => 0, 'admin' => ' ', 'tz' => 0, 'accesslevel' => 0, 'blocked' => 0, 'last_prr' => 0); // Load default guest userdata $this->user = array('nickname' => __('Guest'), 'username' => 'guest', 'admin' => '', 'tz' => (int)@$this->config['default_tz'], 'accesslevel' => 0); $this->initialiseAccess($this->user['admin'], (int)@$userdata['accesslevel']); // Ability for guests to enter nick $_POST['gst_nick'] = mb_substr(trim(@$_POST['gst_nick']), 0, 50); if(!empty($_POST['gst_nick']) && !$this->logged_in){ $this->user['nickname'] = $_POST['gst_nick']; setcookie('reloadcms_nick', $this->user['nickname']); $_COOKIE['reloadcms_nick'] = $this->user['nickname']; } elseif(!$this->logged_in && !empty($_COOKIE['reloadcms_nick'])){ $this->user['nickname'] = mb_substr(trim($_COOKIE['reloadcms_nick']), 0, 50); } if(!$this->users_cache->checkField('nicks', $this->user['nickname'])) { $this->user['nickname'] = __('Guest'); setcookie('reloadcms_nick', '', time() - 16000); unset($_COOKIE['reloadcms_nick']); } // Secure the nickname $this->user['nickname'] = htmlspecialchars($this->user['nickname']); // If user cookie is not present we exiting without error if(empty($_COOKIE[$this->cookie_user])) { $this->logged_in = false; return true; } // So we have a cookie, let's extract data from it $cookie_data = explode(':', $_COOKIE[$this->cookie_user], 2); if(!$skipcheck){ // If this cookie is invalid - we exiting destroying cookie and exiting with error if(sizeof($cookie_data) != 2){ setcookie($this->cookie_user, null, time() - 3600); return false; } // Now we must validate user's data if(!$this->checkUserData($cookie_data[0], $cookie_data[1], 'user_init', true, $this->user)){ setcookie($this->cookie_user, null, time() - 3600); $this->logged_in = false; return false; } } $userdata = $this->getUserData($cookie_data[0]); if($userdata == false){ setcookie($this->cookie_user, null, time() - 3600); $this->logged_in = false; return false; } $this->user = $userdata; $this->logged_in = true; if(!empty($this->config['registered_accesslevel'])){ $level = (int)$this->config['registered_accesslevel']; if(!isset($userdata['accesslevel'])){ $this->user['accesslevel'] = $level; } } // Initialise access levels $this->initialiseAccess($this->user['admin'], (int)@$this->user['accesslevel']); // Secure the nickname $this->user['nickname'] = htmlspecialchars($this->user['nickname']); return true; } /** * @return boolean * @desc This function verifies the existence of user. */ function is_user($username){ if (USERS_MYSQL) { $username=mysql_real_escape_string($username); $query="SELECT * FROM `users` WHERE `username`='$username'"; $result=simple_query($query); return (!empty($result['username'])); } else return (is_file(USERS_PATH . $username)); } /** * @return boolean * @desc This function verifies whether registered users. */ function is_empty_users(){ if (USERS_MYSQL) { $query='SELECT `username` from `users` LIMIT 1;'; $result=simple_query($query); return (empty($result['username'])?true:false); } else return ((sizeof(rcms_scandir(USERS_PATH)) == 0)?true:false); } /** * @return boolean * @param string $username * @param string $password * @param string $report_to * @param boolean $hash * @param link $userdata * @desc This function is an internal private function for class rcms_system and must not be used externally. This function check user's data and validate his data file. */ function checkUserData($username, $password, $report_to, $hash, &$userdata){ if(preg_replace("/[\d\w]+/i", "", $username) != ""){ $this->results[$report_to] = __('Invalid username'); return false; } // If login is not exists - we exiting with error if(!$this->is_user($username)){ $this->results[$report_to] = __('There are no user with this username'); return false; } // So all is ok. Let's load userdata $result = $this->getUserData($username); // If userdata is invalid we must exit with error if(empty($result)) return false; // If password is invalid - exit with error if((!$hash && md5($password) !== $result['password']) || ($hash && $password !== $result['password'])) { $this->results[$report_to] = __('Invalid password'); return false; } // If user is blocked - exit with error if(@$result['blocked']) { $this->results[$report_to] = __('This account has been blocked by administrator'); return false; } $userdata = $result; return true; } /** * @return boolean * @param string $username * @param string $password * @param boolean $remember * @desc This function check user's data and log in him. */ function logInUser($username, $password, $remember){ $username = basename($username); if($username == 'guest') return false; if(!$this->logged_in && $this->checkUserData($username, $password, 'user_login', false, $userdata)){ rcms_log_put(__('Notification'), $this->user['username'], 'Logged in as ' . $username); // OK... Let's allow user to log in :) setcookie($this->cookie_user, $username . ':' . $userdata['password'], ($remember) ? time()+3600*24*365 : null); $_COOKIE[$this->cookie_user] = $username . ':' . $userdata['password']; $this->initializeUser(true); return true; } else { if(!$this->logged_in) { rcms_log_put(__('Notification'), $this->user['username'], 'Attempted to log in as ' . $username); } return false; } } /** * @return boolean * @desc This function log out user from system and destroys his cookie. */ function logOutUser(){ if($this->logged_in){ rcms_log_put(__('Notification'), $this->user['username'], 'Logged out'); setcookie($this->cookie_user, '', time()-3600); $_COOKIE[$this->cookie_user] = ''; $this->initializeUser(false); return true; } } function registerUser($username, $nickname, $password, $confirm, $email, $userdata){ $username = basename($username); $nickname = empty($nickname) ? $username : mb_substr(trim($nickname), 0, 50); if (preg_match("/[^(\\w)|(\\x7F-\\xFF)|(\\-)]/", $nickname)) { $this->results['registration'] = __('Invalid nickname'); return false; } if(empty($username) || preg_replace("/[\d\w]+/i", '', $username) != '' || mb_strlen($username) > 50 || $username == 'guest') { $this->results['registration'] = __('Invalid username'); return false; } if($this->is_user($username)) { $this->results['registration'] = __('User with this username already exists'); return false; } if(!user_check_nick_in_cache($username, $nickname, $cache)) { $this->results['registration'] = __('User with this nickname already exists'); return false; } if(empty($email) || !rcms_is_valid_email($email)) { $this->results['registration'] = __('Invalid e-mail address'); return false; } if(!user_check_email_in_cache($username, $email, $cache)){ $this->results['registration'] = __('This e-mail address already registered'); return false; } if(!empty($this->config['regconf'])) $password = $confirm = rcms_random_string(8); if(empty($password) || empty($confirm) || $password != $confirm) { $this->results['registration'] = __('Password doesnot match it\'s confirmation'); return false; } // If our user is first - we must set him an admin rights if ($this->is_empty_users()) { $_userdata['admin'] = '*'; $arr_conf = parse_ini_file(CONFIG_PATH . 'config.ini'); $arr_conf['admin_email'] = $email; write_ini_file($arr_conf, CONFIG_PATH . 'config.ini'); } else $_userdata['admin'] = ' '; // Also we must set a md5 hash of user's password to userdata $_userdata['password'] = md5($password); $_userdata['nickname'] = $nickname; $_userdata['username'] = $username; $_userdata['email'] = $email; // Parse some system fields $userdata['hideemail'] = empty($userdata['hideemail']) ? '0' : '1'; $userdata['tz'] = (float) @$userdata['tz']; foreach ($this->profile_fields as $field => $acc){ if($acc <= USERS_ALLOW_SET || $acc == USERS_ALLOW_CHANGE){ if(!isset($userdata[$field])) { $userdata[$field] = $this->profile_defaults[$field]; } else { $_userdata[$field] = strip_tags(trim($userdata[$field])); } } } foreach ($this->data['apf'] as $field => $desc) { $_userdata[$field] = strip_tags(trim($userdata[$field])); } if(!$this->save_user($username,$_userdata)){ $this->results['registration'] = __('Cannot save profile'); return false; } user_register_in_cache($username, $nickname, $email, $cache); if(!empty($this->config['regconf'])) { $site_url = parse_url($this->url); rcms_send_mail($email, 'no_reply@' . $site_url['host'], __('Password'), $this->config['encoding'], __('Your password at') . ' ' . $site_url['host'], __('Your username at') . ' ' . $site_url['host'] . ': ' . $username . "\r\n" . __('Your password at') . ' ' . $site_url['host'] . ': ' . $password); } $this->results['registration'] = __('Registration complete. You can now login with your username and password.'); rcms_log_put(__('Notification'), $this->user['username'], 'Registered account ' . $username); return true; } function updateUser($username, $nickname, $password, $confirm, $email, $userdata, $admin = false){ $nickname = empty($nickname) ? $username : mb_substr(strip_tags($nickname), 0, 50); if(empty($username) || preg_replace("/[\d\w]+/i", '', $username) != '') { $this->results['profileupdate'] = __('Invalid username'); return false; } if($username == 'guest') return false; if(!$this->is_user($username)) { $this->results['profileupdate'] = __('There is no user with this name'); return false; } user_remove_from_cache($username, $cache); if(!($_userdata = $this->getUserData($username))) { $this->results['profileupdate'] = __('Cannot open profile'); return false; } if(!user_check_nick_in_cache($username, $nickname, $cache)) { $this->results['profileupdate'] = __('User with this nickname already exists'); return false; } if(empty($email) || !rcms_is_valid_email($email)) { $this->results['profileupdate'] = __('Invalid e-mail address'); return false; } if(!user_check_email_in_cache($username, $email, $cache)){ $this->results['profileupdate'] = __('This e-mail address already registered'); return false; } if(!empty($password) && !empty($confirm) && $password != $confirm) { $this->results['profileupdate'] = __('Password doesnot match it\'s confirmation'); return false; } // Also we must set a md5 hash of user's password to userdata $_userdata['password'] = (empty($password)) ? $_userdata['password'] : md5($password); $_userdata['nickname'] = $nickname; $_userdata['email'] = $email; // Parse some system fields $userdata['hideemail'] = empty($userdata['hideemail']) ? '0' : '1'; $userdata['tz'] = (float) $userdata['tz']; $userdata['accesslevel'] = (int) @$userdata['accesslevel']; foreach ($this->profile_fields as $field => $acc){ if(($admin && $acc < USERS_DISALLOW_CHANGE_ALL) || $acc <= USERS_ALLOW_SET || $acc == USERS_ALLOW_CHANGE){ if(!isset($userdata[$field])) { $userdata[$field] = $this->profile_defaults[$field]; } else { $_userdata[$field] = strip_tags(trim($userdata[$field])); } } } foreach ($this->data['apf'] as $field => $desc) { $_userdata[$field] = strip_tags(trim($userdata[$field])); } if(!$this->save_user($username,$_userdata)){ $this->results['profileupdate'] = __('Cannot save profile'); return false; } user_register_in_cache($username, $nickname, $email, $cache); $this->results['profileupdate'] = __('Profile updated'); if($this->user['username'] == $username) { $this->user = $_userdata; } rcms_log_put(__('Notification'), $this->user['username'], 'Updated userinfo for ' . $username); return true; } function recoverPassword($username, $email){ if(!($data = $this->getUserData($username))) { $this->results['passrec'] = __('Cannot open profile'); return false; } if($email != $data['email']) { $this->results['passrec'] = __('Your e-mail doesn\'t match e-mail in profile'); return false; } $new_password = rcms_random_string(8); $site_url = parse_url($this->url); $time = time(); if(!empty($data['last_prr']) && !empty($this->config['pr_flood']) && (int)$time <= ((int)$data['last_prr'] + (int)$this->config['pr_flood'])){ $this->results['passrec'] = __('Too many requests in limited period of time. Try later.'); $data['last_prr'] = time(); if(!$this->save_user($username,$data)) { $this->results['passrec'] .= '<br />' . __('Cannot save profile'); } rcms_log_put(__('Notification'), $this->user['username'], 'Attempted to recover password for ' . $username); return false; } if(rcms_send_mail($email, 'no_reply@' . $site_url['host'], __('Password'), $this->config['encoding'], __('Your new password at') . ' ' . $site_url['host'], __('Your username at') . ' ' . $site_url['host'] . ': ' . $username . "\r\n" . __('Your new password at') . ' ' . $site_url['host'] . ': ' . $new_password)) { $data['password'] = md5($new_password); $data['last_prr'] = $time; if(!$this->save_user($username,$data)) { $this->results['passrec'] = __('Cannot save profile'); return false; } $this->results['passrec'] = __('New password has been sent to your e-mail'); rcms_log_put(__('Notification'), $this->user['username'], 'Recovered password for ' . $username); return true; } else { rcms_log_put(__('Notification'), $this->user['username'], 'Recovered password for ' . $username . '" (BUT E-MAIL WAS NOT SENT)'); $this->results['passrec'] = __('Cannot send e-mail'); return false; } } function save_user($username,$userdata){ if (USERS_MYSQL) { if ($this->is_user($username)) $query="UPDATE `users` SET `userdata`='".serialize($userdata)."' WHERE `username` ='".$username."';"; else $query="INSERT INTO `users` (`username`,`userdata`) VALUES ('".$username."','".serialize($userdata)."');"; $result = nr_query($query); return (!empty($result)); } elseif(!file_write_contents(USERS_PATH . $username, serialize($userdata))) return false; return true; } function getUserData($username){ if (USERS_MYSQL) { $userdata=simple_query("SELECT `userdata` FROM `users` WHERE `username`='".$username."' LIMIT 1"); $result=@unserialize($userdata['userdata']); } else $result = @unserialize(@file_get_contents(USERS_PATH . basename($username))); if(empty($result)) return false; else return $result; } function getUserList($expr = '*', $id_field = ''){ $return = array(); if (USERS_MYSQL) { $users_array = simple_queryall("SELECT `username` FROM `users`"); foreach($users_array as $user) $users[]=$user['username']; } else $users = rcms_scandir(USERS_PATH, $expr); foreach ($users as $user){ if($data = $this->getUserData($user)) { if(!empty($id_field) && !empty($data[$id_field])) { $return[$data[$id_field]] = $data; } else { $return[] = $data; } } } return $return; } function changeProfileField($username, $field, $value){ if (USERS_MYSQL) $value = mysql_real_escape_string($value); else $username = basename($username); if (!($userdata = $this->getUserData($username))) return false; $userdata[$field] = $value; $this->save_user($username,$userdata); } function deleteUser($username){ if (USERS_MYSQL) { $username = mysql_real_escape_string($username); nr_query("DELETE FROM `users` WHERE `username`='".$username."'"); } else { $username = basename($username); if(!rcms_delete_files(USERS_PATH . $username)) return false; } user_remove_from_cache($username, $cache); return true; } function createLink($user, $nick, $target = ''){ if(!empty($target)) $target = ' target="' . $target . '"'; if($user != 'guest') { return '<a href="' . RCMS_ROOT_PATH . '?module=user.list&user=' . $user . '"' . $target . '>' . strip_tags($nick) . '</a>'; } elseif(!empty($nick)) { return $nick; } else { return __('Guest'); } } } ?>