我了个大擦-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').'","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 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="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的博文就有),一下子取出很多结果集,然后对集进行操作。
实际上是指针一步步下移就好了。
例子我懒了,不想敲了。。。。
虽然没写很多,就这样吧。
过两天想去复查一下脚,虽然还在痛,不知道还敢不敢活血了。。。。
我了个大擦-PDO(二)的更多相关文章
- 决战大数据之二:CentOS 7 最新JDK 8安装
决战大数据之二:CentOS 7 最新JDK 8安装 [TOC] 修改hostname # hostnamectl set-hostname node1 --static # reboot now 重 ...
- HTML5 十大新特性(二)——表单新特性
H5的表单新特性可以分为两大类. 一.10个input的type值 1.email:邮件输入域,在表单提交时提供简单的邮箱格式验证,并弹出一个提示窗口. 2.url:地址输入域,在表单提交时提供简单的 ...
- C/C++ 笔试、面试题目大汇总(二)
一.找错题 试题1: void test1() { charstring[10]; char* str1 ="0123456789"; strcpy( string, str1 ) ...
- 面试大总结之二:Java搞定面试中的二叉树题目
package BinaryTreeSummary; import java.util.ArrayList; import java.util.Iterator; import java.util.L ...
- 初识大数据(二. Hadoop是什么)
hadoop是一个由Apache基金会所发布的用于大规模集群上的分布式系统并行编程基础框架.目前已经是大数据领域最流行的开发架构.并且已经从HDFS.MapReduce.Hbase三大核心组件成长为一 ...
- [luogu4479][BJWC2018]第k大斜率【二维偏序+二分+离散化+树状数组】
传送门 https://www.luogu.org/problemnew/show/P4479 题目描述 在平面直角坐标系上,有 n 个不同的点.任意两个不同的点确定了一条直线.请求出所有斜率存在的直 ...
- 大数据【二】HDFS部署及文件读写(包含eclipse hadoop配置)
一 原理阐述 1' DFS 分布式文件系统(即DFS,Distributed File System),指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连.该系统架构 ...
- Expo大作战(十二)--expo中的自定义样式Custom font,以及expo中的路由Route&Navigation
简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...
- Pmw大控件(二)
Pmw大控件英文名Pmw Python megawidgets 官方参考文档:Pmw 1.3 Python megawidgets 一,如何使用Pmw大控件 下面以创建一个计数器(Counter)为例 ...
随机推荐
- 充满想象力的 JavaScript 物理和重力实验
在这个列表中挑选了9个物理和重力实验,用来展示 Javascript 的强大.几年前,所有这些实验都必须使用 Java 或 Flash 才能做.在下面这些惊人的例子中,就个人而言,我比较喜欢仿真布料的 ...
- 15个最佳的代码评审(Code Review)工具
代码评审可以被看作是计算机源代码的测试,它的目的是查找和修复引入到开发阶段的应用程序的错误,提高软件的整体素质和开发者的技能.代码审查程序以各种形式,如结对编程,代码抽查等.在这个列表中,我们编制了1 ...
- 百度在线编辑器UEditor(v1.3.6) .net环境下详细配置教程之更改图片和附件上传路径
本文是接上一篇博客,如果有疑问请先阅读上一篇:百度在线编辑器UEditor(v1.3.6) .net环境下详细配置教程 默认UEditor上传图片的路径是,编辑器包目录里面的net目录下 下面就演示如 ...
- Ridge Regression(岭回归)
Ridge Regression岭回归 数值计算方法的"稳定性"是指在计算过程中舍入误差是可以控制的. 对于有些矩阵,矩阵中某个元素的一个很小的变动,会引起最后计算结果误差很大,这 ...
- Gartner:用自适应安全架构来应对高级定向攻击
发表于2015-06-24 摘要:当前的防护功能难以应对高级的定向攻击,由于企业系统所受到的是持续攻击,并持续缺乏防御力,面向“应急响应”的特别方式已不再是正确的思维模式,Garnter提出了用自 ...
- Eclipse CDT Linux下内存分析 补记
常用工具汇总 http://www.ibm.com/developerworks/cn/linux/l-cn-memleak/ 常用的内存分析工具 http://en.wikipedia.org/wi ...
- 《The Linux Command Line》 读书笔记01 基本命令介绍
<The Linux Command Line> 读书笔记01 基本命令介绍 1. What is the Shell? The Shell is a program that takes ...
- Android NDK之JNI陷阱
背景: 最近一个月一直在做移植库的工作,将c代码到share library移植到Android平台.这就涉及到Android NDK(native develop kit)内容.这里只想记录下JNI ...
- 【iOS】小项目框架设计(ReactiveCocoa+MVVM+AFNetworking+FMDB)
上一个项目使用到了ReactiveCocoa+MVVM+AFNetworking+FMDB框架设计,从最初的尝试,到后来不断思考和学习,现在对这样一个整体设计还是有了一定了理解与心得.在此与大家分享下 ...
- AFNetworking 3.0.4 的使用
本文永久链接:http://www.cnblogs.com/qianLL/p/5342593.html pod 'AFNetworking', '~>3.0.4' <-------第 ...