使用PDO写数据库交互是可以防止SQL注入的

image_1cc32g77o3lk1cbj1uv2virsj69.png-571.7kB


image_1cc32sdo6pftr6clk8hh98113.png-354.7kB
image_1cc32s7g45hd20j1c24lrfoktm.png-88.7kB
因为没有输入密码 所以执行错误,打印了catch语句里的内容


exec():
返回SQL语句执行后受影响的行数
image_1cc33efh1khk1bnvi4tkcr11kk1g.png-571.3kB

就是这样:
image_1cc33p2h61joh3245hg1avv1rgp2a.png-63.8kB

所以一般增删改都用exec(),这样子我们就可以很清楚的知道是否执行成功,如果exec()返回的结果为0,那么这肯定是没成功执行(增删改)的。


query():
返回SQL语句执行后放回的数据

先看看数据库里都有什么数据:
image_1cc354nl6shfns1ua2vgtoo92n.png-16.5kB

1
<?php
2
    // ... ...(其他省略,主要看sql语句和query的用法)
3
    $sqlTotal = "select * from t1";
4
    $s = $smtTotal = $pdo->query($sqlTotal); 
5
    foreach ($s as $key){
6
        print_r($key);
7
    }
8
    // ... ...
9
?>

页面上返回的结果:

image_1cc356qhj1nov1f433tc1tu4m7l5m.png-159.5kB

所以,一般是用来查询的都是用query(),这样我们就可以看到查询到的结果了。


预处理:

1
<?php
2
    /*这样可以防SQL注入,DVWA的impossible级别也是这样写的*/
3
    $pdo = new PDO('mysql:host=localhost;dbname=blog','root','root'); 
4
    $pdo->exec('set names utf8'); //设置编码
5
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC); //设置默认结果集模式为关联数组
6
    $pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); //修改报错模式
7
    
8
    $sql_query = "select * from users where id=(:id)";
9
    $pre2 = $pdo -> prepare($sql_query); //准备要执行的SQL语句并返回一个 PDOStatement 对象
10
    $pre2 -> bindParam(':id',$id,PDO::PARAM_INT); //绑定参数,想成是把:id的值替换成$id变量里的值
11
    $id = $_GET['id']; //获取GET请求过来的ID值
12
    $pre2 -> execute(); //执行这个SQL语句
13
    $row = $pre2 -> fetch(); //fetch()是返回执行结果(无论怎么查询,最多只能返回一条数据)
14
    print_r($row); //打印查询的结果
15
16
?>

结果:
image_1cc3m5vlj18qnqpjt5s901e0nm.png-130.2kB

也可以这样的方式:
image_1cc3lfrhe1kfsrlpoq25pv166e9.png-419.3kB
这样子是有好处的,比如表单提交过来的数据就是一个数组,我们可以通过直接传递数组,方便许多。

DVWA里impossible级别的SQL注入测试代码:

1
<?php
2
3
if( isset( $_GET[ 'Submit' ] ) ) {
4
    // Check Anti-CSRF token
5
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
6
7
    // Get input
8
    $id = $_GET[ 'id' ];
9
10
    // Was a number entered?
11
    if(is_numeric( $id )) {
12
        // Check the database
13
        $data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
14
        $data->bindParam( ':id', $id, PDO::PARAM_INT );
15
        $data->execute();
16
        $row = $data->fetch();
17
18
        // Make sure only 1 result is returned
19
        if( $data->rowCount() == 1 ) {
20
            // Get values
21
            $first = $row[ 'first_name' ];
22
            $last  = $row[ 'last_name' ];
23
24
            // Feedback for end user
25
            echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
26
        }
27
    }
28
}
29
30
// Generate Anti-CSRF token
31
generateSessionToken(); // 这个是DVWA里的防止CSRF的,可以不用管
32
33
?>

上面的fetch()只返回一条数据,我们可以用fetchALL来返回多条数据

1
<?php 
2
3
    //$sql_query = "select * from users where id=(:id)";
4
    $sql_query = "select * from users where id>(:id)";
5
6
    $pre2 = $pdo -> prepare($sql_query); //准备要执行的SQL语句并返回一个 PDOStatement 对象
7
    $pre2 -> bindParam(':id',$id,PDO::PARAM_INT); //绑定参数,想成是把:id的值替换成$id变量里的值
8
    $id = $_GET['id']; //获取GET请求过来的ID值
9
    $pre2 -> execute(); //执行这个SQL语句
10
    $row = $pre2 -> fetchALL(); //fetch()是返回执行结果
11
    foreach ($row as $key){
12
        print_r($key);
13
        echo "<br>";
14
    }
15
16
?>

结果:
image_1cc3nhcu51gg81v7v1qr01rq71gdg9.png-187.3kB


事物处理:

比如我们去银行汇款的时候,由于某些问题,收款人未收到金额,这个时候汇款人肯定会找银行解决这个问题的,那么久需要用到事物处理了,将用户汇过去的钱还原到数据库里

首先我创建了一个表,里面有one和two用户,他们的存款都有1000:
image_1cc3p6fobp1ugcjulu1gte1ik7m.png-3.6kB

我们先开启事物处理start transaction;
image_1cc3pfsu1fs51plh15s6hbp6de13.png-1.9kB

然后这个时候当one用户想给two用户转100元的时候,出现了问题:
image_1cc3pik7fm031drqil2140mfs20.png-12.2kB
这里one用户的钱没汇到two账户里,却仍然扣除了100元,那么银行知道了事情的真实性,肯定会去处理的,这个时候我们就要用到rollback了,可以回轨(悔棋~)


fetchColumn():
从结果集中的下一行获取第一列

1
<?php
2
3
    $sql_query = "select * from users where id>(:id)";
4
    
5
    $pre2 = $pdo -> prepare($sql_query); //准备要执行的SQL语句并返回一个 PDOStatement 对象
6
    $pre2 -> bindParam(':id',$id,PDO::PARAM_INT); //绑定参数,想成是把:id的值替换成$id变量里的值
7
    $id = $_GET['id']; //获取GET请求过来的ID值
8
    $pre2 -> execute(); //执行这个SQL语句
9
    print_r($pre2 -> fetchColumn());
10
    echo "<br />";
11
    print_r($pre2 -> fetchColumn());
12
    echo "<br />";
13
    
14
    foreach ($row as $key){
15
        print_r($key);
16
        echo "<br>";
17
    }
18
    
19
?>

返回的结果:
image_1cc3qquka1ivlaih137a1mktil8m.png-171.1kB

对比数据库里的数据来看:
image_1cc3qrn5p1f5s2m1n70rm41cr913.png-26.1kB

我们可以看到这个fetchColumn()就是返回数据库里的第一列的数据,这里的第一列是Id,而且我打印了2次,所以对应的输出为7、1,这个结果相当于$row[‘id’]