1. 程式人生 > >【php】PDO資料庫防sql注入

【php】PDO資料庫防sql注入

安全的方式:

$pdo = new PDO('mysql:host=localhost;dbname=phptry','username','passwd');
$pdo->query("SET NAMES 'utf8'");//字符集設定
//$pdo->query("SET character_set_client=binary");?

//設定不在本地做sql語句預處理,php5.3.6之後預設
//$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

//修改預設的錯誤顯示級別
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

//sql預處理和執行------------------------
$statement = $pdo->prepare("select * from user where username = ?"); $statement->bindValue(1,'admin',PDO::PARAM_STR);//bindvalue繫結":XXX"或者用替代第幾個問號,bindparam只能繫結變數 $statement->execute(); //處理返回的結果集---------------------------- //取不到則返回false $row = $statement->fetch(PDO::FETCH_ASSOC); //取不到則返回空陣列
//$row = $statement->fetchAll(PDO::FETCH_OBJ); //debug模式下檢視預處理語句引數,要在execute()方法後呼叫 //$statement->debugDumpParams(); //檢視結果 echo htmlentities(count($row)); //count()/sizeof() var_dump($row); //輸出引數型別和值

或者寫成:


$pdo = new PDO('mysql:host=localhost;dbname=phptry;charset=utf8','username','passwd');

//修改預設的錯誤顯示級別
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //sql預處理和執行------------------------ $statement = $pdo->prepare("select * from user where username = ?"); $statement->bindValue(1,'admin',PDO::PARAM_STR); $statement->execute(array("admin"));//傳遞陣列引數 //省略----------------------------

bindValue和bindParam會對特殊符號進行轉義。

$statement->debugDumpParams();結果顯示:

SQL: [37] select * from user where username = ?
Params:  1
Key: Position #0:
paramno=0
name=[0] ""
is_param=1
param_type=2
Array

防sql注入原理:
在php5.3.6之後,pdo不會在本地對sql進行拼接然後將拼接後的sql傳遞給mysql server處理(也就是不會在本地做轉義處理)。pdo的處理方法是在prepare函式呼叫時,將預處理好的sql模板(包含佔位符)通過mysql協議傳遞給mysql server,告訴mysql server模板的結構以及語義。當呼叫execute時,將兩個引數傳遞給mysql server。由mysql server完成變數的轉移處理。將sql模板和變數分兩次傳遞,即解決了sql注入問題。

sql注入測試:

$statement = $pdo->prepare("select * from user where username = ?");
$statement->execute(array("'' or 1 > 0"));
$row = $statement->fetchAll(PDO::FETCH_OBJ);
var_dump($row);

//輸出array(0) { } ,成功

參考連結: