简介

初学PHP用来练手的项目。只有一些基本功能。

实现

一个基于bootstrap前端框架,PHP+MySQL开发的简易留言板web程序。

基本功能

  • 登录、登出和注册
  • 留言的预览与查看
  • 留言的发布、删除与修改
  • 通过标题搜索留言
  • 个人信息的查询

页面展示

登录和注册

1

2

留言的预览与查看

3

4

留言的发布、修改与删除

5

6

查看个人资料

7

搜索功能

8

配置方式

bootstrap框架下载

数据库脚本。

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
/*
SQLyog 企业版 - MySQL GUI v8.14
MySQL - 5.7.26 : Database - comments
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`comments` /*!40100 DEFAULT CHARACTER SET utf8 */;

USE `comments`;

/*Table structure for table `comments` */

DROP TABLE IF EXISTS `comments`;

CREATE TABLE `comments` (
`title` varchar(20) DEFAULT NULL,
`author` varchar(20) DEFAULT NULL,
`email` varchar(50) DEFAULT NULL,
`content` varchar(2500) DEFAULT NULL,
`time` varchar(30) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

/*Data for the table `comments` */

insert into `comments`(`title`,`author`,`email`,`content`,`time`) values ('我的第一条留言','tsuki','652240843@qq.com','你好!!!','2022-09-03 15:36:31');

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
`uname` varchar(20) DEFAULT NULL,
`email` varchar(50) DEFAULT NULL,
`pswd` varchar(20) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

/*Data for the table `user` */

insert into `user`(`uname`,`email`,`pswd`) values ('tsuki','652240843@qq.com','123456');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

修改db.php的配置信息,修改为本机MySQL的用户名密码

1
2
3
4
5
<?php
//连接数据库服务器
$conn=mysqli_connect("localhost","root","root") or die("数据库服务器连接错误".mysql_error());
mysqli_set_charset($conn,'utf8'); //设定字符集
?>

使用phpstudy集成环境运行即可。

目录结构

  • css存放CSS层叠样式文件(bootstrap框架)
  • js存放JavaScript源文件(bootstrap框架)
  • login.php登录界面 、loginsuc.php登陆成功界面 、reg.php注册界面 、quit.php实现登出功能
  • board.php为首页所有留言预览展示界面
  • write.phpdelete.phpedit.phpsearch.php实现对留言的增删改查
  • comment.php留言正文展示界面
  • mycmt.php个人发布留言展示界面,myinfo.php个人信息展示界面
  • db.php为数据库连接文件

9

关键代码分析

登录和注册

直接使用使用bootstrap框架在前端对输入数据进行验证,节省了很多时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<form action="login.php" class="was-validated">
<div class="form-group">
<label for="uname">Username:</label>
<input type="text" class="form-control" id="uname" placeholder="Enter username" name="uname" required>
<div class="invalid-feedback">请输入用户名!</div>
</div>
<div class="form-group">
<label for="pwd">email:</label>
<input type="email" class="form-control" id="email" placeholder="Enter email" name="email" required>
<div class="invalid-feedback">请输入正确格式的邮箱!</div>
</div>
<div class="form-group">
<label for="pwd">Password:</label>
<input type="password" class="form-control" id="pwd" placeholder="Enter password" name="pswd" required>
<div class="invalid-feedback">请输入密码!</div>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="remember" required> 同意<a href="xieyi.html"></a>
<div class="invalid-feedback">同意协议能登录!</div>
</label>
</div>
<button type="submit" class="btn btn-primary">登录</button>
</form>

登录时根据用户提交的数据来进行数据库的查询,用户名、密码和邮箱均正确后跳转到登陆成功页面。

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
$select = mysqli_select_db($conn,"comments");	
if($select && isset($_GET['remember'])) {
// sql语句
$sql_select = "select uname, email, pswd from user where uname = '$uname' and email = '$email' and pswd = '$pswd'";

//设置编码
mysqli_query($conn, 'SET NAMES UTF8');
//执行sql语句
$ret = mysqli_query($conn, $sql_select);

if (!$ret) {
printf("Error: %s\n", mysqli_error($conn));
exit();
}

$row = mysqli_fetch_array($ret);

if($uname == $row['uname'] && $pswd == $row['pswd'] && $email == $row['email'] && $ret->num_rows > 0){
//跳转登陆成功页面
$_SESSION['uname'] = $uname;
$_SESSION['email'] = $email;
header('location:loginsuc.php');
}else{
//跳转登陆失败页面
echo '<script>alert("用户名或者密码错误")</script>';
}

注册界面同理,判断用户提交的邮箱是否已经被注册。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if($select && isset($_GET['remember'])) {
$sql_select = "select email from user where email = '$email'";
$result = mysqli_query($conn,$sql_select);
//判断用户名是否已存在
$num = mysqli_num_rows($result);

if($num) {
echo '<script>alert("该用户名或者邮箱已经被注册!")</script>';
}else{
$sql_insert = "insert into user(uname,email,pswd) values('$uname','$email','$pswd')";
$ret = mysqli_query($conn,$sql_insert);
echo '<script>alert("注册成功!")</script>';
}
mysqli_close($conn);
}

登录状态

登陆成功后从login.php跳转到login.php,存在可以直接从url定位到成功登录页面的隐患。所以在使用session来存储登录状态。

1
2
3
4
5
session_start(); //创建session
...
//登录成功后设置session
$_SESSION['uname'] = $uname;
$_SESSION['email'] = $email;

之后在需要登录才能访问的页面添加登录逻辑判断,如果无session则重定向到登录页面。

1
2
3
4
5
6
session_start();
$user = $_SESSION["uname"];
if(empty($user)){
header('location:login.php');
exit;
}

实现登出功能就是销毁session

1
2
3
4
5
6
<?php
// 退出时清除session,并返回登录界面
session_start();
unset($_SESSION["uname"]);
header("location:login.php");
?>

除了实现登录登出功能,session在个人信息和个人留言管理界面也提供了便利。可以直接从session获取信息而不用经过数据库。

例如个人信息界面,可以直接输出个人信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
session_start();
$user = $_SESSION["uname"];
$email = $_SESSION["email"];
if(empty($user)){
header('location:login.php');
exit;
}else{
echo '<div class="card" id="myinfo" style="width:400px">
<img class="card-img-top" src="https://upload-bbs.mihoyo.com/upload/2021/02/21/73745121/889dd95182ad248b035a19fbefe90764_4703068301332017047.png" alt="Card image" style="width:100%">
<div class="card-body">
昵称:<h4 class="card-title" id="uname">tsuki</h4>
邮箱地址:<h4 class="card-text" id="email">652240843@qq.com</p>
<a href="quit.php" class="btn btn-primary">登出</a>
</div>';
}

留言的增删改查

写留言

前端用POST方式提交留言的titlecontentauthoremail直接从session中获取。

时间则通过DataTime对象获取。

1
2
3
4
5
6
7
8
9
10
11
12
13
$user = $_SESSION["uname"];
$email = $_SESSION["email"];
$time = new DateTime();
$time = $time->format('Y-m-d H:i:s');
$title = $_POST['title'];
$content = $_POST['content'];
$sql = "INSERT INTO comments (title, author, email, content, time)
VALUES ('" . $title . "','" . $user . "','" . $email . "','" . $content . "','" . $time . "')";
if ($conn->query($sql) === TRUE) {
echo '<script>alert("发布成功!")</script>';
} else {
echo '<script>alert("输入字数超出限度!")</script>';
}

删留言

个人留言展示界面直接echo删除留言的按钮并包含当前的留言的标题,并通过GET方式传入delete.php

<a href="delete.php?title=' . $row["title"] . '"><button type="button" class="btn btn-warning">删除留言</button></a>

然后和GET传入的标题与session中的用户邮箱定位到该留言,并将其删除。

delete.php代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
// 删除留言
session_start();
include("db.php");
$select = mysqli_select_db($conn,"comments");
$user = $_SESSION["uname"];
$email = $_SESSION["email"];
if(empty($user)){
header('location:login.php');
exit;
}
if(isset($_GET['title'])){
$title=$_GET['title'];
$sql = "DELETE FROM comments WHERE title='" . $title . "' and email='" . $email . "'";
mysqli_query($conn,$sql);
header("location:mycmt.php");
}
mysqli_close($conn);
?>

改留言

和删除留言类似,个人留言展示界面直接echo修改留言的按钮并包含当前的留言的标题,并通过GET方式传入editcmt.php

<a href="editcmt.php?title=' . $row["title"] . '"><button type="button" class="btn btn-info">修改留言</button></a>

这里用到了AJAXGET传入的标题和session中的邮箱定位到该留言,然后将旧标题与旧文本写入文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if(isset($_GET['title'])) {
$title=$_GET['title'];
$sql = "SELECT title, content FROM comments where title = '" . $title . "' and email = '" . $email . "'";
$result = mysqli_query($conn, $sql);
$row = mysqli_fetch_assoc($result);
// 写入旧标题
$myfile_1 = fopen("change_title.txt", "w") or die("Unable to open file!");
fwrite($myfile_1, $title);
fclose($myfile_1);
// 写入旧文本
$content = $row['content'];
$myfile_2 = fopen("change_content.txt", "w") or die("Unable to open file!");
fwrite($myfile_2, $content);
fclose($myfile_2);
}

前端JavaScript脚本发送XMLHttpRequest请求获取这两个文件的数据然后输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 旧标题
var xmlhttp;
if (window.XMLHttpRequest){
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp=new XMLHttpRequest();
}else{
// IE6, IE5 浏览器执行代码
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
document.getElementById("biaoti").value=xmlhttp.responseText;
}
}
xmlhttp.open("GET","/change_title.txt",true);
xmlhttp.send();

所以在未进行修改前,显示的数据为原本数据。之后进行修改就和写类似了。

10

修改之后提交,更新数据库,然后重定向到显示信留言的页面。

1
2
3
4
5
6
7
8
if(isset($_POST['title']) && isset($_POST['content'])){
$ex_title = file_get_contents('change_title.txt');
$newtitle=$_POST['title'];
$newcontent=$_POST['content'];
$sql = "UPDATE comments SET title='" . $newtitle . "', content='" . $newcontent . "' WHERE title='" . $ex_title . "' and email='" . $email . "'";
mysqli_query($conn,$sql);
header('location:comment.php?title=' . $newtitle . '&email=' . $email);
}

查留言

查询的逻辑比较简单,因为目前只能将标题打完整才能查询。

留言的预览与查看

预览

comments表中所有数据取出,根据日期降序排列,order by time DESC,实现最新留言展示在最上方。最后将所有留言的预览效果显示在前端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 按照最新留言排序
$sql = "SELECT title, author, email, time FROM comments order by time DESC";
$result = mysqli_query($conn, $sql);

if (mysqli_num_rows($result) > 0) {
// 输出数据
while($row = mysqli_fetch_assoc($result)) {
echo '<a href="comment.php?title=' . $row["title"] . '&email=' . $row["email"] . '">
<div class="media border p-3">
<img src="https://uploadbbs.mihoyo.com/upload/2021/02/21/73745121/
889dd95182ad248b035a19fbefe90764_4703068301332017047.png"
class="mr-3 mt-3 rounded-circle" style="width:60px;">
<div class="media-body"><h3>标题:' . $row["title"] . '</h3>
<h6>发布时间:' . $row["time"] . '</h6>
<h5>留言人:' . $row["author"] . '</h5>
</div>
</div></a>';
}
} else {
echo "<mark>还没有人发布留言喔!</mark>";
}

查看

在主界面输出留言预览框时,添加了<a href="comment.php?title=' . $row["title"] . '&email=' . $row["email"] . '">,点击即可进入comment.php并传入留言的定位数据。之后在该界面通过留言定位数据将该留言的标题作者发布日期正文全部取出显示在前端即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$sql = "SELECT title, author, time, content FROM comments 
where title = '" . $title . "' and email = '" . $email . "'";
$result = mysqli_query($conn, $sql);
if ($result->num_rows > 0) {
// 输出数据
while($row = $result->fetch_assoc()) {
echo '<div class="card">
<div class="card-body">
<h4 class="card-title">' . $row["title"] . '</h4><br>
<p class="card-text">' . $row["content"] . '</p><br>
<mark>留言人:' . $row["author"] . '</mark>
<mark>留言时间:' . $row["time"] . '</mark>
</div>
</div>';
}
} else {
echo "<mark>还没有发布留言喔!</mark>";
}

总结

这是本人初学PHP用于练手的一个简易小项目,花了一天时间,功能并不完善,有很多不足之处。

存在一些开发过程的逻辑错误,还存在一些安全风险,比如SQL注入和XSS。

等待后续深入学习之后再来完善。