. */ /* Original code: https://github.com/Repox/SimpleUsers Used with permission from the original author Dan Storm. */ require_once(dirname(__FILE__)."/comicsdb.php"); // User level define("UL_USER", 0); define("UL_ADMIN", 1); /** * This file is part of SimpleUsers. * */ /** * SimpleUsers is a small-scale and flexible way of adding * user management to your website or web applications. */ class SimpleUsers { private $db; // the SQLite database connection private $sessionName = "SimpleUsers"; public $logged_in = false; public $is_admin = false; public $userdata; public $reservedKeys; /** * Object construct verifies that a session has been started and that a SQLite3 connection can be established. * It takes no parameters. * * @exception Exception If a session id can't be returned. */ public function __construct() { global $comicsdb; $this->reservedKeys = array("id", "username", "password", "salt", "activity", "created", "level"); $this->db = $comicsdb->get(); $sessionId = session_id(); if( strlen($sessionId) == 0) throw new Exception("No session has been started.\n
Please add `session_start();` initially in your file before any output."); $this->_validateUser(); $this->_populateUserdata(); $this->_updateActivity(); } /** * Returns a (int)user id, if the user was created succesfully. * If not, it returns (bool)false. * * @param username The desired username * @param password The desired password * @return The user id or (bool)false (if the user already exists) */ public function createUser( $username, $password, $level = 0 ) { $username = SQLite3::escapeString($username); $salt = $this->_generateSalt(); $password = sha1($salt . $password); $success = $this->db->exec("INSERT INTO user VALUES (NULL, '".$username."', '".$password."', '".$salt."', (DATETIME('now')), (DATETIME('now')), ".$level.")"); if ($success) return $this->db->lastInsertRowID(); return false; } /** * Pairs up username and password as registrered in the database. * If the username and password is correct, it will return (int)user id of * the user which credentials has been passed and set the session, for * use by the user validating. * * @param username The username * @param password The password * @return The (int)user id or (bool)false */ public function loginUser( $username, $password ) { // get salt $username = SQLite3::escapeString($username); $result = $this->db->querySingle("SELECT id, salt, password, level FROM user WHERE username='" . $username . "' LIMIT 1", true); if (!$result) return false; // user not found $password = sha1($result["salt"]. $password); $userId = $result["id"]; if (!$userId || $password != $result["password"]) return false; $_SESSION[$this->sessionName]["userId"] = $userId; $_SESSION[$this->sessionName]["userLevel"] = $result["level"]; $this->logged_in = true; $this->is_admin = $result["level"] == 1; return $userId; } public function isReservedKey($key) { return in_array($key, $this->reservedKeys); } /** * Sets an information pair, consisting of a key name and that keys value. * The information can be retrieved with this objects getInfo() method. * * @param key The name of the key * @param value The keys value * @param userId Can be used if administrative control is needed * @return This returns (bool)true or false. */ public function setInfo( $key, $value, $userId = null) { if ($userId == null) { if( !$this->logged_in ) return false; } // all columns from user table are reserved... if ( $this->isReservedKey($key) ) throw new Exception("User information key \"".$key."\" is reserved for internal use!"); if( $userId == null ) $userId = $_SESSION[$this->sessionName]["userId"]; $value = SQLite3::escapeString("".$value); if( $this->hasInfo($key, $userId) ) { $key = SQLite3::escapeString($key); $success = $this->db->exec("UPDATE user_settings SET value='".$value."' WHERE key='".$key."' AND user_id=".$userId); if( !$success ) { throw new Exception("SQLite3 statement failed, code ".$this->db->lastErrorCode().": ".$this->db->lastErrorMsg()); } } else { $key = SQLite3::escapeString($key); $success = $this->db->exec("INSERT INTO user_settings VALUES (".$userId.", '".$key."', '".$value."')"); if( !$success ) { throw new Exception("SQLite3 statement failed, code ".$this->db->lastErrorCode().": ".$this->db->lastErrorMsg()); } } return true; } /** * Use this function to retrieve user information attached to a certain user * that has been set by using this objects setInfo() method. * * @param key The name of the key you wan't the value from * @param userId Can be used if administrative control is needed * @return String with a given keys value or (bool) false if the user isn't logged in. */ public function getInfo( $key, $userId = null ) { if( $userId == null ) { if( !$this->logged_in ) return false; $userId = $_SESSION[$this->sessionName]["userId"]; } $value = $this->db->querySingle("SELECT value FROM user_settings WHERE user_id=".$userId." AND key='".SQLite3::escapeString($key)."' LIMIT 1", true); if (count($value) == 0) return NULL; return $value["value"]; } public function hasInfo( $key, $userId = null ) { $value = $this->getInfo($key, $userId); return gettype($value) == "string"; } /** * Use this function to permanently remove information attached to a certain user * that has been set by using this objects setInfo() method. * * @param key The name of the key you wan't the value from * @param userId Can be used if administrative control is needed * @return (bool) true on success or (bool) false if the user isn't logged in. */ public function removeInfo( $key, $userId = null ) { if( $userId == null ) { if( !$this->logged_in ) return false; $userId = $_SESSION[$this->sessionName]["userId"]; } $success = $this->db->exec("DELETE FROM user_settings WHERE user_id=".$userId." AND key='".SQLite3::escapeString($key)."' LIMIT 1"); return $success; } /** * Use this function to retrieve all user information attached to a certain user * that has been set by using this objects setInfo() method into an array. * * @param userId Can be used if administrative control is needed * @return An associative array with all stored information */ public function getInfoArray( $userId = null ) { if( $userId == null ) $userId = $_SESSION[$this->sessionName]["userId"]; $result = $this->db->query("SELECT key, value FROM user_settings WHERE user_id=".$userId." ORDER BY key ASC"); $userInfo = array(); while ($res = $result->fetchArray(SQLITE3_ASSOC)) { $userInfo[$res["key"]] = "".$res["value"]; } $result->finalize(); $user = $this->getSingleUser($userId); $userInfo = array_merge($userInfo, $user); asort($userInfo); return $userInfo; } /** * Logout the active user, unsetting the userId session. * This is a void function */ public function logoutUser() { if( isset($_SESSION[$this->sessionName]) ) unset($_SESSION[$this->sessionName]); $this->logged_in = false; } /** * Update the users password with this function. * Generates a new salt and a sets the users password with the given parameter * * @param password The new password * @param userId Can be used if administrative control is needed */ public function setPassword( $password, $userId = null ) { if( $userId == null ) $userId = $_SESSION[$this->sessionName]["userId"]; $salt = $this->_generateSalt(); $password = sha1($salt . $password); $success = $this->db->exec("UPDATE user SET password='".$password."', salt='".$salt."' WHERE id=".$userId); if( !$success ) { throw new Exception("SQLite3 statement failed, code ".$this->db->lastErrorCode().": ".$this->db->lastErrorMsg()); } return true; } public function setLevel( $level, $userId = null ) { if( $userId == null ) $userId = $_SESSION[$this->sessionName]["userId"]; $success = $this->db->exec("UPDATE user SET level=".$level." WHERE id=".$userId); if( !$success ) { throw new Exception("SQLite3 statement failed, code ".$this->db->lastErrorCode().": ".$this->db->lastErrorMsg()); } return true; } /** * Returns an array with each user in the database. * * @return An array with user information */ public function getUsers() { $result = $this->db->query("SELECT DISTINCT id, username, level, activity, created FROM user ORDER BY username ASC"); if($result === false) { throw new Exception("SQLite3 statement failed, code ".$this->db->lastErrorCode().": ".$this->db->lastErrorMsg()); } $users = array(); $i = 0; while ($res = $result->fetchArray(SQLITE3_ASSOC)) { $users[$i] = $res; $i++; } $result->finalize(); return $users; } /** * Gets the basic info for a single user based on the userId * * @param userId The users id * @return An array with the result or (bool)false. */ public function getSingleUser( $userId = null ) { if( $userId == null ) $userId = $_SESSION[$this->sessionName]["userId"]; $result = $this->db->querySingle("SELECT id, username, activity, created, level FROM user WHERE id=".$userId." LIMIT 1", true); if($result === false) { throw new Exception("SQLite3 statement failed, code ".$this->db->lastErrorCode().": ".$this->db->lastErrorMsg()); } if (count($result) == 0) return false; return $result; } /** * Deletes all information regarding a user. * This is a void function. * * @param userId The userId of the user you wan't to delete * @return Boolean true if the user was successfully deleted. false if user was not found. */ public function deleteUser( $userId ) { if ($userId == $_SESSION[$this->sessionName]["userId"]) { // you can't delete yourself return false; } if ($userId == null || !$this->getSingleUser($userId)) { // user not found return false; } $success = $this->db->exec("DELETE FROM user WHERE id=".$userId); if( !$success ) { throw new Exception("SQLite3 statement failed, code ".$this->db->lastErrorCode().": ".$this->db->lastErrorMsg()); } // user_settings are deleted via reference cascading /* $success = $this->db->exec("DELETE FROM user_settings WHERE user_id=".$userId); if( !$success ) { throw new Exception("SQLite3 statement failed, code ".$this->db->lastErrorCode().": ".$this->db->lastErrorMsg()); } */ return true; } /** * Returns a hidden input field with a unique token value * for CSRF to be used with post data. * The token is saved in a session for later validation. * * @param xhtml set to (bool) true for xhtml output * @return Returns a string with a HTML element and attributes */ public function getToken( $xhtml = true ) { $token = $this->_generateSalt(); $name = "token_".md5($token); $_SESSION[$this->sessionName]["csrf_name"] = $name; $_SESSION[$this->sessionName]["csrf_token"] = $token; $string = "sessionName]["csrf_name"]; $token = $_SESSION[$this->sessionName]["csrf_token"]; unset($_SESSION[$this->sessionName]["csrf_token"]); unset($_SESSION[$this->sessionName]["csrf_name"]); if($_POST[$name] == $token) return true; return false; } /** * This function updates the users last activity time * This is a void function. */ private function _updateActivity() { if( !$this->logged_in ) return; $userId = $_SESSION[$this->sessionName]["userId"]; $success = $this->db->exec("UPDATE user SET activity=(DATETIME('now')) WHERE id=".$userId); if (!$success) { throw new Exception("SQLite3 statement failed, code ".$this->db->lastErrorCode().": ".$this->db->lastErrorMsg()); } return; } /** * Validates if the user is logged in or not. * This is a void function. */ private function _validateUser() { if( !isset($_SESSION[$this->sessionName]["userId"]) ) return; if( !$this->_validateUserId() ) return; $this->userId = $_SESSION[$this->sessionName]["userId"]; $this->logged_in = true; $this->is_admin = $_SESSION[$this->sessionName]["userLevel"]; } /** * Validates if the user id, in the session is still valid. * * @return Returns (bool)true or false */ private function _validateUserId() { if( !isset($_SESSION[$this->sessionName]["userId"]) ) return false; $userId = $_SESSION[$this->sessionName]["userId"]; $result = $this->db->querySingle("SELECT id FROM user WHERE id=".$userId." LIMIT 1"); if ($result === false) { throw new Exception("SQLite3 statement failed, code ".$this->db->lastErrorCode().": ".$this->db->lastErrorMsg()); } if( $result !== null ) return true; $this->logoutUser(); return false; } /** * Populates the current users data information for * quick access as an object. * * @return void */ private function _populateUserdata() { $this->userdata = array(); if( $this->logged_in ) { $userId = $_SESSION[$this->sessionName]["userId"]; $data = $this->getInfoArray(); foreach($data as $key => $value) $this->userdata[$key] = $value; } } /** * Generates a 128 len string used as a random salt for * securing you oneway encrypted password * * @return String with 128 characters */ private function _generateSalt() { $salt = null; while( strlen($salt) < 128 ) $salt = $salt.uniqid(null, true); return substr($salt, 0, 128); } } ?>