HTML CSS JavaScript jQuery PHP Python MySQL

Commenting System with PHP, MySQL, and AJAX

Posted on by David Adams

Commenting System with PHP, MySQL, and AJAX

In this tutorial we'll be creating a commenting system with PHP, MySQL, and AJAX (JavaScript). The commenting system will add functionally to your website (blog, news website, etc) that your guests can use to submit content.

The commenting system we'll be creating today will be minimal, clean, and fast! And with the use of AJAX, you can easily implement this system on any webpage.

Submitted comments will be stored and retrieved in and from a MySQL database, and populated with PHP and HTML.

The Advanced package includes additional features and a download link to the source code.

1. Getting Started

You will need to install a web server environment if you're going to test the commenting system on your own computer system, follow the below instructions.

  • Install a web server environment solution package, I recommend you install XAMPP.
  • If you have your own production server (VPS, Dedicated, etc) you'll need to install PHP, Apache, MySQL, and phpMyAdmin (Note: these are already included with XAMPP).
  • Install a code editor, you can use Notepad but I don't recommend it, use one of the following instead: Notepad++, Visual Studio Code, or Atom.

2. Creating the Database and setting-up Tables

Now we need to create the MySQL database and create the comments table, we can do this with phpMyAdmin.

Navigate to phpMyAdmin (e.g. http://localhost/phpmyadmin/) in your browser and follow the below instructions:

  • Click the Databases tab at the top
  • Under Create database, type in phpcomments in the text box
  • Select utf8_general_ci as the collation (UTF-8 is the default encoding in HTML5)
  • Click Create

While the database is selected click the SQL tab and execute the following statement code:

SQL Copy
CREATE TABLE IF NOT EXISTS `comments` (
	`id` int(11) NOT NULL AUTO_INCREMENT,
	`page_id` int(11) NOT NULL,
	`parent_id` int(11) NOT NULL DEFAULT '-1',
	`name` varchar(255) NOT NULL,
	`content` text NOT NULL,
	`submit_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
	PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

INSERT INTO `comments` (`id`, `page_id`, `parent_id`, `name`, `content`, `submit_date`) VALUES
(1, 1, -1, 'John Doe', 'Thank you for taking the time to write this article, I really enjoyed reading it!\r\n\r\nThank you, David!', '2020-07-22 14:35:15'),
(2, 1, 11, 'David Adams', 'It''s good to hear that you enjoyed this article.', '2020-07-22 14:36:19'),
(3, 1, -1, 'Michael', 'I appreciate the time and effort you spent writing this article, good job!', '2020-07-22 14:37:43');

This will create the comments table with the following columns:

  • id — The unique comment ID.
  • page_id — This will determine which comment is for which page, it will be the page ID that you can specify on any webpage.
  • parent_id — The parent comment ID, this will be for comment replies.
  • name — The name of the user (e.g. Joe Bloggs).
  • content — The comment content, this will be what the user inputs.
  • submit_date — The date the comment was posted.

The data that we insert into the comments table will be for testing purposes.

On phpMyAdmin the table structure should look like the following:

http://localhost/phpmyadmin/
MySQL Comments Table Structure

3. Creating the Stylesheets (CSS3)

We'll be creating 2 stylesheets for our commenting system, one will be for our home page, this page will be used as an example of how we'll implement the commenting system, and the other stylesheet will be used for the commenting system itself.

Stylesheets are used to format the layout of our review system.

Create the style.css file and add:

CSS Copy
* {
    box-sizing: border-box;
    font-family: -apple-system, BlinkMacSystemFont, "segoe ui", roboto, oxygen, ubuntu, cantarell, "fira sans", "droid sans", "helvetica neue", Arial, sans-serif;
    font-size: 16px;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
body {
    background-color: #FFFFFF;
    margin: 0;
}
.navtop {
    background-color: #3f69a8;
    height: 60px;
    width: 100%;
    border: 0;
}
.navtop div {
    display: flex;
    margin: 0 auto;
    width: 1000px;
    height: 100%;
}
.navtop div h1, .navtop div a {
    display: inline-flex;
    align-items: center;
}
.navtop div h1 {
    flex: 1;
    font-size: 24px;
    padding: 0;
    margin: 0;
    color: #ecf0f6;
    font-weight: normal;
}
.navtop div a {
    padding: 0 20px;
    text-decoration: none;
    color: #c5d2e5;
    font-weight: bold;
}
.navtop div a i {
    padding: 2px 8px 0 0;
}
.navtop div a:hover {
    color: #ecf0f6;
}
.content {
    width: 1000px;
    margin: 0 auto;
}
.content h2 {
    margin: 0;
    padding: 25px 0;
    font-size: 22px;
    border-bottom: 1px solid #ebebeb;
    color: #666666;
}

Create the comments.css file and add:

CSS Copy
.comments .comment_header {
    display: flex;
    justify-content: space-between;
    border-bottom: 1px solid #eee;
    padding: 15px 0;
    margin-bottom: 10px;
    align-items: center;
}
.comments .comment_header .total {
    color: #777777;
    font-size: 14px;
}
.comments .comment_header .write_comment_btn {
    margin: 0;
}
.comments .write_comment_btn, .comments .write_comment button {
    display: inline-block;
    background-color: #565656;
    color: #fff;
    text-decoration: none;
    margin: 10px 0 0 0;
    padding: 5px 10px;
    border-radius: 5px;
    font-size: 14px;
    font-weight: 600;
    border: 0;
}
.comments .write_comment_btn:hover, .comments .write_comment button:hover {
    background-color: #636363;
}
.comments .write_comment {
    display: none;
    padding: 20px 0 10px 0;
}
.comments .write_comment textarea {
    width: 100%;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
    height: 150px;
    margin-top: 10px;
}
.comments .write_comment input {
    display: block;
    width: 250px;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
    margin-top: 10px;
}
.comments .write_comment button {
    cursor: pointer;
}
.comments .comment {
    padding-top: 10px;
}
.comments .comment .name {
    display: inline;
    padding: 0 5px 3px 0;
    margin: 0;
    font-size: 16px;
    color: #555555;
}
.comments .comment .date {
    color: #888888;
    font-size: 14px;
}
.comments .comment .content {
    padding: 5px 0 5px 0;
}
.comments .comment .reply_comment_btn {
    display: inline-block;
    text-decoration: none;
    margin-bottom: 10px;
    font-size: 14px;
    color: #888888;
}
.comments .comment .replies {
    padding-left: 30px;
}

Feel free to customize the stylesheets above and add your own rules.

4. Creating the Commenting System with PHP

We are now going to start coding our commenting system with PHP, in this section we're going to connect to the database using PDO, create the template functions, and execute queries using prepared statements (prevents SQL injection).

Create the comments.php file and add:

PHP Copy
<?php
// Update the details below with your MySQL details
$DATABASE_HOST = 'localhost';
$DATABASE_USER = 'root';
$DATABASE_PASS = '';
$DATABASE_NAME = 'phpcomments';
try {
    $pdo = new PDO('mysql:host=' . $DATABASE_HOST . ';dbname=' . $DATABASE_NAME . ';charset=utf8', $DATABASE_USER, $DATABASE_PASS);
} catch (PDOException $exception) {
    // If there is an error with the connection, stop the script and display the error
    exit('Failed to connect to database!');
}

The code above will connect to our MySQL database using the PDO interface, remember to update the connection variables if yours are different.

Add after:

PHP Copy
// Below function will convert datetime to time elapsed string
function time_elapsed_string($datetime, $full = false) {
    $now = new DateTime;
    $ago = new DateTime($datetime);
    $diff = $now->diff($ago);
    $diff->w = floor($diff->d / 7);
    $diff->d -= $diff->w * 7;
    $string = array('y' => 'year', 'm' => 'month', 'w' => 'week', 'd' => 'day', 'h' => 'hour', 'i' => 'minute', 's' => 'second');
    foreach ($string as $k => &$v) {
        if ($diff->$k) {
            $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
        } else {
            unset($string[$k]);
        }
    }
    if (!$full) $string = array_slice($string, 0, 1);
    return $string ? implode(', ', $string) . ' ago' : 'just now';
}

This function will convert our date and time to an elapsed string, in the comments section this will appear as "1 day ago" etc.

Add after:

PHP Copy
// This function will populate the comments and comments replies using a loop
function show_comments($comments, $parent_id = -1) {
    $html = '';
    if ($parent_id != -1) {
        // If the comments are replies sort them by the "submit_date" column
        array_multisort(array_column($comments, 'submit_date'), SORT_ASC, $comments);
    }
    // Iterate the comments using the foreach loop
    foreach ($comments as $comment) {
        if ($comment['parent_id'] == $parent_id) {
            // Add the comment to the $html variable
            $html .= '
            <div class="comment">
                <div>
                    <h3 class="name">' . htmlspecialchars($comment['name'], ENT_QUOTES) . '</h3>
                    <span class="date">' . time_elapsed_string($comment['submit_date']) . '</span>
                </div>
                <p class="content">' . nl2br(htmlspecialchars($comment['content'], ENT_QUOTES)) . '</p>
                <a class="reply_comment_btn" href="#" data-comment-id="' . $comment['id'] . '">Reply</a>
                ' . show_write_comment_form($comment['id']) . '
                <div class="replies">
                ' . show_comments($comments, $comment['id']) . '
                </div>
            </div>
            ';
        }
    }
    return $html;
}

This function will populate the array of comments and return the value in HTML format, the replies are populated by executing the same function along with the parent comment ID.

The htmlspecialchars function will convert special characters to HTML entities, this will prevent XSS attacks.

Add after:

PHP Copy
// This function is the template for the write comment form
function show_write_comment_form($parent_id = -1) {
    $html = '
    <div class="write_comment" data-comment-id="' . $parent_id . '">
        <form>
            <input name="parent_id" type="hidden" value="' . $parent_id . '">
            <input name="name" type="text" placeholder="Your Name" required>
            <textarea name="content" placeholder="Write your comment here..." required></textarea>
            <button type="submit">Submit Comment</button>
        </form>
    </div>
    ';
    return $html;
}

This function contains the template for our "write comment" form, this form will be used by visitors to write comments and submit them.

Add after:

PHP Copy
// Page ID needs to exist, this is used to determine which comments are for which page
if (isset($_GET['page_id'])) {
    // Check if the submitted form variables exist
    if (isset($_POST['name'], $_POST['content'])) {
        // POST variables exist, insert a new comment into the MySQL comments table (user submitted form)
        $stmt = $pdo->prepare('INSERT INTO comments (page_id, parent_id, name, content, submit_date) VALUES (?,?,?,?,NOW())');
        $stmt->execute([ $_GET['page_id'], $_POST['parent_id'], $_POST['name'], $_POST['content'] ]);
        exit('Your comment has been submitted!');
    }
    // Get all comments by the Page ID ordered by the submit date
    $stmt = $pdo->prepare('SELECT * FROM comments WHERE page_id = ? ORDER BY submit_date DESC');
    $stmt->execute([ $_GET['page_id'] ]);
    $comments = $stmt->fetchAll(PDO::FETCH_ASSOC);
    // Get the total number of comments
    $stmt = $pdo->prepare('SELECT COUNT(*) AS total_comments FROM comments WHERE page_id = ?');
    $stmt->execute([ $_GET['page_id'] ]);
    $comments_info = $stmt->fetch(PDO::FETCH_ASSOC);
} else {
    exit('No page ID specified!');
}
?>

The code above will check if the page ID variable is specified as this is used to determine which comments to show on which page. If the page ID is not specified, stop the script and output the error.

Comments are then retrieved from the database (ordered by the submit date in descending order) and are stored in an associative array, the total number of comments is calculated using the COUNT(*) function.

Add after:

PHP Copy
<div class="comment_header">
    <span class="total"><?=$comments_info['total_comments']?> comments</span>
    <a href="#" class="write_comment_btn" data-comment-id="-1">Write Comment</a>
</div>

<?=show_write_comment_form()?>

<?=show_comments($comments)?>

This is the template for our commenting system, the comments are populated by executing the show_comments() function along with the comments associative array variable that we previously defined.

The show_write_comment_form() function will show the form that visitors can use to write and submit comments.

That's everything we need to code in this file, the next step is to implement the reviews system on a webpage using AJAX.

5. Implementing the Commenting System into our Webpage with AJAX

Now that we have our server-side PHP file created we can now implement the comment system on our webpage.

Create the index.html file and add:

HTML Copy
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Comments System</title>
		<link href="style.css" rel="stylesheet" type="text/css">
		<link href="comments.css" rel="stylesheet" type="text/css">
	</head>
	<body>

	    <nav class="navtop">
	    	<div>
	    		<h1>Comments System</h1>
	    	</div>
	    </nav>

		<div class="content home">

			<h2>Article</h2>

			<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam tristique vel leo a vestibulum. Praesent varius ex elit, vitae pretium felis laoreet in. Nullam sit amet pretium nulla. Aliquam convallis sem vitae tincidunt pulvinar. Integer id ex efficitur, vulputate ante et, vulputate risus. Maecenas ac nunc est. Donec nisl turpis, aliquet quis turpis mollis, dictum pulvinar est. Vivamus ut suscipit turpis. Sed metus leo, dignissim non vehicula non, tincidunt ac velit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>

			<p>Nunc id lacinia mauris. Aliquam pellentesque orci et neque egestas, vel lobortis risus egestas. Curabitur non rhoncus nibh. Donec ante lorem, luctus eget ex eget, malesuada ornare nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam consectetur egestas magna non dignissim. Pellentesque sit amet mollis mauris. Nunc quis arcu ac diam tempus auctor. Proin nec commodo nisl. Duis gravida lorem quis ipsum mattis, id finibus tortor pretium. Nam maximus pretium nisi, ullamcorper tincidunt dolor sagittis ac. Donec suscipit neque lectus, id fringilla tortor pellentesque ut. Maecenas quam lectus, pharetra vitae commodo sit amet, iaculis quis massa. Aenean varius quam quis posuere viverra. Nullam varius condimentum sem, sit amet bibendum augue porttitor in.</p>

			<p>Morbi purus turpis, finibus vel fermentum nec, egestas eu elit. Fusce eleifend ac massa sit amet eleifend. Suspendisse sit amet facilisis augue. Praesent vitae dui lacus. Suspendisse sodales nisl massa, quis vehicula ante rutrum vitae. Proin scelerisque vestibulum purus, ac ultrices sapien malesuada vel. Proin sit amet tristique orci. Vestibulum in tortor ante.</p>
			
		</div>

	</body>
</html>

This is the sample page we'll use to display our comments, the file does not need to be in PHP format because we'll use AJAX to retrieve the comments from our comments.php page.

Add this code just before the closing body tag:

HTML Copy
<div class="comments"></div>

<script>
const comments_page_id = 1; // This number should be unique on every page
fetch("comments.php?page_id=" + comments_page_id).then(response => response.text()).then(data => {
	document.querySelector(".comments").innerHTML = data;
	document.querySelectorAll(".comments .write_comment_btn, .comments .reply_comment_btn").forEach(element => {
		element.onclick = event => {
			event.preventDefault();
			document.querySelectorAll(".comments .write_comment").forEach(element => element.style.display = 'none');
			document.querySelector("div[data-comment-id='" + element.getAttribute("data-comment-id") + "']").style.display = 'block';
			document.querySelector("div[data-comment-id='" + element.getAttribute("data-comment-id") + "'] input[name='name']").focus();
		};
	});
	document.querySelectorAll(".comments .write_comment form").forEach(element => {
		element.onsubmit = event => {
			event.preventDefault();
			fetch("comments.php?page_id=" + comments_page_id, {
				method: 'POST',
				body: new FormData(element)
			}).then(response => response.text()).then(data => {
				element.parentElement.innerHTML = data;
			});
		};
	});
});
</script>

The JavaScript code above will retrieve the comments using the fetch API and append them to the comments container.

If you're going to add comments on a different page just remember to update the comments_page_id variable, the number should be unique on every page (unless you're going to display the same comments).

And now if we navigate to this file in our web browser (over localhost), we should see something like the following:

http://localhost/phpcomments/index.html
PHP Comments System

Remember to test the commenting system features and make sure everything is working as it should.

Conclusion

Congratulations! You've successfully created a commenting system with PHP, MySQL, and AJAX.

What next? Consider implementing your own features to the system and integrate the system with your own projects.

Feel free to share this article and drop a comment if you've enjoyed it.

If you would like to support us consider purchasing a package below, this will greatly help us create more tutorials and keep our server up and running, packages include improved code and more features.

Advanced

Source code
Database SQL file
Secure commenting system
Home page sample
Comments JavaScript class
Sort by feature (votes, newest, oldest)
Comment votes feature
Comment photo feature
Search feature
Pagination feature
Improved code
Responsive Design (mobile-friendly)
SCSS file
Commented code
Free updates & support (bugs and minor issues)
User Guide
* Payments are processed with PayPal/Stripe.
* Advanced package also includes the tutorial source.

$10.00

Buy with PayPal
Download
Buy with Stripe
Download