美文网首页
MySQLi中使用预处理语句执行的相关操作

MySQLi中使用预处理语句执行的相关操作

作者: 似朝朝我心 | 来源:发表于2021-06-09 20:38 被阅读0次

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对象下有哪些方法和属性?常用的标出来。


值得注意的是:在调用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>

它的页面长这个样子:



当我们点击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 '登录失败!';
    }

验证效果:正常人的登录方式逻辑,输入账号和密码,然后点击登录。
首先我们来看下数据库中有没有该用户,并且匹配密码,有该用户,并且密码匹配成功,才能登录成功。否则都显示登录失败。



那么什么叫sql注入攻击呢?

我们来看下这种情况,完全不需要账号和密码进行登录,也能进行登录成功。


我们来分析一下sql注入攻击为什么能成功实现,首先我们得知道一下,其实在“sql注入攻击”这个的术语当中的注入指的是注释的注,因为在mysql当中,注释语句有2种写法;分别是#号和--短横线。

比如上面这个例子:
后面输入的#号相当于把后面的密码匹配的代码给注释掉了,表面过滤掉密码输入,不需要去查询数据库进行匹配了,这样自然而然就掠过了密码限制,不需要密码输入了。

而前面的or 1=1的判断逻辑和这个有关,只要num_rows>0这个条件



所以上面的代码没有使用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注入攻击还有没有效果


结论:使用了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();
    

效果图:



区分调用mysql_stmt对象下的bind_result()方法:绑定结果集中的记录(值)到变量当中,而调用bind_param()方法:是绑定参数,它对应的是sql语句中的?的部分,一个问号一个参数


MySQLi事物处理

让我们来模仿一个具体的案例,来理解+实现一下什么是事务处理?

事务处理案例:用户转账

来看下任务说明:今天是方珍珠女士的宝贝儿子陆航的生日,按照往常的惯例方珍珠女士都会在儿子生日这天给他转账1000块钱左右,让他自己筹备如何庆祝party。

已知方珍珠女士银行的存款为:1万3000元,陆航的存款为2310元,请按要求开始搭建数据库。

逻辑理解:如果方珍珠女士给陆航成功转账1000元后,那么方珍珠女士的存款就会变为1万2000元,与此同时,陆航的账户就多出了1000元,这一个过程是同步发生的,并不会出现方珍珠女士转了1000元后,而陆航一分钱都没收到的情况。

也就是说,这样一种过程其实就是事务处理,转账双方要不都成功,要不都失败,不能说方珍珠女士账户的钱少了,而陆航账户的钱没加,在这个转账的事物处理中,双方都必须成功。

数据库的实现:创建一张账户表,表中的字段有账户人和账户的存款额



代码实现转账业务:主要通过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();//关闭连接
?>

事物结果预览:


相关文章

网友评论

      本文标题:MySQLi中使用预处理语句执行的相关操作

      本文链接:https://www.haomeiwen.com/subject/phheeltx.html