前言:使用PHP和MySQL开发后台管理系统的过程中,发现有一些通用的【套路小Tip】,这里集中记录一下。结合工作中ing的后台业务,我逐渐体会到:除了技术知识外、能使用户体验好的“使用流程设计”积累也十分重要╭( ・ㅂ・)و ̑̑
项目github地址:https://github.com/66Web/php_book_store,欢迎Star。
一、知识点记录
1、数据库的表名和列名
- 绝对不要和数据库的关键字相同 order order by
- 订单表-indent 分类表-class(数据库中没有class关键词)
- 数据库中 凡是数字 INT FLOAT 一定要UNSIGNED 有负数的不能加UNSIGNED
- 数据库插入时间 使用时间戳 UNIX_TIMESTAMP
2、后台用户模块
- 修改页面change.php:必须要id 隐藏域,带过去id
<input type="hidden" name="id" value='<?php echo $row['id'] ?>' />
- 因为update.php中的update语句中where id= ?才可以形成完整语句
- 图书模块change.php id img 两个隐藏域 方便update.php中图片缩放处理和删除原图
3、_top 是指向:上一级目录
<p><a href="logout.php" target='_top'>|-退出系统</a></p>
4、disabled 禁用username提交,不能修改
<p>管理员名:</p>
<p><input type="text" name='username' value='<?php echo $row['username']?>' disabled></p>
5、后台修改、删除
- 能通过带参数id等实现,就不要查数据库,不灵活,能不查就不查。
6、Select选项‘修改’时显示原选项
<p>类别:</p>
<p>
<select name="class_id">
<?php
$sqlClass="select * from class"; //创建sql语句
$rstClass=mysql_query($sqlClass); //发送sql语句
while($rowClass=mysql_fetch_assoc($rstClass)){ //读取并判断mysql服务器返回结果
if($rowClass['id'] == $rowBook['class_id']){ //rowClass的id 与传过来的rowCook的class_id相同时,选中 加selected
echo "<option value='{$rowClass['id']}' selected>{$rowClass['name']}</option>";
}else{
echo "<option value='{$rowClass['id']}'>{$rowClass['name']}</option>";
}
}
?>
</select>
</p>
7、后台书的模块,delete.php
$file="../../public/uploads/{$img}"; //定义图片文件路径
$file2="../../public/uploads/thumb_{$img}" //定义缩略图文件路径 //删除图片 删除文件用unlink()
unlink($file);
unlink($file2);
8、传文件函数
- move_uploaded_file($src,$dst) 上传成功返回true 否则false
- 第一个参数:$src 上传文件的临时文件名
- 第二个参数:$dst 上传后保存的新的路径和名称
$ext = array_pop(explode('.',$name));
$dst = '../../public/uploads/'.time().mt_rand().'.'.$ext;//指定地址,并随机生成新文件名 // array_pop() 函数删除数组中的最后一个元素
// explode('.',$name) 字符串分割函数获得文件扩展名.jpg等 $src = $_FILES['img']['tmp_name']; //文件上传时在临时目录中被保存成一个临时文件的文件名
$name = $_FILES['img']['name']; //上传文件的文件名
- 为了让前台效率不下降,进行图片缩放
- 等比例计算真实目标资源的宽和高 (算法难度)
//判断 原图x/目标x > 原图y/目标y 以大的比例结果为准 1000/500 500/500
2 1 - 等比例计算真实目标资源的宽和高 如果结果为小数,缩放能小不能大,用floor
$img = basename($dst); //获得目录下的文件名a.jpg
9、PHP中exit; 可以阻止脚本,不用通篇注释。
10、图书模块update.php
$imgerror=$_FILES['img']['error']; //文件上传错误信息 //图片上传--先上传新图,后删除原图,上传失败不删原图
if($imgerror === 0){
11、多表查询
- 三表查询 后台评论模块index.php
$sql="select comment.*,user.username,book.name
from comment,user,book
where comment.user_id=user.id and comment.book_id=book.id";
$rst=mysql_query($sql); - 两表查询 后台书模块index.php
$sql="select book.*,class.name cname from book,class where book.class_id=class.id";
$rst=mysql_query($sql);
12、后台评论模块index.php
- 双引号不能解析函数,要拿出来date(),拼接
echo "<td>".date('Y-m-d',$row['time'])."</td>";
13、在页面里面流通的get post中的数据都变成字符串了
- 不存在数字类型,所以不能用=== ,要用==
if($row['id']==1){
//编号为1 的删除按钮的a链接,禁用--<a href='javascript:'></a>,改背景色为灰色
echo "<td><a href='javascript:' style='background:#888'>删除</a></td>";
}else{
echo "<td><a href='delete.php?id={$row["id"]}'>删除</a></td>";
}
14、后台广告模块
- 一般广告的位置position 按从上往下,然后从左往右 0~8
- 为了不暴露admin,后台广告(图书等)图片上传路径 放在前后台公共 public的文件夹 下
15、订单模块
- 订单模块是电商网站后台错误率最高的地方,一定要检查无误。
- 同一时间下的订单,订单号和时间一致,分组聚合,合并查看
- 按订单号分组聚合:group by indent.code
- 两表查询:
$sql="select indent.price,indent.num,book.name,book.img
from indent,book
where indent.book_id=book.id and indent.code='{$code}'";
$rst=mysql_query($sql);订单编号code是varchar类型,要加单引号:失误率极高!
indent.code='{$code}'
- 报错,排错方法
- 打印出$sql语句
- 把打印出的sql语句在mysql中执行,报出具体错误
echo $sql;
exit;
-
加载出缩略图 thumb_{}
echo "<td><img src='../../public/uploads/thumb_{$row['img']}' width='50px'></td>";
-
输出合计
echo "<td>".$row['price']*$row['num']."</td>";
16、后台权限把控:后台每一个页面都要写(或模块化引入)
- 否则,毫无安全可言!
<?php
session_start(); if(!$_SESSION['userid']){
echo "<script>location='login.php'</script>";
exit; //防止程序在跳转之前,突然的,执行下去下面的代码了
}
?>
17、session数组:将数据存放在服务器中
- 开启session
session_start();
- 设置session
$_SESSION['username']='user1';
$_SESSION['user_id']='15'; - 删除session
- 开启session
session_start();
- 清空session数组
$_SESSION=array();
- 删除客户端的cookie文件
setcookie('PHPSESSID','',time()-1,'/');
- 删除服务器上PHPSESSID所对应的session文件
session_destroy();
18、退出后台登录
<?php
session_start(); $_SESSION = array(); //清空session数组
session_destroy(); //删除服务器上PHPSESSID所对应的session文件
setcookie('PHPSESSID','',time()-3600,'/'); //删除客户端的cookie文件 echo '<script>location="login.php"</script>';
?>
19、前台广告 动态放置
- index.php:从广告表中查到所有数据,放入一个二维数组中;为了与位置一一对应,将位置设置为数组下标
<?php
include '../public/common/conn.php'; $sqlAdvert = "select * from advert";
$rstAdvert = mysql_query($sqlAdvert);
while($rowAdvert=mysql_fetch_assoc($rstAdvert){
$rowAds[$rowAdvert['pos']]=$rowAdvert;
}
?>
<div class="ads">
<img src="../public/upadverts/<?php echo $rowAds[0]['img']?>" alt="">
</div>
20、网站下不要用绝对路径,这样文件名改动会出问题
- header.php:explode('/',$path); //截取字符串函数
<?php
$path = $_SERVER['PHP_SELF'];
$arr = explode('/',$path);
$root = '/'.$arr[1]; //获取根目录
?> <a href="">
<img src="<?php echo $root?>/home/public/img/logo.png" alt="">
</a>
21、首页 重复加载的相似度很高的【楼层、数据块】都要通过 php循环加载
- 前台页面中写sql语句一般都带一个表名,因为一个页面要查很多不同的表
- 在select查找时,order by rand() limit 4 随机取4个
<?php
$sqlClass = "select * from class order by id limit 2";
$rstClass = mysql_query($sqlClass);
$f = 1;
while($rowClass=mysql_fetch_assoc($rstClass)){
?>
<!--楼层开始-->
…… …… ……
<?php
$sqlBook = "select book.* from book,class where book.class_id = class.id and class.id =
{$rowClass['id']} and book.shelf=1 order by book.id limit 4";
$rstBook = mysql_query($sqlBook);
while($rowBook = mysql_fetch_assoc($rstBook)){
?>
<!--楼层数据块开始-->
…… …… ……
<!--楼层数据块结束-->
<?php
}
}
?>
<!--楼层结束-->
22、前台页面中 动态循环添加数据
- 第一步:先查数据表
$id=$_GET['class_id'];
$sqlClass="select * from class where id = {$id} ";
$rstClass=mysql_query($sqlClass); - 第二步:如果抓取一行->数组[下标]
$rowClass=mysql_fetch_assoc($rstClass);
- 如果抓取多行->while循环
while($rowClass=mysql_fetch_assoc($rstClass)){
…… ……
} - 需要数据处:
<?php echo $rowClass['name']?>
23、打印 查看:查到的数据结果
<?php
…… ……
while($rowClass=mysql_fetch_assoc($rstClass)){
echo '<pre>';
print_r($rowClass);
echo '</pre>';
}
?>
24、前台不同页面之间 跳转 通过a链接传递参数,查表,得到想要的结果
- book.php 中 分类>>类别名称 需要传一个class_id
<span><a href='class.php?class_id=<?php echo $class_id?>'>分类</a> » <?php echo $rowClass['name']?></span>
- 分类页面 图书分页显示部分 第一页/上一页/下一页/尾页 传两个值 :page 和 class_id
if($page>=1 && $totalpage>1){
echo "<a href=?page=1&class_id={$rowClass['id']}>第一页 </a>";
}
25、header.php 中控制登录、注册、切换用户名
- 用session判断,前面需要开session_start(); 只能放在第一行,前面不允许有任何输出
- 但是,header.php是被包含的页面,其它页面前面会有输出
- 所以,heder.php里不能加session_start(); 要在加的页面里加
<?php
if(!$_SESSION['home_username']){
echo "<a href='{$root}/home/login.php'>登录</a>";
}else{
echo " <a href='{$root}/home/person/index.php'>欢迎
{$_SESSION['home_username']}登录</a> <a href='{$root}/home/logout.php'>退出</a>";
}
?> - 重新打开浏览器,会有undefined:用@解决
@$_SESSION['home_username'];
26、个人中心 左右结构页面
- 第一种:复杂式
- 左侧 不同的栏目给不同的参数
- 右侧 给一个switch,根据左侧给的不同参数,发生不同的变化
- 优点:只需写一个页面
- 缺点:共用的php里易写乱,易出错
- 第二种:简单式(√)
- 复制页面,写好一个,复制给不同的页面,然后用链接跳转。
- 易错:echo " "; 里原本html里面的双引号,都要改为单引号
27、通过session方法开发购物车,用户关闭浏览器后,自动清空购物车
- 点击【加入购物车】
- 先要跳转到 cart/insert.php 添加进购物车
- 确定后,才跳转到 index.php 查看购物车
- 用户选择 → 加入购物车 后,如果最后没有购买,结账 → 用户关闭浏览器后,自动清空购物车
- 浏览器关闭后,session数组立刻清空,session自动过期
- PHPSESSID 保存在浏览器 cookie中
- 购物车核心原理:数组改造,大数组里面放小数组 insert.php
session_start(); $id = $_GET['id'];
$sql = "select * from book where id = {$id}";
$rst = mysql_query($sql);
$row = mysql_fetch_assoc($rst); $_SESSION['books'][$id]=$row; //用id限制同一图书只能加一个,然后在购物车页面中进行加减数量 //在图书信息的子数组中临时加一个num 默认1, 方便index.php中使用变量 <?php echo $book['num']?>
$_SESSION['books'][$id]['num']=1;
- 跳转到 index.php 查看
echo '<script>location="index.php"</script>';
有了数组,就不用while了,用foreach遍历数组 index.php
<?php
foreach($_SESSION['books'] as $book){
?>
…… ……
<?php
}
?>
- 删除购物车图书 delete.php
// 在session中找到 删除
unset($_SESSION['books'][$id]); - 清空购物车图书
$_SESSION['books']=array();
不可以unset,那样会把 $_SESSION['books']删掉
- 购物车计算总额
$tot = 0
遍历后(foreach 或 while循环)
$tot += $row['price']*$row['num'];
- 购物车图书数量加减:add.php 、cut.php
$_SESSION['books'][$id]['num']++;
$_SESSION['books'][$id]['num']--;限制数量 加→不能多于库存 减→不能少于1个
if($_SESSION['books'][$id]['num']<1){
$_SESSION['books'][$id]['num'] = 1;
}
if($_SESSION['books'][$id]['num'] > $_SESSION['books'][$id]['stock']){
$_SESSION['books'][$id]['num'] = $_SESSION['books'][$id]['stock'];
}
28、购物车的 联系方式、提交订单
- 个人中心的所有页面,都要 提示 先登录,才可以看到
<!--判断用户是否登录 session-->
<?php
if($_SESSION['home_username']){
?>
……
<?php
}
?>
- 用户在【不关闭浏览器】情况下
- 退出登录 → 保留session中购物车的数组内容
- 实现换个账号结算购物车 → 交换数组内容(购物车内容不变)
$arr=$_SESSION['books']; $_SESSION = array(); //清空session数组 $_SESSION['books']=$arr;
29、登录后不仅要在session中放入username ,一般还要放入userid
- 使用userid进行判断,获取数据
- 方便后面在 【用户个人信息】(等其它只有用户自己可看到的页面)中 获取 userid
$_SESSION['home_userid'] = $row['id']; $user_id = $_SESSION['home_userid'];
$sql = "select * from touch where user_id = {$user_id}";
$rst = mysql_query($sql);
30、在各个 后台数据管理模块中 修改都要有一个隐藏域 传id
31、购物车生成订单
- 需要form表单传一个touch的id,其余的图书信息都在购物车的session数组中存放,可直接取
- 核心要点:借用session技术跨页面 ↑
- 注意:一定要把 form表单 放在table的外面,因为一些浏览器会不支持table里面放form,只支持form里面放table
- 生成 订单号 为确保唯一性:随机数 加 时间戳
$code =time().mt_rand();
$code =microtime(true).time().mt_rand(); //microtime(true)微秒
$code =time().mt_rand().mt_rand(1,10);
$code =time().mt_rand().range('a','z');
32、购物车 提交订单之后,要做两件事
- 第一:库存减去 数量
- 第二:购物车清空
- book.php:加入购物车之前 要判断一下 库存stock至少等于1
33、提交订单的用户,只有在 ‘已确认’状态下,才可以评论
34、在CSS样式表里,用class类
- 最好不用id 标签
- 因为 class 类 优点:唯一的能用,不唯一的也能用
二、运行效果图
1、注册功能
注册界面 |
错误提示 |
通过提示 |
2、二手书搜索功能
高级搜索成功界面 |
搜索失败提示 |
3、二手书发布功能
用户发布二手书界面 |
用户发布二手书成功 |
4、二手书购买与评论功能
加入购物车界面 |
购物车界面 |
提交订单成功 |
未确认时查看订单界面 |
未确认时查看订单详情界面 |
确认时查看订单详情界面 |
确认后撰写评论 |
评论成功 |
注:转载请注明出处