375 lines
10 KiB
PHP
375 lines
10 KiB
PHP
<?php
|
|
|
|
namespace Khofmann\Models\User;
|
|
|
|
use Exception;
|
|
use PDO;
|
|
use DateTime;
|
|
use Khofmann\Database\Database;
|
|
use Config\Config;
|
|
use JsonSerializable;
|
|
use Khofmann\GUID\GUID;
|
|
use PDOException;
|
|
|
|
class User implements JsonSerializable
|
|
{
|
|
private int $id;
|
|
private string $username;
|
|
private int $status;
|
|
private string $email;
|
|
private ?string $image;
|
|
private bool $isAdmin;
|
|
private DateTime $memberSince;
|
|
private int $postCount;
|
|
|
|
protected function __construct(int $id, string $username, int $status, string $email, string $timestamp, ?string $image, bool $isAdmin, int $postCount)
|
|
{
|
|
$this->id = $id;
|
|
$this->username = $username;
|
|
$this->status = $status;
|
|
$this->email = $email;
|
|
$this->image = $image;
|
|
$this->isAdmin = $isAdmin;
|
|
$this->memberSince = new DateTime($timestamp);
|
|
$this->postCount = $postCount;
|
|
}
|
|
|
|
private static function getByConfirmCode(string $code): User
|
|
{
|
|
$db = Database::getInstance();
|
|
|
|
$stmt = $db->prepare(
|
|
"SELECT
|
|
b.id, b.benutzer, b.status, b.email, b.image, b.isadmin, b.zeitstempel,
|
|
(SELECT COUNT(*) FROM egb_gaestebuch WHERE benutzer_id = b.id) as postCount
|
|
FROM
|
|
egb_benutzer AS b
|
|
WHERE
|
|
confirmationcode = :COD"
|
|
);
|
|
$stmt->bindValue(":COD", $code);
|
|
$stmt->execute();
|
|
$data = $stmt->fetch();
|
|
|
|
if (!$data) throw new Exception("NotFound");
|
|
|
|
return new User($data["id"], $data["benutzer"], $data["status"], $data["email"], $data["zeitstempel"], $data["image"], $data["isadmin"] === 1, $data["postCount"]);
|
|
}
|
|
|
|
/*
|
|
* Statics
|
|
*/
|
|
|
|
public static function getByID(int $id): User
|
|
{
|
|
$db = Database::getInstance();
|
|
$stmt = $db->prepare(
|
|
"SELECT
|
|
b.benutzer, b.status, b.email, b.image, b.isadmin, b.zeitstempel,
|
|
(SELECT COUNT(*) FROM egb_gaestebuch WHERE benutzer_id = b.id) as postCount
|
|
FROM
|
|
egb_benutzer AS b
|
|
WHERE
|
|
b.id = :ID"
|
|
);
|
|
$stmt->bindValue(":ID", $id);
|
|
$stmt->execute();
|
|
$data = $stmt->fetch();
|
|
|
|
if (!$data) throw new Exception("NotFound");
|
|
|
|
return new User($id, $data["benutzer"], $data["status"], $data["email"], $data["zeitstempel"], $data["image"], $data["isadmin"] === 1, $data["postCount"]);
|
|
}
|
|
|
|
public static function getByEmail(string $email): User
|
|
{
|
|
$db = Database::getInstance();
|
|
$stmt = $db->prepare(
|
|
"SELECT
|
|
b.id, b.benutzer, b.status, b.image, b.isadmin, b.zeitstempel,
|
|
(SELECT COUNT(*) FROM egb_gaestebuch WHERE benutzer_id = b.id) as postCount
|
|
FROM
|
|
egb_benutzer AS b
|
|
WHERE
|
|
email = :EMAIL"
|
|
);
|
|
$stmt->bindValue(":EMAIL", $email);
|
|
$stmt->execute();
|
|
$data = $stmt->fetch();
|
|
|
|
if (!$data) throw new Exception("NotFound");
|
|
|
|
return new User($data["id"], $data["benutzer"], $data["status"], $email, $data["zeitstempel"], $data["image"], $data["isadmin"] === 1, $data["postCount"]);
|
|
}
|
|
|
|
public static function getByToken(string $token): User
|
|
{
|
|
$db = Database::getInstance();
|
|
$stmt = $db->prepare(
|
|
"SELECT
|
|
b.id, b.benutzer, b.status, b.email, b.image, b.isadmin, b.zeitstempel,
|
|
(SELECT COUNT(*) FROM egb_gaestebuch WHERE benutzer_id = b.id) as postCount
|
|
FROM
|
|
egb_benutzer AS b
|
|
WHERE
|
|
token = :TOKEN"
|
|
);
|
|
$stmt->bindValue(":TOKEN", $token);
|
|
$stmt->execute();
|
|
$data = $stmt->fetch();
|
|
|
|
if (!$data) throw new Exception("NotFound");
|
|
|
|
return new User($data["id"], $data["benutzer"], $data["status"], $data["email"], $data["zeitstempel"], $data["image"], $data["isadmin"] === 1, $data["postCount"]);
|
|
}
|
|
|
|
public static function logIn(string $email, string $password): array
|
|
{
|
|
$db = Database::getInstance();
|
|
// Get user data
|
|
$stmt = $db->prepare(
|
|
"SELECT
|
|
b.*,
|
|
(SELECT COUNT(*) FROM egb_gaestebuch WHERE benutzer_id = b.id) as postCount
|
|
FROM
|
|
egb_benutzer AS b
|
|
WHERE
|
|
email LIKE :EMAIL AND
|
|
status = 1"
|
|
);
|
|
$stmt->bindValue(":EMAIL", $email);
|
|
$stmt->execute();
|
|
$data = $stmt->fetch();
|
|
|
|
if ($data) {
|
|
$user = new User($data["id"], $data["benutzer"], $data["status"], $email, $data["zeitstempel"], $data["image"], $data["isadmin"] === 1, $data["postCount"]);
|
|
if (password_verify($password, $data["passwort"])) {
|
|
// REHASH for safety should it somehow change
|
|
if (password_needs_rehash($data["passwort"], PASSWORD_DEFAULT)) {
|
|
$newHash = password_hash($password, PASSWORD_DEFAULT);
|
|
$stmt = $db->prepare("UPDATE egb_benutzer SET passwort = :PAS WHERE id = :ID");
|
|
$stmt->bindValue(":PAS", $newHash);
|
|
$stmt->bindValue(":ID", $user->getID());
|
|
$stmt->execute();
|
|
}
|
|
// Generate token
|
|
$stmt = $db->prepare("UPDATE egb_benutzer SET token = UUID() WHERE id = :ID");
|
|
$stmt->bindValue(":ID", $user->getID());
|
|
$stmt->execute();
|
|
// Get token
|
|
$stmt = $db->prepare("SELECT token FROM egb_benutzer WHERE id = :ID");
|
|
$stmt->bindValue(":ID", $user->getID());
|
|
$stmt->execute();
|
|
$token = $stmt->fetch(PDO::FETCH_COLUMN, 0);
|
|
// Return user and token
|
|
if ($token) {
|
|
return ["user" => $user, "token" => $token];
|
|
}
|
|
// Token generation failed
|
|
throw new Exception("Failed");
|
|
} else {
|
|
// PW wrong
|
|
throw new Exception("Invalid");
|
|
}
|
|
} else {
|
|
// User does not exist
|
|
throw new Exception("NotFound");
|
|
}
|
|
}
|
|
|
|
public static function create(string $username, string $email, string $password): bool
|
|
{
|
|
$db = Database::getInstance();
|
|
$guid = GUID::v4();
|
|
|
|
$stmt = $db->prepare(
|
|
"INSERT INTO
|
|
egb_benutzer(benutzer, passwort, email, confirmationcode)
|
|
VALUES(:USR, :PAS, :EMA, :COD)"
|
|
);
|
|
$stmt->bindValue(":USR", $username);
|
|
$stmt->bindValue(":PAS", password_hash($password, PASSWORD_DEFAULT));
|
|
$stmt->bindValue(":EMA", $email);
|
|
$stmt->bindValue(":COD", $guid);
|
|
|
|
try {
|
|
$stmt->execute();
|
|
|
|
mail(
|
|
$email,
|
|
"Account activation GuestBookDB",
|
|
"Hello $username. To activate your account, visit https://khofmann.userpage.fu-berlin.de/phpCourse/exam/confirm?c=$guid"
|
|
);
|
|
|
|
return true;
|
|
} catch (Exception $err) {
|
|
if ($err->getCode() === "23000") throw new Exception("Duplicate");
|
|
|
|
throw $err;
|
|
}
|
|
}
|
|
|
|
public static function confirm(string $confirmCode): bool
|
|
{
|
|
$db = Database::getInstance();
|
|
$user = User::getByConfirmCode($confirmCode);
|
|
|
|
$stmt = $db->prepare(
|
|
"UPDATE
|
|
egb_benutzer
|
|
SET
|
|
status = 1,
|
|
confirmationcode = NULL
|
|
WHERE id = :UID"
|
|
);
|
|
$stmt->bindValue(":UID", $user->getID());
|
|
return $stmt->execute();
|
|
}
|
|
|
|
public static function list(int $page, int $limit)
|
|
{
|
|
$db = Database::getInstance();
|
|
$stmt = $db->prepare(
|
|
"SELECT
|
|
COUNT(*)
|
|
FROM
|
|
egb_gaestebuch"
|
|
);
|
|
$stmt->execute();
|
|
$count = $stmt->fetch(PDO::FETCH_COLUMN, 0);
|
|
$stmt = $db->prepare(
|
|
"SELECT
|
|
b.id, b.benutzer, b.status, b.email, b.image, b.isadmin, b.zeitstempel,
|
|
(SELECT COUNT(*) FROM egb_gaestebuch WHERE benutzer_id = b.id) as postCount
|
|
FROM
|
|
egb_benutzer AS b"
|
|
);
|
|
$stmt->execute();
|
|
$data = $stmt->fetchAll();
|
|
|
|
$list = array_map(
|
|
fn ($item) => new User($item["id"], $item["benutzer"], $item["status"], $item["email"], $item["zeitstempel"], $item["image"], $item["isadmin"] === 1, $item["postCount"]),
|
|
$data
|
|
);
|
|
|
|
return ["pages" => intdiv($count, $limit) + 1, "data" => $list];
|
|
}
|
|
|
|
/*
|
|
* Members
|
|
*/
|
|
|
|
public function logOut(): bool
|
|
{
|
|
$db = Database::getInstance();
|
|
$stmt = $db->prepare("UPDATE egb_benutzer SET token = NULL WHERE id = :ID");
|
|
$stmt->bindValue(":ID", $this->id);
|
|
return $stmt->execute();
|
|
}
|
|
|
|
public function update(?string $username, ?string $password, $image = null): bool
|
|
{
|
|
$db = Database::getInstance();
|
|
|
|
$error = false;
|
|
if (!empty($username)) {
|
|
$stmt = $db->prepare("UPDATE egb_benutzer SET benutzer = :USR WHERE id = :ID");
|
|
$stmt->bindValue(":USR", $username);
|
|
$stmt->bindValue(":ID", $this->id);
|
|
$error = !$stmt->execute();
|
|
}
|
|
if ($error) throw new Exception("FailedUsername");
|
|
|
|
if (!empty($password)) {
|
|
$stmt = $db->prepare("UPDATE egb_benutzer SET passwort = :PAS WHERE id = :ID");
|
|
$stmt->bindValue(":PAS", password_hash($password, PASSWORD_DEFAULT));
|
|
$stmt->bindValue(":ID", $this->id);
|
|
$error = !$stmt->execute();
|
|
}
|
|
if ($error) throw new Exception("FailedPassword");
|
|
|
|
if (!empty($image)) {
|
|
$destinationFilename = sprintf('%s.%s', uniqid(), $image->getExtension());
|
|
$image->move(Config::getStoragePath() . "profilbilder/$destinationFilename");
|
|
|
|
$stmt = $db->prepare("UPDATE egb_benutzer SET image = :IMG WHERE id = :ID");
|
|
$stmt->bindValue(":IMG", $destinationFilename);
|
|
$stmt->bindValue(":ID", $this->id);
|
|
$error = !$stmt->execute();
|
|
}
|
|
if ($error) throw new Exception("FailedImage");
|
|
|
|
return true;
|
|
}
|
|
|
|
public function delete(): bool
|
|
{
|
|
$db = Database::getInstance();
|
|
$stmt = $db->prepare("DELETE FROM egb_benutzer WHERE id = :ID");
|
|
$stmt->bindValue(":ID", $this->id);
|
|
return $stmt->execute();
|
|
}
|
|
|
|
/*
|
|
* Getters
|
|
*/
|
|
|
|
public function getID(): int
|
|
{
|
|
return $this->id;
|
|
}
|
|
|
|
public function getUsername(): string
|
|
{
|
|
return $this->username;
|
|
}
|
|
|
|
public function getStatus(): int
|
|
{
|
|
return $this->status;
|
|
}
|
|
|
|
public function getEmail(): string
|
|
{
|
|
return $this->email;
|
|
}
|
|
|
|
public function getImage(): ?string
|
|
{
|
|
return $this->image;
|
|
}
|
|
|
|
public function getIsAdmin(): bool
|
|
{
|
|
return $this->isAdmin;
|
|
}
|
|
|
|
public function getMemberSince(): DateTime
|
|
{
|
|
return $this->memberSince;
|
|
}
|
|
|
|
public function getPostCount(): int
|
|
{
|
|
return $this->postCount;
|
|
}
|
|
|
|
/*
|
|
* JSON
|
|
*/
|
|
|
|
public function jsonSerialize(): array
|
|
{
|
|
return [
|
|
'id' => $this->id,
|
|
'username' => $this->username,
|
|
'status' => $this->status,
|
|
'email' => $this->email,
|
|
'image' => $this->image,
|
|
'isAdmin' => $this->isAdmin,
|
|
'memberSince' => $this->memberSince,
|
|
'postCount' => $this->postCount,
|
|
];
|
|
}
|
|
}
|