Contents
  1. 1. 0x01: PDO简介及的相关配置
  2. 2. 0x02: POD的实例化
    1. 2.1. 实例化方法
  3. 3. 0x02使用PDO进行增删改操作
  4. 4. 0x03: 使用PDO进行查询
  5. 5. 0x04: PDO的预处理技术
    1. 5.1. MySQL中的预处理
    2. 5.2. PDO中的预处理
  6. 6. 0x05 PDO事务处理
    1. 6.1. 事务的基本原理
    2. 6.2. MySQL的事务的处理
  7. 7. 0x06 PDO的相关属性(参数)
  8. 8. 0x07异常处理

在17年的安全管理评估国赛中二阶段有一道SQL注入题,在修改程序时用到的PHP PDO技术,考虑着选拔赛可能会用到,所以花了一小段时间对PDO进行了简略的学习

0x01: PDO简介及的相关配置

PDO PHP Data object (PHP数据对象)
在PHP5以上,PHP为用户封装了一套PDO扩展库,专门用来操作不同类型的数据库

开启PDO扩展(mysql)
打开php.ini配置文件,取消下面两行注释

extension=php_pdo_mysql.dll
exitension=php_pdo.dll

0x02: POD的实例化

由于PDO的拓展库是以面向对象的方式封装的,要先了解PDO的类结构,并实例化一个对象

实例化方法

<?php
/**
 *PDO类的实例化
 */

$dbms="mysql";//数据库类型
$host='localhost';//数据库主机名
$post='3306';//数据库端口
$dbname='newdba';//使用的数据库

$dsn="$dbms:host=$host;port=$port;dbname=$dbname";

$user='root';//用户名
$pass='root';//密码

//实例化PDO类
$pdo=new PDO($dsn,$user,$pass);
echo '<pre>';
var_dump($pdo);
?>

0x02使用PDO进行增删改操作

主要调用PDO对象的exec方法,execute的缩写,意思为执行!

PDO::exec()在一个单独的函数调用中执行一条SQL语句,返回受此语句影响的行数

其他方法

String PDO::astInsertId([string $name = NULL])
返回最后插入行的ID,或者是一个序列对象最后的值,取决于底层的驱动。

案例代码:

$sql="insert into persons values(1,'李明','male','23','西天')";
//执行并返回结果

$result=$pdo->exec($sql);
if($result){
    echo "插入成功,最后一条记录的ID号为:",$pdo->lastInsertId();
}else{
    echo "插入失败";
}

删除和更新的实现,只修改sql语句即可

0x03: 使用PDO进行查询

使用pdo对象中的query方法进行查询

PDO::query 
作用:执行一条sql语句(一般来说是查询语句)返回PDOstatement类的对象(类比以前的结果集),也叫做结果对象

PDOstatement::rowCount
作用:获取查询结果中的总记录集数(行数)

PDOstatement::columnCount
作用:获取查询结果中的总字段数,总列数

PDOstatement::fetch
作用:每次从PDOstatement结果集中,获取一条记录,同时将指针下移,其中该方法有一个参数,可以控制返回值的类型。

fetchAll
作用:
返回一个结果集中所有的记录

fetchColumn
作用:
每次获取指定的某一列信息中的一条记录,并将指针下移
该方法需要一个参数,用来代表哪一列的数据

fetchObject
作用:每次读去一条记录放到一个对象中,并使指针下移。

最常用的参数:

PDO::FETCH_ASSOC 返回关联型的数组,数组的下标就是字段的名称,效果类似于以前的mysql_fetch_assoc
PDO::FETCH_NUM  返回一个索引数组,效果类似于以前的mysql_fetch_array();
PDO::FETCH_BOTH 返回一个关联和索引并存的混合数组,也是缺省值(默认值)
PDO::FETCH_OBJ  返回一个对象,其中对象的属性就是字段的值

案例代码:

$sql = "select * from student";

$stmt = $pdo->query($sql);

while($res=$stmt->fetch()){
    echo "id:".$res['id']."<br>";
    echo "name:".$res['name']."<br>";
    echo "money:".$res['money']."<br>";
}

0x04: PDO的预处理技术

预处理技术,最初也是由MySQL提出的减轻服务器压力的技术

传统的sql语句的执行过程

  1. 在客户端准备sql语句
  2. 发送sql语句到MySQL服务器
  3. 在MySQL服务器执行该sql语句
  4. 在服务器将执行结果返回给客户端

预处理的基本策略
将sql语句强制一分为二

  • 第一部分为前面相同的命令和结构部分
  • 第二部分为后面可变的数据部分

在执行sql语句的时候,首先将前面相同的命令和结构部分发送给MySQL服务器,让MySQL服务器事先进行一次预处理(此时并没有真正的执行SQL语句),而是为了保证sql语句的结构完整性,在第一次发送sql语句的时候将其中可变的数据部分都用一个数据的占位符来表示。

MySQL中的预处理

不带参数的预处理

第一步:准备预处理语句

语法形式:

prepate 语句名称 from “预处理的sql语句”;

其中语句名称就是给后面需要预处理的sql语句起一个名字

prepare sql_1 from "select * from php_student";

第二步:执行预处理的语句

语法形式:

execute 语句名称(前面取的语句名称);

第三步:删除预处理

语法形式:

drop prepare 语句名称;

删除之后,就不能再执行预处理程序

需要传参的预处理

第一步:准备预处理语句

和前面的语法是一样的,只是其中需要改变的部分,用占位符表示

prepare sql_2 from "select * from php_student whrere id = ?";

第二步:定义参数变量
语法形式

set @变量名 = 值

注意:这里的@是在MySQL中定义变量的一种语法形式

类比php中的$符号

set @id = 5

第三步:传递参数变量并执行预处理语句

语法形式:

execute 语句名称 using 参数变量;

注意:using后面只能是一个变量,不能是一个常量;
例:

exec sql_2 using @id;

如果想查询其他记录,只需要修改@id的值

如果数据的占位符不止一个,就按顺序传参。

代码案例:

//准备预处理语句
prepare sql_2 from "select * from php_student whrere id < ? and score > ?";
//定义参数
set @id=4;
set @score=90;
//传递参数变量并执行预处理语句
exec sql_2 using @id,@score;

第四步:删除预处理

drop perpare 语句名称;

PDO中的预处理

基本原理和步骤和前面都一致,只不过就是把前面所有命令行的语法封装成了PDO对象的几个公开方法而已

第一步:发送预处理语句
此时,我们需要调用pdo对象的prepare方法,得到一个PDO statement 结果对象

PDO::prepare 准备一条SQL语句,得到 statement结果对象

$sql = "insert into pdotest values(?,?,?,?,?)"; 
$stmt = $pdo->prepare($sql);

第二步:绑定参数
PDOStatement::bindParam方法

$stmt->bindParam(1,$name);
$stmt->bindParam(2,$gender);

注意:

使用bindParam不能使用常量直接绑定,因为绑定的数据与数据站为辐之间是一种引用传递,只能用变量。

PDOStatement::bindValue()方法

$stmt->bindParam(1,"zhang san");

bindValue与bindParam的区别,采用bindValue进行绑定的时候,与数据占位符之间是一种值传递!

bindValue能用变量,能用常量

执行预处理语句
PDOStatement::execute 执行一条预处理语句

$result = $stmt->execute();

此时,我们需要调用PDOStatement中的execute方法,执行成功返回true只是失败返回false

绑定参数的其他方法

使用 :变量名 作为数据占位符
案例:

//占位符
$sql = "insert into persons values(:name,:gender,:class_id,:age,:home)";
//绑定
$stmt->bindpram(":name",$name);
$stmt->bindpram(":gender",$gender);
$stmt->bindpram(":class_id",$class_id);
$stmt->bindpram(":age",$age);
$stmt->bindpram(":home",$home);

使用数组绑定参数
使用数组以键值对的形式,实现保存数据占位符与值的对应关系

$arr=array(
    ":name"     =>  $name;
    ":gender"   =>  $gender;
    ":class_id" =>  $class_id;
    ":age"      =>  $age;
    ":home"     =>  $home;
)

在调用execute方法的时候,将这个数组作为参数进行传递即可。

0x05 PDO事务处理

事务:将两个操作(两个update)认为是一个事务,
其中有任意一条语句执行失败,我们就认为整个事务执行失败!应该回滚“恢复”到最初的状态
注意:目前只有innoDB引擎才支持事务处理
当我们开启一个事务的时候,我们对sql的操作都发生在内存中,但是没有真正的反馈到数据库磁盘的文件中。
此时可以进行回滚操作。
回滚事务

事务的基本原理

普通的执行,之所以是立即执行并生效,因为默认的mysql对sql语句的执行是默认的

所以,开启一个事务的本质,就是关闭了以前的自动提交的功能,而是由用户手动提交(commit)语句
!
所以,还有一种开启事务的方式,就是将

MySQL的事务的处理

开启事务

start transaction

然后就可以执行sql语句

回滚事务

rollback;

所谓的事务的回滚,就是恢复到事务之前的状态。
回滚操作会自动的关闭一个事务

执行事务

commit;

两种开启事务区别
1.通过start transaction 开启,commit之后相当于
上一个事务执行完毕并关闭了事务(以后是sql语句的执行还是默认自动提交)

2.set autocommit=0 关闭自动提交功能,所有的sql语句都要手动提交才能生效!

总结事务的步骤
1,开启事务
2,如果执行成功,就提交commit
3,如果有任何一条sql语句执行失败,则回滚rollback

到此为止,整个事务处理完毕
PDO中事务的处理

基本原理和步骤其实都是一样的,就是调用PDO对象的方法

PDO::beginTransaction 启动一个事务
PDO::commit              提交一个事务
PDO::rollback         回滚一个事务

0x06 PDO的相关属性(参数)

虽然PDO所有的属性都不是public型,但是我们还是可以通过两个方法来设置和查看PDO的属性

PDO::setAttribute 设置属性
PDO::getAttribute 查看属性

PDO种常见的重要的属性

PDO::ATTR_AUTOCOMMIT; 自动提交
只有两个值,0或1
0不开启自动提交,手动提交(调用commit方法)
1开启自动提交,自动实现事务处理

PDO:ATTR_CASE; 返回结果集的大小写(重要)
有三个值可以设置

PDO::CASE_LOWER;  返回的结果集全部小写!
PDO::CASE_UPPER;  返回的结果集全部大写!
PDO::CASE_NATURAL; 返回的结果集正常(原来数据库种什么样现在返回的还是什么样)

PDO::ATTR_ERRMODE:返回的错误模式(重要)
有三个值可以设置:

PDO::ERRMODE_SILENT:静默模式(默认)
PDO::ERRMODE_WARNNING:警告模式
PDO::ERRMODE_EXCEPTION:异常模式

案例代码:

$pdo->setAttribute(ATTR_ERRMODE,ERRMODE_SILENT);

0x07异常处理

异常,其实就是错误,不过实在面向对象编程语言中的一种典型的错误处理方式!所谓的一场,就是把错误信息,放到一个对象中。
异常的发生有一个前提,就是必须保证语法是正确的。

分为两部分:

  • 抛出异常
  • 处理异常,通常有两阶段组成:监听和捕获!
    抛出异常,throw
    抛出异常利用throw关键字来完成,语法形式为

    thorw 异常;
    注意:这里的异常,其实就是一个异常对象,这个对象是由系统预定义的一个异常类(类名为 Exception)或者其子类实例化出来的。

只抛出异常没有监听和捕获的话,会报错

监听捕获异常,try,catch

利用关键字try可以监听一段可能出现异常的代码内,来监听是否发生了异常

try{
    被监听的代码段
}catch(){捕获异常

}

PDO中处理错误的方式

一共提供了三种错误处理方式

PDO::ERRMODE_SILENT:静默模式(默认)
PDO::ERRMODE_WARNNING:警告模式
PDO::ERRMODE_EXCEPTION:异常模式

案例代码:

$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);

获取异常信息的参数

Exception::getMessage 获取错误的信息
Exception::getCode  获取异常代码
Exception::getFile  获取发生异常的程序文件名称
Exception::getLine  获取发生异常的代码在文件中的行号

代码示范

<?php

header("constant-type:text/html;charset=utf-8");

class Goods
{
    public function getPrice()
    {
        $price = $_GET['p'];
        if($price < 0){
            //实例化一个异常对象
            $e = new Exception($message = '价格不能为负值!');
            throw $e;
        }
    }
}


try{//对代码进行监听
    $book = new Goods;
    $book -> getPrice();
}catch(Exception $e){ //捕获异常
    echo '错误的信息为',$e->getMessage(),'<br>';
    echo '错误的代码为',$e->getCode(),'<br>';
    echo '错误的程序文件为',$e->getFile(),'<br>';
    echo '错误的行号为',$e->getLine(),'<br>';
}

?>
Contents
  1. 1. 0x01: PDO简介及的相关配置
  2. 2. 0x02: POD的实例化
    1. 2.1. 实例化方法
  3. 3. 0x02使用PDO进行增删改操作
  4. 4. 0x03: 使用PDO进行查询
  5. 5. 0x04: PDO的预处理技术
    1. 5.1. MySQL中的预处理
    2. 5.2. PDO中的预处理
  6. 6. 0x05 PDO事务处理
    1. 6.1. 事务的基本原理
    2. 6.2. MySQL的事务的处理
  7. 7. 0x06 PDO的相关属性(参数)
  8. 8. 0x07异常处理