use php to build multi level comment system

use php to build multi level comment system

multi level comment system

http://www.roytuts.com/nested-comment-system-in-php-ajax/

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Nested or hierarchical comment system in PHP, AJAX, Jquery</title>
<link rel="stylesheet" href="comments.css">
<script src="js/jquery-1.9.1.min.js"></script>
<script src="js/jquery-ui-1.10.3-custom.min.js"></script>
<script src="js/jquery-migrate-1.2.1.js"></script>
<script src="js/jquery.blockUI.js"></script>
<script src="comments_blog.js"></script>
</head>
<body>
<?php
require("comments.php");
?>
<div style="width: 600px;">
<div id="comment_wrapper">
<div id="comment_form_wrapper">
<div id="comment_resp"></div>
<h4>Please Leave a Reply<a href="javascript:void(0);" id="cancel-comment-reply-link">Cancel Reply</a></h4>
<form id="comment_form" name="comment_form" action="" method="post">
<div>
Name<input type="text" name="comment_name" id="comment_name" size="54"/>
</div>
<div>
Email<input type="text" name="comment_email" id="comment_email" size="54"/>
</div>
<div>
Website<input type="text" name="comment_web" id="comment_web" size="54"/>
</div>
<div>
Comment<textarea name="comment_text" id="comment_text" rows="6"></textarea>
</div>
<div>
<input type="hidden" name="reply_id" id="reply_id" value=""/>
<input type="hidden" name="depth_level" id="depth_level" value=""/>
<input type="submit" name="comment_submit" id="comment_submit" value="Post Comment" class="button"/>
</div>
</form>
</div>
<?php
echo $comments;
?>
</div>
</div>
</body>
</html>

create table in mysql

1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE `comment` (
`comment_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`comment_text` text NOT NULL,
`parent_id` int(10) unsigned NOT NULL,
`ip_address` varchar(20) NOT NULL,
`email_address` varchar(100) NOT NULL,
`web_address` varchar(255) DEFAULT NULL,
`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created_by` varchar(45) NOT NULL,
PRIMARY KEY (`comment_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

comments.php

1
2
3
4
5
6
7
8
9
10
11
<?php
require("helper.php");
require("config.php");
$sql = "SELECT * FROM comment";
$results = mysqli_query($con,$sql);
$items = array();
while ($row = mysqli_fetch_assoc($results)) {
$items[] = $row;
}
$comments = format_comments($items);
?>

config.php

1
2
3
4
5
6
7
8
9
10
11
<?php
$hostname = 'localhost'; //it's localhost in all all cases
$db_username = 'root';
$db_password = '';
$dbname = 'comments';
$con = new mysqli($hostname, $db_username, $db_password,$dbname);
if (mysqli_connect_errno($con))
{
echo "Error: " . mysqli_connect_error();
}
?>

helper.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?php
function format_comments($comments) {
$html = array();
$root_id = 0;
foreach ($comments as $comment)
$children[$comment['parent_id']][] = $comment;
// loop will be false if the root has no children (i.e., an empty comment!)
$loop = !empty($children[$root_id]);
// initializing $parent as the root
$parent = $root_id;
$parent_stack = array();
// HTML wrapper for the menu (open)
$html[] = '<ul class="comment">';
while ($loop && ( ( $option = each($children[$parent]) ) || ( $parent > $root_id ) )) {
if ($option === false) {
$parent = array_pop($parent_stack);
// HTML for comment item containing childrens (close)
$html[] = str_repeat("\t", ( count($parent_stack) + 1 ) * 2) . '</ul>';
$html[] = str_repeat("\t", ( count($parent_stack) + 1 ) * 2 - 1) . '</li>';
} elseif (!empty($children[$option['value']['comment_id']])) {
$tab = str_repeat("\t", ( count($parent_stack) + 1 ) * 2 - 1);
$keep_track_depth = count($parent_stack);
if ($keep_track_depth <= 3) {
$reply_link = '%1$s%1$s<a href="#" class="reply_button" id="%2$s">reply</a><br/>%1$s';
} else {
$reply_link = '';
}
$name = strlen($option['value']['created_by']) ? $option['value']['created_by'] : 'anonymous_user';
//$reply_link = '%1$s%1$s<a href="#" class="reply_button" id="%2$s">reply</a><br/>';
// HTML for comment item containing childrens (open)
$html[] = sprintf(
'%1$s<li id="li_comment_%2$s" data-depth-level="' . $keep_track_depth . '">' .
'%1$s%1$s<div><span class="commenter">%3$s</span>&nbsp;' .
'<span class="comment_date">%5$s</span></div>' .
'%1$s%1$s<div style="margin-top:4px;">%4$s</div>' .
$reply_link . '</li>', $tab, // %1$s = tabulation
$option['value']['comment_id'], //%2$s id
$name . ' says', // %3$s = commenter
$option['value']['comment_text'], // %4$s = comment
', ' . $option['value']['created_date'] // %5$s = comment created_date
);
//$check_status = "";
$html[] = $tab . "\t" . '<ul class="comment">';
array_push($parent_stack, $option['value']['parent_id']);
$parent = $option['value']['comment_id'];
} else {
$name = strlen($option['value']['created_by']) ? $option['value']['created_by'] : 'anonymous user';
$keep_track_depth = count($parent_stack);
if ($keep_track_depth <= 3) {
$reply_link = '%1$s%1$s<a href="#" class="reply_button" id="%2$s">reply</a><br/>%1$s';
} else {
$reply_link = '';
}
//$reply_link = '%1$s%1$s<a href="#" class="reply_button" id="%2$s">reply</a><br/>%1$s</li>';
// HTML for comment item with no children (aka "leaf")
$html[] = sprintf(
'%1$s<li id="li_comment_%2$s" data-depth-level="' . $keep_track_depth . '">' .
'%1$s%1$s<div><span class="commenter">%3$s</span>&nbsp;' .
'<span class="comment_date">%5$s</span></div>' .
'%1$s%1$s<div style="margin-top:4px;">%4$s</div>' .
$reply_link . '</li>', str_repeat("\t", ( count($parent_stack) + 1 ) * 2 - 1), // %1$s = tabulation
$option['value']['comment_id'], //%2$s id
$name . ' says', // %3$s = commenter
$option['value']['comment_text'], // %4$s = comment
', ' . $option['value']['created_date'] // %5$s = comment created_date
);
}
}
// HTML wrapper for the comment (close)
$html[] = '</ul>';
return implode("\r\n", $html);
}
?>

add_comment.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php
require("config.php");
require("helper.php");
if (isset($_POST)) {
$parent_id = ($_POST['reply_id'] == NULL || $_POST['reply_id'] == '') ? 0 : $_POST['reply_id'];
$email = $_POST['comment_email'];
$name = $_POST['comment_name'];
$web = $_POST['comment_web'];
$comment_text = $_POST['comment_text'];
$depth_level = $_POST['depth_level'];
$sql = "INSERT INTO comment(comment_text, parent_id, ip_address, email_address, web_address, created_by) VALUES('$comment_text', $parent_id, '" . $_SERVER['REMOTE_ADDR'] . "', '$email', '$web', '$name')";
$query = mysqli_query($con,$sql);
$inserted_id = mysqli_insert_id($con);
$sql = "SELECT * FROM comment WHERE comment_id=" . $inserted_id;
$results = mysqli_query($con,$sql);
if ($results) {
while ($row = mysqli_fetch_assoc($results)) {
if ($depth_level < 3) {
$reply_link = "<a href=\"#\" class=\"reply_button\" id=\"{$row['comment_id']}\">reply</a><br/>";
} else {
$reply_link = '';
}
$depth = $depth_level + 1;
$name = strlen($row['created_by']) ? $row['created_by'] : 'anonymous user';
echo "<li id=\"li_comment_{$row['comment_id']}\" data-depth-level=\"{$depth}\">" .
"<div><span class=\"commenter\">{$name} says</span>&nbsp;<span class=\"comment_date\">, {$row['created_date']}</span></div>" .
"<div style=\"margin-top:4px;\">{$row['comment_text']}</div>" .
$reply_link . "</li>";
}
echo '<div class="success">Comment successfully posted</div>';
} else {
echo '<div class="error">Error in adding comment</div>';
}
} else {
echo '<div class="error">Please enter required fields</div>';
}
/*
* End of add_comment.php
*/
?>

comments_blog.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
$(function() {
$("#cancel-comment-reply-link").hide();
$(".reply_button").live('click', function(event) {
event.preventDefault();
var id = $(this).attr("id");
if ($("#li_comment_" + id).find('ul').size() > 0) {
$("#li_comment_" + id + " ul:first").prepend($("#comment_form_wrapper"));
} else {
$("#li_comment_" + id).append($("#comment_form_wrapper"));
}
var depth_level = $('#li_comment_' + id).data('depth-level');
$("#reply_id").attr("value", id);
$("#depth_level").attr("value", depth_level);
$("#cancel-comment-reply-link").show();
});
$("#cancel-comment-reply-link").bind("click", function(event) {
event.preventDefault();
$("#reply_id").attr("value", "");
$("#comment_wrapper").prepend($("#comment_form_wrapper"));
$(this).hide();
});
$("#comment_form").bind("submit", function(event) {
event.preventDefault();
if ($("#comment_name").val() == "")
{
alert("Please enter your name");
return false;
}
if ($("#comment_email").val() == "")
{
alert("Please enter your email");
return false;
}
var regex_email = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
if (regex_email.test($("#comment_email").val()) == false) {
alert('Invalid Email Address');
return false;
}
var regex_web = /^((ftp|https?):\/\/)?(www\.)?[a-z0-9\-\.]{3,}\.[a-z]{2,3}$/;
if ($("#comment_web").val() != "" && regex_web.test($("#comment_web").val()) == false) {
alert('Invalid Website Address');
return false;
}
if ($("#comment_text").val() == "")
{
alert("Please enter your comment");
return false;
}
$.ajax({
type: "POST",
//async: false,
url: "add_comment.php",
data: $('#comment_form').serialize(),
dataType: "html",
cache: false,
beforeSend: function() {
$('#comment_wrapper').block({
message: 'Please wait....',
css: {
border: 'none',
padding: '15px',
backgroundColor: '#ccc',
'-webkit-border-radius': '10px',
'-moz-border-radius': '10px'
},
overlayCSS: {
backgroundColor: '#ffe'
}
});
},
success: function(comment) {
var reply_id = $("#reply_id").val();
if (reply_id == "") {
$("#comment_wrapper ul:first").prepend(comment);
}
else {
if ($("#li_comment_" + reply_id).find('ul').size() > 0) {
$("#li_comment_" + reply_id + " ul:first").prepend(comment);
}
else {
$("#li_comment_" + reply_id).append('<ul class="comment">' + comment + '</ul>');
}
}
$("#comment_name").attr("value", "");
$("#comment_email").attr("value", "");
$("#comment_web").attr("value", "");
$("#comment_text").attr("value", "");
$("#reply_id").attr("value", "");
$("#cancel-comment-reply-link").hide();
$("#comment_wrapper").prepend($("#comment_form_wrapper"));
$('#comment_wrapper').unblock();
},
error: function(jqXHR, textStatus, errorThrown) {
//console.log(textStatus, errorThrown);
alert(textStatus + " " + errorThrown);
}
});
});
});

comments.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#comment_wrapper {
width:100%;
font-family:serif,sans-serif,cursive;
}
#comment_form_wrapper {
margin: 12px 12px 12px 12px;
padding: 12px 0px 12px 12px; /* Note 0px padding right */
background-color: #ebefee;
border: thin dotted #39C;
}
#comment_name{
padding: 4px 2px 4px 5px;
margin: 3px 0 3px 13px;
}
#comment_email{
padding: 4px 2px 4px 5px;
margin: 3px 0 3px 15px;
}
#comment_web{
padding: 4px 2px 4px 5px;
margin: 3px;
}
#comment_form textarea {
width: 93.4%;
background: white;
/*border: 4px solid #EEE;*/
border: 1px solid #eee;
/* -moz-border-radius: 5px;
border-radius: 5px;*/
padding: 10px;
margin-left: 5px;
font-family:serif,sans-serif,cursive;
font-size:14px;
}
#comment_resp_err{
color: red;
font-size: 13px;
}
ul.comment {
width: 100%;
/* margin: 12px 12px 12px 0px;
padding: 3px 3px 3px 3px;*/
}
ul.comment li {
margin: 12px 12px 12px 12px;
padding: 12px 0px 12px 12px; /* Note 0px padding right */
list-style: none; /* no glyphs before a list item */
background-color: #ebefee;
border: thin dotted #39C;
}
ul.comment li span.commenter {
font-weight:bold;
color:#369;
}
ul.comment li span.comment_date {
color:#666;
}
#comment_wrapper .button,
#comment_wrapper .reply_button {
background: none repeat scroll 0 0 #5394A8;
color: #FFFFFF;
float: right;
font-size: 10px;
font-weight: bold;
margin: -10px 5px ;
padding: 3px 10px;
text-transform: uppercase;
text-decoration: none;
cursor: pointer;
border: 1px solid #369;
}
#comment_wrapper #comment_submit {
float:none;
margin: 0px 5px ;
}
#comment_wrapper .button:hover,
#comment_wrapper .reply_button:hover {
background: none repeat scroll 0 0 #069;
text-decoration: underline;
}
#cancel-comment-reply-link {
color: #666;
margin-left: 10px;
margin-right:10px;
text-decoration: none;
font-size: 10px;
font-weight: normal;
float:right;
text-transform: uppercase;
}
#cancel-comment-reply-link:hover{
text-decoration: underline;
}

comment plugin:commentics-3.2

https://www.commentics.org

Thinkphp带表情的无限评论回复

http://www.thinkphp.cn/code/1691.html