使用环境:PHP 7.4.9;PhpStorm 2025.1.0.1; PHPStudy 8.1.1.3 ; Mysql 5.7.26小迪还有使用DW我这里没有使用,我的环境与小迪用的不同,后面也确实出现了一些问题
知识点:
PHP留言板前后端功能实现 数据库创建&构建&增删改查 内置超全局变量&HTML&JS混编 第三方应用插件&传参&对象调用
章节点:
功能:新闻列表,会员中心,资源下载,留言板,后台模式,模板引用,框架开发等 技术:输入输出,超全局变量,数据库操作,逻辑架构,包含上传&下载删除 技术:JS&CSS混用,Cookie,Session操作
实验过程:
本次实验:使用php原生代码实现留言板功能(也就是没有使用php开发架构)
留言板功能实现流程:


1、浏览器想服务器发起请求然后提交数据
2、服务器向数据库提交数据
3、数据库判断是否接受并写入输入,然后返回给服务器
4、服务器将最后的结果返回给浏览器
步骤:
使用Navicat连接MySql,然后在MySql中创建一个数据库,定义一个表,然后定义表中的字段;数据库中储存留言数据。


注:username和content由用户在留言板输入,ipaddr和uagent由PHP收集用户访问信息
php使用mysqli函数对数据库进行连接 &增删改查等操作,相关使用参考: PHP 5 MySQLi 函数 | 菜鸟教程
常用:
mysqli_connect() 打开一个到MySQL的新链接
mysqli_select_db() 更改连接的默认数据库
mysqli_query() 执行对数据库的查询
mysqli_fetch_row() 从数据库查询结果中取得一行,并作为枚举数组返回
mysqli_close() 关闭打开的数据库
MySQL增删改查:
查:select * from 表名 where 列名 +'条件';
增:insert into 表名(`列名1`,`列名2`) value ('列1值1','列2值2');
删:delete from 表名 where 列名 = '条件';
改:update 表名 set 列名 = 数据 where 列名 = '条件';
phpstorm配置环境


配置前端页面 因为这次代码简单,所以我直接手写没有使用DW,然后如果使用AI生成的话需要修改框选位置的名字以防后面操作出现问题(PHP通过的$_POST通过对name中的关键字获取到表单提交的值,小迪是以这个名字写的代码,如果这里名字修改了后面也需要同时进行修改)


然后在form标签中注意method值和action值,method值表示这个表单提交方式,action表示表单提交到哪里
测试接收值
<?php
$u = $_POST['username'];
$c = $_POST['content'];
echo $u."<br>",$c;

成功从表单中接收到数据
如果网页出现了报错可以在接收变量的时候加上容错符然后就不会报错了(我没有报错)
$u = @$_POST['username'];
$c = @$_POST['content'];
接下来做数据库通讯
连接数据库使用 mysqli_connect() ,然后为了增加代码的复用性,可以将相关参数通过变量传递
<?php
$dbip = '127.0.0.1'; //或者是localhost
$dbuser = 'root';
$dbpass = '123123';
$dbname = 'demo01';
$dbport = 3307; //我的端口冲突了,修改了端口号
$con = mysqli_connect($dbip, $dbuser, $dbpass, $dbname, $dbport);
if (!$con) {
die("连接失败". mysqli_connect_error()); //die是php内置函数,作用是终止脚本返回错误
}
else{
echo "连接成功!";
}

连接成功之后可以开始执行sql语句,向数据库中提交表单数据
向数据库提交数据使用 insert into 表名('列名1','列名2') value ('列1值1','列2值2');
if (!$con) {
die("连接失败". mysqli_connect_error()); //die是php内置函数,作用是终止脚本返回错误
}
else{
// echo "连接成功!";
$u = $_POST['username'];
$c = $_POST['content'];
$ip = $_SERVER['REMOTE_ADDR'];
$ua = $_SERVER['HTTP_USER_AGENT'];
$sql = "insert into gbook(`username`, `content`,`ipaddr`,`uagent`) values ('$u','$c','$ip','$ua');"; //列名就是创建数据库时候的字段
//sql语句使用双引号包括,双引号数组可以解析变量,如果是单引号则不可以解析
//变量使用单引号因为变量接收的可能是字符串,字符串需要用引号扩起来,用双引号的话可能会解析变量什么的
//然后使用mysqli_query向数据库执行sql语句
mysqli_query($con, $sql);
然后查看数据库中现在是还没有信息的

然后在网页提交留言然后再查看数据库数据

php获取表单信息成功提交到数据库
ip和ua信息是通过PHP的超全局变量获取到的关于超全局变量参考以下
下面是常用的一些超全局变量
$_SERVER 这种可以保存关于报头、路径和脚本位置的信息
$_REQUEST 用于收集HTML表单提交的数据
$_POST 用于收集method="post"的HTML表单数据
$_GET 收集URL中的发送的数据,可以用于收集HTML表单数据(method="get")
$_FILES 文件上传且处理包含通过HTTP POST方法上传给当前脚本的文本内容
$_ENV 是一个包含服务器环境变量的数组
$_SERVER['SERVER_ADDR'] 获取系统的IP地址
$_SERVER['SERVER_NAME'] 获取服务器主机的名称
$_SERVER['REQUEST_METHOD'] 获取当前网页的请求方法
$_SERVER['REQUEST_ADDR'] 正在浏览当前网页的用户IP地址
$_SERVER['REQUEST_NAME'] 正在访问的当前网页的用户的主机名
$_SERVER['REQUEST_POST'] 用户连接到服务器的时候用的端口号
$_SERVER[''SCRIPT_FILENAME] 当前执行脚本的绝对路径
$_SERVER['SERVER_SIGNAIURE'] 包含服务器版本和虚拟主机名的字符串
$_SERVER['DOCUMENT_ROOT'] 当前运行脚本所在的文档根目录
$_SERVER['SERVER_PORT'] 服务器使用的端口号
$_COOKIE 通过httpcookie传递脚本的信息 包含通过cookie传递给当前脚本的内容
$_SESSION 包含与所有会话变量有关的信息 包含当前脚本中的所有session内容
$_PORT 包含通过POST方法传递的参数相关信息
$_GET 包含通过GET方法传递参数的相关信息
$GLOBALS 由所有已定义全局变量组成的数组 这种全局变量可以在PHP脚本中访问任意位置的全局变量
现在基本功能可以实现,但是只要刷新就会接收到ip和ua信息就会向数据库提交数据,就会导致有很多空白数据
所以这里可以通过一个判断,判断$u中是否有值决定是否执行向数据库写入数据
$u = $_POST['username'];
if(isset($u)){
$c = $_POST['content'];
$ip = $_SERVER['REMOTE_ADDR'];
$ua = $_SERVER['HTTP_USER_AGENT'];
$sql = "insert into gbook(`username`, `content`,`ipaddr`,`uagent`) values ('$u','$c','$ip','$ua');"; //列名就是创建数据库时候的字段
//sql语句使用双引号包括,双引号数组可以解析变量,如果是单引号则不可以解析
//变量使用单引号因为变量接收的可能是字符串,字符串需要用引号扩起来,用双引号的话可能会解析变量什么的
//然后使用mysqli_query向数据库执行sql语句
mysqli_query($con, $sql); //query($con,$sql)是执行向哪个数据库执行sql语句
}
这样可以实现如果是空数据的话,刷新不会向数据库写入数据,But,如果你提交过数据,在刷新浏览器的时候,浏览器会提交最后一次提交的POST请求,会继续向网页写入数据,这里如果想要解决的话需要使用PRG模式提交
然后在向数据库提交数据之后(留言成功)输出一个弹窗
<form method="post" name="form1" action="">
<p>
用户名: <input type="text" name="username">
</p>
<p>
内容: <textarea name='content'></textarea>
</p>
<p>
<input name='submit' type='submit' value="提交">
</p>
</form>
<?php
$dbip = '127.0.0.1'; //或者是localhost
$dbuser = 'root';
$dbpass = '123123';
$dbname = 'demo01';
$dbport = 3307; //我的端口冲突了,修改了端口号
$con = mysqli_connect($dbip, $dbuser, $dbpass, $dbname, $dbport);
if (!$con) {
die("连接失败". mysqli_connect_error()); //die是php内置函数,作用是终止脚本返回错误
}
else{
// echo "连接成功!";
$u = $_POST['username'];
if(isset($u)){
$c = $_POST['content'];
$ip = $_SERVER['REMOTE_ADDR'];
$ua = $_SERVER['HTTP_USER_AGENT'];
$sql = "insert into gbook(`username`, `content`,`ipaddr`,`uagent`) values ('$u','$c','$ip','$ua');"; //列名就是创建数据库时候的字段
//sql语句使用双引号包括,双引号数组可以解析变量,如果是单引号则不可以解析
//变量使用单引号因为变量接收的可能是字符串,字符串需要用引号扩起来,用双引号的话可能会解析变量什么的
//然后使用mysqli_query向数据库执行sql语句
if (mysqli_query($con, $sql)) { //使用mysqli_query($con,$sql)是执行向哪个数据库执行sql语句
echo "<script>alert('留言成功');</script>";
}
else{
echo "<script>alert('留言失败');</script>";
} //使用echo输出js语句,然后浏览器会自动渲染
}
}


然后再实现将留言内容显示出来的功能,这里需要使用到sql的查询语句,以及php的mysqli_fetch_row() 函数逐行提取数据

以上实现了基本的功能,下面开始是一些拓展功能,例如:包含
将部分重复的功能实现代码(例如数据库连接)放在单独的文件中管理,以及将管理部分(也就是查询部分代码)写入到admin目录下的gbook-admin.php文件中,然后在gbook-admin.php使用 include "../config.php"将config.php包含到文件内,然后代码就可以正常访问了



这里的红色波浪线可以忽略
上面的代码已经可以实现:(对于我的环境)2.php是用户访问的页面,可以进行留言和显示留言;config.php存放的是数据库连接相关代码;gbook-admin.php用于管理留言(查看留言和删除留言[删除留言功能在后面写)
现在完成对管理页面的删除留言功能的代码
在显示留言的后面增加一个删除按钮,实现点击之后可以删除留言
while($row = mysqli_fetch_row($data)){
echo "<hr>";
echo "用户名: ".$row[0]."<br>";
echo "内容: ".$row[1]."<br>";
echo "<hr>";
echo "<a href='gbook-admin.php?id=$row[0]'>删除</a>";
}
删除按钮是进行URL访问,所以这里是get访问
$delstr = $_GET['del'];
//del后面跟着的是需要删除的数据,也就是字符串的第一个值(username列的值)
if(isset($delstr)){
$sql2 = "delete from gbook where username = '$delstr';";
if(mysqli_query($con, $sql2)){
echo "<script>alert('删除成功');</script>";
}
}
到目前为止基本功能已经实现,但是还是有点问题;接下来将三个文件中的文件都封装为函数
这里我将三个文件的代码直接贴出来让,然后在详细解释修改部分
<form method="post" name="form1" action="">
<p>
用户名: <input type="text" name="username">
</p>
<p>
内容: <textarea name='content'></textarea>
</p>
<p>
<input name='submit' type='submit' value="提交">
</p>
</form>
<?php
include"config.php";
function add_gbook($con){
$u = $_POST['username'];
if(isset($u)){
$c = $_POST['content'];
$ip = $_SERVER['REMOTE_ADDR'];
$ua = $_SERVER['HTTP_USER_AGENT'];
$sql = "insert into gbook(`username`, `content`,`ipaddr`,`uagent`) values ('$u','$c','$ip','$ua');";
if (mysqli_query($con, $sql)) {
echo "<script>alert('留言成功');</script>";
}
else{
echo "<script>alert('留言失败');</script>";
}
}
}
function show_gbook($con,$del){
$sql1 = "select * from gbook";
$data = mysqli_query($con, $sql1);
while($row = mysqli_fetch_row($data)){
echo "<hr>";
echo "用户名: ".$row[0]."<br>";
echo "内容: ".$row[1]."<br>";
echo "<hr>";
if($del == 'del'){
echo "<a href='gbook-admin.php?del=$row[0]'>删除</a>";
}
}
}
add_gbook($con);
show_gbook($con,1);
<?php
$dbip = '127.0.0.1'; //或者是localhost
$dbuser = 'root';
$dbpass = '123123';
$dbname = 'demo01';
$dbport = 3307; //我的端口冲突了,修改了端口号
$con = mysqli_connect($dbip, $dbuser, $dbpass, $dbname, $dbport);
<?php
include"../config.php";
include '../2.php';
show_gbook($con,'del');
$delstr = $_GET['del'];
//del后面跟着的是需要删除的数据,也就是字符串的第一个值(username列的值)
if(isset($delstr)){
$sql2 = "delete from gbook where username = '$delstr';";
if(mysqli_query($con, $sql2)){
echo "<script>alert('删除成功');</script>";
}
}
1、在2.php中,将向数据库写入数据和查看留言板两个功能分别封装了起来--也就是将对应的功能代码放进函数里面,然后可以通过调用调用函数传递相关参数即可实现对应功能
2、在gbook-admin.php中引用2.php,将管理留言板(查看和删除留言)功能部分代码直接使用2.php中的函数实现
但是这里还是有一点问题的,就是因为管理页面的引入了2.php代码,所以在执行的之后2.php也会被执行,所以会执行两次show_gbook(),其中一次是2.php执行的因为没有达成if条件没有删除按钮的,一次是达成条件包含按钮的
对于show_gkook函数在定义参数的时候,还可以给$del定一个默认值,如果不传递参数则使用默认值,如果传递参数的话是用指定值,这样的话在不需要显示删除按钮的时候,可以不考虑传递$del的值
接下来的知识点主要是第三方插件的引入&&JS传参&&函数对象调用;
为了实现一些其他功能,需要引入插件,例如在留言板中,现在的功能只能上传文字,如果想要支持上传图片或者其他功能则需要引入第三方的插件实现
演示项目使用的是ueditor插件,在这之前需要先将项目文件下载下来然后放入网站目录下
然后在网站主页面里面通过script标签在网站的head标签中引入文件(这里需要将html代码补全,在phpstorm中可以使用 html:5 加tab键生成html)
<script src = ueditor/utf8-php/ueditor.config.js>/*引入配置文件*/</script>
<script src = ueditor/utf8-php/ueditor.all.js>/*引入源码文件*/</script>
然后可以实现效果

也可以实现图片上传效果

然后查看数据库可以得知,这个图片是上传到了插件的目录下,然后在数据库中记录了这个图片的位置
然后需要注意的是,如果form表单的method的值是get,那么在php获取值的时候就需要将超全局变量修改为$_GET
然后关于前端代码的混编就是将代码按照字符串的方式输出,然后浏览器会自动按照对应的html标签或者是脚本语言进行渲染输出;例如
echo "<br>" //输出到浏览器之后就是换行
echo "<script>alert("弹窗"))</script>" //输出到浏览器就是一个js的弹窗效果
最后加一个小迪没有演示成功的XSS攻击

首先将数据全部清空,然后在用户名处写上js语句,然后这个语句会被执行

然后在数据库中,内容部分虽然不是原本内容,但是在web提交内容的时候依旧会被执行



每次访问网页的时候都会被执行
新人学习网安,此blog为记录学习
1208






