PDO(PHP Data Object),Mysqli,以及對sql注入等問題的解決

這篇是上一篇 http://www.cnblogs.com/charlesblc/p/5987951.html 的續集。php

看有的文章提到mysqli和PDO都支持多重查詢,因此下面的url會形成表數據被刪。html

http://localhost:8080/test.php?id=3;delete%20from%20users

但是我在mysql版本的函數,上面的sql都不能執行。是否是不支持多重查詢了?mysql

 

這篇文章 http://www.runoob.com/php/php-mysql-connect.html 對mysqli, PDO的方式有一些介紹,不詳細。spring

主要用的這篇文章:http://blog.csdn.net/yipiankongbai/article/details/17277477sql

三種鏈接方式:數組

// 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過程型:app

<?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);
?>

測試:ide

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 選擇哪個?》

相關文章
相關標籤/搜索