前言

这两周用php和mysql为工作室搭了一个积分管理系统,这也是第一次搞网页端的开发。为了防止sql注入也为了锻炼一下自己就用了pdo来连接数据库和对数据库进行查询。这里就记录一下pdo的学习,顺便记录一下搭建网站的过程中遇到的一些坑

## 正文

pdo是什么

pdo全称是PHP Data Object,也就是php数据对象,PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。PDO 提供了一个 数据访问 抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。

通俗点说就是pdo拥有和mysqli的功能,它也能对数据库进行连接并且能查询数据库,得到相应结果。但是它是在数据抽象层的,能在sql语句执行之前先对它进行预处理,然后将用户要拼接sql的内容一起放到数据库执行,最后得到执行结果

pdo的优点之防注入

举个例子,比如mysql语句是select * from account where name=”zhangsan”;用php的mysqli写应该是

mysqli_query($link,"select * from account where name={$_GET['name']}");//直接进行拼接拿去查询得到结果

执行的时候是先把$_GET[‘name’]找到,然后拼接到sql语句,然后再把sql语句放到数据库进行查询,最后得到结果,如果此时有个恶意的人传了-1 or 1=1 –进去,那查到的就是整个表的内容了。这就造成了sql注入。

如果是用pdo进行数据库请求的话,应该就是这样写的

$stmt =$pdo ->prepare("slect * from account where name=?");//预处理sql语句,也就是跟数据库说我即将处理这一句sql命令,叫数据库先给编译好,至于?就是等下我要填充数据的地方
$stmt -> bindParam(1,$_GET['name']);//进行参数绑定
$stmt ->execute();  //执行查询,得到结果

这里即使传了-1 or 1=1 –进去,数据库将它理解为字段为name的某行,它的值是-1 or 1=1 –,显然数据表里面没有这个值,所以直接返回一个空的查询结果

pdo的优点之效率提升

继续拿上面那个例子来说,假如我想多次查询,应该这样写

mysqli_query($link,"select * from account where name={$name1}");
mysqli_query($link,"select * from account where name={$name2}");
mysqli_query($link,"select * from account where name={$name3}");
mysqli_query($link,"select * from account where name={$name4}");

这样给数据库服务器的任务相对来说比较多,因为数据库服务器在执行sql语句之前不知道用户是想要增删还是想要改查,这时就要对四条语句都进行编译执行

用pdo的话,就这么写

$stmt =$pdo ->prepare("slect * from account where name=?"); //一次编译就可以
$stmt ->execute([$name1]);  //可以直接传数组,这样就不用绑定参数
$stmt ->execute([$name2]); 
$stmt ->execute([$name3]); 
$stmt ->execute([$name4]); //多次执行

这样给数据库服务器的负载比较低,因为数据库已经知道用户要干嘛了,接下来的只是把数据填进来查询就行

pdo安装

安装的话现在基本都扩展了pdo了,可以通过phpinfo()知道,这样的话就是已经支持pdo了

pdo基本语法

连接数据库

$dbh = new PDO("mysql:host=$address;dbname=$databaseName", "$username", "$password");
//例如
$dbh = new PDO("mysql:host=localhost;dbname=account", "root", "root");

连接之后得到的是一个数据库对象,有点像mysqli的mysqli_connect()返回的数据库对象

执行sql命令

//方法1:exec执行:用来增删改,返回影响的行数,不支持绑定参数和预处理
$sql="delete from commit where name='jack'";
$res=$pdo->exec($sql);
echo '影响的行数:'.$res;
//方法2:query执行:用来增删改,返回一个PDOStatement对象,不支持绑定参数和预处理
$sql="select * from commit where name='jack'";
$res=$pdo->query($sql);
//方法3:execute执行,增删查改都可以,返回一个PDOStatement对象,支持参数绑定,要求execute之前要prepare预处理
//用?作为占位符,单参数绑定
$stmt =$pdo ->prepare("slect * from account where name=?");//预处理
$stmt -> bindParam(1,$_GET['name']);//参数绑定
$stmt ->execute();  //执行查询

//用?作为占位符,多参数绑定,多个参数也是一样的增加
$stmt =$pdo ->prepare("slect * from account where name=? and password=?");//预处理
$stmt -> bindParam(1,$_GET['name']);//参数绑定
$stmt -> bindParam(2,$_GET['password']);//参数绑定
$stmt ->execute();  //执行查询

//用:作为占位符,单参数绑定
$stmt =$pdo ->prepare("slect * from account where name=:para1");//预处理
$stmt -> bindParam(:para1,$_GET['name']);//参数绑定
$stmt ->execute();  //执行查询

//用:作为占位符,多参数绑定
$stmt =$pdo ->prepare("slect * from account where name=:para1 and password=:para2");//预处理
$stmt -> bindParam(:para1,$_GET['name']);//参数绑定
$stmt -> bindParam(:para2,$_GET['password']);
$stmt ->execute();  //执行查询

//用数组传参
$stmt =$pdo ->prepare("slect * from account where name=? and password=?");//预处理
$stmt ->execute([$_GET['name'],$_GET['password']]);  //执行查询,这样用就不用参数绑定

得到结果条数

query和execute语句执行结束后,可以用rowCount()得到结果的条数

$line = $stmt -> rowCount();

得到结果数据

array fetchAll ([ int $fetch_style [, mixed $fetch_argument [, array $ctor_args = array() ]]] ) //得到所有的值

mixed fetch ([ int $fetch_style [, int $cursor_orientation = PDO::FETCH_ORI_NEXT [, int $cursor_offset = 0 ]]] ) //得到某一行的数据

//fetch示例
$result = $stmt -> fetch(PDO::FETCH_ASSOC);//以关联数组形式得到一条结果,即一维数组用
echo $result['id'];
echo $result['item'];

$result = $stmt -> fetch(PDO::FETCH_NUM);//以数字索引数组形式得到一条结果,即一维数组用数字下标索引
echo $result[0];
echo $result[1];

//fetchAll示例
$result = $stmt -> fetchAll(PDO::FETCH_ASSOC);//以数字索引数组形式得到多条结果,即二维数组
foreach($result as $line){
    echo $line['id'];
    echo $line['item'];
}

$result = $stmt -> fetchAll(PDO::FETCH_NUM);//以数字索引数组形式得到多条结果,即二维数组
foreach($result as $line){
    echo $line[0];
    echo $line[1];
}

避坑

坑1

这个是我亲自经历过的,曾经搞了很久都不知道是哪里问题

比如select * from account limit ?,10;绑定参数之后查询结果为空,但是数据库是有数据的,一番百度没有结果

这是一个介歇性问题本来是正常的突然会查询不到,一番调试发现没有问题

后面继续调试,发现先绑定参数再赋值就不会有问题,一段时间后发现问题没有解决,还是间歇性出现

后面继续调试,才猛然发现是不是类型问题,毕竟limit查询后面是整数型才行,一番百度果然如此

因为绑定参数执行的时候默认是参数类型是字符串,导致查询结果为空,此时语句就像这样子select * from account limit “0”,10;直接到时sql语句查询为空

解决方法:

连接数据库得到pdo对象之后加上一句

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);

这样就不会出现int转化为string了

愿天下无bug(祈祷.jpg)

坑2

乱码问题,可以在得到pdo对象的时候加上

$dbh->exec("set names 'utf8'");

尾言

其实很多问题都是因为自己只是对它一知半解,所以更好的解决方法是学一样东西学的更多学得更深。

参考链接:

http://www.thinkphp.cn/topic/44116.html

https://www.cnblogs.com/52php/p/5677929.html

https://blog.csdn.net/onepiece_only/article/details/78208550

https://www.imooc.com/qadetail/246493?t=395263

说点什么
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...