fields['users'] = array( "guid", "auth", "salt", "alias", "email", "emailVer", "admin", "reg", "emailConf", ); parent::__construct($guid); $this->expectType("user"); } /* * Get the GUID of a user object from a given username, or NULL if * the username is not in use. Therefore, this function can be * used to test the existence of a user with the given username. */ public static function getGuidByUname(string $uname) : ?string { $uname = database::esc($uname); $query = "SELECT guid FROM objects WHERE objtype = 'user' AND name = '" . $uname . "'"; $res = database::query($query); if (count($res) == 0) return NULL; return $res[0]['guid']; } /* * Get a user object from a given username, or NULL if the username * is not in use. This function can be used to test the existence * of a user with the given username. */ public static function getByUname(string $uname) : ?user { if (($guid = self::getGuidByUname($uname))) return new user($guid); return NULL; } /* * Get an array of all users, sorted by username */ public static function getAll_ordByUname() : array { $query = "SELECT guid FROM objects WHERE objtype = 'user' ORDER BY name"; $res = database::query($query); $users = array(); foreach ($res as $u) $users[] = new user($u['guid']); return $users; } /* * Get an array of all users, sorted by admin (descending, admins * first), then by username. */ public static function getAll_ordByAdminByUname() : array { $query = "SELECT o.guid FROM objects o JOIN users u ON o.guid = u.guid " . "WHERE o.objtype = 'user' ORDER BY u.admin DESC, o.name"; $res = database::query($query); $users = array(); foreach ($res as $u) $users[] = new user($u['guid']); return $users; } /* * Get an array of all admins, sorted by username */ public static function getAllAdmin_ordByUname() : array { $query = "SELECT o.guid FROM objects o JOIN users u ON o.guid = u.guid " . "WHERE o.objtype = 'user' AND u.admin = 1 ORDER BY o.name"; $res = database::query($query); $users = array(); foreach ($res as $u) $users[] = new user($u['guid']); return $users; } /* * Get the currently logged in user, or NULL if logged out. This * function will throw if unable to aquire a PHP session. This * function will also forcibly log the current user out if it * detects any changes in the user-agent or remote IP address. */ public static function getCurrent() : ?user { if (!session_start()) throw new Exception("Unable to aquire a PHP session"); if (!isset($_SESSION['userguid'])) return NULL; /* detect session hijacking */ if (($_SESSION['useragent'] != $_SERVER['HTTP_USER_AGENT']) || ($_SESSION['userip'] != $_SERVER['REMOTE_ADDR'])) { self::setCurrent(); location("/"); return NULL; } return new user($_SESSION['userguid']); } /* * Set the currently logged in user. Using NULL will logout any * current user. This function will throw if unable to aquire a * PHP session. This function will also cache the user-agent and * remote IP address of the current request to help validate future * requests made under the same session. */ public static function setCurrent(?user $user = NULL) : void { if (!session_start()) throw new Exception("Unable to aquire a PHP session"); unset($_SESSION['userguid']); unset($_SESSION['useragent']); unset($_SESSION['userip']); if ($user) { $_SESSION['userguid'] = $user->guid; $_SESSION['useragent'] = $_SERVER['HTTP_USER_AGENT']; $_SESSION['userip'] = $_SERVER['REMOTE_ADDR']; } } /* * Initialize a new user object with the given username and plain * text password. This function returns NULL if $uname is already * being used. */ public static function initNew(string $uname, string $passwd) : ?user { if (self::getByUname($uname)) return NULL; $user = new user(); /* if there exist no users already, make this new one an admin */ if (count(self::getAll_ordByUname()) == 0) $user->admin = 1; $user->name = $uname; $user->objtype = "user"; $user->setPasswd($passwd); $user->setEmail(""); $user->reg = 1; return $user; } /* * Get the salted and hashed form of a password */ private static function getAuth(string $passwd, string $salt) : string { return hash("sha256", $passwd . $salt); } /* * Validate the given plain-text password for this user. Returns true if * correct, false otherwise. */ public function validatePasswd(string $passwd) : bool { $auth = self::getAuth($passwd, $this->salt); return $auth == $this->auth; } /* * Update the auth and salt for this user, given a new plain-text * password. */ public function setPasswd(string $passwd) : void { $this->salt = self::getBlob(); $this->auth = self::getAuth($passwd, $this->salt); } /* * Validate the email confirmation code for this user. Returns true if * correct, false otherwise. On success, $this->emailConf is also set * to 1 */ public function verifyEmail(string $ver) : bool { if ($ver != $this->emailVer) return false; $this->emailConf = 1; return true; } /* * Update the email address for this user. This function will automatically * reset the emailConf flag and confirmation code for this user as well. */ public function setEmail(string $email) : void { $this->email = $email; $this->emailVer = substr(self::getBlob(), 0, 8); $this->emailConf = 0; } } ?>