Home >Backend Development >PHP Problem >Installation, configuration and use of PDO objects worth collecting in php
This article brings you knowledge about the pdo object in PHP. The PHP Data Object (PDO) extension defines a lightweight consistent interface for PHP to access the database. How to understand it Use, let’s take a look at it together, I hope it will be helpful to everyone.
PHP Data Object (PDO) extension defines a lightweight database for PHP access level consistent interface. Each database driver that implements the PDO interface can expose database-specific features as standard extensions. Note that using PDO extensions by itself does not implement any database functionality; a database-specific PDO driver must be used to access database services.
PDO provides a data access abstraction layer, which means that no matter which database is used, the same functions (methods) can be used to query and obtain data. PDO does not provide a database abstraction layer; it does not rewrite SQL and does not emulate missing features. If necessary, a mature abstraction layer should be used.
extension=php_pdo.dll
Note: This step is not necessary in PHP 5.3 and higher versions, and PDO no longer needs to be a DLL file.
extension=php_pdo.dll extension=php_pdo_firebird.dll extension=php_pdo_informix.dll extension=php_pdo_mssql.dll extension=php_pdo_mysql.dll extension=php_pdo_oci.dll extension=php_pdo_oci8.dll extension=php_pdo_odbc.dll extension=php_pdo_pgsql.dll extension=php_pdo_sqlite.dll
PDO::__construct — Create a PDO instance that represents a database connection
PDO::__construct ( string $dsn , string $username = ? , string $password = ? , array $driver_options = ? )
mysql:host=localhost;dbname=pxscj
<?php /* Connect to an ODBC database using driver invocation */$dsn = 'mysql:host=localhost;dbname=pxscj';$user = 'user';$password = '123456';try { $dbh = new PDO($dsn, $user, $password);} catch (PDOException $e) { echo 'Connection failed: ' . $e->getMessage();}?>
PDO::exec — Execute a SQL statement and return the affected Number of rows
PDO::exec ( string $statement ) : int
Insights: The statement here should properly handle user input to prevent SQL injection
<?php $db=new PDO("mysql:host=localhost;dbname=PXSCJ","user","123456");$delete_sql="delete from userinfo where username='user1'"; //注销自己的SQL语句$affected=$db->exec($delete_sql); //执行没有返回的sql语句$delete_sqlif($affected) //如果受影响记录数不为0 echo "注销用户成功!";else echo "注销用户失败!";?>
PDO::query — Execute a SQL statement and return it as a PDOStatement object Result set
public PDO::query ( string $statement ) : PDOStatement
<?php $db=new PDO("mysql:host=localhost;dbname=pxscj","user","123456");$query="select * from kcb"; //SQL语句foreach($db->query($query) as $row) { //执行SQL语句$query--执行有结果集的SQL语句 echo "课程号:".$row[0]."<br>"; //返回的是一个PDOStatement类(型)的对象 echo "课程名:".$row[1]."<br>"; //还可以用PDOStatement类的方法fetch()行读 echo "开课日期:".$row[2]."<br>"; echo "学时:".$row[3]."<br><br>";}?>
PDO::prepare — Prepare a statement for execution and return the statement Object
public PDO::prepare ( string $statement , array $driver_options = array() ) : PDOStatement
Preparing the SQL statement to be executed for the PDOStatement::execute() method. An SQL statement can contain zero or more parameter placeholder markers, in the form of names (:name) or question marks (?), which will be replaced with real data when it is executed. In the same SQL statement, the named form and question mark form cannot be used at the same time; only one of the parameter forms can be selected. Note:Use parameter form to bind the data entered by the user. Do not directly splice the string into the query to prevent SQL injection
statement
must be a valid SQL statement template for the target database server.
driver_options
The array contains one or more key=>value pairs that set properties for the returned PDOStatement object.
模拟模式下的 prepare 语句不会和数据库服务器交互,所以 PDO::prepare() 不会检查语句。
$db=new PDO("mysql:host=localhost;dbname=pxscj","user","123456");$in_sql="insert into userinfo(username,password,sex,age,email) values(?,?,?,?,?)"; $in_result=$db->prepare($in_sql); //预处理SQL语句$in_sql$userid="php3"; $pwd1="111111"; $sex=0; $age=36; $email="php3@qq.com";$in_result->bindParam(1, $userid); //PDOStatement的bindParam()的作用是绑定参数给execute()$in_result->bindParam(2, $pwd1); //SQL语句使用问号参数时--bindParam()第一个参数是问号索引偏移(第几个)$in_result->bindParam(3, $sex); //bindParam()第二个参数是赋值给SQL语句参数(问号)的变量$in_result->bindParam(4, $age); $in_result->bindParam(5, $email);$in_result->execute(); //执行经过预处理的SQL语句$in_resultif($in_result->rowCount()==0) //用PDOStatement的rowCount()返回结果集行的总数 echo "插入记录失败!";else echo "插入记录成功!";
PDO::beginTransaction — 启动一个事务
PDO::beginTransaction():bool
PDO::rollBack — 回滚一个事务
PDO::rollBack():bool
回滚由 PDO::beginTransaction() 发起的当前事务。如果没有事务激活,将抛出一个 PDOException 异常。
如果数据库被设置成自动提交模式,此函数(方法)在回滚事务之后将恢复自动提交模式。
<?php /* 开始一个事务,关闭自动提交 */$dbh->beginTransaction();/* 更改数据库架构和数据 */$sth = $dbh->exec("DROP TABLE fruit");$sth = $dbh->exec("UPDATE dessert SET name = 'hamburger'");/* 识别错误且回滚更改 */$dbh->rollBack();/* 此时数据库连接恢复到自动提交模式 */?>
PDO::beginTransaction — 启动一个事务 PDO::commit — 提交一个事务 PDO::__construct — 创建一个表示数据库连接的 PDO 实例 PDO::errorCode — 获取跟数据库句柄上一次操作相关的 SQLSTATE PDO::errorInfo — Fetch extended error information associated with the last operation on the database handle PDO::exec — 执行一条 SQL 语句,并返回受影响的行数 PDO::getAttribute — 取回一个数据库连接的属性 PDO::getAvailableDrivers — 返回一个可用驱动的数组 PDO::inTransaction — 检查是否在一个事务内 PDO::lastInsertId — 返回最后插入行的ID或序列值 PDO::prepare — 准备要执行的语句,并返回语句对象 PDO::query — 执行 SQL 语句,以 PDOStatement 对象形式返回结果集 PDO::quote — 为 SQL 查询里的字符串添加引号 PDO::rollBack — 回滚一个事务 PDO::setAttribute — 设置属性
PDOStatement::bindParam — 绑定一个参数到指定的变量名
PDOStatement::bindParam ( mixed $parameter , mixed &$variable , int $data_type = PDO::PARAM_STR , int $length = ? , mixed $driver_options = ? ):bool
绑定一个PHP变量到用作预处理的SQL语句中的对应命名占位符或问号占位符。 不同于 PDOStatement::bindValue() ,此变量作为引用被绑定,并只在 PDOStatement::execute() 被调用的时候才取其值。
<?php /* 通过绑定的 PHP 变量执行一条预处理语句 */$calories = 150;$colour = 'red';$sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories bindParam(':calories', $calories, PDO::PARAM_INT);$sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12);$sth->execute();?>
PDOStatement::bindParam — 绑定一个参数到指定的变量名
PDOStatement::execute ( array $input_parameters = ? ) : bool
执行预处理过的语句。如果预处理过的语句含有参数标记,必须选择下面其中一种做法:
1)调用 PDOStatement::bindParam() 绑定 PHP 变量到参数标记:如果有的话,通过关联参数标记绑定的变量来传递输入值和取得输出值
2)或传递一个只作为输入参数值的数组
<?php /* 通过传递一个含有插入值的数组执行一条预处理语句 */$calories = 150;$colour = 'red';$sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories execute(array(':calories' => $calories, ':colour' => $colour));?>
PDOStatement::fetch — 从结果集中获取下一行
PDOStatement::fetch ( int $fetch_style = ? , int $cursor_orientation = PDO::FETCH_ORI_NEXT , int $cursor_offset = 0 ):mixed
从一个 PDOStatement 对象相关的结果集中获取下一行。fetch_style 参数决定 POD 如何返回行。
PDO::FETCH_ASSOC:返回一个索引为结果集列名的数组 PDO::FETCH_BOTH(默认):返回一个索引为结果集列名和以0开始的列号的数组 PDO::FETCH_BOUND:返回 true ,并分配结果集中的列值给 PDOStatement::bindColumn() 方法绑定的 PHP 变量。 PDO::FETCH_CLASS:返回一个请求类的新实例,映射结果集中的列名到类中对应的属性名。如果 fetch_style 包含 PDO::FETCH_CLASSTYPE(例如:PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE),则类名由第一列的值决定 PDO::FETCH_INTO:更新一个被请求类已存在的实例,映射结果集中的列到类中命名的属性 PDO::FETCH_LAZY:结合使用 PDO::FETCH_BOTH 和 PDO::FETCH_OBJ,创建供用来访问的对象变量名 PDO::FETCH_NUM:返回一个索引为以0开始的结果集列号的数组 PDO::FETCH_OBJ:返回一个属性名对应结果集列名的匿名对象
<?php $sth = $dbh->prepare("SELECT name, colour FROM fruit");$sth->execute();/* 运用 PDOStatement::fetch 风格 */print("PDO::FETCH_ASSOC: ");print("Return next row as an array indexed by column name\n");$result = $sth->fetch(PDO::FETCH_ASSOC);print_r($result);print("\n");?>
PDOStatement::fetchAll — 返回一个包含结果集中所有行的数组
PDOStatement::fetchAll ( int $fetch_style = ? , mixed $fetch_argument = ? , array $ctor_args = array() ):array
使用此方法获取大结果集将导致系统负担加重且可能占用大量网络资源。与其取回所有数据后用PHP来操作,倒不如考虑使用数据库服务来处理结果集。例如,在取回数据并通过PHP处理前,在 SQL 中使用 WHERE 和 ORDER BY 子句来限定结果。
<?php $sth = $dbh->prepare("SELECT name, colour FROM fruit");$sth->execute();/* 获取结果集中所有剩余的行 */print("Fetch all of the remaining rows in the result set:\n");$result = $sth->fetchAll();print_r($result);?>
PDOStatement::rowCount — 返回受上一个 SQL 语句影响的行数
PDOStatement::rowCount():int
PDOStatement::rowCount() 返回上一个由对应的 PDOStatement 对象执行DELETE、 INSERT、或 UPDATE 语句受影响的行数。
如果上一条由相关 PDOStatement 执行的 SQL 语句是一条 SELECT 语句,有些数据可能返回由此语句返回的行数。但这种方式不能保证对所有数据有效,且对于可移植的应用不应依赖于此方式。
<?php /* 从 FRUIT 数据表中删除所有行 */$del = $dbh->prepare('DELETE FROM fruit');$del->execute();/* 返回被删除的行数 */print("Return number of rows that were deleted:\n");$count = $del->rowCount();print("Deleted $count rows.\n");?>
PDOStatement::bindColumn — 绑定一列到一个 PHP 变量 PDOStatement::bindParam — 绑定一个参数到指定的变量名 PDOStatement::bindValue — 把一个值绑定到一个参数 PDOStatement::closeCursor — 关闭游标,使语句能再次被执行。 PDOStatement::columnCount — 返回结果集中的列数 PDOStatement::debugDumpParams — 打印一条 SQL 预处理命令 PDOStatement::errorCode — 获取跟上一次语句句柄操作相关的 SQLSTATE PDOStatement::errorInfo — 获取跟上一次语句句柄操作相关的扩展错误信息 PDOStatement::execute — 执行一条预处理语句 PDOStatement::fetch — 从结果集中获取下一行 PDOStatement::fetchAll — 返回一个包含结果集中所有行的数组 PDOStatement::fetchColumn — 从结果集中的下一行返回单独的一列。 PDOStatement::fetchObject — 获取下一行并作为一个对象返回。 PDOStatement::getAttribute — 检索一个语句属性 PDOStatement::getColumnMeta — 返回结果集中一列的元数据 PDOStatement::nextRowset — 在一个多行集语句句柄中推进到下一个行集 PDOStatement::rowCount — 返回受上一个 SQL 语句影响的行数 PDOStatement::setAttribute — 设置一个语句属性 PDOStatement::setFetchMode — 为语句设置默认的获取模式。
以上PDO类及PDOStatement类的说明摘录自php开发手册,详细描述只摘录了常用的几个内部函数。实话实说对于一个程序员最好的提升技术的方法之一就是看文档,通过查阅文档可以解决我们在开发中遇到的许多问题,而且通过文档我们可以知道很多api使用的细节和注意点,帮助我们规避很多错误。总而言之遇到问题看文档,多百度,多看博客,多总结,这才是长久的学习之道。
多说不做也是不行的,练习才是技术提升的必由之路,练习实践才可以在其中发现问题,提升自己,下面代码是我对PDO的一些常见用法的整理:
try { $db=new PDO("mysql:host=localhost;dbname=pxscj","user","123456"); }catch (PDOException $e) { echo "数据库连接失败:".$e->getMessage(); }$db->exec("set names utf-8"); //插入 $query="insert into kcb values('606','PHP程序设计',6,48,3)"; if($affCount=$db->exec($query)) { echo "插入成功,受影响条数为:".$affCount."<br><br>"; }//查询$query="select * from kcb"; foreach($db->query($query) as $row) { echo "课程号:".$row[0]."<br>"; echo "课程名:".$row[1]."<br>"; echo "开课日期:".$row[2]."<br>"; echo "学时:".$row[3]."<br><br>";}//事务处理try { $db->exec("set names utf-8"); $db->beginTransaction(); $affrows=$db->exec("insert into kcb values('506','UML系统分析',5,48,3)"); if(!$affrows) throw new PDOException("插入失败1"); $affrows=$db->exec("insert into kcb values('606','PHP程序设计',6,32,2)"); if(!$affrows) throw new PDOException("插入失败2"); echo "插入成功!"; $db->commit(); }catch (PDOException $e) { echo $e->getMessage(); $db->rollBack(); //回滚(要么成功要么失败)}//prepare 可以防sql注入$in_sql="insert into userinfo(username,password,sex,age,email) values(?,?,?,?,?)"; $in_result=$db->prepare($in_sql); $userid="php3"; $pwd1="111111"; $sex=0; $age=36; $email="php3@qq.com";$in_result->bindParam(1, $userid); $in_result->bindParam(2, $pwd1); $in_result->bindParam(3, $sex); $in_result->bindParam(4, $age); $in_result->bindParam(5, $email);$in_result->execute(); if($in_result->rowCount()==0) echo "插入记录失败!";else echo "插入记录成功!";//更新 改密码$oldpwd=$_POST['oldpwd']; //原密码$newpwd=$_POST['newpwd']; //新密码$s_sql="select * from userinfo where username='$username'"; //SQL语句$s_result=$db->query($s_sql); list($username,$password,$sex,$age,$email)=$s_result->fetch(PDO::FETCH_NUM);if($password!=$oldpwd) //判断原密码是否正确 echo "原密码错误!";else { $checkpwd=preg_match('/^\w{6,20}$/',$newpwd);if(!$checkpwd) echo "新密码格式不满足要求!";else { $update_sql="update userinfo set password='$newpwd' where username='$username'"; $affected=$db->exec($update_sql); if($affected) echo"密码修改成功!"; else echo "密码修改失败!"; }}//删除 注销session_start();$username=@$_SESSION['userid'];$delete_sql="delete from userinfo where username='$username'"; //注销自己的SQL语句$affected=$db->exec($delete_sql); if($affected) echo "注销用户成功!";else echo "注销用户失败!";
软件开发框架总是有很多互通的地方,因为无论任何开发语言,java或者php底层实现都离不开数据结构,算法,还有软件设计模式,而这些都是互通的,而好的软件框架离不开设计模式运用.
自从学习php接触了解到PDO对象扩展时我便联想到我曾使用的springboot JPA持久层框架,于是我查了些资料,以下便是我的个人理解:
首先先解释一下PDO和JPA的概念
PHP 数据对象(PHP Data Objects) 扩展为PHP访问数据库定义了一个轻量级的一致接口。
PDO 提供了一个 数据访问 抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。PDO 不提供 数据库 抽象层;它不会重写 SQL,也不会模拟缺失的特性。如果需要的话,应该使用一个成熟的抽象层。
PDO架构概念图
JPA
JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
JPA仅仅是一种规范,也就是说JPA仅仅定义了一些接口,而接口是需要实现才能工作的。所以底层需要某种实现,而Hibernate就是实现了JPA接口的ORM框架。
从上述概念和架构图可以看出PDO和JPA还是有一定区别的。首先PHP的PDO只是一个抽象的数据访问接口层,它对数据库的访问还要依赖相应的数据库驱动,而且需要自行编写操作数据的SQL语句。
而java的JPA则是一个持久层规范,也就是说JPA仅仅定义了一些接口,这些接口是关于类和数据库表的映射的,也就是说,JPA这个规范在数据访问接口层之上,而真正实现这个规范和底层数据访问接口是在如Hibernate的这些数据持久层框架内.
以Hibernate这个持久层框架为例,它实现了对象和数据库表的映射关系,仅需要操作相应的访问DAO层接口即可实现数据库的查询并转换为java对象内部属性数据。而Hibernate底层对数据库的访问还得依赖JDBC接口。
由此可见PDO和JPA规范完全处于两个不同层次,JPA是数据访问方法底层的高层次抽象,而PDO仅相当于java的JDBC接口层。PDO的抽象层次相对较低,这也符合PHP的轻量级web开发语言
的特点,这也是它的一个优点,可以方便清晰地实现一些复杂的数据库访问操作,但不利于复杂的高抽象度的大型项目的开发.
以上内容为个人对PHP PDO对象和java JPA规范的一些理解和比较,水平有限,可能会有不准确的地方。
php使用mysql原生密码连接如
$conn=mysqli_connect('localhost','user','123456')or die('连接失败');
会出现错误:The server requested authentication method unknown to the client.
原因:
由于本地使用mysql版本在8.0以上,而mysql 8升级了密码的验证方式 caching_sha2_password,所以原生连接会失败,解决办法使用sql修改用户登录验证方式:
use mysql;ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码';
php使用mysqli或pdo的query方法查询时,如未对用户表单输入数据进行处理可能会存在SQL注入隐患,如
$username=$_POST['username'];$password=$_POST['password']; //magic_quotes_gpc设为off的情况下//mysql$conn = mysqli_connect("localhost", "user" ,"123456") or die('连接失败'); //mysql_connect()链接MySQL服务器mysqli_select_db($conn,'PXSCJ') or die('选择数据库失败'); //mysql_select_db()选择数据库mysqli_query($conn,"SET NAMES utf-8");//设置字符集为utf-8$str="select * from userinfo where username='$username' and password='$password'";$result=mysqli_query($conn,$str); //PDO//连接数据库,新建PDO对象$pdo=new PDO("mysql:host=localhost;dbname=pxscj","user","123456");$str="select * from userinfo where username='$username' and password='$password'";$result=$pdo->query($str);
当用户输入username值为user
,password值为123 ' or 1=1
,即查询sql被转义为:
select * from userinfo where username='user' and password='123 ' or ' 1=1'
则用户将跳过密码的查询验证得到所有userinfo的数据,并且还存在其他SQL语句越权执行的风险
处理风险的方法有以下几种:
$password=addslashes($password);
addslashes()
函数返回在预定义字符之前添加反斜杠的字符串。预定义字符是:单引号(')
双引号(")
反斜杠(\)
NULL
$sql="select * from userinfo where username='$username' and password='$password'";//注意不是中文状态下的问号? $result=$pdo->prepare($sql); //按照?的顺序绑定参数值 $result->bindParam(1,$username); $result->bindParam(2,$password); $result->execute();
大家如果感兴趣的话,可以点击《PHP视频教程》进行更多关于PHP知识的学习。
The above is the detailed content of Installation, configuration and use of PDO objects worth collecting in php. For more information, please follow other related articles on the PHP Chinese website!