prepare("SELECT * FROM users WHERE id=?"); $stmt->bind_param("d", $id); $stmt->execute(); $query = $stmt->get_result(); if (!$query->num_rows) { throw new Exception("User doesn't exist."); return; } $result = $query->fetch_array(); $this->id = $id; $this->active = $result['active']; $this->name = $result['name']; $this->email = $result['email']; $this->surname = $result['surname']; $this->username = $result['username']; $this->rank = $result['permission']; } /** * Returns username of this user * @return String username */ public function get_username() { return $this->username; } /** * Returns whether this user is active * @return Boolean user active status */ public function is_active() { return $this->active; } /** * Returns rank of this user * @return int rank */ public function get_rank() { return $this->rank; } /** * Returns full name of this user * @return String name in "Name Surname" format */ public function get_name() { return $this->name . " " . $this->surname; } /** * Toggles active status of this user. First checks if the user * making the change has permission to do that. * @return void */ public function toggle() { global $mysqli, $message, $user; $id = $_GET['id']; if ($this->id != $_SESSION['user'] && $user->get_rank() <= 1 && ($user->get_rank() < $this->rank)) { $stmt = $mysqli->prepare("UPDATE users SET active = !active WHERE id=?"); $stmt->bind_param("i", $this->id); $stmt->execute(); $stmt->close(); header("Location: " . WEB_URL . "/admin/?do=user&id=" . $id); } else { $message = _("You don't have the permission to do that!"); } } /** * Processes submitted form and adds user unless problem is encountered, * calling this is possible only for Superadmin (other ranks cannot add users) * or when the installation script is being run. Also checks requirements * for username and email being unique and char limits. * @return void */ public static function add() { global $user, $message, $mysqli; if (INSTALL_OVERRIDE || $user->get_rank() == 0) { if (strlen(trim($_POST['name'])) == 0) { $messages[] = _("Name"); } if (strlen(trim($_POST['surname'])) == 0) { $messages[] = _("Surname"); } if (strlen(trim($_POST['email'])) == 0) { $messages[] = _("Email"); } if (strlen(trim($_POST['password'])) == 0) { $messages[] = _("Password"); } if (!isset($_POST['permission'])) { $messages[] = _("Rank"); } if (isset($messages)) { $message = "Please enter " . implode(", ", $messages); return; } $name = $_POST['name']; $surname = $_POST['surname']; $username = $_POST['username']; $email = $_POST['email']; $pass = $_POST['password']; if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $message = "Invalid email!"; return; } $variables = array(); if (strlen($name) > 50) { $variables[] = 'name: 50'; } if (strlen($surname) > 50) { $variables[] = 'surname: 50'; } if (strlen($username) > 50) { $variables[] = 'username: 50'; } if (strlen($email) > 60) { $variables[] = 'email: 60'; } if (!empty($variables)) { $message = _("Please mind the following character limits: "); $message .= implode(", ", $variables); return; } $salt = uniqid(mt_rand(), true); $hash = hash('sha256', $pass . $salt); $permission = $_POST['permission']; $stmt = $mysqli->prepare("INSERT INTO users values (NULL, ?, ?, ?, ?, ?, ?, ?, 1)"); $stmt->bind_param("ssssssi", $email, $username, $name, $surname, $hash, $salt, $permission); $stmt->execute(); if ($stmt->affected_rows == 0) { $message = _("Username or email already used"); return; } $to = $email; $subject = _('User account created') . ' - ' . NAME; $msg = sprintf(_("Hi %s!
" . "Your account has been created. You can login with your email address at %s with password %s - please change it as soon as possible."), $name . " " . $surname, WEB_URL . "/admin", WEB_URL . "/admin", $pass); $headers = "Content-Type: text/html; charset=utf-8 " . PHP_EOL; $headers .= "MIME-Version: 1.0 " . PHP_EOL; $headers .= "From: " . MAILER_NAME . ' <' . MAILER_ADDRESS . '>' . PHP_EOL; $headers .= "Reply-To: " . MAILER_NAME . ' <' . MAILER_ADDRESS . '>' . PHP_EOL; mail($to, $subject, $msg, $headers); if (!INSTALL_OVERRIDE) { header("Location: " . WEB_URL . "/admin/?do=settings"); } } else { $message = _("You don't have the permission to do that!"); } } /** * Processes submitted form and logs user in, unless the user is deactivated or wrong * password or email has been submitted. The script doesn't let anyone know which * field was wrong as it is not possible to verify email address from outside admin panel, * so this actually helps with security :) * @return void */ public static function login() { global $message, $mysqli; if (!isset($_POST['email']) && !isset($_POST['email'])) { return; } if ((!isset($_POST['email']) || !isset($_POST['email']))) { $message = _("Please fill in your email and password!"); return; } $email = $_POST['email']; $pass = $_POST['pass']; $stmt = $mysqli->prepare("SELECT id,password_salt as salt,active FROM users WHERE email=?"); $stmt->bind_param("s", $email); $stmt->execute(); $query = $stmt->get_result(); if ($query->num_rows < 1) { $message = _("Wrong email or password"); return; } $result = $query->fetch_assoc(); $salt = $result["salt"]; $id = $result["id"]; $active = $result["active"]; if (!$active) { $message = _("Your account has been disabled. Please contact administrator."); return; } $hash = hash('sha256', $pass . $salt); $stmt = $mysqli->prepare("SELECT count(*) as count FROM users WHERE id=? AND password_hash=?"); $stmt->bind_param("is", $id, $hash); $stmt->execute(); $query = $stmt->get_result(); if (!$query->fetch_assoc()['count']) { $message = _("Wrong email or password"); return; } if (isset($_POST['remember']) && $_POST['remember']) { $year = strtotime('+356 days', time()); $token = Token::add($id, 'remember', $year); setcookie('token', $token, $year, "/"); setcookie('user', $id, $year, "/"); } $_SESSION['user'] = $id; header("Location: " . WEB_URL . "/admin"); } /** * Checks whether token is valid (this means is in database and associated * with the user) and sets session data if it is, so user remains logged in. * The script deletes the token either way. * @return void */ public static function restore_session() { global $message; $id = $_COOKIE['user']; $token = $_COOKIE['token']; if (Token::validate($token, $id, "remember")) { $year = strtotime('+356 days', time()); unset($_COOKIE['token']); $_SESSION['user'] = $id; $new_token = Token::add($id, 'remember', $year); setcookie('token', $new_token, $year, "/"); setcookie('user', $id, $year, "/"); } else { unset($_COOKIE['user']); unset($_COOKIE['token']); setcookie('user', null, -1, '/'); setcookie('token', null, -1, '/'); $message = _("Invalid token detected, please login again!"); } Token::delete($token); } /** * Renders settings for this user so it can be displayed in admin panel. * @return void */ public function render_user_settings() { global $permissions, $user; ?>
<?php echo _(">
id == $_SESSION['user'] || $user->get_rank() < 1) { ?>
" title="" class="form-control form-name" value=name, ENT_QUOTES); ?>> " title="" class="form-control form-name" value=surname, ENT_QUOTES); ?>>

name . " " . $this->surname; ?>

id == $_SESSION['user'] || $user->get_rank() < 1) { ?>
username . " "; if ($user->get_rank() >= 1) { echo ""; } } ?>
get_rank() == 0 && $this->id != $_SESSION['user']) { ?>
rank]; } ?>
id == $_SESSION['user'] || $user->get_rank() < 1) { ?>
Email
email; ?>
id == $_SESSION['user']) { ?>
" type="password" class="form-control" name="old_password"> " type="password" class="form-control" name="password"> " type="password" class="form-control" name="password_repeat">
id != $_SESSION['user'] && $user->get_rank() <= 1 && ($user->get_rank() < $this->rank)) { ?>
active) { echo '' . _("Deactivate user") . ""; } else { echo '' . _("Activate user") . ""; } ?>
id; $stmt = $mysqli->prepare("SELECT count(*) FROM users WHERE username LIKE ?"); $stmt->bind_param("s", $_POST["username"]); $stmt->execute(); if ($stmt->num_rows > 0) { $message = _("This username is already taken."); return; } $stmt->close(); if ($_SESSION['user'] != $id && $user->get_rank() > 0) { $message = _("Cannot change username of other users!"); } else { $stmt = $mysqli->prepare("UPDATE users SET username = ? WHERE id=?"); $stmt->bind_param("si", $_POST["username"], $id); $stmt->execute(); $stmt->close(); header("Location: " . WEB_URL . "/admin/?do=user&id=" . $id); } } /** * Changes name and surname of user by POST[ID]. * @return void */ public function change_name() { global $mysqli, $message, $user; if (strlen(trim($_POST['name'])) == 0) { $messages[] = _("Name"); } if (strlen(trim($_POST['surname'])) == 0) { $messages[] = _("Surname"); } if (!empty($messages)) { $message = "Please enter " . implode(", ", $messages); return; } $id = $this->id; if ($_SESSION['user'] != $id && $user->get_rank() > 0) { $message = _("Cannot change names of other users!"); } else { $stmt = $mysqli->prepare("UPDATE users SET `name` = ?, `surname` = ? WHERE id=?"); $stmt->bind_param("ssi", $_POST["name"], $_POST["surname"], $id); $stmt->execute(); $stmt->close(); header("Location: " . WEB_URL . "/admin/?do=user&id=" . $id); } } /** * Changes user password and deletes all remember tokens so all other sessions * won't stay logged in without knowing new pass. Uses token when reseting password. * @param String $token * @return void */ public function change_password($token = false) { global $mysqli, $message; $id = $this->id; if ($_POST['password'] != $_POST['password_repeat']) { $message = _("Passwords do not match!"); return; } if (!$token) { if ($_SESSION['user'] != $id) { $message = _("Cannot change password of other users!"); } else { $stmt = $mysqli->prepare("SELECT password_salt as salt FROM users WHERE id=?"); $stmt->bind_param("i", $id); $stmt->execute(); $query = $stmt->get_result(); $result = $query->fetch_assoc(); $salt = $result['salt']; $pass = $_POST['old_password']; $hash = hash('sha256', $pass . $salt); $stmt = $mysqli->prepare("SELECT count(*) as count FROM users WHERE id=? AND password_hash = ?"); $stmt->bind_param("is", $id, $hash); $stmt->execute(); if ($stmt->get_result()->fetch_assoc()['count']) { $pass = $_POST['password']; $hash = hash('sha256', $pass . $salt); $stmt = $mysqli->prepare("UPDATE users SET password_hash = ? WHERE id=?"); $stmt->bind_param("si", $hash, $id); $stmt->execute(); $stmt->close(); $stmt = $mysqli->prepare("DELETE FROM tokens WHERE user = ? AND data = 'remember'"); $stmt->bind_param("d", $id); $stmt->execute(); $stmt->get_result(); User::logout(); } else { $message = _("Wrong password!"); } } } else { if (Token::validate($token, $id, "passwd")) { $stmt = $mysqli->prepare("SELECT password_salt as salt FROM users WHERE id=?"); $stmt->bind_param("i", $id); $stmt->execute(); $query = $stmt->get_result(); $result = $query->fetch_assoc(); $salt = $result['salt']; $pass = $_POST['password']; $hash = hash('sha256', $pass . $salt); $stmt = $mysqli->prepare("UPDATE users SET password_hash = ? WHERE id=?"); $stmt->bind_param("si", $hash, $id); $stmt->execute(); $stmt->close(); $stmt = $mysqli->prepare("DELETE FROM tokens WHERE user = ? AND data = 'remember'"); $stmt->bind_param("d", $id); $stmt->execute(); $stmt->get_result(); } else { $message = _("Invalid token detected, please retry your request from start!"); } Token::delete($token); } } /** * Sends email with link for password reset, link is token protected and valid only once. * @return void */ public static function password_link() { global $mysqli; $email = $_POST['email']; $stmt = $mysqli->prepare("SELECT id FROM users WHERE email=?"); $stmt->bind_param("s", $email); $stmt->execute(); $query = $stmt->get_result(); $id = $query->fetch_assoc()['id']; $time = strtotime('+1 day', time()); $token = Token::add($id, 'passwd', $time); $link = WEB_URL . "/admin/?do=lost-password&id=$id&token=$token"; $to = $email; $user = new User($id); $subject = _('Reset password') . ' - ' . NAME; $msg = sprintf(_("Hi %s!
Below you will find link to change your password. The link is valid for 24hrs. If you didn't request this, feel free to ignore it.

RESET PASSWORD

If the link doesn't work, copy & paste it into your browser:
%s"), $user->get_name(), $link, $link); $headers = "Content-Type: text/html; charset=utf-8 " . PHP_EOL; $headers .= "MIME-Version: 1.0 " . PHP_EOL; $headers .= "From: " . MAILER_NAME . ' <' . MAILER_ADDRESS . '>' . PHP_EOL; $headers .= "Reply-To: " . MAILER_NAME . ' <' . MAILER_ADDRESS . '>' . PHP_EOL; mail($to, $subject, $msg, $headers); } /** * Sends email with link for email change confirmation (security reasons), link is token protected and valid only once. * @return void */ public function email_link() { global $user, $mysqli; $email = $_POST['email']; $id = $this->id; if ($user->get_rank() < 1 && $id != $_SESSION['user']) { $stmt = $mysqli->prepare("UPDATE users SET email = ? WHERE id=?"); $stmt->bind_param("sd", $email, $id); $stmt->execute(); $stmt->get_result(); header("Location: " . WEB_URL . "/admin/?do=user&id=" . $id); return; } $time = strtotime('+1 day', time()); $token = Token::add($id, 'email;$email', $time); $link = WEB_URL . "/admin/?do=change-email&id=$id&token=$token"; $to = $email; $subject = _('Email change') . ' - ' . NAME; $msg = sprintf(_("Hi %s!
Below you will find link to change your email. The link is valid for 24hrs. If you didn't request this, feel free to ignore it.

CHANGE EMAIL

If the link doesn't work, copy & paste it into your browser:
%s"), $user->get_name(), $link, $link); $headers = "Content-Type: text/html; charset=utf-8 " . PHP_EOL; $headers .= "MIME-Version: 1.0 " . PHP_EOL; $headers .= "From: " . MAILER_NAME . ' <' . MAILER_ADDRESS . '>' . PHP_EOL; $headers .= "Reply-To: " . MAILER_NAME . ' <' . MAILER_ADDRESS . '>' . PHP_EOL; mail($to, $subject, $msg, $headers); return _('Confirmation email sent!'); } /** * Changes email. * @return void */ public function change_email() { global $mysqli, $message; $token = $_GET['token']; $id = $_GET['id']; if (Token::validate($token, $id, "email;%")) { $data = explode(";", Token::get_data($token, $id)); $email = $data[1]; $stmt = $mysqli->prepare("UPDATE users SET email = ? WHERE id=?"); $stmt->bind_param("sd", $email, $id); $stmt->execute(); $stmt->get_result(); Token::delete($token); header("Location: " . WEB_URL . "/admin/"); } else { $message = _("Invalid token detected, please retry your request from start!"); } Token::delete($token); } /** * Logs current user out. * @return void */ public static function logout() { session_unset(); if (isset($_COOKIE['token'])) { $token = $_COOKIE['token']; Token::delete($token); unset($_COOKIE['user']); unset($_COOKIE['token']); setcookie('user', null, -1, '/'); setcookie('token', null, -1, '/'); } header("Location: " . WEB_URL . "/admin"); } /** * Changes permissions of current user - only super admin can do this, so it checks permission first. * @return void */ public function change_permission() { global $mysqli, $message, $user; if ($user->get_rank() == 0) { $permission = $_POST['permission']; $id = $_GET['id']; $stmt = $mysqli->prepare("UPDATE users SET permission=? WHERE id=?"); $stmt->bind_param("si", $permission, $id); $stmt->execute(); header("Location: " . WEB_URL . "/admin/?do=user&id=" . $id); } else { $message = _("You don't have permission to do that!"); } } }