id); } public function getUsername($flag = 0) { switch ($flag) { case HTMLSAFE: return htmlspecialchars($this->lastname); break; case HTMLFORMSAFE: return htmlspecialchars($this->lastname, ENT_QUOTES); break; case CSVSAFE: return str_replace('"', '""', $this->lastname); break; default: return $this->username; break; } } public function getFirstName($flag = 0) { switch ($flag) { case HTMLSAFE: return htmlspecialchars($this->firstname); break; case HTMLFORMSAFE: return htmlspecialchars($this->firstname, ENT_QUOTES); break; case CSVSAFE: return str_replace('"', '""', $this->firstname); break; default: return $this->firstname; break; } } public function getLastName($flag = 0) { switch ($flag) { case HTMLSAFE: return htmlspecialchars($this->lastname); break; case HTMLFORMSAFE: return htmlspecialchars($this->lastname, ENT_QUOTES); break; case CSVSAFE: return str_replace('"', '""', $this->lastname); break; default: return $this->lastname; break; } } public function getFullName($flag = 0) { $fullname = $this->firstname . " " . $this->lastname; switch ($flag) { case HTMLSAFE: return htmlspecialchars($fullname); break; case HTMLFORMSAFE: return htmlspecialchars($fullname, ENT_QUOTES); break; case CSVSAFE: return str_replace('"', '""', $fullname); break; default: return $fullname; break; } } public function getCreateTime($flag = 0) { switch ($flag) { case TIMESTAMP: return strtotime($this->createtime); break; case PRETTY: return date("F j Y H:i:s", strtotime($this->createtime)); break; default: return $this->createtime; break; } } public function getLastLogin($flag = 0) { switch ($flag) { case TIMESTAMP: return strtotime($this->lastlogin); break; case PRETTY: return (($this->lastlogin == "0000-00-00 00:00:00") || ($this->lastlogin == "")) ? "Never" : date("F j Y H:i:s", strtotime($this->lastlogin)); break; default: return $this->lastlogin; break; } } public function getLastBadLogin($flag = 0) { switch ($flag) { case TIMESTAMP: return strtotime($this->lastbadlogin); break; case PRETTY: return (($this->lastbadlogin == "0000-00-00 00:00:00") || ($this->lastbadlogin == "")) ? "Never" : date("F j Y H:i:s", strtotime($this->lastbadlogin)); break; default: return $this->lastbadlogin; break; } } public function getBadLoginCount() { return intval($this->badlogincount); } public function getLastUpdate($flag = 0) { switch ($flag) { case TIMESTAMP: return strtotime($this->lastupdate); break; case PRETTY: return date("F j Y H:i:s", strtotime($this->lastupdate)); break; default: return $this->lastupdate; break; } } public function setID($id = null) { if (is_null($id)) return false; $id = abs(intval($id)); if ($id == 0) return false; $this->id = $id; return true; } public function setUsername($username = null) { if (is_null($username) || ($username == "")) return false; settype($username, "string"); $this->username = $username; return true; } public function setPassword($password = null) { if (is_null($password)) return false; $this->password = password_hash($password, PASSWORD_DEFAULT); return true; } public function setPasswordHash($hash = null) { if (is_null($hash)) return false; $this->password = $hash; return true; } public function setFirstName($firstname = null) { if (is_null($firstname) || ($firstname == "")) return false; settype($firstname, "string"); $this->firstname = $firstname; return true; } public function setLastName($lastname = null) { if (is_null($lastname) || ($lastname == "")) return false; settype($lastname, "string"); $this->lastname = $lastname; return true; } public function setBadLoginCount($count = null) { if (is_null($count)) return false; $this->badlogincount = intval($count); } public function saveLastLogin() { global $globaldbh; $query = "UPDATE " . AppDB::TABLE_USERS . " SET lastlogin=:lastlogin WHERE id=:id"; $fields = array(); $fields[':id'] = $this->getID(); $fields[':lastlogin'] = (new DateTime("now", new DateTimeZone("UTC")))->format('Y-m-d H:i:s'); $sth = $globaldbh->prepare($query); $sth->execute($fields); } public static function getUserByUsername($username = null) { global $globaldbh; if (is_null($username)) return false; $query = "SELECT id FROM " . AppDB::TABLE_USERS . " WHERE username=:username"; $fields = array(); $fields[':username'] = $username; $sth = $globaldbh->prepare($query); $sth->execute($fields); if ($row = $sth->fetch()) { return new User($row['id']); } else { return false; } } public function setCookie() { global $globaldbh; $query = "DELETE FROM " . AppDB::TABLE_COOKIES . " WHERE user_id=:user_id AND ipaddress=:ipaddress"; $fields = array(); $fields[':user_id'] = $this->getID(); $fields[':ipaddress'] = $_SERVER['REMOTE_ADDR']; $sth = $globaldbh->prepare($query); $sth->execute($fields); $hash = uniqid("", true) . uniqid("", true); $query = "INSERT INTO " . AppDB::TABLE_COOKIES . " "; if (DBTYPE == 'mysql') { $query .= "VALUES(:hash, :user_id, :ipaddress, UTC_TIMESTAMP() + INTERVAL 30 DAY)"; } elseif (DBTYPE == 'sqlite') { $query .= "VALUES(:hash, :user_id, :ipaddress, DATETIME('NOW','+30 DAY'))"; } $fields[':hash'] = $hash; $sth = $globaldbh->prepare($query); $sth->execute($fields); setcookie(User::COOKIENAME, $hash, array('expires' => time() + (60 * 60 * 24 * 30), 'path' => "/", 'domain' => $_SERVER['SERVER_NAME'], 'samesite' => 'Lax')); } public function saveLastUpdate() { global $globaldbh; $query = "UPDATE " . AppDB::TABLE_USERS . " "; if (DBTYPE == 'mysql') { $query .= "SET lastupdate=UTC_TIMESTAMP() WHERE id=:id"; } elseif (DBTYPE == 'sqlite') { $query .= "SET lastupdate=DATETIME('NOW') WHERE id=:id"; } $fields = array(':id' => $this->getID()); $sth = $globaldbh->prepare($query); $sth->execute($fields); } public function incrementBadLogins() { global $globaldbh; $this->badlogincount++; $query = "UPDATE " . AppDB::TABLE_USERS . " "; if (DBTYPE == 'mysql') { $query .= "SET badlogincount=:badlogincount, lastbadlogin=UTC_TIMESTAMP() WHERE id=:id"; } elseif (DBTYPE == 'sqlite') { $query .= "SET badlogincount=:badlogincount, lastbadlogin=DATETIME('NOW') WHERE id=:id"; } $fields = array(); $fields[':id'] = $this->getID(); $fields[':badlogincount'] = $this->getBadLoginCount(); $sth = $globaldbh->prepare($query); $sth->execute($fields); } public static function getUserFromLogin($username = null, $password = null) { global $globaldbh; $user = User::getUserByUsername($username); if ($user === false) { return User::LOGININVALID; } if (($user->getBadLoginCount() >= MAXBADLOGINS) && ((strtotime($user->getLastBadLogin()) + (BADLOGINEXPIRATION * 60)) > time())) { return User::LOGINLOCKED; } $query = "SELECT id, password FROM " . AppDB::TABLE_USERS . " WHERE username=:username"; $fields = array(':username' => $username); $sth = $globaldbh->prepare($query); $sth->execute($fields); if ($row = $sth->fetch(PDO::FETCH_ASSOC)) { if (password_verify($password, $row['password'])) { $user = new User($row['id']); $user->setBadLoginCount(0); $saved = $user->save(); return $user; } } $user->incrementBadLogins(); return User::LOGININVALID; } public static function validateUserCookie($hash = null) { global $globaldbh; $query = "SELECT user_id FROM " . AppDB::TABLE_COOKIES . " WHERE hash=:hash AND ipaddress=:ipaddress "; if (DBTYPE == 'mysql') { $query .= "AND expiration >= UTC_TIMESTAMP()"; } elseif (DBTYPE == 'sqlite') { $query .= "AND DATETIME(expiration) >= DATETIME('NOW')"; } $fields = array(); $fields[':hash'] = $hash; $fields[':ipaddress'] = $_SERVER['REMOTE_ADDR']; $sth = $globaldbh->prepare($query); $sth->execute($fields); if ($row = $sth->fetch()) { $user = new User($row['user_id']); return $user->getID(); } else { return 0; } } public function removeCookie() { global $globaldbh; if (!isset($_COOKIE[User::COOKIENAME])) return; setcookie(User::COOKIENAME, "", time() - 3600, "/", $_SERVER['SERVER_NAME']); $query = "DELETE FROM " . AppDB::TABLE_COOKIES . " WHERE user_id=:user_id AND ipaddress=:ipaddress"; $fields = array(); $fields[':user_id'] = $this->getID(); $fields[':ipaddress'] = $_SERVER['REMOTE_ADDR']; $sth = $globaldbh->prepare($query); $sth->execute($fields); } public static function getList($search = null) { global $globaldbh; $fields = array(); if (is_null($search)) { $query = "SELECT id FROM " . AppDB::TABLE_USERS . " ORDER BY firstname, lastname"; } else { $query = "SELECT id FROM " . AppDB::TABLE_USERS . " WHERE (firstname LIKE :search) OR (lastname LIKE :search) OR (username LIKE :search) ORDER BY firstname, lastname"; $fields[':search'] = "%" . $search . "%"; } $sth = $globaldbh->prepare($query); $thelist = array(); if ($sth->execute($fields)) { while ($row = $sth->fetch()) { $thelist[] = new User($row['id']); } } return $thelist; } public function isLoggedIn() { if ( $this->getID() != 0 ) { return true; } else { return false; } } public function save() { global $globaldbh; if ($this->getFirstName() == "") return false; if ($this->getLastName() == "") return false; $fields = array(); if ($this->getID() == 0) { $query = "INSERT INTO " . AppDB::TABLE_USERS . " "; $query .= "(username, password, firstname, lastname, createtime, lastupdate) "; $query .= "VALUES(:username, :password, :firstname, :lastname, :createtime, :lastupdate)"; $fields[':password'] = $this->password; // There is no "getter" for password since it should never read outside the class $fields[':createtime'] = (new DateTime("now", new DateTimeZone("UTC")))->format('Y-m-d H:i:s'); } else { $query = "UPDATE " . AppDB::TABLE_USERS . " SET username=:username, "; if ($this->password != "") { $query .= "password=:password, "; $fields[':password'] = $this->password; // There is no "getter" for password since it should never read outside the class } $query .= "firstname=:firstname, lastname=:lastname, "; $query .= "lastupdate=:lastupdate, badlogincount=:badlogincount WHERE id=:id"; $fields[':id'] = $this->getID(); $fields[':badlogincount'] = $this->getBadLoginCount(); } $fields[':username'] = $this->getUsername(); $fields[':firstname'] = $this->getFirstName(); $fields[':lastname'] = $this->getLastName(); $fields[':lastupdate'] = (new DateTime("now", new DateTimeZone("UTC")))->format('Y-m-d H:i:s'); $sth = $globaldbh->prepare($query); $saved = $sth->execute($fields); return $saved; } function __construct($reqid = 0) { global $globaldbh; $reqid = intval($reqid); $query = "SELECT id, username, firstname, lastname, createtime, lastlogin, " . "lastbadlogin, badlogincount, lastupdate FROM " . AppDB::TABLE_USERS . " WHERE id=:id"; $fields = array(); $fields[':id'] = $reqid; $sth = $globaldbh->prepare($query); if ($sth->execute($fields)) { if ($row = $sth->fetch()) { $this->setID($row['id']); $this->setUsername($row['username']); $this->setFirstName($row['firstname']); $this->setLastName($row['lastname']); $this->createtime = $row['createtime']; $this->lastlogin = $row['lastlogin']; $this->lastbadlogin = $row['lastbadlogin']; $this->setBadLoginCount($row['badlogincount']); $this->lastupdate = $row['lastupdate']; } } } } // vim: set ts=3:sw=3