程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> 我了個大擦-PDO(二),擦-pdo

我了個大擦-PDO(二),擦-pdo

編輯:關於PHP編程

我了個大擦-PDO(二),擦-pdo


  hi

昨天又213了,雖然有室友3點多才睡覺的客觀影響,但是昨晚不想學東西是本質原因。今天搞起。打算3、4天之內,學完PDO和AJAX這兩個,還望大家沒事兒來罵罵我,免的我又偷懶。

1、PDO

二、PDO對象的使用(二)

2.2 錯誤信息

errorCode()——錯誤號;

errorInfo()——錯誤信息;

舉個栗子

<?php
/*
* PDO錯誤信息
*/

$pdo=new PDO('mysql:host=localhost;dbname=imooc','root','');

$pdo->exec('use imooc_pdo');
$resultd=$pdo->exec('delete from user where id=13');
var_dump($resultd);
$insert='insert user(username,password,email) values("Knga","'.md5('king').'","[email protected]")';
$result1=$pdo->exec($insert);
var_dump($result1);

if ($result1==false) {
echo "出錯了";
echo $pdo->errorCode();
print_r($pdo->errorInfo());
}

看一下錯誤信息

Array ( [0] => 23000 [1] => 1062 [2] => Duplicata du champ 'Knga' pour la clef 'username' )

0為錯誤類型,1062是代碼,2是錯誤信息;(這裡是由於username設置為了unique鍵,但是id號是還在增長的其實)。

2.3 query()實現查詢

執行一條語句,返回一個PDOstatement對象。

--舉個栗子

<?php

/*
* PDOquery
*/

$pdo=new PDO('mysql:host=localhost;dbname=imooc','root','');

$pdo->exec('use imooc_pdo');

$insert='select * from user';
$result1=$pdo->query($insert);
var_dump($result1);  //查看statement對象
foreach ($result1 as $row){  //查看輸出結果(根據返回情況)
print_r($row);
}
if ($result1==false) {
echo "出錯了";
echo $pdo->errorCode();
print_r($pdo->errorInfo());
}

如果sql語句有問題的話,statement對象是false,然後後面的輸出也是錯誤信息;

如果sql語句正確,但查詢的內容是不存在的,那麼statement對象沒問題,然後輸出為空。

當然這樣會好看一些:

foreach ($result1 as $row){ //查看輸出結果(根據返回情況)
// print_r($row);echo "<br/>";
echo '編號:'.$row['id'];echo "<br/>";
echo '用戶名:'.$row['username'];echo "<br/>";
echo '密碼:'.$row['password'];echo "<br/>";
echo '郵箱:'.$row['email'];echo "<br/>";
echo "<hr/>";
}

當然,query執行增刪改都是沒問題的。

2.4 prepare()和execute()方法實現查詢

推薦使用的查詢方法,可以實現條件查詢。

prepare()——准備要執行的SQL語句,返回PDOstatement對象;

execute()——執行一條預處理語句,返回true或false;

所以上面是一對。

--舉個例子

<?php
/*
* PDOprepare&execute方法
*/

$pdo=new PDO('mysql:host=localhost;dbname=imooc','root','');

$pdo->exec('use imooc_pdo');

$insert='select * from user where username="king"';
$result=$pdo->prepare($insert);
var_dump($result);

$result1=$result->execute();//執行是對預處理語句
var_dump($result1);

print_r($result->fetchAll());//對statement對象才能有結果輸出

 

if ($result1==false) {
echo "出錯了";
echo $pdo->errorCode();
print_r($pdo->errorInfo());
}

這裡要小心預處理這種特殊情況,分清楚對象到底是誰就好辦了。

--選取輸出形式

要關聯數組輸出或者全部或者索引數組,有參數和方法兩種不同的方法。

<?php
header('content-type:text/html;charset=utf-8');
try{
$pdo=new PDO('mysql:host=localhost;dbname=imooc','root','root');
$sql='select * from user';
$stmt=$pdo->prepare($sql);
$res=$stmt->execute();
// if($res){
// while($row=$stmt->fetch(PDO::FETCH_ASSOC)){//僅需要關聯數組輸出
// print_r($row);
// echo '<hr/>';
// }
// }
// $rows=$stmt->fetchAll(PDO::FETCH_ASSOC);
// print_r($rows);
echo '<hr/>';
$stmt->setFetchMode(PDO::FETCH_ASSOC); //同樣的實現效果,用這個方法也可以,設置默認模式
//var_dump($stmt);
$rows=$stmt->fetchAll();
print_r($rows);
}catch(PDOException $e){
echo $e->getMessage();
}

一般的我們都是想要索引數組的。

2.5 設置數據庫連接屬性

setAttribute()——設置數據庫連接屬性;

getAttribute()——得到數據庫連接屬性;

--舉個例子

$pdo=new PDO('mysql:host=localhost;dbname=imooc','root','');
echo "自動提交".$pdo->getAttribute(PDO::ATTR_AUTOCOMMIT);echo "<hr/>";
//記住pdo是個對象,所以得到屬性,你懂的。然後它內部是有很多設定好的屬性值的,這就是我們得到屬性的前提。
echo "默認的錯誤處理模式:".$pdo->getAttribute(PDO::ATTR_ERRMODE);echo "<hr/>";
$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, 0);
echo "自動提交".$pdo->getAttribute(PDO::ATTR_AUTOCOMMIT);echo "<hr/>";

然後試著得到一大波屬性信息:

$attrArr=array(
'AUTOCOMMIT','ERRMODE','CASE','PERSISTENT','SERVER_INFO','SERVER_VERSION'
);
foreach ($attrArr as $attr){
echo "PDO::ATTR_$attr: ";
echo $pdo->getAttribute(constant("PDO::ATTR_$attr"))."<br/>";
}

有些是沒有的,會有錯誤信息,沒什麼關系。

 

三、PDOstatement對象的使用

3.1 quote()方法防止SQL注入

--SQL注入

首先舉個例子說明這個簡單的SQL注入(其實我也不是很懂——百度一下http://baike.baidu.com/link?url=jiMtgmTeePlWAqdAntWbk-wB8XKP8xS3ZOViJE9IVSToLP_iT2anuUaPdMEM0b-VDknjolQ8BdxN8ycNLohup_)

所謂SQL注入,就是通過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。

所以也就是要有表單,然後需要跟數據庫進行查詢數據等等,然後通過惡意的運用規則上的漏洞,得到大量的,而不是頁面所希望的數據。栗子如下:

例子為登錄的情況——登錄需要有用戶名密碼等,需要與數據庫中的信息進行比對;

首先是登錄頁面

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html>
<title>登錄</title>
</head>
<body>
<form action='doAction.php' method='post'>
用戶名:<input type='text' name='username'/><br/>
密碼:<input type='password' name='password'/><br/>
<input type='submit' value='登錄'/>
</form>
</body>
</html>

注意這裡出現了表單。然後是php文件:

<?php
header('content-type:text/html;charset=utf-8');
$username=$_POST['username'];
$password=$_POST['password'];
try {
$pdo=new PDO('mysql:host=localhost;dbname=imooc','root','');
$pdo->exec('use imooc_pdo');
$sql="select * from user where username='{$username}' and password='{$password}'";
$stmt=$pdo->query($sql);
echo $stmt->rowCount();//顯示結果集statement對象中的行數

} catch (PDOException $e) {
echo $e->getMessage();
}

然後浏覽器中打開login.html,輸入數據庫中有的username和password,點擊登陸,會得到1;

若輸入錯誤的信息,一般會得到0;

注意,若輸入諸如用戶名為'or 1=1#,密碼隨意,就會輕松得到數據庫的所有數據。這是由於sql語句本身的規則造成的。

所以需要過濾用戶輸入的信息,不要相信用戶的所有操作。

--應對方法

echo $pdo->quote($username);

寫這麼一句,再用上述的作弊代碼,輸出會多出單引號,以及自動加上\:

 '\'or 1=1#'

但這麼做的話,$username的調用,會自動加上引號,所以下面的sql語句就要跟著變動:

$username=$pdo->quote($username);
$pdo->exec('use imooc_pdo');
$sql="select * from user where username={$username} and password='{$password}'";

簡單的說就是把用戶名上個套,對於有數據庫的情況,似乎都要防這個。

但是不建議使用這種手段——建議使用prepare+execute的預處理手段

3.2 預處理語句中占位符的使用

很好的防止注入;而且一次編譯即可,多次執行,減小系統的開銷;

--占位符:(命名參數)(推薦)

<?php
header('content-type:text/html;charset=utf-8');
$username=$_POST['username'];
$password=$_POST['password'];
try {
$pdo=new PDO('mysql:host=localhost;dbname=imooc','root','');
$pdo->exec('use imooc_pdo');
$sql="select * from user where username=:username and password=:$password";
$stmt=$pdo->prepare($sql);
$stmt->execute(array(":username"=>$username,":password"=>$password));
//$stmt=$pdo->query($sql);
echo $stmt->rowCount();//顯示結果集statement對象中的行數

} catch (PDOException $e) {
echo $e->getMessage();
}

對應的sql語句,對應的執行,需要傳遞的參數也要對應的上。

--占位符?  

$sql="select * from user where username=? and password=?";
$stmt=$pdo->prepare($sql);
$stmt->execute(array($username,$password));

感覺?方式要簡單一點,就三個點——sql語句中輸入占位符+預處理+執行(傳遞多個數據用array)。

3.3 bindParam()方法綁定參數

把一個參數綁定到變量名。 

<?php
/*
* 綁定參數
*/

header('content-type:text/html;charset=utf-8');
try {
$pdo=new PDO('mysql:host=localhost;dbname=imooc','root','');
$pdo->exec('use imooc_pdo');
$sql="insert user(username,password,email) values(:username,:password,:email)";
$stmt=$pdo->prepare($sql);
$username="Wid";$password="123";$email="[email protected]"; //定義參數
$stmt->bindParam(":username", $username,PDO::PARAM_STR);
$stmt->bindParam(":password",$password);
$stmt->bindParam(":email",$email);
$stmt->execute();
$res=$pdo->query("select * from user");
foreach ($res as $row){ //查看輸出結果(根據返回情況)
// print_r($row);echo "<br/>";
echo '編號:'.$row['id'];echo "<br/>";
echo '用戶名:'.$row['username'];echo "<br/>";
echo '密碼:'.$row['password'];echo "<br/>";
echo '郵箱:'.$row['email'];echo "<br/>";
echo "<hr/>";
}

} catch (PDOException $e) {
echo $e->getMessage();
}

其實就是為了不用每次更改sql語句來執行略重復的操作。 

當然還可以換個占位符

// $sql="insert user(username,password,email) values(?,?,?)";

// $stmt->bindParam(1,$username);

所以,總之,實際上:占位符會比較清楚,?會混淆。

3.4 bindValue()實現綁定參數

把值綁定到參數中。

<?php

/*
* 綁定參數
*/

header('content-type:text/html;charset=utf-8');
try {
$pdo=new PDO('mysql:host=localhost;dbname=imooc','root','');
$pdo->exec('use imooc_pdo');
$sql="insert user(username,password,email) values(:username,:password,:email)";
// $sql="insert user(username,password,email) values(?,?,?)";
$stmt=$pdo->prepare($sql);

//假設email參數不變
$stmt->bindValue(":email", '[email protected]');
$username="Wade";$password="123";
$stmt->bindParam(":username", $username,PDO::PARAM_STR);
$stmt->bindParam(":password",$password);
$stmt->execute();
$res=$pdo->query("select * from user");
foreach ($res as $row){ //查看輸出結果(根據返回情況)
// print_r($row);echo "<br/>";
echo '編號:'.$row['id'];echo "<br/>";
echo '用戶名:'.$row['username'];echo "<br/>";
echo '密碼:'.$row['password'];echo "<br/>";
echo '郵箱:'.$row['email'];echo "<br/>";
echo "<hr/>";
}


} catch (PDOException $e) {
echo $e->getMessage();
}

應用場景就是當某個值固定不變的時候,就可以固定變量的參數值。

3.5 bindColumn()方法綁定參數

將綁定一列到php對象。

$pdo=new PDO('mysql:host=localhost;dbname=imooc','root','');
$pdo->exec('use imooc_pdo');
$sql="select * from user";
$stmt=$pdo->prepare($sql);
$stmt->execute();
//控制輸出
$stmt->bindColumn(2, $username);
$stmt->bindColumn(3,$password);
$stmt->bindColumn(4,$email);
while ($stmt->fetch(PDO::FETCH_BOUND)){
echo '用戶名:'.$username.'-密碼:'.$password.'-郵箱:'.$email.'<hr/>';
}

這裡的用法就是對輸出結果進行控制,利於輸出格式的調控。

當然,可以看看結果集中到底有幾列,然後每一列是什麼:

echo '結果集中的列數:'.$stmt->columnCount().'<hr/>';
print_r($stmt->getColumnMeta(2));

3.6 fetchColumn()從結果集中取一列

上述的getColumnMeta()方法實際上在PHP該版本中是個實驗的函數,可能會在將來的版本中消失。

$stmt->execute();

print_r($stmt->fetchColumn(3));

需要注意該方法很蛋疼的地方在於會每執行一次,指針向下一位,所以只需要指定第幾列,但並不知道在哪一行。

3.7 debugDumpParams()打印一條預處理語句

在bindParam中測試這個方法:

$stmt->debugDumpParams();

結果是一大堆:

SQL: [71] insert user(username,password,email) values(:username,:password,:email) Params: 3 Key: Name: [9] :username paramno=-1 name=[9] ":username" is_param=1 param_type=2 Key: Name: [9] :password paramno=-1 name=[9] ":password" is_param=1 param_type=2 Key: Name: [6] :email paramno=-1 name=[6] ":email" is_param=1 param_type=2

也就是說會給出預處理時的詳細情況。

很明顯就是為了Debug而生的方法。

3.8 nextRowset()方法取出所有結果集

用於比如,mysql的存儲過程(看我之前mysql的博文就有),一下子取出很多結果集,然後對集進行操作。

實際上是指針一步步下移就好了。

例子我懶了,不想敲了。。。。

 

雖然沒寫很多,就這樣吧。

過兩天想去復查一下腳,雖然還在痛,不知道還敢不敢活血了。。。。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved