Introduce User and DatabaseHandle class

This commit is contained in:
Floorb 2021-07-17 18:17:29 -04:00
parent cbcfe5cb76
commit 8f940d718d
15 changed files with 151 additions and 104 deletions

24
fav.php
View file

@ -6,28 +6,18 @@ require_once('includes/functions.php');
// UTF-8
header('Content-Type: text/html; charset=utf-8');
$date = date('jS F Y');
$ip = $_SERVER['REMOTE_ADDR'];
if (isset($_POST['fid']) && isset($_SESSION['token'])) {
$f_user = htmlspecialchars($_SESSION['username']);
$f_pasteid = Trim(htmlspecialchars($_POST['fid']));
$f_pasteid = preg_replace('/[^0-9]/', '', $f_pasteid);
$f_pasteid = (int)filter_var($f_pasteid, FILTER_SANITIZE_NUMBER_INT);
$f_time = gmmktime(date("H"), date("i"), date("s"), date("n"), date("j"), date("Y"));
$query = $conn->prepare('SELECT 1 FROM pins WHERE f_paste = ? AND m_fav = ?');
$query->execute([$f_pasteid, $f_user]);
if ($current_user && !empty($_POST['fid'])) {
$paste_id = intval($_POST['fid']);
$query = $conn->prepare('SELECT 1 FROM pins WHERE paste_id = ? AND user_id = ?');
$query->execute([$paste_id, $current_user->user_id]);
if ($query->fetch()) { /* Already favorited */
$query = $conn->prepare('DELETE FROM pins WHERE f_paste = ? AND m_fav = ?');
$query = $conn->prepare('DELETE FROM pins WHERE paste_id = ? AND user_id = ?');
} else {
$query = $conn->prepare('INSERT INTO pins (m_fav, f_paste, f_time) VALUES (?, ?, NOW())');
$query = $conn->prepare('INSERT INTO pins (paste_id, user_id, f_time) VALUES (?, ?, NOW())');
}
$query->execute([$f_pasteid, $f_user]);
$query->execute([$paste_id, $current_user->user_id]);
$error = 'Paste has been favorited.';
}

View file

@ -0,0 +1,32 @@
<?php
class DatabaseHandle {
private static DatabaseHandle $instance;
private PDO $conn;
public function __construct(string $conString, string $username, string $password) {
$this->conn = new PDO($conString, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false
]);
}
public function query(string $query, array $params = null) : PDOStatement {
if (empty($params)) {
return $this->conn->query($query);
}
$stmt = $this->conn->prepare($query);
$stmt->execute($params);
return $stmt;
}
public static function get() {
if (DatabaseHandle::$instance === null) {
DatabaseHandle::$instance = new DatabaseHandle();
}
return DatabaseHandle::$instance;
}
}

54
includes/User.class.php Normal file
View file

@ -0,0 +1,54 @@
<?php
class User {
public int $user_id;
public string $username;
private function __construct(array $row) {
$this->user_id = intval($row['user_id']);
$this->username = $row['username'];
}
public static function current(DatabaseHandle $conn) : User | null {
$session_user = User::createFromPhpSession($conn);
if ($session_user !== null) {
return $session_user;
}
if (!empty($_COOKIE['_ponepaste_token']) &&
($token_user = User::createFromRememberToken($conn, $_COOKIE['_ponepaste_token']))) {
$_SESSION['user_id'] = $token_user->user_id;
return $token_user;
}
return null;
}
public static function createFromRememberToken(DatabaseHandle $conn, string $remember_token) : User | null {
$result = $conn->query(
'SELECT users.id AS id, users.username AS username
FROM user_sessions
INNER JOIN users ON users.id = user_sessions.user_id
WHERE user_sessions.token = ?', [$remember_token]
);
if ($row = $result->fetch()) {
return new User($row);
}
return null;
}
public static function createFromPhpSession(DatabaseHandle $conn) : User | null {
if (empty($_SESSION['user_id'])) {
return null;
}
$user_id = intval($_SESSION['user_id']);
$row = $conn->query('SELECT id, username FROM users WHERE id = ?', [$user_id])->fetch();
return $row ? new User($row) : null;
}
}

View file

@ -5,6 +5,8 @@ if (!defined('IN_PONEPASTE')) {
require_once(__DIR__ . '/config.php');
require_once(__DIR__ . '/functions.php');
require_once(__DIR__ . '/DatabaseHandle.class.php');
require_once(__DIR__ . '/User.class.php');
/* View functions */
function urlForPaste($paste_id) : string {
@ -47,18 +49,6 @@ function getSiteTotal_unique_views(PDO $conn) : int {
return intval($conn->query('SELECT tvisit FROM page_view ORDER BY id DESC LIMIT 1')->fetch(PDO::FETCH_NUM)[0]);
}
function getCurrentUser(PDO $conn) : array | null {
if (empty($_SESSION['username'])) {
return null;
}
$query = $conn->prepare('SELECT * FROM users WHERE username = ?');
$query->execute([$_SESSION['username']]);
return $query->fetch();
}
/**
* Specialization of `htmlentities()` that avoids double escaping and uses UTF-8.
*
@ -115,6 +105,8 @@ $conn = new PDO(
$db_opts
);
$new_conn = new DatabaseHandle("mysql:host=$db_host;dbname=$db_schema;charset=utf8", $db_user, $db_pass);
// Setup site info
$site_info = getSiteInfo();
$row = $site_info['site_info'];
@ -147,9 +139,7 @@ if ($site_permissions) {
$privatesite = $siteprivate;
$noguests = $disableguest;
if (isset($_SESSION['username'])) {
$noguests = "off";
}
// Prevent a potential LFI (you never know :p)
$lang_file = "${default_lang}.php";
@ -164,8 +154,7 @@ if (is_banned($conn, $ip)) die($lang['banned']); // "You have been banned from "
// Logout
if (isset($_GET['logout'])) {
header('Location: ' . $_SERVER['HTTP_REFERER']);
unset($_SESSION['token']);
unset($_SESSION['username']);
unset($_SESSION['user_id']);
unset($_SESSION['pic']);
session_destroy();
}
@ -175,4 +164,9 @@ $total_pastes = getSiteTotalPastes($conn);
$total_page_views = getSiteTotalviews($conn);
$total_unique_views = getSiteTotal_unique_views($conn);
$current_user = getCurrentUser($conn);
$current_user = User::current($new_conn);
//$current_user = getCurrentUser($conn);
if ($current_user) {
$noguests = "off";
}

View file

@ -31,8 +31,9 @@ function verifyCaptcha() : string|bool {
global $mode;
global $recaptcha_secretkey;
global $lang;
global $current_user;
if ($cap_e == "on" && !isset($_SESSION['username'])) {
if ($cap_e == "on" && !$current_user) {
if ($mode == "reCAPTCHA") {
$response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=" . $recaptcha_secretkey . "&response=" . $_POST['g-recaptcha-response']);
$response = json_decode($response, true);
@ -104,8 +105,6 @@ header('Content-Type: text/html; charset=utf-8');
$date = date('jS F Y');
$ip = $_SERVER['REMOTE_ADDR'];
$current_user = getCurrentUser($conn);
// Sitemap
$site_sitemap_rows = $conn->query('SELECT * FROM sitemap_options LIMIT 1');
if ($row = $site_sitemap_rows->fetch()) {

View file

@ -26,8 +26,9 @@ $ip = $_SERVER['REMOTE_ADDR'];
// Check if already logged in
if (isset($_SESSION['token'])) {
if ($current_user !== null) {
header("Location: ./");
die();
}
// Page title
@ -84,8 +85,7 @@ if (isset($_POST['forgot'])) {
$error = $lang['banned'];
} else {
// Login successful
$_SESSION['token'] = md5($db_id . $username);
$_SESSION['username'] = $username;
$_SESSION['user_id'] = $row['id'];
header('Location: ' . $_SERVER['HTTP_REFERER']);
exit();

View file

@ -28,10 +28,12 @@ $p_title = $lang['myprofile']; //"My Profile";
// Check if already logged in
if (!isset($_SESSION['token'])) {
if ($current_user === null) {
header("Location: ./login.php");
die();
}
$user_username = htmlentities(trim($_SESSION['username']));
$user_username = $current_user->username;
$query = $conn->prepare('SELECT * FROM users WHERE username = ?');
$query->execute([$user_username]);

View file

@ -6,21 +6,15 @@ require_once('includes/functions.php');
// UTF-8
header('Content-Type: text/html; charset=utf-8');
$date = date('jS F Y');
$ip = $_SERVER['REMOTE_ADDR'];
//Report paste
$p_reasonrep = Trim(htmlspecialchars($_POST['reasonrep']));
if (isset($_SESSION['token'])) {
$p_memreport = htmlspecialchars($_SESSION['username']);
} else {
$p_memreport = "Guest";
}
$p_pastereport = Trim(htmlspecialchars($_POST['reppasteid']));
$p_reporttime = gmmktime(date("H"), date("i"), date("s"), date("n"), date("j"), date("Y"));
$p_memreport = $current_user ? $current_user ->username : 'Guest';
$p_pastereport = $_POST['reppasteid'];
$p_reasonrep = preg_replace("/[^0-9]/", "", $p_reasonrep);
$conn->prepare('INSERT INTO user_reports (m_report, p_report, t_report, rep_reason) VALUES (?, ?, ?, ?)')
->execute([$p_memreport, $p_pastereport, $p_reporttime, $p_reasonrep]);
$conn->prepare('INSERT INTO user_reports (m_report, p_report, t_report, rep_reason) VALUES (?, ?, NOW(), ?)')
->execute([$p_memreport, $p_pastereport, $p_reasonrep]);
$repmes = "Paste has been reported.";

View file

@ -76,9 +76,8 @@ $start = $time;
<div id="navMenuDocumentation" class="navbar-menu">
<div class="navbar-end">
<div class="navbar-item">
<?php if (isset($_SESSION['token'])) {
if (isset($privatesite) && $privatesite == "on") { // Hide if site is private
} else {
<?php if ($current_user !== null) {
if (!isset($privatesite) || $privatesite !== "on") {
if ($mod_rewrite == '1') {
echo ' <a class="button navbar-item mx-2" href="' . '//' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['PHP_SELF']), '/\\') . '/">
<span class="icon has-text-info">
@ -124,13 +123,13 @@ $start = $time;
}
}
echo '<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" role="presentation">' . $_SESSION['username'] . '</a>
<a class="navbar-link" role="presentation">' . pp_html_escape($current_user->username) . '</a>
<div class="navbar-dropdown">';
if ($mod_rewrite == '1') {
echo '<a class="navbar-item" href="' . '//' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['PHP_SELF']), '/\\') . '/user/' . $_SESSION['username'] . '">Pastes</a>';
echo '<a class="navbar-item" href="' . '//' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['PHP_SELF']), '/\\') . '/user/' . urlencode($current_user->username) . '">Pastes</a>';
echo '<a class="navbar-item" href="' . '//' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['PHP_SELF']), '/\\') . '/profile">Settings</a>';
} else {
echo '<a class="navbar-item" href="' . '//' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['PHP_SELF']), '/\\') . '/user.php?user=' . $_SESSION['username'] . '">Pastes</a>';
echo '<a class="navbar-item" href="' . '//' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['PHP_SELF']), '/\\') . '/user.php?user=' . urlencode($current_user->username) . '">Pastes</a>';
echo '<a class="navbar-item" href="' . '//' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['PHP_SELF']), '/\\') . '/profile.php">Settings</a>';
}
echo '<hr class="navbar-divider">
@ -141,8 +140,7 @@ $start = $time;
<?php } else { ?>
<div class="buttons">
<?php
if (isset($privatesite) && $privatesite == "on") { // Hide if site is private
} else {
if (!isset($privatesite) || $privatesite != "on") {
if ($mod_rewrite == '1') {
echo '<a class="button navbar-item mx-2" href="' . '//' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['PHP_SELF']), '/\\') . '/archive">
<span class="icon has-text-info">

View file

@ -83,7 +83,7 @@
</div>
<div class="column">
<?php
if (isset($site_ads) && !isset($_SESSION['username'])) {
if (isset($site_ads) && $current_user === null) {
echo $site_ads['ads_2'];
}
?>
@ -139,7 +139,7 @@
</div>
<div class="column">
<?php
if (isset($site_ads) && !isset($_SESSION['username'])) {
if (isset($site_ads) && $current_user === null) {
echo $site_ads['ads_2'];
}
?>
@ -187,7 +187,7 @@
</div>
<div class="column">
<?php
if (isset($site_ads) && !isset($_SESSION['username'])) {
if (isset($site_ads) && $current_user === null) {
echo $site_ads['ads_2'];
}
?>
@ -206,7 +206,7 @@
</div>
<div class="column">
<?php
if (isset($site_ads) && !isset($_SESSION['username'])) {
if (isset($site_ads) && $current_user === null) {
echo $site_ads['ads_2'];
}
?>

View file

@ -329,7 +329,7 @@
<option value="1" <?php echo ($post_visibility == "1") ? 'selected="selected"' : ''; ?>>
Unlisted
</option>
<?php if (isset($_SESSION['token'])) { ?>
<?php if ($current_user) { ?>
<option value="2" <?php echo ($post_visibility == "2") ? 'selected="selected"' : ''; ?>>
Private
</option>
@ -385,14 +385,14 @@
<!-- $text_ads -->
<?php
// don't display ads for logged in users.
if (!empty($site_ads) && !isset($_SESSION['username'])) {
if (!empty($site_ads) && $current_user === null) {
echo $site_ads['text_ads'];
}
?>
</div>
<div class="column is-4">
<!-- ReCaptcha & Captcha -->
<?php if ($cap_e == "on" && !isset($_SESSION['username'])) {
<?php if ($cap_e == "on" && $current_user === null) {
if ($_SESSION['captcha_mode'] == "recaptcha") {
?>
<div class="g-recaptcha" style="float: right; right: 0;"

View file

@ -21,7 +21,7 @@
<div class="bd-duo">
<div class="bd-lead">
<h1 class="title is-5"><?php echo $lang['totalpastes'] . ' ' . $total_user_pastes ?></h1>
<h1 class="subtitle is-6"><?php echo '<a href="user.php?user=' . $_SESSION['username'] . '" target="_self">' . $lang['mypastes'] . '</a>'; ?></h1>
<h1 class="subtitle is-6"><?php echo '<a href="user.php?user=' . urlencode($current_user->username) . '" target="_self">' . $lang['mypastes'] . '</a>'; ?></h1>
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if (isset($success)) {
@ -58,7 +58,7 @@
<label class="label">Username</label>
<div class="control has-icons-left has-icons-right">
<input disabled="" type="text" class="input" name="username"
style="cursor:not-allowed;" placeholder="<?php echo $user_username; ?>">
style="cursor:not-allowed;" placeholder="<?php echo pp_html_escape($current_user->username); ?>">
<span class="icon is-small is-left">
<i class="fas fa-user"></i>
</span>

View file

@ -32,7 +32,7 @@ $protocol = paste_protocol();
})
});
</script>
<?php if (isset($_SESSION['token'])) { ?>
<?php if ($current_user) { ?>
<script>
$(document).ready(function () {
$('#favs').DataTable({
@ -119,7 +119,7 @@ $protocol = paste_protocol();
?>
<?php
if ($_SESSION['username'] == $profile_username) {
if ($current_user && $current_user->username === $profile_username) {
?>
<?php echo $lang['profile-stats']; ?><br/>
<?php echo $lang['totalpastes'] . ' ' . $profile_total_pastes; ?> &mdash;
@ -146,12 +146,12 @@ $protocol = paste_protocol();
<tr>
<td><?php echo $lang['pastetitle']; ?></td>
<td><?php echo $lang['pastetime']; ?></td>
<?php if (isset($_SESSION) && $_SESSION['username'] == $profile_username) {
<?php if ($is_current_user) {
echo "<td>" . $lang['visibility'] . "</td>";
} ?>
<td><?php echo $lang['pasteviews']; ?></td>
<td><?php echo $lang['tags']; ?></td>
<?php if (isset($_SESSION) && $_SESSION['username'] == $profile_username) {
<?php if ($is_current_user) {
echo "<td>" . $lang['delete'] . "</td>";
} ?>
</tr>
@ -160,12 +160,12 @@ $protocol = paste_protocol();
<tr>
<td><?php echo $lang['pastetitle']; ?></td>
<td><?php echo $lang['pastedate']; ?></td>
<?php if (isset($_SESSION) && $_SESSION['username'] == $profile_username) {
<?php if ($is_current_user) {
echo "<td>" . $lang['visibility'] . "</td>";
} ?>
<td><?php echo $lang['pasteviews']; ?></td>
<td><?php echo $lang['tags']; ?></td>
<?php if (isset($_SESSION) && $_SESSION['username'] == $profile_username) {
<?php if ($is_current_user) {
echo "<td>" . $lang['delete'] . "</td>";
} ?>
</tr>
@ -202,7 +202,7 @@ $protocol = paste_protocol();
$title = truncate($title, 20, 50);
// Guests only see public pastes
if (!isset($_SESSION['token']) || $_SESSION['username'] != $profile_username) {
if (!$is_current_user) {
if ($row['visible'] == 0) {
echo '<tr>
<td>
@ -254,7 +254,7 @@ $protocol = paste_protocol();
</tbody>
</table>
</div>
<?php if ($_SESSION['username'] == $profile_username) { ?>
<?php if ($is_current_user) { ?>
<div class="tab-content" id="second-tab">
<table id="favs" class="table is-fullwidth is-hoverable">
<thead>

View file

@ -372,7 +372,6 @@ $selectedloader = "$bg[$i]"; // set variable equal to which random filename was
<!-- Expiry -->
<div class="select">
<select name="paste_expire_date">
<?php// if (isset($_SESSION['token'])) {?>
<option value="N" selected="selected">Never</option>
<option value="self">View Once</option>
<option value="10M">10 Minutes</option>
@ -381,17 +380,6 @@ $selectedloader = "$bg[$i]"; // set variable equal to which random filename was
<option value="1W">1 Week</option>
<option value="2W">2 Weeks</option>
<option value="1M">1 Month</option>
<?php// } else { ?>
<!--
<option value="1D" selected="selected">1 Day</option>
<option value="self">View Once</option>
<option value="10M">10 Minutes</option>
<option disabled >1 Week (Register)</option>
<option disabled >2 Weeks (Register)</option>
<option disabled >1 Month (Register)</option>
<option disabled >Never (Register)</option>
-->
<?php// } ?>
</select>
</div>
</div>
@ -413,7 +401,7 @@ $selectedloader = "$bg[$i]"; // set variable equal to which random filename was
<option value="1" <?php echo ($p_visible == "1") ? 'selected="selected"' : ''; ?>>
Unlisted
</option>
<?php if (isset($_SESSION['token'])) { ?>
<?php if ($current_user) { ?>
<option value="2" <?php echo ($p_visible == "2") ? 'selected="selected"' : ''; ?>>
Private
</option>
@ -535,7 +523,7 @@ $selectedloader = "$bg[$i]"; // set variable equal to which random filename was
});
</script>
<?php if (isset($_SESSION['token'])) { ?>
<?php if ($current_user) { ?>
<script>
$(document).ready(function () {
$('#favorite').on('click', null, function () {

View file

@ -23,9 +23,6 @@ header('Content-Type: text/html; charset=utf-8');
$date = date('jS F Y');
$ip = $_SERVER['REMOTE_ADDR'];
// If username defined in URL, then check if it's exists in database. If invalid, redirect to main site.
$user_username = trim($_SESSION['username']);
if (empty($_GET['user'])) {
// No username provided
header("Location: ../error.php");
@ -48,18 +45,17 @@ $p_title = $profile_username . $lang['user_public_pastes']; // "Username's Publi
// Favorite Counts
$query = $conn->prepare(
'SELECT COUNT(*) AS total_favs FROM pins INNER JOIN pastes ON pastes.id = pins.paste_id WHERE pins.paste_id = ?'
'SELECT COUNT(*) FROM pins INNER JOIN pastes ON pastes.id = pins.paste_id WHERE pins.paste_id = ?'
);
$query->execute([$profile_info['id']]);
$total_pfav = intval($query->fetch(PDO::FETCH_NUM)[0]);
$query = $conn->prepare(
'SELECT COUNT(*) AS total_favs
FROM pins INNER JOIN users ON users.id = pins.user_id
WHERE users.username = ?'
'SELECT COUNT(*)
FROM pins INNER JOIN users ON users.id = pins.user_id
WHERE users.id = ?'
);
$query->execute([$profile_username]);
$query->execute([$profile_info['id']]);
$total_yfav = intval($query->fetch(PDO::FETCH_NUM)[0]);
// Badges
@ -94,19 +90,19 @@ $profile_total_paste_views = intval($query->fetch(PDO::FETCH_NUM)[0]);
$profile_join_date = $profile_info['date'];
$profile_pastes = getUserPastes($conn, $profile_info['id']);
$is_current_user = ($current_user !== null) && ($profile_info['id'] == $current_user->user_id);
updatePageViews($conn);
if (isset($_GET['del'])) {
if ($_SESSION['token']) { // Prevent unauthorized deletes
if ($current_user !== null) { // Prevent unauthorized deletes
$paste_id = intval(trim($_GET['id']));
$query = $conn->prepare('SELECT user_id FROM pastes WHERE id = ?');
$query->execute([$paste_id]);
$result = $query->fetch();
if (empty($result) || $result['user_id'] !== $profile_info['id']) {
if (empty($result) || $result['user_id'] !== $current_user->user_id) {
$error = $lang['delete_error_invalid']; // Does not exist or not paste owner
} else {
$query = $conn->prepare('DELETE FROM pastes WHERE id = ?');