我了个大擦-PDO(二)

王朝学院·作者佚名  2016-08-28
窄屏简体版  字體: 小  |  中  |  大  |  超大  

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').'","shit@shit.com")';

$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 userwhere 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="324@QQ.com"; //定义参数

$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", 'shit@shit.com');

$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的博文就有),一下子取出很多结果集,然后对集进行操作。

实际上是指针一步步下移就好了。

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

虽然没写很多,就这样吧。

过两天想去复查一下脚,虽然还在痛,不知道还敢不敢活血了。。。。

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航