如何用PDO替换MySQL函数?

Mou*_*ser 7 php sql pdo

php.net上阅读有关MySQL功能的内容.我遇到了这条消息

警告此扩展自PHP 5.5.0起已弃用,将来将被删除.相反,应该使用MySQLi或PDO_MySQL扩展.另请参阅MySQL:选择API指南和相关的常见问题解答以获取更多信息.该功能的替代方案包括:

我读过关于PDO的文章.如何使用MySQL或MSSQL将代码更新为PDO?

Mou*_*ser 16

我看到很多代码发布在SO上实现my_sql函数.其他人(包括我自己)的评论迫使提问者放弃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提供了一种连接多个数据库的解决方案.这个答案仅涵盖MySQLMSSQL服务器.

连接到MySQL数据库,先决条件

这非常简单,不需要任何预先设置的PHP.现代PHP安装是标准附带的模块,允许PDO连接到MySQL服务器.

该模块是 php_pdo_mysql.dll

连接到MSSQL数据库的先决条件

这是一个更高级的设置.你需要php_pdo_sqlsrv_##_ts.dllphp_pdo_sqlsrv_##_nts.dll drivers.它们是版本特定的,因此##.在撰写本文时,Microsoft已发布PHP 5.5.x的官方驱动程序.5.6驱动程序尚未由Microsoft正式发布,但可由其他人以非官方版本提供.

该模块php_pdo_sqlsrv_##_ts.dll用于线程安全变体该模块php_pdo_sqlsrv_##_nts.dll用于非线程安全变体

使用PDO 连接到数据库要连接到数据库,需要从PDO构造创建新的PDO实例.

$connection = new PDO(arguments);
Run Code Online (Sandbox Code Playgroud)

PDO构造函数需要3个必需参数和1个可选参数.

  1. DSN或数据源名称,主要是包含有关驱动程序,主机和数据库名称的信息的字符串.
  2. 用户名
  3. 密码
  4. 选项

连接到MySQL

$dsn = 'mysql:dbname=databasename;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';

$dbh = new PDO($dsn, $user, $password);
Run Code Online (Sandbox Code Playgroud)

我们来看看$dsn:首先它定义了driver(mysql).然后是数据库名称,最后是主机.

连接到MSSQL

$dsn = 'sqlsrv:Server=127.0.0.1;Database=databasename';
$user = 'dbuser';
$password = 'dbpass';

$dbh = new PDO($dsn, $user, $password);
Run Code Online (Sandbox Code Playgroud)

我们来看看$dsn:首先它定义了driver(sqlsrv).然后是主机,最后是数据库名称.

创建实例时,将建立与数据库的连接.您只需在执行PHP脚本期间执行一次此操作.

您需要在try-catch子句中包装PDO实例创建.如果创建失败,则会显示返回跟踪,显示有关应用程序的关键信息,如用户名和密码.为了避免这种错误.

try 
{
    $connection = new PDO($dsn, $user, $password);
}
catch( PDOException $Exception ) 
{   
     echo "Unable to connect to database.";
     exit;
}
Run Code Online (Sandbox Code Playgroud)

要抛出SQL Server返回的错误,请使用setAttribute以下命令将此选项添加到PDO实例: $connection->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

执行查询

PDO使用预准备语句.这是PDO方法和mysql函数之间的真正区别.后者非常容易受到SQL-INJECTION的影响.一个人会构建一个这样的查询:

$SQL = 'SELECT ID FROM users WHERE user = '.$username ;
Run Code Online (Sandbox Code Playgroud)

当恶意网站或个人发布用户名时injector; DROP TABLE users.结果将是毁灭性的.您需要通过使用引号转义和封装字符串和变量来证明您的代码.必须为每个查询完成此操作.在较大的网站或维护不良的代码上,拥有允许SQL注入的表单的风险可能会变得非常高.准备好的语句消除了第一层SQL注入的可能性,如上例所示.

PDO驱动程序充当PHP服务器和数据库服务器之间的中间人,称为数据访问抽象层.它不会重写您的SQL查询,但确实提供了一种连接到多种数据库类型的通用方法,并为您处理将变量插入查询的过程.Mysql函数构造了执行PHP代码的查询.使用PDO,查询实际上是在数据库服务器上构建的.

一个准备好的SQL示例:

$SQL = 'SELECT ID, EMAIL FROM users WHERE user = :username';
Run Code Online (Sandbox Code Playgroud)

注意区别; $我们在字符串中引入变量,而不是在字符串外部使用PHP变量:.另一种方式是:

$SQL = 'SELECT ID, EMAIL FROM users WHERE user = ?';
Run Code Online (Sandbox Code Playgroud)

如何执行实际查询

您的PDO实例提供了两种执行查询的方法.如果没有变量,可以使用query()变量prepare().query()在通话时立即执行.请注意面向对象的调用方式(->).

$result = $connection->query($SQL);
Run Code Online (Sandbox Code Playgroud)

准备方法

准备的方法有两个参数.第一个是SQL字符串,第二个是Array形式的选项.一个基本的例子

$connection->prepare($SQL, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
Run Code Online (Sandbox Code Playgroud)

在我们的SQL字符串示例中,我们使用了一个名为的变量:username.我们仍然需要将PHP变量,整数或字符串绑定到它.我们可以通过两种方式做到这一点.构建包含命名变量的Array key或使用方法bindParambindValue.bindValue为简单起见,我将解释数组变体和方法.

Array
您可以对命名变量执行类似的操作,您可以将变量作为数组键提供:

$queryArguments = Array(':username' => $username);
Run Code Online (Sandbox Code Playgroud)

这对于索引变量(?):

$queryArguments = Array($username);
Run Code Online (Sandbox Code Playgroud)

添加完所需的所有变量后,可以调用该方法execute()来执行查询.从而将数组作为参数传递给函数execute.

$result = $connection->execute($queryArguments);
Run Code Online (Sandbox Code Playgroud)

bindValue
bindValue方法可以让你值绑定到PDO实例.该方法需要两个必需参数和一个可选参数.可选参数设置值的数据类型.

对于命名变量:

$connection->bindValue(':username', $username);
Run Code Online (Sandbox Code Playgroud)

对于索引变量:

$connection->bindValue(1, $username);
Run Code Online (Sandbox Code Playgroud)

将值绑定到实例后,可以在execute不传递任何参数的情况下调用.

$result = $connection->execute();
Run Code Online (Sandbox Code Playgroud)

注意:您只能使用一次命名变量!使用它们两次将导致无法执行查询.根据您的设置,这将会或不会引发错误.

获取结果

同样,我将仅介绍从返回的集合中获取结果的基础知识.PDO是一个相当先进的补充.

使用fetchfetchAll

如果您执行了select查询或执行了返回结果集的存储过程:

fetch
fetch是一种最多可能需要三个可选参数的方法.它从结果集中获取单行.默认情况下,它返回一个包含列名作为键和索引结果的Array.我们的示例查询可以返回类似的内容

ID      EMAIL
1       someone@example.com
Run Code Online (Sandbox Code Playgroud)

fetch 将返回为:

Array
(
    [ID] => 1
    [0] => 1
    [EMAIL] => someone@example.com
    [1] => someone@example.com
)
Run Code Online (Sandbox Code Playgroud)

要回显结果集的所有输出:

while($row = $result->fetch())
{
    echo $row['ID'];
    echo $row['EMAIL'];
}
Run Code Online (Sandbox Code Playgroud)

您可以在这里找到其他选项:fetch_style ;

fetchAll
获取一个Array对象中的所有行.使用相同的默认选项fetch.

$rows = $result->fetchAll();
Run Code Online (Sandbox Code Playgroud)

如果您使用的查询未返回结果(如插入或更新查询),则可以使用该方法rowCount检索受影响的行数.

一个简单的课程:

class pdoConnection
{
    public $isConnected;
    protected $connection;
    public function __construct($dsn, $username, $password, $host, $dbname, $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 Exception($e->getMessage());
        }
    }
    public function prepare($SQL, $params=array())
    {
        try
        { 
            $result = $this->connection->prepare($SQL); 
            $result->execute($params);
            return $result;     
        }
        catch(PDOException $e)
        {
            throw new Exception($e->getMessage());
        }       
    }
}
Run Code Online (Sandbox Code Playgroud)

如何使用:

$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'];
}   
Run Code Online (Sandbox Code Playgroud)