PHP使用PDO、mysqli扩展实现与数据库交互操作详解


Posted in PHP onJuly 20, 2019

本文实例讲述了PHP使用PDO、mysqli扩展实现与数据库交互操作。分享给大家供大家参考,具体如下:

数据库

在我们开发php时,可能有人已经学习了php数据库的连接交互,也可能正准备学习。如今,按照php的发展趋势,mysql扩展已经停止开发,在以后的发展中可能被淘汰,如mysql->query(),mysql->connect()等以后可能就无法使用。所以我们要尽量使用PDO和mysqli扩展。

PDO

基本操作如下:

<?php
// PDO + MySQL
$servername = "localhost";
$username = "username";
$password = "password";
try{
  $pdo = new PDO('mysql:host=$servername;dbname=myDB', '$username',
   '$password');
  echo '连接成功';
}
catch(PDOExcepton $e){
  echo $e->getMessge();
}
$statement = $pdo->query("SELECT some_field FROM some_table");
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo htmlentities($row['some_field']);
// PDO + SQLite
$pdo = new PDO('sqlite:/path/db/foo.sqlite');
$statement = $pdo->query("SELECT some_field FROM some_table");
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo htmlentities($row['some_field']);
//关闭连接
$pdo=null;

PDO 并不会对 SQL 请求进行转换或者模拟实现并不存在的功能特性;它只是单纯地使用相同的 API 连接不同种类的数据库。

更重要的是,PDO 使你能够安全的插入外部输入(例如 ID)到你的 SQL 请求中而不必担心 SQL 注入的问题。这可以通过使用 PDO 语句和限定参数来实现。

我们来假设一个 PHP 脚本接收一个数字 ID 作为一个请求参数。这个 ID 应该被用来从数据库中取出一条用户记录。下面是一个错误的做法:

<?php
$pdo = new PDO('sqlite:/path/db/users.db');
$pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO!

这是一段糟糕的代码。你正在插入一个原始的请求参数到 SQL 请求中。这将让被黑客轻松地利用[SQL 注入]方式进行攻击。想一下如果黑客将一个构造的 id 参数通过像 http://domain.com/?id=1%3BDELETE+FROM+users 这样的 URL 传入。这将会使 $_GET[‘id'] 变量的值被设为 1;DELETE FROM users 然后被执行从而删除所有的 user 记录!因此,你应该使用 PDO 限制参数来过滤 ID 输入。

<?php
$pdo = new PDO('sqlite:/path/db/users.db');
$stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
$id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT); // <-- 首先过滤您的数据 ,对于INSERT,UPDATE等特别重要
$stmt->bindParam(':id', $id, PDO::PARAM_INT); // <-- 通过PDO自动对SQL进行清理
$stmt->execute();

这是正确的代码。它在一条 PDO 语句中使用了一个限制参数。这将对外部 ID 输入在发送给数据库之前进行转义来防止潜在的 SQL 注入攻击。

对于写入操作,例如 INSERT 或者 UPDATE,进行数据过滤并对其他内容进行清理(去除 HTML 标签,Javascript 等等)是尤其重要的。PDO 只会为 SQL 进行清理,并不会为你的应用做任何处理。

mysqli扩展

mysqli基本操作如下:

<?php
$servername = "localhost";
$username = "username";
$password = "password";
// 创建连接
$conn = new mysqli($servername, $username, $password);
// 检测连接
if ($conn->connect_error) {
  die("连接失败: " . $conn->connect_error);
} 
echo "连接成功";
?>

注意在以上面向对象的实例中 $connect_error 是在 PHP 5.2.9 和 5.3.0 中添加的。如果你需要兼容更早版本 请使用以下代码替换:

// 检测连接
if (mysqli_connect_error()) {
  die("数据库连接失败: " . mysqli_connect_error());
}

数据库交互

<ul>
<?php
foreach ($db->query('SELECT * FROM table') as $row) {
  echo "<li>".$row['field1']." - ".$row['field1']."</li>";
}
?>
</ul>

这从很多方面来看都是错误的做法,主要是由于它不易阅读又难以测试和调试。而且如果你不加以限制的话,它会输出非常多的字段。

其实还有许多不同的解决方案来完成这项工作 — 取决于你倾向于 面向对象编程(OOP)还是函数式编程 — 但必须有一些分离的元素。

来看一下最基本的做法:

<?php
function getAllFoos($db) {
  return $db->query('SELECT * FROM table');
}
foreach (getAllFoos($db) as $row) {
  echo "<li>".$row['field1']." - ".$row['field1']."</li>"; 
}

这是一个不错的开头。将这两个元素放入了两个不同的文件于是你得到了一些干净的分离。
创建一个类来放置上面的函数,你就得到了一个「Model」。创建一个简单的.php文件来存放表示逻辑,你就得到了一个「View」。这已经很接近 MVC — 一个大多数框架常用的面向对象的架构。

//foo.php

<?php
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
// 使模板可见
include 'models/FooModel.php';
// 实例化类
$fooModel = new FooModel($db);
// Get the list of Foos
$fooList = $fooModel->getAllFoos();
// 显示视图
include 'views/foo-list.php';

//models/FooModel.php

<?php
class FooModel
{
  protected $db;
  public function __construct(PDO $db)
  {
    $this->db = $db;
  }
  public function getAllFoos() {
    return $this->db->query('SELECT * FROM table');
  }
}

//views/foo-list.php

<?php foreach ($fooList as $row): ?>
  <?= $row['field1'] ?> - <?= $row['field1'] ?>
<?php endforeach ?>

许多框架都提供了自己的数据库抽象层,其中一些是设计在 PDO 的上层的。这些抽象层通常将你的请求在 PHP 方法中包装起来,通过模拟的方式来使你的数据库拥有一些之前不支持的功能。这种抽象是真正的数据库抽象,而不单单只是 PDO 提供的数据库连接抽象。这类抽象的确会增加一定程度的性能开销,但如果你正在设计的应用程序需要同时使用 MySQL,PostgreSQL 和 SQLite 时,一点点的额外性能开销对于代码整洁度的提高来说还是很值得的。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
php环境配置 php5 MySQL5 apache2 phpmyadmin安装与配置图文教程
Mar 16 PHP
浅析PHP原理之变量分离/引用(Variables Separation)
Aug 09 PHP
PHP 通过Socket收发十六进制数据的实现代码
Aug 16 PHP
PHP判断是否有Get参数的方法
May 05 PHP
PhpDocumentor 2安装以及生成API文档的方法
May 21 PHP
php实现的任意进制互转类分享
Jul 07 PHP
一个PHP实现的轻量级简单爬虫
Jul 08 PHP
php把数组值转换成键的方法
Jul 13 PHP
PHP使用逆波兰式计算工资的方法
Jul 29 PHP
PHP的数组中提高元素查找与元素去重的效率的技巧解析
Mar 03 PHP
php版阿里大于(阿里大鱼)短信发送实例详解
Nov 30 PHP
php实现的读取CSV文件函数示例
Feb 07 PHP
Smarty模板语法详解
Jul 20 #PHP
Smarty模板变量与调节器实例详解
Jul 20 #PHP
Smarty模板配置实例简析
Jul 20 #PHP
详解PHP 7.4 中数组延展操作符语法知识点
Jul 19 #PHP
php的优点总结 php有哪些优点
Jul 19 #PHP
Yii框架页面渲染操作实例详解
Jul 19 #PHP
Yii2 queue的队列使用详解
Jul 19 #PHP
You might like
php access 数据连接与读取保存编辑数据的实现代码
2010/05/12 PHP
PHP中文件读、写、删的操作(PHP中对文件和目录操作)
2012/03/06 PHP
php中有关合并某一字段键值相同的数组合并的改进
2015/03/10 PHP
php自定义函数br2nl实现将html中br换行符转换为文本输入中换行符的方法【与函数nl2br功能相反】
2017/02/17 PHP
PHP实现数组根据某个单元字段排序操作示例
2018/08/01 PHP
xss文件页面内容读取(解决)
2010/11/28 Javascript
JavaScript图像延迟加载库Echo.js
2016/04/05 Javascript
JAVA中截取字符串substring用法详解
2017/04/14 Javascript
JavaScript简单拖拽效果(1)
2017/05/17 Javascript
JavaScript 上传文件(psd,压缩包等),图片,视频的实现方法
2017/06/19 Javascript
Angular2关于@angular/cli默认端口号配置的问题
2017/07/15 Javascript
详解用函数式编程对JavaScript进行断舍离
2017/09/18 Javascript
浅谈vue引入css,less遇到的坑和解决方法
2018/01/20 Javascript
Vuex实现数据共享的方法
2019/12/20 Javascript
浅谈vue生命周期共有几个阶段?分别是什么?
2020/08/07 Javascript
如何利用JavaScript编写更好的条件语句详解
2020/08/10 Javascript
[01:53]3.19 DOTA2发布会 现场精彩Coser表演
2014/03/25 DOTA
[56:35]DOTA2上海特级锦标赛主赛事日 - 5 总决赛Liquid VS Secret第一局
2016/03/06 DOTA
[02:13] 完美世界DOTA2联赛PWL DAY5集锦
2020/11/03 DOTA
Python中还原JavaScript的escape函数编码后字符串的方法
2014/08/22 Python
对于Python异常处理慎用“except:pass”建议
2015/04/02 Python
scrapy爬虫实例分享
2017/12/28 Python
Python玩转加密的技巧【推荐】
2019/05/13 Python
pandas计数 value_counts()的使用
2019/06/24 Python
Python搭建代理IP池实现接口设置与整体调度
2019/10/27 Python
Python venv虚拟环境配置过程解析
2020/07/08 Python
python 操作excel表格的方法
2020/12/05 Python
DKNY品牌官网:纽约大都会时尚风格
2016/10/20 全球购物
露营世界:Camping World
2017/02/02 全球购物
介绍一下linux的文件系统
2015/10/06 面试题
2014市府办领导班子“四风问题”对照检查材料思想汇报
2014/09/24 职场文书
2015年助理工程师工作总结
2015/04/03 职场文书
2015年领导班子工作总结
2015/05/23 职场文书
幼儿园见习总结
2015/06/23 职场文书
考教师资格证不要错过的4个最佳时机
2019/07/17 职场文书
《飘》英文读后感五篇
2019/10/11 职场文书