Comment writing added

This commit is contained in:
Zdenek Borovec 2024-05-04 23:02:24 +02:00
parent 8a67f70166
commit 87c9f9d188
5 changed files with 199 additions and 51 deletions

View file

@ -284,8 +284,13 @@ code {
height: 5em; height: 5em;
} }
.comment-content {
margin: 0.5em;
}
.comment-author { .comment-author {
margin: 0.5em; margin: 0.5em;
max-width: 100%;
display: inline-block; display: inline-block;
} }
@ -312,4 +317,5 @@ input[type=checkbox]:checked ~ .comment-response{
.comment-response { .comment-response {
display: none; display: none;
border-top: double black; border-top: double black;
padding: 0.5em;
} }

View file

@ -3,6 +3,9 @@
// Include config file // Include config file
include_once("config.php"); include_once("config.php");
// Include utils to have access to custom classes
include_once("utils.php");
// Start session // Start session
session_start(); session_start();

View file

@ -1,4 +1,26 @@
<?php <?php
/**
* Object to store info about logged in user
*/
class User
{
public $user_id;
public $user_name;
public $email;
public $permissions;
/**
* Constructor for the User.
*/
public function __construct($userId, $username, $email, $permissions) {
$this->user_id = $userId;
$this->user_name = $username;
$this->email = $email;
$this->permissions = $permissions;
}
}
/** /**
* Sanitize a given input string to be safe to display and process. * Sanitize a given input string to be safe to display and process.
*/ */

View file

@ -2,7 +2,6 @@
$COMMONS = $_SERVER['DOCUMENT_ROOT'] . "/../common"; $COMMONS = $_SERVER['DOCUMENT_ROOT'] . "/../common";
include_once($COMMONS."/header.php"); include_once($COMMONS."/header.php");
include_once($COMMONS."/utils.php");
class BlogpostComment class BlogpostComment
{ {
@ -10,6 +9,7 @@ class BlogpostComment
public $blogpost_id; public $blogpost_id;
public $poster_id; public $poster_id;
public $poster_name; public $poster_name;
public $parent_id;
public $timestamp; public $timestamp;
public $content; public $content;
public $children; public $children;
@ -32,13 +32,26 @@ class BlogpostComment
%s %s
</div> </div>
<div class=\"comment-response\"> <div class=\"comment-response\">
peepeepoopoo <form method=\"post\" action=\"%s\">
<input type=\"hidden\" name=\"blogpost_id\" value=\"%s\">
<input type=\"hidden\" name=\"comment_id\" value=\"%s\">
<label for=\"comment_entry\">Write response:</label>
<div class=\"centered-container\">
<textarea name=\"comment_entry\" class=\"comment-box\"> </textarea>
</div>
<input name=\"submit\" type=\"submit\" value=\"Send\">
</form>
</div> </div>
</div> </div>
<div class=\"comment-child-wrapper\"> <div class=\"comment-child-wrapper\">
", $this->poster_name, date("Y-m-d H:i", ",
strtotime($this->timestamp)), $this->comment_id, $this->comment_id, $this->poster_name, date("Y-m-d H:i", strtotime($this->timestamp)),
$this->content); $this->comment_id,
$this->comment_id,
$this->content,
htmlspecialchars($_SERVER["PHP_SELF"]),
$this->blogpost_id,
$this->comment_id);
if($this->children != null) { if($this->children != null) {
for($i = 0; $i < count($this->children); $i++) for($i = 0; $i < count($this->children); $i++)
@ -56,9 +69,8 @@ class BlogpostComment
public function load_children($conn) { public function load_children($conn) {
// Prepare new statement for selecting all the child comments. // Prepare new statement for selecting all the child comments.
$stmt = $conn->prepare("SELECT comment_id, poster_id, timestamp, $stmt = $conn->prepare("SELECT comment_id, poster_id, timestamp,
content, username FROM (blogpost_comments INNER JOIN users ON content FROM blogpost_comments WHERE blogpost_id = :blogpost_id AND
poster_id = user_id) WHERE blogpost_id = :blogpost_id parent_id = :comment_id ORDER BY timestamp ASC;");
AND parent_id = :comment_id ORDER BY timestamp ASC;");
// Bind and execute the comment select // Bind and execute the comment select
$stmt->bindParam(":blogpost_id", $this->blogpost_id); $stmt->bindParam(":blogpost_id", $this->blogpost_id);
@ -69,12 +81,37 @@ class BlogpostComment
$results_arr = $stmt->fetchall(PDO::FETCH_ASSOC); $results_arr = $stmt->fetchall(PDO::FETCH_ASSOC);
$comments_arr = []; $comments_arr = [];
// Prepare comment author selection statement
$stmt = $conn->prepare("SELECT username FROM users WHERE
user_id = :user_id;");
// Recursively fetch all the child comments // Recursively fetch all the child comments
for($i = 0; $i < count($results_arr); $i++) { for($i = 0; $i < count($results_arr); $i++) {
$com = $results_arr[$i]; $com = $results_arr[$i];
// If comment has a registered author, fetch their name
if($com["poster_id"]) {
$stmt->bindParam(":user_id", $com["poster_id"]);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
// If user was erased from database, set name to [Deleted]
if(!$result) {
$username = "[Deleted]";
}
else {
$username = $result["username"];
}
}
else {
$username = "[Guest]";
}
$commentObj = new BlogpostComment($com["comment_id"], $commentObj = new BlogpostComment($com["comment_id"],
$com["poster_id"], $com["username"], $this->blogpost_id, $com["poster_id"], $username, $this->blogpost_id,
$com["timestamp"], $com["content"]); $com["timestamp"], $com["content"], $this->comment_id);
$comments_arr[] = $commentObj; $comments_arr[] = $commentObj;
$commentObj->load_children($conn); $commentObj->load_children($conn);
} }
@ -90,15 +127,17 @@ class BlogpostComment
* $blogpost_id GUID of the blogpost this comment is under. * $blogpost_id GUID of the blogpost this comment is under.
* $timestamp Timestamp at comment creation. * $timestamp Timestamp at comment creation.
* $content Content of the comment. * $content Content of the comment.
* $parent_id GUID of the comment this is a reply to (or NULL).
*/ */
public function __construct($comment_id, $poster_id, $poster_name, public function __construct($comment_id, $poster_id, $poster_name,
$blogpost_id, $timestamp, $content) { $blogpost_id, $timestamp, $content, $parent_id) {
$this->comment_id = $comment_id; $this->comment_id = $comment_id;
$this->blogpost_id = $blogpost_id; $this->blogpost_id = $blogpost_id;
$this->poster_id = $poster_id; $this->poster_id = $poster_id;
$this->poster_name = $poster_name; $this->poster_name = $poster_name;
$this->timestamp = $timestamp; $this->timestamp = $timestamp;
$this->content = $content; $this->content = $content;
$this->parent_id = $parent_id;
} }
} }
@ -188,16 +227,42 @@ class Blogpost
} }
} }
/**
* Send a comment to the database.
* If the poster is not signed in, send "NULL" (as a string) as the $posterID
* The same goes for $parentId (that is the parent comment,
* if this one is a response)
* Returns: error message string or null on success.
*/
function send_comment($conn, $blogId, $posterId, $content, $parentId) {
// Prepare the statemtnt
$stmt = $conn->prepare("INSERT INTO blogpost_comments
( parent_id, blogpost_id, poster_id, content) VALUES
(:parent_id, :blogpost_id, :poster_id, :content);");
// Bind all the parameters
$stmt->bindValue(":parent_id", $parentId == "NULL"
? NULL : $parentId, PDO::PARAM_STR);
$stmt->bindValue(":blogpost_id", $blogId, PDO::PARAM_STR);
$stmt->bindValue(":poster_id", $posterId == "NULL"
? NULL : $posterId, PDO::PARAM_STR);
$stmt->bindValue(":content", $content, PDO::PARAM_STR);
// Execute the statement
$stmt->execute();
return null;
}
/** /**
* Load comments under a given blog. * Load comments under a given blog.
* Returns array of BlogpostComment objects. * Returns array of BlogpostComment objects.
*/ */
function load_comments($conn, $blogId) { function load_comments($conn, $blogId) {
// Prepare new statement for selecting all the "root" comments on the post. // Prepare new statement for selecting all the child comments.
$stmt = $conn->prepare("SELECT comment_id, poster_id, timestamp, content, $stmt = $conn->prepare("SELECT comment_id, poster_id, timestamp,
username FROM (blogpost_comments INNER JOIN users ON content FROM blogpost_comments WHERE blogpost_id = :blogpost_id
poster_id = user_id) WHERE blogpost_id = :blogpost_id AND AND parent_id IS NULL ORDER BY timestamp ASC;");
parent_id IS NULL ORDER BY timestamp ASC;");
// Bind and execute the comment select // Bind and execute the comment select
$stmt->bindParam(":blogpost_id", $blogId); $stmt->bindParam(":blogpost_id", $blogId);
@ -207,11 +272,36 @@ function load_comments($conn, $blogId) {
$results_arr = $stmt->fetchall(PDO::FETCH_ASSOC); $results_arr = $stmt->fetchall(PDO::FETCH_ASSOC);
$comments_arr = []; $comments_arr = [];
// Prepare comment author selection statement
$stmt = $conn->prepare("SELECT username FROM users WHERE
user_id = :user_id;");
// Recursively fetch all the child comments // Recursively fetch all the child comments
for($i = 0; $i < count($results_arr); $i++) { for($i = 0; $i < count($results_arr); $i++) {
$com = $results_arr[$i]; $com = $results_arr[$i];
// If comment has a registered author, fetch their name
if($com["poster_id"]) {
$stmt->bindParam(":user_id", $com["poster_id"]);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
// If user was erased from database, set name to [Deleted]
if(!$result) {
$username = "[Deleted]";
}
else {
$username = $result["username"];
}
}
else {
$username = "[Guest]";
}
$commentObj = new BlogpostComment($com["comment_id"], $com["poster_id"], $commentObj = new BlogpostComment($com["comment_id"], $com["poster_id"],
$com["username"], $blogId, $com["timestamp"], $com["content"]); $username, $blogId, $com["timestamp"], $com["content"], NULL);
$commentObj->load_children($conn); $commentObj->load_children($conn);
$comments_arr[] = $commentObj; $comments_arr[] = $commentObj;
} }
@ -277,6 +367,23 @@ if($conn == null){
die(); die();
} }
// If the method is post (user submitted a comment), try to post it,
// Refill the appropriate comment sumbmission form and display
// error message on error.
if(isset($_POST["submit"])) {
// Sanitise the user-submitted data
$blogId = sanitize_input($_POST["blogpost_id"]);
$commentContent = sanitize_input($_POST["comment_entry"]);
$parentId = isset($_POST["comment_id"]) ? $_POST["comment_id"] : "NULL";
$posterId = isset($_SESSION["current_user"]) ? $_SESSION["current_user"]->user_id : "NULL";
// Try to send the comment
send_comment($conn, $blogId, $posterId, $commentContent, $parentId);
// Redirect to this page with GET
header("Location: http://www.zdenekborovec-dev.cz/blog/article?guid=".$blogId);
}
// Get the blog id. // Get the blog id.
$blogId = sanitize_input($_GET["guid"]); $blogId = sanitize_input($_GET["guid"]);
@ -318,14 +425,18 @@ printf("
<article> <article>
<h2> Comments: </h2> <h2> Comments: </h2>
<form method=\"post\" action=\"%s\"> <form method=\"post\" action=\"%s\">
<label for=\"comment-entry\">Write comment</label> <input type=\"hidden\" name=\"blogpost_id\" value=\"%s\">
<label for=\"comment_entry\">Write a comment (%s):</label>
<div class=\"centered-container\"> <div class=\"centered-container\">
<textarea id=\"comment-entry\" class=\"comment-box\" tabindex=\"1\"> </textarea> <textarea name=\"comment_entry\" class=\"comment-box\" tabindex=\"1\"> </textarea>
</div> </div>
<input type=\"submit\" tabindex=\"2\" value=\"Send\"> <input name=\"submit\" type=\"submit\" tabindex=\"2\" value=\"Send\">
</form> </form>
</article> </article>
", htmlspecialchars($_SERVER["PHP_SELF"]), $blogId); ",
htmlspecialchars($_SERVER["PHP_SELF"]), $blogId,
isset($_SESSION["current_user"]) ? $_SESSION["current_user"]->user_name :
"Guest");
// Display the blog comments // Display the blog comments
$blogPost->display_comments(); $blogPost->display_comments();

View file

@ -2,22 +2,21 @@
$COMMONS = $_SERVER['DOCUMENT_ROOT'] . "/../common"; $COMMONS = $_SERVER['DOCUMENT_ROOT'] . "/../common";
include_once($COMMONS."/header.php"); include_once($COMMONS."/header.php");
include_once($COMMONS."/utils.php");
display_header("Login"); display_header("Login");
// Define previous attempt and error variables and set to empty values. // Define previous attempt and error variables and set to empty values.
$emailOld = $passwordOld = ""; $usernameOld = $passwordOld = "";
$emailErr = $passwordErr = ""; $usernameErr = $passwordErr = "";
/** /**
* Process the information, and if there are no errors, log the user in. * Process the information, and if there are no errors, log the user in.
*/ */
function attempt_login($email, $password) { function attempt_login($conn, $username, $password) {
// Access global variables // Access global variables
global $emailOld; global $usernameOld;
global $passwordOld; global $passwordOld;
global $emailErr; global $usernameErr;
global $passwordErr; global $passwordErr;
global $conn; global $conn;
@ -34,27 +33,27 @@ function attempt_login($email, $password) {
} }
// Sanitize inputs // Sanitize inputs
$email = sanitize_input($email); $username = sanitize_input($username);
$password = sanitize_input($password); $password = sanitize_input($password);
// Check if both fields are filled, if not, set appropriate error messages. // Check if both fields are filled, if not, set appropriate error messages.
if (empty($email)) if (empty($username))
$emailErr = "Please enter your email"; $usernameErr = "Please enter your email";
if (empty($password)) if (empty($password))
$passwordErr = "Please enter your password"; $passwordErr = "Please enter your password";
// If either of the fields were empty, // If either of the fields were empty,
// set old values for prefill and return. // set old values for prefill and return.
if(!empty($emailErr) || !empty($passwordErr)) { if(!empty($usernameErr) || !empty($passwordErr)) {
$emailOld = $email; $usernameOld = $username;
$passwordOld = $password; $passwordOld = $password;
return; return;
} }
// Prepare and bind the sql statement // Prepare and bind the sql statement
$stmt = $conn->prepare("SELECT user_id, username, email, password $stmt = $conn->prepare("SELECT user_id, email, password,
FROM users WHERE email = :email;"); created_at, permissions FROM users WHERE username = :username;");
$stmt->bindParam(":email", $email); $stmt->bindParam(":username", $username);
// Execute the statement // Execute the statement
$stmt->execute(); $stmt->execute();
@ -64,41 +63,48 @@ function attempt_login($email, $password) {
// If the user isn't in the database, set errors, old values, and return. // If the user isn't in the database, set errors, old values, and return.
if(!$result) { if(!$result) {
$emailOld = $email; $usernameOld = $username;
$passwordOld = $password; $passwordOld = $password;
$emailErr = "This user either doesn't exist, $usernameErr = "This user either doesn't exist,
or has a different password."; or has a different password.";
return; return;
} }
// Load results to variables // Load results to variables
$db_id = $result["user_id"]; $db_id = $result["user_id"];
$db_username = $result["username"];
$db_email = $result["email"]; $db_email = $result["email"];
$db_password = $result["password"]; $db_password = $result["password"];
$db_permissions = $result["permissions"];
// If user entered incorrect password, set errors, old values, and return. // If user entered incorrect password, set errors, old values, and return.
// Keep the error string the same as non-existing so that an attacker // Keep the error string the same as non-existing so that an attacker
// cannot asses whether a given user has an account. // cannot asses whether a given user has an account.
if(!password_verify($password, $db_password)){ if(!password_verify($password, $db_password)){
$emailOld = $email; $usernameOld = $username;
$passwordOld = $password; $passwordOld = $password;
$emailErr = "This user either doesn't exist, $usernameErr = "This user either doesn't exist,
or has a different password."; or has a different password.";
return; return;
} }
$_SESSION["user_id"] = $db_id; // Set the session logged in user.
$_SESSION["user_name"] = $db_username; $_SESSION["current_user"] = new User($db_id, $username,
$_SESSION["user_email"] = $db_email; $db_email, $db_permissions);
} }
/** /**
* If user sent the form, process it. * If user sent the form, process it.
* Either login user or set error message variables. * Either login user and redirect to index or set error message variables.
*/ */
if ($_SERVER["REQUEST_METHOD"] == "POST") { if (isset($_POST["submit"])) {
attempt_login($_POST["email"], $_POST["password"]); // Log user out
$_SESSION["current_user"] = null;
// Attempt to log in
attempt_login($conn, $_POST["username"], $_POST["password"]);
// If login succeeded, go to index
if($_SESSION["current_user"] != null) {
header("Location: "."http://www.zdenekborovec-dev.cz");
}
} }
?> ?>
@ -107,13 +113,13 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>"> echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
<h2> Login: </h2> <h2> Login: </h2>
<table class="noborder-table"><tr> <table class="noborder-table"><tr>
<td> Email: </td> <td> Username: </td>
<td> <td>
<input type="text" name="email" tabindex="1" <input type="text" name="username" tabindex="1"
autofocus="autofocus" value="<?php echo $emailOld;?>"> autofocus="autofocus" value="<?php echo $usernameOld;?>">
</td> </td>
<td> <td>
<?php echo $emailErr; ?> <?php echo $usernameErr; ?>
</td> </td>
</tr><tr> </tr><tr>
<td> Password: </td> <td> Password: </td>
@ -124,7 +130,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
<?php echo $passwordErr; ?> <?php echo $passwordErr; ?>
</td> </td>
</tr></table> </tr></table>
<input type="submit" tabindex="3" value="Send"> <input name="submit" type="submit" tabindex="3" value="Send">
</form> </form>
</article> </article>