PDO一是PHP数据对象(PHP Data Object)的缩写。
并不能使用PDO扩展本身执行任何数据库操作,必须使用一个database-specific PDO driver(针对特定数据库的PDO驱动)访问数据库服务器。
PDO并不提供数据库抽象,它并不会重写SQL或提供数据库本身缺失的功能,如果你需要这种功能,你需要使用一个更加成熟的抽象层。
PDO需要PHP5核心OO特性的支持,所以它无法运行于之前的PHP版本。
一.下面首先我们介绍一下PDO的好处:
PDO有非常多的操作却是MySQL扩展库所不具备的:
1:PDO真正的以底层实现的统一接口数库操作接口,不管后端使用的是何种数据库,如果代码封装好了以后,应用层调用基本上差不多的,当后端数据库更换了以后,应用层代码基本不用修改.
2:PDO支持更高级的DB特性操作,如:存储过程的调度等,mysql原生库是不支持的.
3:PDO是PHP官方的PECL库,兼容性稳定性必然要高于MySQL Extension,可以直接使用 pecl upgrade pdo 命令升级.
4:PDO可以防止SQL注入,确保数据库更加安全(原理其实就是:PHP就是通过实现SQL模板和参数变量分两次发送给MySQL,由MYSQL完成变量的转义处理,既然变量和SQL模板是两次发送的,也就不存在SQL注入的问题了)
下面是pdo方sql注入的代码:(即pdo通过预处理防止sql注入)
<?php
$pdo = new PDO("mysql:host=192.168.0.1;dbname=test;charset=utf8","root");
$st = $pdo->prepare("select * from info where id =? and name = ?");
$id = 21;
$name = 'zhangsan';
$st->bindParam(1,$id);
$st->bindParam(2,$name);
$st->execute();
$st->fetchAll();
?>
预处理语句
使用语句预处理将帮助你免于SQL注入攻击。
一条预处理语句是一条预编译的 SQL 语句,它可以使用多次,每次只需将数据传至服务器。其额外优势在于可以对使用占位符的数据进行安全处理,防止SQL注入攻击。
下面是未进行预处理和进行预处理的两段代码:
1.未进行预处理的代码:
- <?php
- header('content-type:text/html;charset=utf-8');
- $username=$_POST['username'];
- $psw=$_POST['psw'];
- try {
- $pdo=new PDO('mysql:host=localhost;dbname=test','root','root');
- $sql="select * from user where username='{$username}' and password='{$psw}'";
- $stmt=$pdo->query($sql);
- //返回结果集中的行数
- echo $stmt->rowCount();
- } catch (Exception $e) {
- echo $e->getMessage();
- }
- ?>
(占位符的使用:)
- <?php
- header('content-type:text/html;charset=utf-8');
- $username=$_POST['username'];
- $psw=$_POST['psw'];
- try {
- $pdo=new PDO('mysql:host=localhost;dbname=test','root','root');
- $sql="select * from user where username=:username and password=:psw";
- $stmt=$pdo->prepare($sql);
- $stmt->execute(array(":username"=>$username,":psw"=>$psw));
- echo $stmt->rowCount();
- } catch (Exception $e) {
- echo $e->getMessage();
- }
- ?>
- <?php
- header('content-type:text/html;charset=utf-8');
- $username=$_POST['username'];
- $psw=$_POST['psw'];
- try {
- $pdo=new PDO('mysql:host=localhost;dbname=test','root','root');
- $sql="select * from user where username=? and password=?";
- $stmt=$pdo->prepare($sql);
- $stmt->execute(array($username,$psw));
- echo $stmt->rowCount();
- } catch (Exception $e) {
- echo $e->getMessage();
- }
- ?>
回归主题,为什么说PHP必须要用PDO?除了官方要求之外,我认为作为PHP程序员,只要你目前是做开发的话,那么请选择用PDO的程序/框架!PDO除了安全和万金油式数据库链接,还有一点是我目前觉得非常好用的!下面我就用我最近的切身体会来说。
业务环境:公司某老架构,数据库设计的人员太菜了,设计过程完全没有按照数据库范式进行。各种表中使用大量的序列化形式保存(补充:json同理)。
出现问题:销售的客服反馈,网站某用户在编辑地址时,Mysql报错了。
问题猜想:不用说了。肯定是引号,反斜杠引起序列化入库不正常。
http://zhidao.baidu.com/question/1541430860923158627
6.安装配置及测试
在windows下进行有关pdo测试的时候,php.ini中的extension_dir的值要填为pdo*.dll的路径,否则无法运行pdo的相关程序。
; Directory in which the loadable extensions (modules) reside.
extension_dir = "E:\www\php5\ext"
下面是一段PDO使用的代码,可以看一下:
1 <?php 2 $host = 'localhost'; 3 $user = 'root'; 4 $password = 'develop'; 5 $dbname = '99game'; 6 7 $dbh = new PDO("mysql:host=$host;dbname=$dbname", $user, $password); 8 9 //======================================================= 10 //例子 1. Execute a prepared statement with named placeholders 11 /* Execute a prepared statement by binding PHP variables */ 12 $user_id = 1; 13 $email = 'caihf_73940@qq.com'; 14 $sth = $dbh->prepare('SELECT user_id,email,token FROM 99game_user 15 WHERE user_id = :user_id AND email = :email'); 16 $sth->bindParam(':user_id', $user_id, PDO::PARAM_INT); 17 $sth->bindParam(':email', $email, PDO::PARAM_STR, 30); 18 $sth->execute(); 19 $result = $sth->fetch(PDO::FETCH_ASSOC); 20 print_r($result); 21 print("<br />\n"); 22 23 //例子 2. Execute a prepared statement with question mark placeholders 24 /* Execute a prepared statement by binding PHP variables */ 25 $user_id = 2; 26 $email = 'caihuafeng1@gmail.com'; 27 $sth = $dbh->prepare('SELECT user_id,email,token FROM 99game_user 28 WHERE user_id = ? AND email = ?'); 29 $sth->bindParam(1, $user_id, PDO::PARAM_INT); 30 $sth->bindParam(2, $email, PDO::PARAM_STR, 30); 31 $sth->execute(); 32 $result = $sth->fetch(PDO::FETCH_ASSOC); 33 print_r($result); 34 print("<br />\n"); 35 36 print "<hr />\n"; 37 //======================================================= 38 39 //======================================================= 40 $sth = $dbh->prepare("SELECT user_id,email,token FROM 99game_user limit 10"); 41 $sth->execute(); 42 43 /* 运用 PDOStatement::fetch 风格 */ 44 print("PDO::FETCH_ASSOC: "); 45 print("Return next row as an array indexed by column name<br />\n"); 46 $result = $sth->fetch(PDO::FETCH_ASSOC); 47 print_r($result); 48 print("<br />\n"); 49 print("\n"); 50 51 print("PDO::FETCH_BOTH: "); 52 print("Return next row as an array indexed by both column name and number<br />\n"); 53 $result = $sth->fetch(PDO::FETCH_BOTH); 54 print_r($result); 55 print("<br />\n"); 56 print("\n"); 57 58 print("PDO::FETCH_LAZY: "); 59 print("Return next row as an anonymous object with column names as properties<br />\n"); 60 $result = $sth->fetch(PDO::FETCH_LAZY); 61 print_r($result); 62 print("<br />\n"); 63 print("\n"); 64 65 print("PDO::FETCH_OBJ: "); 66 print("Return next row as an anonymous object with column names as properties<br />\n"); 67 $result = $sth->fetch(PDO::FETCH_OBJ); 68 print_r($result); 69 print 'user_id:' . $result->user_id; 70 print("<br />\n"); 71 print("\n"); 72 73 print "<hr />\n"; 74 //======================================================= 75 76 //======================================================= 77 function readDataForwards($dbh) { 78 $sql = 'SELECT user_id,email,token FROM 99game_user limit 10'; 79 try { 80 $stmt = $dbh->prepare($sql, array(PDO::ATTR_CURSOR, PDO::CURSOR_SCROLL)); 81 $stmt->execute(); 82 while ($row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_NEXT)) { 83 $data = $row[0] . "\t" . $row[1] . "\t" . $row[2] . "<br />\n"; 84 print $data; 85 } 86 $stmt = null; 87 } 88 catch (PDOException $e) { 89 print $e->getMessage(); 90 } 91 } 92 93 function readDataBackwards($dbh) { 94 $sql = 'SELECT user_id,email,token FROM 99game_user limit 10'; 95 try { 96 $stmt = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL)); 97 $stmt->execute(); 98 $row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_LAST); 99 do { 100 $data = $row[0] . "\t" . $row[1] . "\t" . $row[2] . "<br />\n"; 101 print $data; 102 } while ($row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_PRIOR)); 103 $stmt = null; 104 } 105 catch (PDOException $e) { 106 print $e->getMessage(); 107 } 108 } 109 110 print "Reading forwards:<br />\n"; 111 readDataForwards($dbh); 112 113 print "<hr />\n"; 114 115 print "Reading backwards:<br />\n"; 116 //下面的数据没有按照想像中的倒排输出,暂时不知道什么原因,php.net官方手册中的例子也是这么写的 117 readDataBackwards($dbh); 118 //======================================================= 119 ?>
二.php mysql PDO 查询操作的实例详
php mysql PDO 查询操作的实例详解
<?php
$dbh = new PDO('mysql:host=localhost;dbname=access_control', 'root', '');
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->exec('set names utf8');
/*添加*/
//$sql = "INSERT INTO `user` SET `login`=:login AND `password`=:password";
$sql = "INSERT INTO `user` (`login` ,`password`)VALUES (:login, :password)"; $stmt = $dbh->prepare($sql); $stmt->execute(array(':login'=>'kevin2',':password'=>''));
echo $dbh->lastinsertid();
/*修改*/
$sql = "UPDATE `user` SET `password`=:password WHERE `user_id`=:userId";
$stmt = $dbh->prepare($sql);
$stmt->execute(array(':userId'=>'7', ':password'=>'4607e782c4d86fd5364d7e4508bb10d9'));
echo $stmt->rowCount();
/*删除*/
$sql = "DELETE FROM `user` WHERE `login` LIKE 'kevin_'"; //kevin%
$stmt = $dbh->prepare($sql);
$stmt->execute();
echo $stmt->rowCount();
/*查询*/
$login = 'kevin%';
$sql = "SELECT * FROM `user` WHERE `login` LIKE :login";
$stmt = $dbh->prepare($sql);
$stmt->execute(array(':login'=>$login));
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
print_r($row);
}
print_r( $stmt->fetchAll(PDO::FETCH_ASSOC));
?>
1 建立连接
<?php
$dbh=newPDO('mysql:host=localhost;port=3306; dbname=test',$user,$pass,array(
PDO::ATTR_PERSISTENT=>true
));
?>
持久性链接PDO::ATTR_PERSISTENT=>true
2. 捕捉错误
<?php
try{
$dbh=newPDO('mysql:host=localhost;dbname=test',$user,$pass);
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$dbh->exec("SET CHARACTER SET utf8");
$dbh=null; //断开连接
}catch(PDOException$e){
print"Error!:".$e->getMessage()."<br/>";
die();
}
?>
3. 事务的
<?php
try{
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$dbh->beginTransaction();//开启事务
$dbh->exec("insertintostaff(id,first,last)values(23,'Joe','Bloggs')");
$dbh->exec("insertintosalarychange(id,amount,changedate)
values(23,50000,NOW())");
$dbh->commit();//提交事务
}catch(Exception$e){
$dbh->rollBack();//错误回滚
echo"Failed:".$e->getMessage();
}
?>
4. 错误处理
a. 静默模式(默认模式)
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_SILENT); //不显示错误
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);//显示警告错误,并继续执行
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);//产生致命错误,PDOException
<?php
try{
$dbh = new PDO($dsn, $user, $password);
$sql = 'Select * from city where CountryCode =:country';
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':country', $country, PDO::PARAM_STR);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
print $row['Name'] . "/t";
}
} // if there is a problem we can handle it here
catch (PDOException $e) {
echo 'PDO Exception Caught. ';
echo 'Error with the database: <br />';
echo 'SQL Query: ', $sql;
echo 'Error: ' . $e->getMessage();
}
?>
1. 使用 query()
<?php
$dbh->query($sql); 当$sql 中变量可以用$dbh->quote($params); //转义字符串的数据
$sql = 'Select * from city where CountryCode ='.$dbh->quote($country);
foreach ($dbh->query($sql) as $row) {
print $row['Name'] . "/t";
print $row['CountryCode'] . "/t";
print $row['Population'] . "/n";
}
?>
2. 使用 prepare, bindParam和 execute [建议用,同时可以用添加、修改、删除]
<?php
$dbh->prepare($sql); 产生了个PDOStatement对象
PDOStatement->bindParam()
PDOStatement->execute();//可以在这里放绑定的相应变量
?>
3. 事物
<?php
try {
$dbh = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$dbh->query('set names utf8;');
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh->beginTransaction();
$dbh->exec("Insert INTO `test`.`table` (`name` ,`age`)VALUES ('mick', 22);");
$dbh->exec("Insert INTO `test`.`table` (`name` ,`age`)VALUES ('lily', 29);");
$dbh->exec("Insert INTO `test`.`table` (`name` ,`age`)VALUES ('susan', 21);");
$dbh->commit();
} catch (Exception $e) {
$dbh->rollBack();
echo "Failed: " . $e->getMessage();
}
?>
PDO常用方法:
PDO::query()主要用于有记录结果返回的操作(PDOStatement),特别是select操作。
PDO::exec()主要是针对没有结果集合返回的操作。如insert,update等操作。返回影响行数。
PDO::lastInsertId()返回上次插入操作最后一条ID,但要注意:如果用insert into tb(col1,col2) values(v1,v2),(v11,v22)..的方式一次插入多条记录,lastinsertid()返回的只是第一条(v1,v2)插入时的ID,而不是最后一条记录插入的记录ID。
PDOStatement::fetch()是用来获取一条记录。配合while来遍历。
PDOStatement::fetchAll()是获取所有记录集到一个中。
PDOStatement::fetchcolumn([int column_indexnum])用于直接访问列,参数column_indexnum是该列在行中的从0开始索引值,但是,这个方法一次只能取得同一行的一列,只要执行一次,就跳到下一行。因此,用于直接访问某一列时较好用,但要遍历多列就用不上。
PDOStatement::rowcount()适用于当用query("select ...")方法时,获取记录的条数。也可以用于预处理中。$stmt->rowcount();
PDOStatement::columncount()适用于当用query("select ...")方法时,获取记录的列数。
注解:
1、选fetch还是fetchall?
小记录集时,用fetchall效率高,减少从数据库检索次数,但对于大结果集,用fetchall则给系统带来很大负担。数据库要向WEB前端传输量太大反而效率低。
2、fetch()或fetchall()有几个参数:
mixed pdostatement::fetch([int fetch_style [,int cursor_orientation [,int cursor_offset]]])
array pdostatement::fetchAll(int fetch_style)
fetch_style参数:
■$row=$rs->fetchAll(PDO::FETCH_BOTH); FETCH_BOTH是默认的,可省,返回关联和索引。
■$row=$rs->fetchAll(PDO::FETCH_ASSOC); FETCH_ASSOC参数决定返回的只有关联数组。
■$row=$rs->fetchAll(PDO::FETCH_NUM); 返回索引数组
■$row=$rs->fetchAll(PDO::FETCH_OBJ); 如果fetch()则返回对象,如果是fetchall(),返回由对象组成的二维数组
如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!