426 lines
14 KiB
PHP
426 lines
14 KiB
PHP
<?php
|
|
|
|
class User {
|
|
private $id = 0;
|
|
private $username = "";
|
|
private $password = "";
|
|
private $firstname = "";
|
|
private $lastname = "";
|
|
// createtime will be stored in the class using the native SQL datetime format
|
|
private $createtime = "";
|
|
// lastlogin will be stored in the class using the native SQL datetime format
|
|
private $lastlogin = "";
|
|
// lastbadlogin will be stored in the class using the native SQL datetime format
|
|
private $lastbadlogin = "";
|
|
private $badlogincount = 0;
|
|
// lastupdate will be stored in the class using the native SQL datetime format
|
|
private $lastupdate = "";
|
|
|
|
const COOKIENAME = SESSNAME . "_rememberme";
|
|
const ROLE_ADMIN = "admin";
|
|
const ROLE_USER = "user";
|
|
const ROLE_GUEST = "guest";
|
|
const ROLE_VALIDROLES = array(User::ROLE_GUEST, User::ROLE_ADMIN, User::ROLE_USER);
|
|
const GUEST = 1000601;
|
|
const USER = 1000602;
|
|
const ADMIN = 1000603;
|
|
const LOGININVALID = 1000604;
|
|
const LOGINLOCKED = 1000605;
|
|
|
|
public function getID() {
|
|
return intval($this->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
|