前言-关于为什么会有这篇文章

那当然是因为我想要水篇文章啦
咳咳,还不是因为某个Final Mission,写完了当然来水一篇文章咯(
1

关于前端

当写到这里的时候,忽然想起来之前做的某道web题的前端还行,于是就过来咯(x)

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
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Rabbit House 成员管理系统</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@4.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="content container pt-5">

<h1>Rabbit House 成员管理系统</h1>
<form method="post" action=".">
<div class="form-group">
<label>
用户名:<input type="text" class="form-control" name="username">
</label>
</div>
<div class="form-group">
<label>
密码:<input type="password" class="form-control" name="password">
</label>
</div>
<button type="submit" class="btn btn-primary">登录</button>
</form>
</div>
</body>
</html>

数据库部分

考虑到这个项目的要求有登录,注销以及留言功能,所以需要用到数据库。我建立的数据表结构如下:

首先建一个final_database来存放这个项目的数据。

final_user 结构如下:


username显然是用户的id,password用来保存用户的密码,按照需要也可以保存密码的md5,head_path保存用户的头像路径。

msg_book 结构如下:


username是用户id,post_time保存用户留言的时间,text是用户留言的内容,最后的post_time是偷个懒,用户留言时直接把头像路径保存,略去输出用户留言时再去查询头像。

user_auth 结构如下:


username是用户id,再用户登陆时会随机生成一串数字作为验证,随机数保存于userauth,登陆时间保存于authtime

项目包含文件

由于项目各个模块基本都要用到cookie,mysql查询等功能,为了提高代码的复用率,所以这些代码写到一个文件,各个部分再包含这个文件。

常量定义

1
2
3
4
5
6
7
8
9
10
//Contest definations.
define("MYSQL_HOST", "**.**.**.**");
define("MYSQL_USERNAME", "*********");
define("MYSQL_PASSWORD", "********");
define("MYSQL_DATABASE", "final_database");
//我的mysql怎么可能放在这呢(

define("TABLE_USERLIST", "final_user");
define("TABLE_MSGBOOK", "msg_book");
define("TABLE_USERAUTH", "user_auth");

cookie部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Cookie control
// 开启Session
session_start();

$isLogin = false;
if(isset($_COOKIE['username'])){
$isLogin=true;
$user_name = $_COOKIE['username'];
$head_path = $_COOKIE['headpath'];
$user_auth = $_COOKIE['userauth'];
}//把cookie的数据保存至变量方便后续使用
else{
$isLogin=false;
}

mysql部分

1
2
//MySql Control
$link = mysqli_connect(MYSQL_HOST, MYSQL_USERNAME, MYSQL_PASSWORD, MYSQL_DATABASE);

MySql部分就相对比较简单了,后面需要查询的时候都是单独写的。。

防XSS攻击模块

由于用户的id和留言内容都是直接使用用户提交的字符串,就存在xss攻击的风险,所以要对用户提交的内容进行过滤。

1
2
3
4
5
6
7
function anti_xss($text){
$text_anti_xss = trim($text); //清理空格
$text_anti_xss = strip_tags($text_anti_xss); //过滤html标签
$text_anti_xss = htmlspecialchars($text_anti_xss); //将字符内容转化为html实体
$text_anti_xss = addslashes($text_anti_xss); //防止SQL注入
return $text_anti_xss;
}

用户登录验证模块

在用户登录之后发表信息的时候验证用户身份的部分,,,emm算了不描述了(

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
function auth_check($auth, $name, $link){
$sql = "SELECT * FROM `".TABLE_USERAUTH."` WHERE username = '$name'";
$res = mysqli_query($link, $sql);
$arr = mysqli_fetch_assoc($res);
if($arr){
if($arr['userauth']==$auth && $arr['authtime'] + 3600 > time()){
return 1;
}
else {
return 0;
}
}
else {
return -1;
}
}

function auth_insert($auth, $name, $link){
//Check that user authentication exists.
$tmp = auth_check($auth, $name, $link);
if($tmp >= 0){
$sql2 = "UPDATE `user_auth` SET `userauth` = '$auth', `authtime` = '".time()."' WHERE `user_auth`.`username` = '$name'";
mysqli_query($link, $sql2);
}
else if($tmp == -1){
$sql2 = "INSERT INTO `".TABLE_USERAUTH."` (`username`, `userauth`, `authtime`) VALUES ('$name', '$auth', '".time()."')";
mysqli_query($link, $sql2);
}
}

具体讲解之后再补吧emm

用户登录部分设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function user_login($username, $password, $link){
$sql = "SELECT * FROM `final_user` WHERE username = '$username'";
$res = mysqli_query($link, $sql);
$arr = mysqli_fetch_assoc($res);
$password_md5ed = md5($password);
if($arr){
if($arr['password']==$password_md5ed){
$auth_tmp = rand(1000000,9999999);
setcookie("username",$_POST["username"],time()+3600);
setcookie("headpath",$arr["head_path"],time()+3600);
setcookie("userauth",$auth_tmp,time()+3600);
auth_insert($auth_tmp, $username, $link);
echo"<script>alert('登录成功!');location.href = 'index.php';</script>";
}else{
echo"<script>alert('密码错误!');location.href = 'index.php';</script>";
}
}else{
echo "<script>alert('".$username."');</script>";
echo"<script>alert('用户名不存在,请先注册!');location.href = 'index.php';</script>";
}
}

在收到用户的登录请求时,通过提交的用户名查询到密码的md5值,然后再将密码md5之后进行比较。登录成功后进行cookie的设置和用户auth信息的更新。

用户注册部分设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function user_register($username, $password, $link){
$username_anti_xss = anti_xss($username);
$sql = "SELECT * FROM `".TABLE_USERLIST."` WHERE username = '$username_anti_xss'";
$res = mysqli_query($link, $sql);
$arr = mysqli_fetch_assoc($res);
if($arr){
echo"<script>alert('用户名已存在!');location.href = 'index.php';</script>";
}else{
$password_md5ed = md5($password);
$sql2 = "INSERT INTO `".TABLE_USERLIST."` (`username`, `password`, `head_path`) VALUES ('$username_anti_xss', '$password_md5ed', NULL)";
mysqli_query($link, $sql2);
echo"<script>alert('注册成功!');location.href = 'index.php';</script>";
}
}

和用户登录部分大体一致

用户登出部分设计

1
2
3
4
5
6
function user_logout(){
setcookie("username",$user_name,time()-3600);
setcookie("headpath",$head_path,time()-3600);
setcookie("userauth",$user_auth,time()-3600);
echo "<script>alert('注销成功!');location.href = 'index.php';</script>";
}

在用户登出时删除所有cookie,还应该更新下用户的auth信息的,之后再补吧emmm

发布留言部分设计

1
2
3
4
5
6
function post_msg($text, $username, $headpath, $link){
$text_anti_xss = anti_xss($text);
$sql2 = "INSERT INTO `".TABLE_MSGBOOK."` (`username`, `post_time`, `text`, `post_head`) VALUES ('$username', CURRENT_TIMESTAMP, '$text_anti_xss', '$headpath')";
mysqli_query($link, $sql2);
echo"<script>alert('发送成功!');location.href = 'index.php';</script>";
}

代码言简意赅,就这样吧(

上传头像部分设计

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
function post_img($img, $username, $link){
// 服务器中文件的存放目录
$tmp_dir=$img['tmp_name'];
//用户上传的文件名(带后缀)
$fileName=$img['name'];

if($img['error']!=0){
echo '上传文件出现错误!请重试!';
return;
}else if($img['size']>10240000){
echo "文件超过".$maxSize;
return;
}else if($img['size']<20480){
echo "上传文件出现错误!请重试!";
return;
}else{
//创建目录
$fileDir='./upload/';
if(!is_dir($fileDir)){
mkdir($fileDir);
}
//文件名
$newFileName=date('YmdHis',time()).rand(100,999);
//文件后缀
$FileExt=substr($fileName,strrpos($fileName,'.'));
$FilePath=$newFileName.$FileExt;

//生成缩略图
$img_info=getimagesize($tmp_dir);
// var_dump($img_info);
$width=$img_info[0]; //原图的宽
$height=$img_info[1]; //原图的高
$newWidth=$width*0.5;
$newHeight=$height*0.5;

//绘制画布
$thumb=imagecreatetruecolor($newWidth, $newHeight);
//创建一个和原图一样的资源
$source=imagecreatefromjpeg($tmp_dir);

//根据原图创建缩略图
imagecopyresized($thumb,$source,0,0,0,0,$newWidth,$newHeight,$width,$height);

//保存缩略图
imagejpeg($thumb,'./upload/'.$newFileName.$FileExt,100);

//移动文件到指定的目录
move_uploaded_file($tmp_dir,'./upload/'.$newFileName.'_temp'.$FileExt);
unlink('./upload/'.$newFileName.'_temp'.$FileExt);
$sql2 = "update final_user set `head_path`='$FilePath' WHERE username = '$username'";
mysqli_query($link, $sql2);
setcookie("headpath",$FilePath,time()+3600);
echo "<script>alert('上传成功!');location.href = 'index.php';</script>";

}
}

为了避免文件上传存在的风险,于是选择在用户上传图片后进行压缩,从而避免文件上传的风险。


接下来就是各个部分的前端了

首页部分 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
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
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Rabbit 留言本 ^ - ^</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@4.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="content container pt-5">

<h1>Rabbit 留言本 ^ - ^</h1>
<p>本站提供注册,登录,留言板功能!</p>
<?php
include "include.php";
if ($isLogin) {
// 若已经登录
//输出用户信息
echo "你好! ".$user_name.' ,欢迎来到个人中心!<br>';
echo "<img src=\"./upload/$head_path\" width=50 height=50> ";
echo "<a class=\"btn btn-warning\" href='logout.php'>注销</a> ";
echo "<a class=\"btn btn-warning\" href='upimg.html'>上传/修改头像</a>";
} else {
// 若没有登录
echo "您还没有登录,请先登录!</a>";
}
?>
<form method="post" action="login.php" <?php if ($isLogin)echo "hidden"?>>
<div class="form-group">
<label>
用户名:<input type="text" class="form-control" name="username">
</label>
</div>
<div class="form-group">
<label>
密码:<input type="password" class="form-control" name="password">
</label>
</div>
<button type="submit" class="btn btn-primary">登录</button>
<a class="btn btn-success" href="register.php">没有id?点击注册</a>
</form>
<div id="loged" <?php if (!$isLogin)echo "hidden"?>>
<p>test233</p>
<table border="1" width=80%>
<tr>
<td>Test</td>
<td width=80%>test message</td>
</tr>
<?php //输出留言信息
$query='select * from msg_book';
$result=mysqli_query($link, $query);

//echo '<br> <br>';

while ($data=mysqli_fetch_assoc($result)){
echo '<tr>';
echo '<td>';
echo "<img src=\"./upload/".$data[post_head]."\" width=50 height=50> <br> $data[username] <br> ";
echo $data[post_time];
echo '</td>';
echo '<td>'.$data[text].'</td>';
//echo '</tr>\n'
}

?>
<tr>
<td>Admin<br>2019-11-3 22:45</td>
<td width=80%>Welcome!</td>
</tr>
<tr>
<td colspan="2">
<form name="input" action="postmsg.php" method="post">
回复内容: <input type="text" name="text">
<input type="submit" value="Submit">
</form>
</td>
</tr>
</table>
</div>
<br>
<p>本站仅供学习使用,请勿用于任何非法用途!<del>更不要日站!!!</del></p>

</div>
</body>
</html>

判断用户是否登录来对对部分内容进行隐藏,中间通过查询留言本按照表格输出数据。

注册页面 register.php

(注:后面html部分基本相同所以只写body部分了。。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
header('content-type:text/html;charset=utf-8');
include "include.php";
//检测用户是否登录
if ($isLogin) {
echo"<script>alert('您已经登录请不要重复注册!');location.href = 'index.php';</script>";
}


if(isset($_POST['username'])){
$name = $_POST["username"];
$pwd = $_POST["password"];
user_register($name, $pwd, $link);
}
?>

登录页面 login.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
header('content-type:text/html;charset=utf-8');
include "include.php";
//检测用户是否登录
if ($isLogin) {
echo"<script>alert('您已经登录请不要重复登录!');location.href = 'index.php';</script>";
}


//接受客户端的数据:
$name = $_POST["username"];
$pwd = $_POST["password"];
user_login($name, $pwd, $link);
?>

登出页面 louout.php

1
2
3
4
5
<?php
header('content-type:text/html;charset=utf-8');
include "include.php";
user_logout();
?>

发布留言页面 postmsg.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
header('content-type:text/html;charset=utf-8');
include "include.php";
//检测用户是否登录
if (!$isLogin) {
echo"<script>alert('您还没有登录!');location.href = 'index.php';</script>";
exit();
}
//检测认证信息
if(auth_check($user_auth, $user_name, $link)!=1){
echo"登陆信息出错,信息提交失败!";
exit();
}


//接受客户端的数据:
$text = $_POST["text"];
$name = $_COOKIE["username"];
$hdpath=$_COOKIE['headpath'];

post_msg($text, $name, $hdpath, $link);
?>

上传头像页面

upimg.html

1
2
3
4
5
6
<body>
<p>建议上传jpg格式图片。</p>
<form action="upImg.php" method="post" enctype="multipart/form-data">
<input type="file" name="userImg" >
<input type="submit" value="上传">
</form>

upimg.php

1
2
3
4
5
6
7
8
9
<?php
header('content-type:text/html;charset=utf-8');
date_default_timezone_set("PRC");
include "include.php";

$img=$_FILES['userImg'];

post_img($img, $user_name, $link);
?>

之后,是这个项目的一些参考:
PHP上传用户头像及头像的缩略图
PHP防XSS攻击
b站之前学php的视频(的笔记)


项目已上传至github,欢迎一起来玩鸭~
https://github.com/panedioic/rabbit_msgbook