使用
PDO
写数据库交互是可以防止SQL
注入的
因为没有输入密码 所以执行错误,打印了catch语句里的内容
exec():
返回SQL语句执行后受影响的行数
就是这样:
所以一般增删改都用exec(),这样子我们就可以很清楚的知道是否执行成功,如果exec()返回的结果为0,那么这肯定是没成功执行(增删改)的。
query():
返回SQL语句执行后放回的数据
先看看数据库里都有什么数据:
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 | ?> |
页面上返回的结果:
所以,一般是用来查询的都是用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 | ?> |
结果:
也可以这样的方式:
这样子是有好处的,比如表单提交过来的数据就是一个数组,我们可以通过直接传递数组,方便许多。
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 | ?> |
结果:
事物处理:
比如我们去银行汇款的时候,由于某些问题,收款人未收到金额,这个时候汇款人肯定会找银行解决这个问题的,那么久需要用到事物处理了,将用户汇过去的钱还原到数据库里
首先我创建了一个表,里面有one和two用户,他们的存款都有1000:
我们先开启事物处理start transaction;
:
然后这个时候当one用户想给two用户转100元的时候,出现了问题:
这里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 | ?> |
返回的结果:
对比数据库里的数据来看:
我们可以看到这个fetchColumn()
就是返回数据库里的第一列的数据,这里的第一列是Id,而且我打印了2次,所以对应的输出为7、1,这个结果相当于$row[‘id’]