我看到很多关于 SO 实现 my_sql 函数 的代码。其他人(包括我自己)的 cmets 要求提问者放弃 MySQL 函数,开始使用 PDO 或 MySQLI。这篇文章是为了帮助。您可以参考它,因为它解释了为什么不推荐使用它们以及 PDO 是什么,以及实现 PDO 的最小代码示例。
首先:
从mysql 函数 到PDO 的转换不是一个简单的搜索和替换案例。 PDO 是 PHP 语言的面向对象编程插件。
这意味着使用 mysql 函数 编写代码的另一种方法。首先为什么要转换?
为什么不推荐使用 mysql 函数?
mysql 扩展是古老的,自 15 年前发布的 PHP 2.0 以来一直存在(!!);这与现代 PHP 截然不同,后者试图摆脱过去的不良做法。 mysql 扩展是一个非常原始的、低级的 MySQL 连接器,它缺乏许多便利功能,因此很难以安全的方式正确应用;因此,这对新手不利。许多开发人员不了解 SQL 注入,而且 mysql API 非常脆弱,即使您知道它也很难阻止它。它充满了全局状态(例如隐式连接传递),这使得编写难以维护的代码变得容易。由于它很旧,在 PHP 核心级别上维护可能会非常困难。
mysqli 扩展更新很多,可以解决上述所有问题。 PDO 也是相当新的,它也解决了所有这些问题,而且还解决了更多问题。
由于这些原因* mysql 扩展将在未来某个时候被删除。
来源Deceze
如何实现 PDO
PDO 提供了一种连接多个数据库的解决方案。此答案仅涵盖 MySQL 和 MSSQL 服务器。
连接到 MySQL 数据库,先决条件
这相当简单,不需要任何 PHP 预先设置。现代 PHP 安装标准附带一个允许 PDO 连接到 MySQL 服务器的模块。
模块是php_pdo_mysql.dll
连接到 MSSQL 数据库,先决条件
这是一个更高级的设置。您需要php_pdo_sqlsrv_##_ts.dll 或php_pdo_sqlsrv_##_nts.dll drivers。它们是特定于版本的,因此是##。在撰写本文时,微软已发布
PHP 5.5.x 的官方驱动程序。 Microsoft 尚未正式发布 5.6 驱动程序,但others 提供非官方版本。
模块是 php_pdo_sqlsrv_##_ts.dll 用于线程安全变体
该模块是php_pdo_sqlsrv_##_nts.dll,用于非线程安全变体
使用 PDO 连接到数据库
要连接到数据库,您需要从 PDO 构造创建一个新的 PDO 实例。
$connection = new PDO(arguments);
PDO 构造函数接受 1 个必需参数和 3 个可选参数。
- DSN 或数据源名称,主要是包含驱动程序、主机和数据库名称信息的字符串。从 PHP 7.4 开始,它还可以包含用户名和密码。
- 用户名
- 密码
- 选项
连接到 MySQL
$dsn = 'mysql:dbname=databasename;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';
$dbh = new PDO($dsn, $user, $password);
让我们看一下$dsn:首先它定义了驱动程序(mysql)。然后是数据库名称,最后是主机。
连接到 MSSQL
$dsn = 'sqlsrv:Server=127.0.0.1;Database=databasename';
$user = 'dbuser';
$password = 'dbpass';
$dbh = new PDO($dsn, $user, $password);
让我们看一下$dsn:首先它定义了驱动程序(sqlsrv)。然后是主机名,最后是数据库名。
当您创建实例时,会与数据库建立连接。您只需在 PHP 脚本执行期间执行一次。
您需要将 PDO 实例的创建包装在 try-catch 子句中。如果创建失败,则会显示回溯,揭示有关您的应用程序的关键信息,例如用户名和密码。为了避免这种情况,请捕获错误。
try
{
$connection = new PDO($dsn, $user, $password);
}
catch( PDOException $Exception )
{
echo "Unable to connect to database.";
exit;
}
要抛出 SQL 服务器返回的错误,请使用 setAttribute 将此选项添加到 PDO 实例:$connection->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
执行查询
PDO 使用准备好的语句。这是PDO 的 方法和mysql 函数 之间的真正区别。后者很容易受到SQL-INJECTION 的影响。可以构建这样的查询:
$SQL = 'SELECT ID FROM users WHERE user = '.$username ;
当恶意网站或个人发布用户名injector; DROP TABLE users 时。结果将是毁灭性的。您需要通过转义和用引号封装字符串和变量来证明您的代码。必须这样做
对于每个查询。在较大的网站或维护不善的代码上,拥有允许 SQL 注入的表单的风险可能会变得非常高。准备好的语句消除了第一层 SQL 注入的机会,就像上面的例子一样。
PDO 驱动程序充当 PHP 服务器和数据库服务器之间的中间人,称为 数据访问抽象层。它不会重写您的 SQL 查询,但确实提供了一种连接到多种数据库类型的通用方法
并为您处理将变量插入到查询中。 Mysql 函数 在 PHP 代码执行时构造查询。使用 PDO,查询实际上是在数据库服务器上构建的。
准备好的 SQL 示例:
$SQL = 'SELECT ID, EMAIL FROM users WHERE user = :username';
注意区别;代替在字符串外使用$ 的PHP 变量,我们在字符串内引入使用: 的变量。另一种方法是:
$SQL = 'SELECT ID, EMAIL FROM users WHERE user = ?';
如何执行实际查询
您的 PDO 实例提供了两种执行查询的方法。当你没有变量时,你可以使用query(),变量使用prepare()。 query() 在调用时立即执行。请注意调用的面向对象方式(->)。
$result = $connection->query($SQL);
准备方法
prepare 方法有两个参数。第一个是 SQL 字符串,第二个是数组形式的选项。一个基本的例子
$connection->prepare($SQL, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
在我们的 SQL 字符串示例中,我们使用了一个名为 :username 的命名变量。我们仍然需要将 PHP 变量、整数或字符串绑定到它。我们可以通过两种方式做到这一点。构建一个包含命名变量为key 的数组,或者使用方法bindParam 或bindValue。
为了简单起见,我将解释数组变体和方法bindValue。
Array
您可以对命名变量执行类似的操作,将 variable 作为 array 键:
$queryArguments = array(':username' => $username);
这对于索引变量(?):
$queryArguments = array($username);
添加完所有需要的变量后,您可以调用方法execute() 来执行查询。从而将数组作为参数传递给函数execute。
$result = $connection->execute($queryArguments);
bindValue
bindValue 方法允许您将值绑定到 PDO 实例。该方法采用两个必需参数和一个可选参数。可选参数设置值的数据类型。
对于命名变量:
$connection->bindValue(':username', $username);
对于索引变量:
$connection->bindValue(1, $username);
将值绑定到实例后,您可以在不传递任何参数的情况下调用execute。
$result = $connection->execute();
注意:命名变量只能使用一次!使用它们两次将导致无法执行查询。根据您的设置,这将或不会引发错误。
获取结果
再次,我将只介绍从返回的集合中获取结果的基础知识。 PDO 是一个相当高级的插件。
使用fetch 和fetchAll
如果您执行了选择查询或执行了返回结果集的存储过程:
fetch
fetch 是一种最多可以采用三个可选参数的方法。它从结果集中获取一行。默认情况下,它返回一个 array,其中包含作为键的列名和索引结果。
我们的示例查询可能会返回类似
ID EMAIL
1 someone@example.com
fetch 将返回:
Array
(
[ID] => 1
[0] => 1
[EMAIL] => someone@example.com
[1] => someone@example.com
)
回显结果集的所有输出:
while($row = $result->fetch())
{
echo $row['ID'];
echo $row['EMAIL'];
}
您可以在此处找到其他选项:fetch_style;
fetchAll
获取单个数组中的所有行。使用与fetch 相同的默认选项。
$rows = $result->fetchAll();
如果您使用不返回结果的查询,例如插入或更新查询,您可以使用方法rowCount 来检索受影响的行数。
一个简单的类:
class pdoConnection {
public $isConnected;
protected $connection;
public function __construct($dsn, $username, $password, $options = array()) {
$this->isConnected = true;
try {
$this->connection = new PDO($dsn, $username, $password, $options);
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->connection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); //sets the default to return 'named' properties in array.
} catch (PDOException $e) {
$this->isConnected = false;
throw new Exception($e->getMessage());
}
}
public function disconnect() {
$this->connection = null;
$this->isConnected = false;
}
public function query($SQL) {
try {
$result = $this->connection->query($SQL);
return $result;
} catch (PDOException $e) {
throw new PDOException($e->getMessage());
}
}
public function prepare($SQL, $params = array()) {
try {
$result = $this->connection->prepare($SQL);
$result->execute($params);
return $result;
} catch (PDOException $e) {
throw new PDOException($e->getMessage());
}
}
}
使用方法:
$dsn = 'mysql:dbname=databasename;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';
$db = new pdoConnection($dsn, $user, $password);
$SQL = 'SELECT ID, EMAIL FROM users WHERE user = :username';
$result = $db->prepare($SQL, array(":username" => 'someone'));
while($row = $result->fetch())
{
echo $row['ID'];
echo $row['EMAIL'];
}