Files
vintagecoding.net/functions/user.php
T
2025-06-10 10:46:22 -06:00

316 lines
10 KiB
PHP

<?php
require_once 'relationships/spaceMember.php';
class LoginCredentials
{
private string $username;
private string $password;
public function __construct(string $username, string $password)
{
// More intensive SQL injection checks (example - adapt as needed)
if (preg_match('/[\'";\-\_]/', $username) || preg_match('/[\'";\-\_]/', $password)) {
throw new InvalidArgumentException('Invalid characters in username or password.');
}
// Consider using a more robust validation library
$this->username = $username;
$this->password = $password;
}
public function getUsername(): string
{
return $this->username;
}
public function getPassword(): string
{
return $this->password;
}
}
class User
{
private int $id;
private ?array $spaces;
private string $username;
private bool $isActive;
private ?string $profilePicture;
private ?string $bio;
private ?string $website;
private int $role;
private ?string $passwordHash;
public function __construct(int $id, ?array $spaces, string $username, ?string $profilePicture = null, ?string $bio = null, ?string $website = null, int $role = 3, ?string $passwordHash)
{
error_log('Constructing a User with id: ' . $id);
// Basic XSS prevention on construction (can be enhanced)
$username = htmlspecialchars($username, ENT_QUOTES, 'UTF-8');
$bio = htmlspecialchars($bio ?? '', ENT_QUOTES, 'UTF-8');
$website = htmlspecialchars($website ?? '', ENT_QUOTES, 'UTF-8');
$profilePicture = htmlspecialchars($profilePicture ?? 'default-profile.png', ENT_QUOTES, 'UTF-8');
// Basic SQL injection prevention (should primarily rely on prepared statements)
/* if (preg_match('/[\'";\-\_]/', $username) || preg_match('/[\'";\-\_]/', $bio) || preg_match('/[\'";\-\_]/', $website) || preg_match('/[\'";\-\_]/', $profilePicture)) { */
/* throw new InvalidArgumentException('Invalid characters in user data.'); */
/* } */
$this->username = $username;
$this->profilePicture = $profilePicture;
$this->bio = $bio;
$this->website = $website;
$this->isActive = false;
$this->role = $role;
$this->spaces = $spaces;
$this->passwordHash = $passwordHash;
if ($id < 0) {
$this->id = $id * -1;
$stmt = 'INSERT INTO user (id, username, passwordHash, profilePicture, bio, website) VALUES (?, ?, ?, ?, ?, ?)';
exec_stmt($stmt, 'isssss', $this->id, $this->username, $passwordHash, $this->profilePicture, $this->bio, $this->website);
Space::addUserToSpace($this->id, 2025);
$space = new Space($id, $this->username, $this->username . "'s private Space.", 5, [], null, true);
$this->spaces[] = new SpaceMember(randomId(4), $this, $space, 1, new Datetime('now'), true);
} else
$this->id = $id;
}
public static function exists($identifier): bool
{
if (is_int($identifier)) {
$stmt = 'SELECT count(id) FROM user WHERE id = ?';
$result = exec_stmt($stmt, 'i', $identifier)->fetch_assoc();
if ($result['count(id)'] == 1)
return true;
else if ($result['count(id)'] > 1)
return true;
else
return false;
} else if (is_string($identifier)) {
$stmt = 'SELECT count(id) FROM user WHERE username = ?';
$result = exec_stmt($stmt, 's', $identifier)->fetch_assoc();
if ($result['count(id)'] == 1)
return true;
else if ($result['count(id)'] > 1)
return true;
else
return false;
}
return true;
}
public function add(SpaceMember $sm)
{
$this->spaces[] = $sm;
}
public static function retrieveFromDB($identifier): ?User
{
error_log('Instantiating a user');
if (is_int($identifier)) {
$stmt = 'SELECT id, username, profilePicture, bio, website, role, passwordHash FROM user WHERE id = ?';
$rawUser = exec_stmt($stmt, 'i', $identifier)->fetch_assoc();
if (!$rawUser)
return null;
} else if (is_string($identifier)) {
$stmt = 'SELECT id, username, profilePicture, bio, website, role, passwordHash FROM user WHERE username = ?';
$rawUser = exec_stmt($stmt, 'i', $identifier)->fetch_assoc();
if (!$rawUser)
return null;
} else {
return null;
}
$user = new User($rawUser['id'], null, $rawUser['username'], $rawUser['profilePicture'], $rawUser['bio'], $rawUser['website'], $rawUser['role'], $rawUser['passwordHash']);
$stmt = 'SELECT id, space, role, addedAt, favorited from spaceMembers WHERE user = ?';
$rels = exec_stmt($stmt, 'i', $user->getId());
if (!$rels)
return null;
while ($r = $rels->fetch_assoc())
$user->add(new SpaceMember($r['id'], $user, Space::retrieveFromDB($r['space'], $user->getId()), $r['role'], new DateTime($r['addedAt']), $r['favorited']));
return $user;
}
public static function login(LoginCredentials $credentials): ?User
{
$user = User::retrieveFromDB($credentials->getUsername());
if (!password_verify($credentials->getPassword(), $user->getPasswordHash()))
return null;
else
return $user;
}
public static function logout(): void
{
foreach (array_keys($_SESSION) as $key) {
unset($_SESSION[$key]);
}
// Consider destroying the session cookie as well: session_destroy();
header('Location: .'); // Redirect to the homepage or login page
exit();
}
public function getPasswordHash()
{
return $this->passwordHash;
}
public function getHomeSpace()
{
// TODO: Need to implement. Requires fleshing out additional space types.
return Space::retrieveFromDB(1, 1);
}
public function getSpaces()
{
$baseSpaces = [];
foreach ($this->spaces as $s)
if (!$s->getSpace()->hasParent())
$baseSpaces[] = $s;
return $baseSpaces;
}
public function getAllSpaces()
{
$stmt = 'SELECT space FROM spaceMembers WHERE user = ?';
$rawSpaces = exec_stmt($stmt, 'i', $this->id);
$spaces = [];
while ($r = $rawSpaces->fetch_assoc())
$spaces[] = Space::retrieveFromDB($r['space']);
return $spaces;
}
public function getRole(): int
{
return $this->role;
}
public function getId(): int
{
return $this->id;
}
public function getUsername(): string
{
return $this->username;
}
public function isActive(): bool
{
return $this->isActive;
}
public function getProfilePicture(): ?string
{
return $this->profilePicture;
}
public function getBio(): ?string
{
return $this->bio;
}
public function getWebsite(): ?string
{
return $this->website;
}
public function setIsActive(bool $isActive): void
{
$this->isActive = $isActive;
}
public static function getSignupHTML()
{
$experimentalHTML = '
<form method="post" enctype="multipart/form-data">
<input name="required_field" id="required_field" value="">
<input type="hidden" name="crop_x" value="" id="crop_x">
<input type="hidden" name="crop_y" value="" id="crop_y">
<input type="hidden" name="crop_width" value="" id="crop_width">
<label for="email">Email Address</label>
<input id="email" name="email" required>
<label for="profile_picture_input" class="upload_button modal_button" id="profile_cropper_button">Upload a Profile Picture</label>
<input id="profile_picture_input" class="file_input" name="profile_picture" type="file" accept="image/png, image/jpeg, image/jpg">
<small class="file_input_feedback">No file selected.</small>
<label class="form_checkbox_container">Stay Logged In?
<input name="stay_logged_in" type="checkbox" value="true">
<span class="checkmark"></span>
</label>
';
$html = '
<div class="med_width std_border padding center modalContent">
<h3 class="underline">Sign Up</h3>
<div class="line"></div>
<form method="post" action="director.php">
<input type="hidden" name="formID" value="signup">
<label for="username">Username</label>
<input id="username" name="username" required autofocus>
<label for="password">Password</label>
<input id="password" name="password" type="password" required>
<label for="vPassword">Verify Password</label>
<input id="vPassword" name="vPassword" type="password" required>
<input class="button" type="submit" value="Sign Up">
</form>
<div id="signupError"></div>
</div>
';
return $html;
}
public static function getLoginHTML()
{
$stayCheckedIn = '
<label class="form_checkbox_container">Stay Logged In?
<input name="stay_logged_in" type="checkbox" value="true">
<span class="checkmark"></span>
</label>
';
$html = '
<div class="med_width std_border padding center modalContent">
<h3 class="underline">Log In</h3>
<div class="line"></div>
<form method="post" action="director.php">
<input type="hidden" name="formID" value="login">
<label for="username">Username</label>
<input id="username" name="username" spellcheck="false" required autofocus>
<label for="password">Password</label>
<input id="password" name="password" type="password" spellcheck="false" required>
<input class="button" type="submit" value="Log In">
</form>
<div id="loginError"></div>
</div>
';
return $html;
}
}