使用PHP PDO开发安全的数据库应用

欢迎您,来自IP地址为:54.80.123.20的隐士朋友

付款前,可以输入宝贝名称查一查有没有优惠券可以用哦!



PHP PDO由于语句支持预处理,所以在开发PHP应用时就可以提供更高的安全性。语句预处理是指在SQL语句中使用特定用户输入的语句模板,这个模板中包含了用于变量值替换的点位符。采用这种方式处理SQL语句,不仅让PHP处理SQL语句更加容量,并且可以有效的防止SQL注入攻击(由于PHP PDO在执行SQL语句前会自动忽略其它字符的引用)。

PDO同时支持命名点位符和匿名点位符,同时,点位符只能用在字段值,而不能应用于SQL语句的其它部分,例如字段名或操作符。

使用预处理语句同SQL服务器间存在两次交互,第一次是让SQL语句生效,第二次是将变量值传递给点位符。

1、PHP PDO使用简介

本步骤将使用PHP PDO进行一些基本操作,包括使用PDO连接数据库、执行简单的SQL语句以及高效的显示错误信息等。

1.1 连接数据库

为使用PHP PDO,我们只需要创建一个PDO对象就完成了数据库的连接。当然,在创建这个对象之前,我们需要给出数据库类型、主机名、数据库名、数据库用户名以及数据库用户密码等。

首先,我们先创建一个 DSN 数据源变量,用于指定数据库类型为”mysql”、主机名为”localhost”以及数据库名为”demo”。然后使用PDO创建一个新的数据库对象,完成数据库连接,示例如下:

 $dsn = 'mysql:host=localhost;dbname=demo';
 $db = new PDO($dsn, 'root', '');

在这里,示例设置的数据库用户为”root”,并且密码为空,可以根据实际情况进行设置。方便起见,将以上代码保存为”pdo-connect.php”,方便其它代码使用。

1.2 PHP PDO的第一条SQL语句

这里,将使用PDO对象执行第一条SQL语句,并且使用PHP print_r函数将取得的结果打印出来。为了程序可以顺利执行,首先使用以下语句在MySQL数据库中添加一些数据:

 USE DEMO;
 CREATE TABLE tb_Daehub (
    id INT NOT NULL,
    first_name VARCHAR(255) NOT NULL,
    last_name varchar(255) not null,
    gender varchar(255) NOT NULL,
    age varchar(255) not null,
    email_id varchar(255) not null,
    PRIMARY KEY(id)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 INSERT INTO TB_DAEHUB VALUES (1,'Dae','hub','male','20','mail@daehub.com'),(2,'Ru','ltr','female','22','mail@rultr.com');

现在就可以调用pdo对象的”query”方法来执行查询语句,并将结果集返回给”$row”变量。示例程序如下:

 require_once 'pdo-connect.php';
 $sql = "SELECT * FROM tb_daehub";
 $rows = $db->query($sql);

产生的结果集将每条记录转换为既包含下标又包含”字段名”的数组,可以使用”foreach”循环来遍历,示例代码如下:

 foreach ($rows as $row) {
     echo "<pre>";
     print_r($row);
     echo "</pre>";
 }

程序执行结果如下图所示:

1.3 使用PHP PDO的错误处理

如果之前的代码里连接的数据库不存在,那么程序在执行SQL语句时会报错,显示代码在哪里有问题。为了能够得到正确的错误信息,我们可以使用”try-catcht”结构来捕获错误信息。我们可以使用”setAttribute”或者”errorInfo”方法,下面将对两种方法分别进行示例。捕获的错误被分配给变量”$e”,然后就可以使用其”getMseeage”方法获得具体错误信息。如果产生了错误,那么就会在浏览器中显示具体的错误信息。

使用”setAttribute”:

 try{
     require_once 'pdo-connect.php';
     $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
     $sql = "SELECT * FROM tb_error";
     $rows = $db->query($sql);
     } catch(Exception $e){
     $error = $e->getMessage();
 }
 if(isset($error)){echo "Errors : ". $error;}

使用”errorInfo”

 try {
     require_once 'pdo-connect.php';
     $sql = "SELECT * FROM tb_error";
     $rows = $db->query($sql);
     $errorInfo = $db->errorInfo();
     print_r($errorInfo);
     echo '</br>';
     if(isset($errorInfo[2])){
         $error = $errorInfo[2];
     }
 } catch (Exception $e) {
     $error = $e->getMessage();
 }
 if(isset($error)){echo "Errors : ". $error;}

根据查看”errorInfo”的内容,可以发现具体的错误信息被保存在下标为2的错误信息数组中,于是使用”$errorInfo[2]”来显示具体内容。代码的执行结果如下图所示:

2、使用PHP PDO获取数据

现在我们将深入了解如何使用PDO对象从数据库中获取数据,并且我们将尝试使用不同的方法。首先将了解如何使用”fetch”方法,然后是”fetchall”方法,最后了解如何使用”fetchcolumn”以及”rowcount”方法来获得特定记录。

2.1 使用”fetch”方法

在PDO中,”fetch”方法将从结果集中获得一条记录的数值,如果想获得多条记录,那么需要使用循环来实现。”while”循环是同”fetch”方法配合最为常用的。以下是使用”while”循环来获得数据的示例代码:

 require_once 'pdo-connect.php';
 $sql = "SELECT * FROM tb_Daehub";
 $result = $db->query($sql);

 while($row = $result->fetch()){
     echo "<pre>";
     print_r($row);
     echo "</pre>";
 }

程序执行后的结果如之前的示意图所示,可以看到,结果集中既包含数值下标型数据也包含键值对型数据,可以通过设置”fetch”方法的类型参数来指定获取数值型还是字符型结果。关于”fetch”的类型参数将在最后讲解。

2.2 使用”fetchall”方法

“fetchall”方法将获得SQL语句的所有内容作为结果集,之后就可以使用手环来遍历结果集中的内容,也可以直接查看,示例代码如下:

 require_once 'pdo-connect.php';
 $sql = "SELECT * FROM tb_daehub";
 $result = $db->query($sql);
 $all = $result->fetchAll();

 echo "<pre>";
 print_r($all);
 echo "</pre>";

程序执行结果如下图所示:

可以看到,”fetchall”返回的结果是一个二维数组,同”fetch”方法的执行结果略有区别。

2.3 使用”fetchColumn”方法获得特定字段的数值

“fetchColumn”方法用于返回特定字段(也就是某一列)的数值,并且只返回一条数据。如果不指定方法的参数,则”fetchColumn”默认返回结果集中第一个字段的数值。

注意”fetchColumn”接收的参数是结果集字段序号值而不是字段名,以下示例将返回email字段的数据:

 require_once 'pdo-connect.php';
 $sql = "SELECT * FROM tb_daehub";
 $result = $db->query($sql);

 while ($col = $result->fetchColumn(5)){
     echo "Email : ". $col . "<br>";
 }

2.4 计算PDO结果集的数量

在PDO中可以使用”rowCount”方法来计算结果集的数量,使用示例如下:

 require_once 'pdo-connect.php';
 $sql = "SELECT * FROM tb_daehub";
 $result = $db->query($sql);
 $count = $result->rowCount();
 echo $count;

3、使用PDO增加和删除记录

3.1 使用”query”方法插入数据

首先,我们直接使用SQL语句插入记录,执行完SQL语句后,我们直接用”var_dump”打印出结果:

 require_once 'pdo-connect.php';
 $sql = "INSERT INTO TB_DAEHUB VALUES(3,'daehub','rultr','male','42','daehub@rultr.com');";
 $result = $db->query($sql);
 var_dump($result);

执行结果如下所示:

可以看到,程序会将SQL语句显示出来,事实上调用完”query”方法时,记录已经插入完成,而使用”query”方法时不会得到SQL语句的执行结果。为了可以更好的跟踪SQL执行过程,可以使用”exec”方法来替代”query”方法来获取执行结果。

3.2 使用”exec”方法插入数据

使用之前的”query”方法,我们不能确切知道SQL语句的执行结果,现在,我们使用”exec”方法来重新编码执行插入的代码:

 require_once 'pdo-connect.php';
 $sql = "INSERT INTO TB_DAEHUB VALUES(3,'daehub','rultr','male','42','daehub@rultr.com');";
 $result = $db->exec($sql);
 var_dump($result);

此时,程序执行完后会将语句执行后的结果反馈回来。此处如果执行成功,则返回受影响的数量,这里会显示1。

3.3 得到最后一个插入记录的ID

使用”lastInsertID”方法可以得到插入记录后的ID值,示例代码如下:

 $db->lastInsertID();

3.4 使用PDO删除刻录

使用PDO删除记录同插入记录类似,就是将SQL语句改为删除语句,然后使用”exec”方法执行,最后查看程序执行的结果,示例代码如下:

 require_once 'pdo-connect.php';
 $sql = "DELETE FROM TB_DAEHUB WHERE ID = 3;";
 $result = $db->exec($sql);
 var_dump($result);

如果SQL语句删除执行正确,则返回1,而删除错误则返回0。

3.5 “query”和”exec”方法的使用场合

“query”方法同”exec”方法的区别在于”query”方法可以用于”SELECT”语句,可以返回结果集;而”exec”方法则适合用于其它”INSERT”、”DELETE”和”UPDATE”的SQL语句场合,用于得到实际影响的记录数量。

4、预处理语句介绍:数值绑定

预处理语句使用点位符来表示接收外部的数据,例如表单中提交的数据。可以把数据同点位符通过”bindParam”或者”bindValue”方法进行绑定。

PDO支持使用全名或匿名参数来绑定数值,我们介绍如何使用命名或匿名参数来进行绑定。当然,也可以通过一个数组来进行数值传递。

使用预处理语句执行单条查询时会同服务器进行两次交互,首先验证和优化SQL语句,然后将数值发送给点位符,并得到结果。

4.1 数据绑定的不同方法

可以使用”bindParam”或者”bindValue”方法来将数值绑定到点位符。

“bindParam”方法同一个变量同时工作,你不能通过表达式例如计算或者字符串连接来绑定变量。这是由于绑定的变量直到执行时才会变量数值,换句话说,我们绑定的是变量而不是变量的数值。

“bindValue”方法会立即绑定数值,所以这个数值必须是确知的,我们甚至可以使用”bindValue”方法来设置一个字段为NULL。

4.2 使用占位符

这里,将讲解如何使用命名占位符,为了理解方便,采用”INSERT”语句,当然也可以使用”DELETE”或”UPDATE”语句。

首先,需要将点位符放置于SQL语句中,这个具有名字的点位符使用”:firstname, :lastname, :email, :gender, :age”形式,然后使用”prepare”方法预处理SQL语句,之后进行外部数据的绑定,最后使用”exec”方法执行SQL语句,以下是示例代码:

 $lastName = 'Rultr';
 $gender = 'Male';
 $age = '44';
 $email ='daehub@rultr.com';

 require_once 'pdo-connect.php';
 $sql = "INSERT INTO TB_DAEHUB VALUES(:id, :firstname, :lastname, :gender, :age , :email)";
 $result = $db->prepare($sql);
 $result->bindValue(':id',3);
 $result->bindValue(':firstname', 'Daehub');
 $result->bindParam(':lastname', $lastName);
 $result->bindParam('gender',$gender);
 $result->bindParam('age',$age);
 $result->bindParam('email',$email);
 $res = $result->execute();
 var_dump($res);

程序执行结果如下:

可以看到,程序将返回SQL语句是否执行成功,这是一个布尔值,可以方便用于其它条件。

4.3 使用匿名点位符

匿名点位符同命名点位符正好相反,它将使用”?”来当点位符,然后使用占位符序号来绑定数据,最后执行SQL语句。示例代码如下:

 $lastName = 'Rultr';
 $gender = 'Male';
 $age = '44';
 $email ='daehub@rultr.com';

 require_once 'pdo-connect.php';
 $sql = "INSERT INTO TB_DAEHUB VALUES(?, ?, ?, ?, ?, ?)";
 $result = $db->prepare($sql);
 $result->bindValue(1,3);
 $result->bindValue(2, 'Daehub');
 $result->bindParam(3, $lastName);
 $result->bindParam(4,$gender);
 $result->bindParam(5,$age);
 $result->bindParam(6,$email);
 $res = $result->execute();
 var_dump($res);

执行结果同命名占位符一样,也是返回一个布尔值来表示语句是否执行成功。

4.4 关联数组点位符

关联数组是命名占位符的一种推荐方式,可以在预处理语句中使用关联数组。这样,我们就可以在数据绑定时使用关联数组,示例代码如下:

 require_once 'pdo-connect.php';
 $sql = "INSERT INTO TB_DAEHUB VALUES(:id, :firstname, :lastname, :gender, :age , :email)";
 $result = $db->prepare($sql);
 $values = array(':id'          => 3,
                 ':firstname' 	=> 'Daehub',
                 ':lastname' 	=> 'Rultr',
                 ':gender' 	=> 'Male',
                 ':age' 	=> '44',
                 ':email' 	=> 'daehub@rultr.com'
 );
 $res = $result->execute($values);
 var_dump($res);

4.5 匿名占位符使用数组

使用”?”号的匿名占位符,可以使用数组来进行进行数据绑定,示例代码如下:

  require_once 'pdo-connect.php';
  $sql = "INSERT INTO TB_DAEHUB VALUES(?, ?, ?, ?, ?, ?);";
  $result = $db->prepare($sql);
  $values = array( 3, 'Daehub', 'Rultr', 'Male', '44', 'daehub@rultr.com'
  );
  $res = $result->execute($values);
  var_dump($res);

4.6 绑定输出结果

预处理语句同样可以用于绑定输出结果集,可以使用”bindColumn”方法将结果集的字段同变量进行绑定,然后通过循环将变量的值分别打印出来,示例代码如下:

 require_once 'pdo-connect.php';
 $sql = "SELECT * FROM TB_DAEHUB";
 $result = $db->prepare($sql);
 $result->execute();
 $result->bindColumn('first_name', $fname);
 $result->bindColumn('last_name', $lname);
 $result->bindColumn('id', $id);
 $result->bindColumn('email_id', $email);

 while($row = $result->fetch()){
    echo $fname ." ". $lname ." ". $id ." ". $email."<br>";
 }

发表评论

电子邮件地址不会被公开。 必填项已用*标注