BootStrap+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
|- bs # Bootstrap3的js
|- config # 系统配置文件
|- css # Bootstrap4的js
|- fonts # Bootstrap4的fonts
|- js # Bootstrap4的js
|
|- showItem # 显示物品
| |- addMes.php # 添加留言
| |- favorite.php # 收藏物品
| |- index.php # 显示物品
|
|- uploads # 上传图片存放的目录
|
|- user # 用户相关的目录
| |- checklogin.php # 登录验证
| |- delFavo.php # 取消收藏
| |- delGood.php # 删除物品
| |- index.php # 用户首页
| |- login.php # 登录界面
| |- loginout.php # 注销登录
| |- myFavorite.php # 查看我的收藏
| |- myGood.php # 查看我发布的物品
| |- register.php # 注册
| |- resetPass.php # 修改密码
|
|- addGood.php # 发布物品
|- addMess.php # 发布留言
|- header.php # 站点头部文件
|- index.php # 主页
|- upload_file.php # 上传文件
|- db.sql # 数据库文件

数据库设计

user 用户表

1
2
3
4
5
6
7
8
9
10
11
12
/*
user 用户信息表
*/
CREATE TABLE user(
id int auto_increment primary key,
username char(20) not null unique,
password char(40) not null,
email char(40) not null unique,
photo char(88) default 'img/nophoto.gif',
reg_date TIMESTAMP default CURRENT_TIMESTAMP
-- 自动获取默认创建时间,不需要可以添加
)character set utf8;

good 物品表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
good 物品表
*/

CREATE TABLE good(
id int auto_increment primary key,
title char(20) not null,
descr varchar(500) not null,
newOld char(20) not null,
wanted char(80) not null,
qq char(20) not null,
tel char(20),
city char(20),
image char(60),
username char(40) not null,
insert_date TIMESTAMP default CURRENT_TIMESTAMP
)character set utf8;

message 物品留言表

1
2
3
4
5
6
7
8
9
10
11
/*
message 留言表
*/

CREATE TABLE message(
mid int auto_increment primary key,
username char(40) not null,
content varchar(100) not null,
insert_date TIMESTAMP default CURRENT_TIMESTAMP,
pid int not null
)character set utf8;

favorite 收藏表


1
2
3
4
5
6
7
8
/*
favorite 收藏表
*/
CREATE TABLE favorite(
id int auto_increment primary key,
username char(40) not null,
pid int not null
)character set utf8;

系统功能实现

头部代码header.php

is_login检测

  is_login检测是用来检测用户是否登陆的代码,存放在header.php中。检测用户是否登陆的方法:启动session,然后检测session数组中是否存在username键,username键的值就是用户名。

  检测登陆的目的:

  • 1.决定输出注册和登陆按钮还是输出用户的个人下拉菜单

  • 2.很多登陆后才具有权限操作的地方要判断是否登陆(可直接包含header.php),比如:登陆界面、修改个人信息界面、添加留言界面、发布物品界面。

1
2
3
4
5
6
$is_login = false;
session_start();
if(isset($_SESSION['username'])){
$username = $_SESSION['username'];
$is_login = true;
}

导航栏

  如果用户未登陆,则右侧导航栏显示”注册”、”登陆” 按钮,如果用户登陆则右侧显示下拉菜单(个人中心,我的发布,我的收藏,注销登陆)

1
2
3
4
5
<?php if($is_login){?>
// html 下拉菜单
<?php }else{?>
// html 登陆 、注册按钮
<?php }?>

  导航栏的active(设置哪个按钮被选中)管理:在每个页面中加入自己的标志,存放于$here中,然后在header中用switch case语句进行选择。

1
2
3
4
5
6
7
8
9
10
//  注意$here赋值要在包含header.php前面
switch($here){
case 'login':
//登陆按钮 ative
break;
....
default:
//主页按钮 active
break;
}

注意事项:

  /user/login.php 包含 header.php而header.php包含config/config.php的问题:此时当前目录会变成/user/ 如果header中包含./config/config.php,则会在/user/config/中寻找config.php,而如果header中包含config/config.php,那么先会/user/config/寻找,如果没有则以header所在目录为根目录寻找config/config.php

登陆相关

  涉及文件:

1
2
user/login.php
user/checklogin.php

user/login.php 登陆表单

  login.php中有登陆表单,并且包含header.php。

  login.php中直接调用header.php中的变量$is_login来判断用户是否登陆,如果已登陆则直接跳转到”个人中心”,否则显示登陆表单(表单的action属性指向checklogin.php)。

1
2
3
4
5
6
7
8
9
10
11
<?php @require('./../config/config.php');?>
<?php
$here = 'login';
require('../header.php');
if($is_login){
die(header("Location: ".$basedir."user/index.php"));
}
?>
<html>
...(表单html)
</html>

user/checklogin.php 登陆验证

  登陆验证主要做两个方面:

  • 1.判断账号密码是否正确
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   /**
1.判断账号密码是否正确
*/

// 1.1 接收登陆界面传递来的数据
$username = $_POST['username'];
$password = md5($_POST['password']);

// 1.2 拼接SQL语句,带入数据库查询

$sql = "select * from user where username='$username' and password='$password'";
$res = mysql_query($sql) or die("<script>alert('数据库查询出错!');</script>");
$row = mysql_fetch_assoc($res);
if(!$row){
echo "<script>alert('账号或密码错误!');</script>";
echo "<script>history.go(-1);</script>";
exit();
}
  • 2.设置session
1
2
3
   session_start();
$_SESSION['username']=$username;
header("Location: $basedir".'user/login.php');

上传图片upload.php

  上传图片的功能单独写到一个php中,因为站点内有多处图片上传点,这样可以复用代码,不用过多的写重复代码。

  • 1.检测是存在file
1
2
3
if(isset($_FILES['file'])){
...
}
  • 2.安全性检测1 - Content-type验证
1
2
3
4
5
6
7
if ((($_FILES["file"]["type"] == "image/png")|| ($_FILES["file"]["type"] == "image/jpeg")|| ($_FILES["file"]["type"] == "image/gif")))
{
...
}else{
echo "<script>alert('Invalid file!');</script>";
echo "<script>history.go(-1);</script>";
}
  • 3.获取上传文件的信息
1
2
3
$uploaded_name = $_FILES[ 'file' ][ 'name' ]; // 从数据包获取上传的文件名
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1); // 提取文件名中的后缀,用于后面检测后缀
$target_name = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext; // 生成一个独一无二的md5作为文件名存放在本地
  • 4.安全性检测2 - 后缀名检测
1
2
3
4
5
6
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" )){
...
}else{
echo "<script>alert('Invalid file!');</script>";
echo "<script>history.go(-1);</script>";
}
  • 5.移动临时文件,并将图片完整路径赋值给$result

  PHP的文件上传,上传后的文件是一个临时文件.tmp文件,需要将其移动到指定目录下,并重命名。

1
2
3
4
5
6
7
8
9
10
11
$dir = "uploads/";
if (file_exists("$dir" . $target_name))
{
echo $_FILES["file"]["name"] . " already exists. ";
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"],"$dir" . $target_name);
$result = $dir . $target_name;
//echo "$result";
}

发布物品addGood.php

  • 1.包含header.php并检测用户是否登录
1
2
3
4
5
6
7
8
include('config/config.php');
$here = 'addGood';
include('header.php');
if(!$is_login){
header('location:'.$basedir.'user/login.php');
exit();
}
header('Content-type:text/html;charset=utf8');
  • 2.如果存在$_POST[‘submit’]则接收数据,并检测数据

  因为表单也是像这个界面提交的,所以我们需要判断是访问物品发布界面还是已经填写完信息后的发布物品,使用isset($_POST['submit'])可以判断,因为如果在addGood.php点击发布物品按钮产生的访问请求中,存在该参数,而从主页或其他地方进入发布物品界面则不会有$_POST['submit']

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if(isset($_POST['submit']))
{
// 第一步:接收参数
$title = $_POST['title'];
$desc = $_POST['desc'];
$newOld = $_POST['newOld'];
$wanted = $_POST['wanted'];
$qq = $_POST['qq'];
$tel = $_POST['tel'];
$city = $_POST['city'];
// 第二步:数据判断
if(empty($title)&&empty($desc)&&empty($newOld)&&empty($wanted)&&empty($qq)&&empty($city))
{
echo "<script>alert('请先将所有必填项填写后再提交!');</script>";
echo "<script>history.go(-1);</script>";
exit();
}
}
  • 3.在尾部添加向数据库插入数据的代码

  插入数据库代码必须在包含upload_file.php后面,否则无法访问到$result变量的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php 
if(isset($_POST['submit'])){
//echo"$title && $desc && $newOld && $wanted && $qq && $tel && $city && $result && username";
$sql = "INSERT INTO good(title,descr,newOld,wanted,qq,tel,city,image,username) VALUES('$title','$desc','$newOld','$wanted','$qq','$tel','$city','$result','$username')";
$res = mysql_query($sql);
if(!$res){
echo "<script>alert('插入失败!');</script>";
echo "<script>history.go(-1);</script>";
//echo $sql;
}else{
$sql = "select id from good where image='$result'";
$res = mysql_query($sql);
$row = mysql_fetch_assoc($res);
$id = $row['id'];
echo "<script>alert('插入成功!');window.location.href='showItem/index.php?id=$id';</script>";
}
}
?>

查看物品相关功能

  涉及文件:

1
2
showItem/index.php # 显示物品
showItem/addMess.php # 添加留言

显示物品信息

  • 1.检测URL中是否存在id参数

  如果没有id参数就结束程序。

1
2
3
4
5
6
if(!isset($_GET['id']))
{
// 没有id参数
echo "<script>alert('Error id!');window.location.href='../index.php';</script>";
exit();
}

  • 2.从good表中查询信息

  如果信息不为空,那么说明记录存在,则把查询出来的记录存放在$row变量中,供后面调用。如果信息为空,说明该id在数据库中不存在,则提示Error id!程序退出。

1
2
3
4
5
6
7
8
9
10
$id = $_GET['id'];
$sql = "select * from good where id='$id'";
$res = mysql_query($sql);
$row = mysql_fetch_assoc($res);

// 数据库不存在的id
if(!$row){
echo "<script>alert('Error id!');window.location.href='../index.php';</script>";
exit();
}

  • 3.拼接html和数据库的信息,以期望交换的物品为例

  因为多个期望交换的物品是以;隔开的,因此我们需要先以;为单位,分割字符串,分割后的每一个子串就是一个期望的物品,然后用foreach遍历数据,将数据中的信息打印到html的指定位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div class="col-md-4">
<div class="card">
<h5 class="card-header">
期望交换的物品
</h5>
<?php $wanted = explode(";",$row['wanted']);?>
<div class="card-body">
<?php foreach($wanted as $k=>$v){?>
<p class="card-footer">
<?php echo $v;?>
</p>
<?php }?>
</div>
</div>
</div>

  • 4.发表留言按钮

  设置留言块dividmessage,然后将发布留言按钮的href指向#message锚点即可。

1
<a href="#message" class="btn btn-secondary btn-block btn-lg" type="button">发布留言</a>
  • 5.收藏物品按钮

  将该物品的username字段内容作为user/showuser.php?user=的值查询即可。

1
<a href="favorite.php?pid=<?php echo $id;?>" class="btn btn-secondary btn-lg btn-block" type="button">收藏物品</a>

添加物品留言addMes.php

  • 1.将留言内容和物品id提交给showItem/addMes.php界面

  • 2.showItem/addMes.php检测提交信息,并补全username
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
@include('../config/config.php');
header('Content-type:text/html;charset=utf8');
if(!isset($_POST['content']))
{
echo "<script>alert('非法访问!');history.go(-1);</script>";
exit();
}

if(empty($_POST['content']))
{
echo "<script>alert('留言内容不能为空!');history.go(-1);</script>";
exit();
}

if( (!isset($_POST['pid'])) || empty($_POST['pid']))
{
echo "<script>alert('非法访问!');history.go(-1);</script>";
}

SESSION_START();
if($_SESSION['username']=='')
{
header('location:'.$basedir.'user/login.php');
exit();
}

$username = $_SESSION['username'];
$content = $_POST['content'];
$pid = $_POST['pid'];
  • 3.数据检测并插入数据库后返回显示物品界面
1
2
3
4
5
6
7
8
9
$sql = "INSERT INTO message(pid,content,username) VALUES('$pid','$content','$username')";
$res = mysql_query($sql);
if(!$res)
{
echo "<script>alert('留言失败!');history.go(-1);</script>";
exit();
}else{
echo "<script>alert('留言成功!');window.location.href='$basedir/showItem/?id=$pid#message';</script>";
}

显示物品留言

  • 1.从message表中查询并显示留言每页3条
1
2
3
第一步:查询当前物品的留言条数确定$page_max
第二步:根据page确定显示哪3条
第三步:将内容打印在对应html中
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
// 查询当前物品的留言条数确定$page_max
$page = isset($page) ? $page : '1';
$sql = "select count(*) as num from message where pid=$id";
$res = mysql_query($sql);
if(!$res)
{
echo "<script>alert('数据库查询失败!');window.location.href='../index.php';</script>";
exit();
}
$row1 = mysql_fetch_assoc($res);
$page_max = ceil($row1['num']/3);
if($page > $page_max)
{
echo "<script>alert('Page num illegal!');history.go(-1);</script>";
}

// 根据page确定显示哪3条
$offset = ($page-1)*3;
$sql = "select * from message where pid=$id limit $offset,3";
$res = mysql_query($sql);
if(!$res){
echo "<script>alert('数据库查询失败!');window.location.href='../index.php';</script>";
exit();
}
$rows = array();
while($row2 = mysql_fetch_assoc($res))
{
$rows[] = $row2;
}
  • 2.显示留言翻页

  无留言情况:

收藏物品favorite.php

  把物品的id作为GET参数传递给favorite.php,然后再获取用户的用户名,一并存入favorite表中。

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
header("Content-type:text/html;charset=utf8");
@include('../config/config.php');
if( (!isset($_GET['pid'])) || empty($_GET['pid']) )
{
echo "<script>alert('非法访问!');history.go(-1);</script>";
}

SESSION_START();
if($_SESSION['username']=='')
{
header('location:'.$basedir.'user/login.php');
exit();
}
$username = $_SESSION['username'];
$pid = $_GET['pid'];

$sql = "INSERT INTO favorite(username,pid) VALUES('$username','$pid')";

$res = mysql_query($sql);
if(!$res)
{
echo "<script>alert('收藏失败!');history.go(-1);</script>";
exit();
}else{
echo "<script>alert('收藏成功!');history.go(-1);</script>";
}

主页 index.php

  • 1.轮播图的设置

  把数据库中按照id的降序排序,查询出3条记录,然后将此3条记录中的tiltedescrimage输出到轮播图的前端中。

1
2
3
4
5
6
7
8
9
10
11
12
// 1.先查询轮播图的信息
$sql = 'select * from good order by id desc limit 0,3';
$res = mysql_query($sql);
if(!$res){
echo "<script>alert('数据库查询出错,请检查数据库配置!');</script>";
exit();
}
$rows=array();
while($row=mysql_fetch_assoc($res))
{
$rows[] = $row;
}
  • 2.每页显示6个物品

  每页显示6个物品,设置偏移量offset来从数据库查询指定页面的条目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$page = isset($_GET['page']) ? $_GET['page'] : '1';
$offset = ($page-1) * 6;
$sql = "select * from good order by id desc limit $offset,6";
$res = mysql_query($sql);
if(!$res)
{
echo "<script>alert('数据库查询出错,请检查数据库配置!');</script>";
exit();
}
$card_rows = array();
while($row=mysql_fetch_assoc($res))
{
$card_rows[] = $row;
}

  然后将条目中的内容输出到前端的指定位置,但descr只输出36个汉字(108字节)的数据。

  查看和分享

  • 3.翻页设置
1
2
3
4
5
6
7
8
9
10
// 3.翻页 - 从数据库中查出所有的记录数量,然后/6 = pageMax
$sql = "select count(*) as num from good";
$res = mysql_query($sql);
if(!$res)
{
echo "<script>alert('数据库查询出错,请检查数据库配置!');</script>";
exit();
}
$row = mysql_fetch_assoc($res);
$pageMax = ceil($row['num']/6);

用户后台相关

  涉及文件

1
2
3
4
5
6
7
user/index.php   #用户后台主页
user/delFavo.php # 删除收藏
user/delGood.php # 删除发布的物品
user/myGood.php # 显示用户自己发布的物品
user/myFavorite.php # 显示用户的收藏
user/resetPass.php # 重置密码
user/loginout.php # 退出登录

用户后台主页user/index.php

  • 1.检测用户是否登录
1
2
3
4
5
session_start();
if(!isset($_SESSION['username']))
{
die(Header('Location: '.$basedir.'user/login.php'));
}
  • 2.查询用户的信息并打印到指定的HTML位置
1
2
3
4
5
$username=$_SESSION['username'];
@include('../config/config.php');
$sql = "select * from user where username='$username'";
$res = mysql_query($sql);
$row = mysql_fetch_assoc($res);

我的物品

  为了将用户发布的物品展示到后台,采用action参数决定后台的显示。

  • 1.接收action参数
1
2
3
4
if(isset($_GET['action']))
{
$page=$_GET['action'];
}
  • 2.根据参数来包含文件

  • 3.显示物品功能的实现myGood.php

  先判断用户是否登录,然后将用户的用户名作为引索到good表中查询。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
include('../config/config.php');
session_start();
if(!isset($_SESSION['username']))
{
die(Header('Location: '.$basedir.'user/login.php'));
}
$username = $_SESSION['username'];
$sql = "select * from good where username='$username' order by id desc";
$res = mysql_query($sql);
$rows_table = array();
while($row_table=mysql_fetch_assoc($res))
{
$rows_table[]=$row_table;
}

  用一个table来显示结果

  其中,查看物品引一个链接到showItem/index.php,删除物品的实现:接收一个参数物品的id,然后先检测物品的主人是不是当前登录的用户,如果是则删除该物品,如果不是则提示非法访问,代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Header('Content-type:text/html;charset=utf-8');
@include('../config/config.php');
$id = $_GET['id'];
$sql = "select username from good where id=$id";
$res = mysql_query($sql);
$row = mysql_fetch_assoc($res);
SESSION_START();
if($_SESSION['username']!==$row['username'])
{
echo "<script>非法操作</script>";
exit();
}
$sql = "delete from good where id=$id";
$res = mysql_query($sql);
if($res)
{
echo "<script>alert('删除成功!');window.location.href='$basedir/user/?action=showItem';</script>";
}
else
{
echo "<script>alert('删除失败');history.go(-1);</script>";
}
  • 4.物品发布

  直接一个超链接到addGood.php即可。

我的收藏

  收藏列表也是通过action参数,将收藏显示实现界面包含在后台主页的。

  • 1.查询用户的收藏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@include('../config/config.php');
if(!isset($_SESSION['username']))
{
die(Header('Location: '.$basedir.'user/login.php'));
}
$username = $_SESSION['username'];
$sql = "select * from favorite where username='$username'";
$res = mysql_query($sql);
//var_dump($res);
$rows_table1 = array();
while($row_table1 = mysql_fetch_assoc($res))
{
$rows_table1[]=$row_table1;
}
  • 2.将收藏信息打印到表格中

  由于收藏表只记录了用户名和收藏的物品id,所以需要到good表中去查询具体的物品信息。

  • 3.查看收藏的物品详情

  打印出的表格会有一个按钮,是查看收藏物品的详情的,如下图:

  其实现方法就是把物品id作为参数,超链接到showItem/index.php

  • 4.取消收藏

  其实现方法就是把物品id作为参数,超链接到user/delFavo.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
<?php
Header('Content-type:text/html;charset=utf-8');
@include('../config/config.php');
$id = $_GET['id'];
$sql = "select username from favorite where id=$id";
$res = mysql_query($sql);
$row = mysql_fetch_assoc($res);
SESSION_START();
if($_SESSION['username']!==$row['username'])
{
echo "<script>非法操作</script>";
exit();
}
$sql = "delete from favorite where id=$id";
$res = mysql_query($sql);
if($res)
{
echo "<script>alert('取消收藏成功!');window.location.href='$basedir/user/?action=favorite';</script>";
}
else
{
echo "<script>alert('取消收藏失败');history.go(-1);</script>";
}
?>

用户操作

  • 1.修改密码

  在用户主页包含resetPass.phpresetPass.php的实现:1.接收参数,检查参数;2.检测旧密码是否正确;3.新密码是否相同,如果相同则修改。

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
include('../config/config.php');
if(isset($_POST['submit']))
{
// 1.接收参数,检查参数
if(isset($_POST['oldPass']) && isset($_POST['newPass']) && isset($_POST['newPass1']))
{
$oldPass = $_POST['oldPass'];
$newPass = $_POST['newPass'];
$newPass1 = $_POST['newPass1'];
if($oldPass && $newPass && $newPass1)
{

}
else
{
echo "<script>alert('密码不能为空!');history.go(-1);</script>";
exit();
}
}
else{
echo "<script>alert('非法访问!');history.go(-1);</script>";
exit();
}

// 2.检测旧密码是否正确
session_start();
$username = $_SESSION['username'];
$oldPass = md5($oldPass);
$sql = "select password from user where username='$username'";
$res = mysql_query($sql);
$row = mysql_fetch_assoc($res);
if($row['password']!==$oldPass)
{
echo "<script>alert('旧密码不正确!');history.go(-1);</script>";
exit();
}

// 3.新密码是否相同,如果相同则修改
if($newPass!==$newPass1)
{
echo "<script>alert('新密码与重复新密码不同!');history.go(-1);</script>";
exit();
}
$newPass = md5($newPass);
$sql = "UPDATE user SET password='$newPass' where username='$username'";
$res = mysql_query($sql);
if($res)
{
echo "<script>alert('修改密码成功!');window.location.href='$basedir/user/index.php';</script>";
}else
{
echo "<script>alert('修改密码失败!');history.go(-1);</script>";
}
}

  • 2.注销登录

  超链接到loginout.php,其实现方法就是把session删掉。

1
2
3
4
5
6
<?php
include('../config/config.php');
session_start();
unset($_SESSION['username']);
header("Location: ".$basedir);
?>

成品地址

easegood