PDO(PHP Data Object),Mysqli,以及对sql注入等问题的解决
Posted 笨鸟居士的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PDO(PHP Data Object),Mysqli,以及对sql注入等问题的解决相关的知识,希望对你有一定的参考价值。
这篇是上一篇 http://www.cnblogs.com/charlesblc/p/5987951.html 的续集。
看有的文章提到mysqli和PDO都支持多重查询,所以下面的url会造成表数据被删。
http://localhost:8080/test.php?id=3;delete%20from%20users
可是我在mysql版本的函数,上面的sql都不能执行。是不是不支持多重查询了?
这篇文章 http://www.runoob.com/php/php-mysql-connect.html 对mysqli, PDO的方式有一些介绍,不详细。
主要用的这篇文章:http://blog.csdn.net/yipiankongbai/article/details/17277477
三种连接方式:
// PDO $pdo = new PDO("mysql:host=localhost;dbname=database", \'username\', \'password\'); // mysqli, procedural way $mysqli = mysqli_connect(\'localhost\',\'username\',\'password\',\'database\'); // mysqli, object oriented way $mysqli = new mysqli(\'localhost\',\'username\',\'password\',\'database\');
先看mysqli过程型:
<?php header(\'Content-Type: text/html; charset=utf-8\'); echo "PHP version:" . PHP_VERSION . "<br/>"; $con = mysqli_connect(\'10.117.146.21:8306\', \'root\', \'[password]\'); mysqli_select_db($con, \'springdemo\'); $input_id = trim($_GET[\'id\']); $sql = \'select nickname from user where id = \' . $input_id; print_r(\'SQL is:\' . $sql . \'<br/>\'); $result = mysqli_query($con, $sql); if ($result != null) { print_r(\'rows:\' . mysqli_num_rows($result) . \'<br/>\'); while ($row = mysqli_fetch_array($result)) { print_r($row[\'nickname\'] . \'<br/>\'); } } mysqli_close($con); ?>
测试:
http://localhost:8080/test.php?id=3 PHP version:5.5.30 SQL is:select nickname from user where id = 3 rows:1 micro http://localhost:8080/test.php?id=3%20or%201=1 PHP version:5.5.30 SQL is:select nickname from user where id = 3 or 1=1 rows:4 abc micro helloworld 你好
加上real_escape函数:
?php header(\'Content-Type: text/html; charset=utf-8\'); echo "PHP version:" . PHP_VERSION . "<br/>"; $con = mysqli_connect(\'10.117.146.21:8306\', \'root\', \'[password]\'); mysqli_select_db($con, \'springdemo\'); $input_id = mysqli_real_escape_string($con, $_GET[\'id\']); $sql = \'select nickname from user where id = \' . $input_id; print_r(\'SQL is:\' . $sql . \'<br/>\'); $result = mysqli_query($con, $sql); if ($result != null) { print_r(\'rows:\' . mysqli_num_rows($result) . \'<br/>\'); while ($row = mysqli_fetch_array($result)) { print_r($row[\'nickname\'] . \'<br/>\'); } } mysqli_close($con); ?>
测试:
http://localhost:8080/test.php?id=3%20or%201=1 PHP version:5.5.30 SQL is:select nickname from user where id = 3 or 1=1 rows:4 abc micro helloworld 你好 注:仍然有问题,因为没有在url里面加引号!
采用推荐的mysqli的PreparedStatement方式:
?php header(\'Content-Type: text/html; charset=utf-8\'); echo "PHP version:" . PHP_VERSION . "<br/>"; $con = new mysqli(\'10.117.146.21:8306\', \'root\', \'[password]\', \'springdemo\'); //mysqli_select_db($con, \'springdemo\'); $query = $con->prepare(\'SELECT nickname FROM user WHERE id = ?\'); $query->bind_param(\'s\', $_GET[\'id\']); $query->execute(); $result = $query->get_result(); if ($result != null) { print_r(\'rows:\' . mysqli_num_rows($result) . \'<br/>\'); while ($row = mysqli_fetch_array($result)) { print_r($row[\'nickname\'] . \'<br/>\'); } } mysqli_close($con); ?>
测试:
http://localhost:8080/test.php?id=3 PHP version:5.5.30 rows:1 micro http://localhost:8080/test.php?id=3%20or%201=1 PHP version:5.5.30 rows:1 micro
PDO与mysqli的对比:
性能
PDO和MySQLi都有非常好的性能。在非prepared statements的基准测试下,MySQLi略快2.5%,而prepared statements下是6.5%,可以说对于性能无关紧要。
PDO | MySQLi | |
Database support | 12 different drivers | MySQL only |
API | OOP | OOP + procedural |
Connection | Easy | Easy |
Named parameters | Yes | No |
Object mapping | Yes | Yes |
Prepared statements (client side) |
Yes | No |
Performance | Fast | Fast |
Stored procedures | Yes | Yes |
PDO方式:
<?php header(\'Content-Type: text/html; charset=utf-8\'); echo "PHP version:" . PHP_VERSION . "<br/>"; $pdo = new PDO("mysql:host=10.117.146.21:8306;dbname=springdemo", \'root\', \'[password]\'); class Name { public $nickname; public function info() { return \'#\'.$this->nickname; } } $input_id = $_GET[\'id\']; $sql = \'select nickname from user where id = \' . $input_id; print_r(\'SQL is:\' . $sql . \'<br/>\'); $result = $pdo->query($sql); $result->setFetchMode(PDO::FETCH_CLASS, \'Name\'); if ($result != null) { while ($row = $result->fetch()) { print_r($row->info() . \'<br/>\'); } } $pdo=null; ?>
测试:
http://localhost:8080/test.php?id=3 PHP version:5.5.30 SQL is:select nickname from user where id = 3 #micro http://localhost:8080/test.php?id=3%20or%201=1 PHP version:5.5.30 SQL is:select nickname from user where id = 3 or 1=1 #abc #micro #helloworld #你好
加上转码:
$input_id = $pdo->quote($_GET[\'id\']);
测试:
http://localhost:8080/test.php?id=3 PHP version:5.5.30 SQL is:select nickname from user where id = \'3\' #micro http://localhost:8080/test.php?id=3%20or%201=1 PHP version:5.5.30 SQL is:select nickname from user where id = \'3 or 1=1\' #micro
注意,pdo的quote自动加了引号,解决了这个问题。
http://localhost:8080/test.php?id=3%27%20or%201=%271 PHP version:5.5.30 SQL is:select nickname from user where id = \'3\\\' or 1=\\\'1\' #micro
并且,尝试自己加引号去做侵入也没有用的。引号被转码了,所以成功防住攻击。
PDO的prepared statement:
<?php header(\'Content-Type: text/html; charset=utf-8\'); echo "PHP version:" . PHP_VERSION . "<br/>"; $pdo = new PDO("mysql:host=10.117.146.21:8306;dbname=springdemo", \'root\', \'[password]\'); $prepared = $pdo->prepare(\'select nickname from user where id = :id\'); $prepared->execute(array(\':id\' => $_GET[\'id\'])); while ($results = $prepared->fetch(PDO::FETCH_ASSOC)) { print_r($results[\'nickname\'] . \'<br/>\'); } $pdo=null; ?>
实验:
http://localhost:8080/test.php?id=3 PHP version:5.5.30 micro http://localhost:8080/test.php?id=3%20or%201=1 PHP version:5.5.30 micro
都不再出现sql注入的威胁。
PDO里面多次用到fetch:
值 | 说明 |
---|---|
PDO::FETCH_ASSOC | 关联数组形式。 |
PDO::FETCH_NUM | 数字索引数组形式。 |
PDO::FETCH_BOTH | 两者数组形式都有,这是默认的。 |
PDO::FETCH_OBJ | 按照对象的形式,类似于以前的mysql_fetch_object()函数。 |
PDO::FETCH_BOUND | 以布尔值的形式返回结果,同时将获取的列值赋给bindParam()方法中指定的变量。 |
PDO::FETCH_LAZY | 以关联数组、数字索引数组和对象3种形式返回结果。 |
把上面程序给prepared statement传参数的过程改了一下:
<?php header(\'Content-Type: text/html; charset=utf-8\'); echo "PHP version:" . PHP_VERSION . "<br/>"; $pdo = new PDO("mysql:host=10.117.146.21:8306;dbname=springdemo", \'root\', \'[password]\'); $prepared = $pdo->prepare(\'select nickname from user where id = :id\'); $prepared->bindParam(\':id\', $_GET[\'id\']); $prepared->execute(); while ($results = $prepared->fetch(PDO::FETCH_ASSOC)) { print_r($results[\'nickname\'] . \'<br/>\'); } $pdo=null; ?>
实验之后,结果对于上面哪些url,都能得到正确的结果。
性能方面:
PDO和MySQLi都有非常好的性能。在非prepared statements的基准测试下,MySQLi略快2.5%,而prepared statements下是6.5%,可以说对于性能无关紧要。
如果你真的非常介意这一点点性能的话,而自带的MySQL扩展比两者都快,你可以考虑下它。
上面部分来自这篇:http://blog.csdn.net/yipiankongbai/article/details/17277477 《PDO vs. MySQLi 选择哪一个?》
以上是关于PDO(PHP Data Object),Mysqli,以及对sql注入等问题的解决的主要内容,如果未能解决你的问题,请参考以下文章