MySQLi中使用预处理语句执行数据的插入操作
首先在书写sql语句时,它的值换成了使用?的方式来作替代。
#书写sql语句
$sql = "insert into student(stu_name,stu_psd,stu_age) values(?,?,?)";
MySQLi中使用预处理语句,主要调用mysqli这个类下的prepare()方法,准备执行预处理sql语句,调用了这个prepare()方法后,接着会返回一个mysqli_stmt对象,通过调用mysqli_stmt对象下的bind_param()方法来进行绑定参数,最后通过调用mysqli_stmt对象下的execute()方法来执行完成预处理操作。
我们可以来看一下mysqli_stmt对象下有哪些方法和属性?常用的标出来。
![](https://img.haomeiwen.com/i19781462/83ac7ec3d0903822.png)
值得注意的是:在调用bind_param()方法,绑定参数的时候,需要留意bind_param()方法的第一个参数是填写参数类型,它代表着哪些含义?
主要的参数类型常用有3种:
- i 代表整型
- d 代表浮点型
- s 代表字符串型
案例代码
<?php
#设置头信息
header('content-type:text/html;charset=utf-8');
#创建数据库连接,new一个mysqli类
$mysqli = @new mysqli('localhost','root','12345678','qinfb_school');//主机(服务器IP)、数据库用户、数据库密码、你要使用的数据库
// var_dump($mysqli);
if($mysqli -> errno){
//检测数据库的连接状态,如果数据库连接失败,给出报错反馈码和报错信息。
die('connect_error:'.$mysqli -> error);
}
#设置字符集
$mysqli -> set_charset('utf8');
#书写sql语句
$sql = "insert into student(stu_name,stu_psd,stu_age) values(?,?,?)";
#准备s预处理语句
$mysqli_stmt = $mysqli -> prepare($sql);//返回的就是一个stmt对象
print_r($mysqli_stmt);
$stuName = '李芳';
$stuPsd = md5('123456');
$stuAge = 21;
//绑定参数
$mysqli_stmt -> bind_param('ssi',$stuName,$stuPsd,$stuAge);
//执行预处理语句
if( $mysqli_stmt -> execute()){//如果预处理语句执行成功
echo $mysqli_stmt -> insert_id;//打印自增长ID
}else {
$mysqli_stmt -> error;//给出页面报错信息
}
$mysqli -> close();//关闭数据库连接,释放结果集
?>
MySQLi中使用预处理语句可以有效防止sql注入攻击
什么叫sql注入攻击?如何产生sql注入?我们通过具体的案例来look一look.
首先准备一个登录界面login.php(简单点就好了)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<form action="doAction.php" method="post">
<table border="1">
<tr>
<td>用户名:</td>
<td><input type="text" name="userName"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td colspan="2"><input style="width: 100%;" type="submit" value="提交"></td>
</tr>
</table>
</form>
</body>
</html>
它的页面长这个样子:
![](https://img.haomeiwen.com/i19781462/016721871286a46c.png)
当我们点击form表单提交的的时候,会将用户名和密码发送doAction页面进行处理。
doAction页面代码:
<?php
#设置头信息
header('content-type:text/html;charset=utf-8');
#创建数据库连接,new一个mysqli类
$mysqli = @new mysqli('localhost','root','12345678','qinfb_school');//主机(服务器IP)、数据库用户、数据库密码、你要使用的数据库
// var_dump($mysqli);
if($mysqli -> errno){
//检测数据库的连接状态,如果数据库连接失败,给出报错反馈码和报错信息。
die('connect_error:'.$mysqli -> error);
}
#设置字符集
$mysqli -> set_charset('utf8');
//拿到form表单提交过来的数据
$userName = $_POST["userName"];
$password = $_POST["password"];
#书写sql语句
$sql = "select * from student where stu_name = '{$userName}' and stu_psd = '{$password}'";
#通过调用mysqli类下的query()方法来执行一条语句,返回的是一个mysqli_mysqli对象
$mysqli_result = $mysqli -> query($sql);
//逻辑判断依据
if($mysqli_result && $mysqli_result -> num_rows > 0){//mysqli_result为真,并且返回值>0
echo '登录成功!';
}else {
echo '登录失败!';
}
验证效果:正常人的登录方式逻辑,输入账号和密码,然后点击登录。
首先我们来看下数据库中有没有该用户,并且匹配密码,有该用户,并且密码匹配成功,才能登录成功。否则都显示登录失败。
![](https://img.haomeiwen.com/i19781462/2270fb2d7ba44e77.png)
![](https://img.haomeiwen.com/i19781462/3a714eb86881b62b.png)
那么什么叫sql注入攻击呢?
我们来看下这种情况,完全不需要账号和密码进行登录,也能进行登录成功。
![](https://img.haomeiwen.com/i19781462/f35b7011e734cefe.png)
我们来分析一下sql注入攻击为什么能成功实现,首先我们得知道一下,其实在“sql注入攻击”这个的术语当中的注入指的是注释的注,因为在mysql当中,注释语句有2种写法;分别是#号和--短横线。
比如上面这个例子:
后面输入的#号相当于把后面的密码匹配的代码给注释掉了,表面过滤掉密码输入,不需要去查询数据库进行匹配了,这样自然而然就掠过了密码限制,不需要密码输入了。
而前面的or 1=1的判断逻辑和这个有关,只要num_rows>0这个条件
![](https://img.haomeiwen.com/i19781462/a67fcb733ea079c1.png)
所以上面的代码没有使用MySQLi中的预处理语句,就会被一些不法分子钻空子,通过sql注入的方式,直接越过了登录限制和数据库的检索,给数据库造成相当大的不可测风险。
不过sql注入攻击的话题早已经成为了过去时了,查了下资料,据说在2010年的时候很流行,但在mysqli增强扩展推出后,特别使用了预处理语句后,sql注入攻击这种过时的玩法已经被淘汰了。
使用预处理语句方案替换:防范sql注入攻击,相当于给数据库装上一堵墙
<?php
#设置头信息
header('content-type:text/html;charset=utf-8');
#创建数据库连接,new一个mysqli类
$mysqli = @new mysqli('localhost','root','12345678','qinfb_school');//主机(服务器IP)、数据库用户、数据库密码、你要使用的数据库
// var_dump($mysqli);
if($mysqli -> errno){
//检测数据库的连接状态,如果数据库连接失败,给出报错反馈码和报错信息。
die('connect_error:'.$mysqli -> error);
}
#设置字符集
$mysqli -> set_charset('utf8');
//拿到form表单提交过来的数据
$userName = $_POST["userName"];
$password = $_POST["password"];
#使用预处理的方式书写sql语句
$sql = "select * from student where stu_name = ? and stu_psd = ?";
#准备预处理语句,返回mysqli_stmt对象
$mysqli_stmt = $mysqli -> prepare($sql);
#绑定参数
$mysqli_stmt -> bind_param('ss',$userName,$password);
#执行预处理语句
//逻辑判断依据
if($mysqli_stmt -> execute()){ //如果为执行成功,获取结果集中的所有记录
$mysqli_stmt -> store_result();#保存结果集
if($mysqli_stmt -> num_rows > 0){//打印结果集>0,也就是证明有数据的时候执行
echo "登录成功!";
}else {
echo '登录失败!';
}
}
#释放结果集
$mysqli_stmt -> free_result();
#关闭预处理语句
$mysqli_stmt -> close();
#关闭数据库连接
$mysqli -> close();
来看下效果:看看sql注入攻击还有没有效果
![](https://img.haomeiwen.com/i19781462/08e8525042d36e1e.png)
结论:使用了sql预处理语句后,sql注入攻击会失效,大大提高了数据的安全性
MySQLi中使用预处理语句执行查询操作
<?php
#设置头信息
header('content-type:text/html;charset=utf-8');
#创建数据库连接,new一个mysqli类
$mysqli = @new mysqli('localhost','root','12345678','qinfb_school');//主机(服务器IP)、数据库用户、数据库密码、你要使用的数据库
// var_dump($mysqli);
if($mysqli -> errno){
//检测数据库的连接状态,如果数据库连接失败,给出报错反馈码和报错信息。
die('connect_error:'.$mysqli -> error);
}
#设置字符集
$mysqli -> set_charset('utf8');
#使用预处理的方式书写sql语句
$sql = "select stu_id,stu_name,stu_psd,stu_age from student where stu_id >= ?";
#准备预处理语句,返回mysqli_stmt对象
$mysqli_stmt = $mysqli -> prepare($sql);
$stu_id = 10;
#绑定参数,绑的是?号部分
$mysqli_stmt -> bind_param('i',$stu_id);
//逻辑判断依据
if($mysqli_stmt -> execute()){ //执行预处理语句,如果执行成功,
$mysqli_stmt -> bind_result($stu_id,$stu_name,$stu_psd,$stu_age);//绑定结果集中的记录(值)到变量中去
//遍历结果集
while($mysqli_stmt -> fetch()){
echo <<< end
<p>编号:$stu_id</p>
<p>名字:$stu_name</p>
<p>密码:$stu_psd</p>
<p>年龄:$stu_age</p>
<hr>
end;
}
}
#释放结果集
$mysqli_stmt -> free_result();
#关闭预处理语句
$mysqli_stmt -> close();
#关闭数据库连接
$mysqli -> close();
效果图:
![](https://img.haomeiwen.com/i19781462/4ff0800af877e945.png)
区分调用mysql_stmt对象下的bind_result()方法:绑定结果集中的记录(值)到变量当中,而调用bind_param()方法:是绑定参数,它对应的是sql语句中的?的部分,一个问号一个参数
MySQLi事物处理
让我们来模仿一个具体的案例,来理解+实现一下什么是事务处理?
事务处理案例:用户转账
来看下任务说明:今天是方珍珠女士的宝贝儿子陆航的生日,按照往常的惯例方珍珠女士都会在儿子生日这天给他转账1000块钱左右,让他自己筹备如何庆祝party。
已知方珍珠女士银行的存款为:1万3000元,陆航的存款为2310元,请按要求开始搭建数据库。
逻辑理解:如果方珍珠女士给陆航成功转账1000元后,那么方珍珠女士的存款就会变为1万2000元,与此同时,陆航的账户就多出了1000元,这一个过程是同步发生的,并不会出现方珍珠女士转了1000元后,而陆航一分钱都没收到的情况。
也就是说,这样一种过程其实就是事务处理,转账双方要不都成功,要不都失败,不能说方珍珠女士账户的钱少了,而陆航账户的钱没加,在这个转账的事物处理中,双方都必须成功。
数据库的实现:创建一张账户表,表中的字段有账户人和账户的存款额
![](https://img.haomeiwen.com/i19781462/f65d460d20b784d4.png)
![](https://img.haomeiwen.com/i19781462/102663fcfc2eb60f.png)
代码实现转账业务:主要通过update语句
<?php
#设置头信息
header('content-type:text/html;charset=utf-8');
#创建数据库连接,new一个mysqli类
$mysqli = @new mysqli('localhost','root','12345678','qinfb_school');//主机(服务器IP)、数据库用户、数据库密码、你要使用的数据库
// var_dump($mysqli);
if($mysqli -> errno){
//检测数据库的连接状态,如果数据库连接失败,给出报错反馈码和报错信息。
die('connect_error:'.$mysqli -> error);
}
#设置字符集
$mysqli -> set_charset('utf8');
#关闭自动提交功能:false
$mysqli -> autocommit(false);
#书写sql语句
$sql1 = "update account
set saving = saving - 1000
where userName = '方珍珠'";
$res1 = $mysqli -> query($sql1); //query()执行单挑sql语句,返回res对象
#得到受影响的记录条数
$res_affect1 = $mysqli -> affected_rows;//产生受影响的记录条数,affected_rows
$sql2 = "update account
set saving = saving + 1000
where userName = '陆航'";
$res2 = $mysqli -> query($sql2);
$res_affect2 = $mysqli -> affected_rows;
//逻辑判断:当双方都转账成功。
if($res1 && $res_affect1 > 0 && $res2 && $res_affect2 > 0) {//都为真
$mysqli -> commit();
echo '转账成功!';
$mysqli -> autocommit(true);//开启自动提交功能
}else {
$mysqli -> rollback();//回滚事物
echo '转账失败';
}
$mysqli -> close();//关闭连接
?>
事物结果预览:
![](https://img.haomeiwen.com/i19781462/9969daee7fbbef84.png)
网友评论