2019-07-29 PHP+MySQL开发简单的留言板(2)
前端界面写好以后,就可以开始编写后端的PHP代码了。
接下来需要实现:登录与注册功能、会话控制
开发工具:PHPStorm 2019.1.2
运行环境:PHPStudy 2018(PHP版本为5.4.45)
参考文档:https://blog.csdn.net/tanlangqie/article/details/80685429、https://blog.csdn.net/tanlangqie/article/details/80703451
MySQL设置
创建一个叫bbs
的数据库,并使用以下SQL语句创建user
表:
CREATE TABLE `user` (
`id` int(32) NOT NULL AUTO_INCREMENT,
`username` varchar(30) DEFAULT NULL,
`password` varchar(32) DEFAULT NULL,
`createtime` int(80) DEFAULT NULL,
`createip` varchar(60) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
初始化完成的效果如下:
注册功能的实现
首先需要连接数据库。这个比较简单,而且这个文件在后面会经常用。
connect.php
<?php
/**
* 连接数据库
* @Author NullP0
*/
header('content-type: text/html;charset=utf-8');
// 数据库的信息
$serverName = 'localhost';
$dbName = 'bbs';
$userName = 'root';
$password = 'root';
// 连接数据库
$con = mysqli_connect($serverName, $userName, $password, $dbName);
if (!$con) {
die('数据库连接失败!'.mysqli_connect_error());
}
mysqli_query($con, 'set names utf-8'); // 使用utf-8编码
?>
注册功能的本质还是向数据库中插入数据。
register.php
<?php
/**
* 实现注册的页面,与register.html配合使用
* @Author NullP0
*/
include_once 'connect.php';
// 检查非法字符
function check($parm) {
$patten = '[^A-Za-z0-9]';
if (preg_match($patten, $parm)) {
die('不能输入非法字符!');
}
}
// 获取用户输入
$username = trim($_POST['username']);
$password = trim($_POST['password']);
$repassword = trim($_POST['repassword']);
check($username);
check($password);
check($repassword);
if ($username === '') {
die('<script>alert("用户名不能为空!")</script>');
} elseif ($password === '') {
die('<script>alert("密码不能为空!")</script>');
} elseif ($password !== $repassword) {
die('<script>alert("两次输入的密码不一致!")</script>');
} else {
// 处理信息
$password = md5($password);
$time = time();
$ip = $_SERVER['REMOTE_ADDR'];
mysqli_select_db($con, 'bbs'); // 选择数据库
mysqli_set_charset($con, 'utf-8'); // 选择字符集
// 编写sql语句并向数据库中插入用户信息、返回结果
$sql = "insert into user (username,password,createtime,createip) values('$username','$password', '$time' ,'$ip' )";
$result = mysqli_query($con, $sql);
if ($result) {
echo '<script>alert("恭喜你注册成功!现在返回登录页面……"); document.location.href = "login.html";</script>';
mysqli_close($con);
} else {
echo '注册失败!';
mysqli_close($con);
}
}
?>
首先,使用trim()
函数处理用户输入的原因是以前做题的时候曾经听说过一种攻击方法叫基于约束的SQL攻击
,大概成因就是服务端不同的组成部分对空格的处理不同。于是在这里移除空格,杜绝被攻击的可能性。
编写check()
函数,用正则表达式匹配非法字符,提高安全性。
使用md5()
函数对password进行加密之后存储在数据库中。虽然确实也有攻击手段可以破解这样的防护措施,但是总比明文存储要好。
最后,在处理完成后,向客户端返回JavaScript并跳回登录页面(别问我为什么用JavaScript,只是习惯了而已……)。
登录功能的实现
登录页面是SQL注入和XSS的高发地。不过过滤了特殊字符之后应该可以提高一些安全性。
当用户名为admin(以管理员的身份登录时),跳转到后台管理页面。
login.php
<?php
/**
* 实现登录功能
* @Author NullP0
*/
session_start();
include_once 'connect.php';
function check($parm) {
$patten = '[^A-Za-z0-9]';
if (preg_match($patten, $parm)) {
die('不能输入非法字符!');
}
}
if ($_POST['username'] === '') {
die('请输入用户名!');
} elseif ($_POST['password'] === '') {
die('请输入密码!');
} else {
$username = $_POST['username'];
$password = $_POST['password'];
mysqli_select_db($con, 'bbs');
check($username);
$sql = "select * from user where username = '$username' ";
$res = mysqli_query($con, $sql);
$row = mysqli_fetch_assoc($res);
if ($row['password'] === md5(trim($password))) {
// 使用session进行会话控制,把用户名存放到session中
$_SESSION['username'] = $username;
if ($username === 'admin') {
die('<script>alert("欢迎,管理员。"); document.location.href = "admin.php"</script>');
}
echo '<script>alert("登录成功,现在回到主页。"); document.location.href = "index.php"</script>';
} else {
die('<script>alert("密码不正确!"); document.location.href = "html/login.html"</script>');
}
}
?>
登录功能也没什么好说的,其实就是查询数据库。这里全用了===
防止因为弱类型而出一些莫名其妙的bug。
至于会话控制,这里使用了Session
,并把用户名存放在Session
中,因为Cookie
还没有研究明白。而且用Session的效果也还可以。
登出功能的实现
登出功能的本质是销毁Session。
logout.php
<?php
/**
* 销毁session、退出登录
* @Author NullP0
*/
session_start();
if (!isset($_SESSION['username'])) {
die('<script>document.location.href = "html/login.html"</script>');
} else {
// 销毁Session
unset($_SESSION['username']);
$_SESSION = array();
setCookie("PHPSESSID","",time()-1,"/");
session_destroy();
die('<script>document.location.href = "index.php"</script>');
}
?>
这里针对未登录、没有Session
的情况进行了判断。如果未登录,就直接跳到登录页面,不做任何事。
将登录状态反馈给前端
因为现在还没有开始开发留言模块,所以首页还是什么都没有。这里规划的是页面右上角的按钮根据是否登录显示不同的链接——未登录显示登录,已登录显示登出。
index.php(未完成)
<!DOCTYPE html>
<?php session_start(); ?>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>NullP0的留言板</title>
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<div class="topbar">
<div class="toptitle">NullP0的留言板</div>
<div class="loginOrLogout">
<?php
if (!isset($_SESSION['username'])) {
echo '<a href="html/login.html" class="loginOrLogoutLink">登录</a>';
} else {
echo '<a href="logout.php" class="loginOrLogoutLink">登出</a>';
}
?>
</div>
</div>
<div class="bigbox">
<?php
if (!isset($_SESSION['username'])) {
echo '欢迎,游客。';
} else {
echo '欢迎,';
echo $_SESSION['username'];
}
?>
</div>
<!-- TODO:开发留言模块 -->
</body>
</html>
CSS:
index.css(未完成)
* {
margin: 0;
padding: 0;
}
html {
font-family: DengXian, "Microsoft YaHei";
}
.topbar {
display: flex;
width: 100%;
height: 40px;
background-color: #036;
position: fixed;
}
.toptitle {
display: flex;
align-items: center;
justify-content: center;
padding-left: 30px;
padding-right: 30px;
font-size: 1.2em;
color: white;
text-decoration: none;
}
.bigbox {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.loginOrLogout {
display: flex;
margin-left: auto;
align-items: center;
justify-content: center;
padding-left: 30px;
padding-right: 30px;
font-size: 1.2em;
color: white;
text-decoration: none;
}
.loginOrLogoutLink {
color: white;
text-decoration: none;
}
实际效果: