PDO错误处理

时间:2013-05-07 08:13:13

标签: pdo

从关于intertubes的教程中我学到了一些关于做PDO查询的知识。本教程使用了try / catch,查询的结构基本如下:

try {
    $dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $user, $pass);

    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    $stmt = $dbh->prepare("UPDATE users yada yada yadda");

    $stmt->bindParam(':param1', $param1, PDO::PARAM_INT);
    $stmt->bindParam(':param2', $param2, PDO::PARAM_INT);

    $stmt->execute();

}

catch(PDOException $e)
{
    echo $e->getMessage();
}

这当然是屏幕上的echos mysql错误。并不是说我打算进行错误的查询,但我不喜欢在屏幕上回显错误的想法,想知道如果攻击者试图引发错误并尝试从中学习一些东西会怎样。

有没有更好的方法来做到这一点,以便任何错误转到日志文件,或者实际上我没有什么可担心的,因为绑定参数消除了任何SQL注入的风险?

3 个答案:

答案 0 :(得分:4)

本教程是正确的,因为您希望使用try..catch块来捕获可能导致错误的代码并降低您正在加载的内容。因此,如果您有一些依赖于此代码执行的代码,您希望将其包含在您的try部分中。如果您绝对需要此代码来执行您正在创建的任何工作,那么您可能希望捕获错误并将用户重定向到某种类型的错误页面。

如果您使用the php error log function,而不是

echo $e->getMessage();

您可以使用

error_log($e->getMessage(),0);

将错误消息从PDO直接发送到您的php错误日志。如果您不知道错误日志的位置,you can check out this link如果您正在运行* nix系统,则会指向它。如果您正在运行Windows,那么应该有一个配置文件可以告诉您。或者你可以检查php ini文件中它指向的位置,以便找到日志。

答案 1 :(得分:1)

  

有更好的方法吗

是的,当然!

这显然是处理本教程教你的PDO错误的错误方法 所以,只需摆脱这些try..catch命令 - 就是这样。

这样您就可以像处理其他PHP错误一样处理PDO异常。因此,在查询错误的情况下,您的脚本将被暂停并且将记录错误(如果您这样告诉PHP) 要告诉PHP,你必须将log_errors ini指令设置为1 要告诉PHP不要在屏幕上显示错误,请将display_errors ini指令设置为0(在开发服务器上,您可能希望将其反转)

答案 2 :(得分:0)

好吧,我的回答可能不是最佳做法,所以请将它留给最后一个选项。但就我而言,它完美无缺。

无论你在PDO :: ATTR_ERRMODE中设置什么,

PDO :: __ construct都会给你一个例外。我不知道他们为什么设计它表现得那样。

我解决这个问题的方法是创建一个代码区域,我将其命名为Debug Critical Section(意味着您需要非常小心该部分中的代码),本节中的任何错误都不会直接输出给用户。

以下是我为我的框架制作的代码:

private function doPDOConnect($dbIndex, &$DBInfo, &$error) {
    $dbh = null;
    $successed = false;

    if (!isset($this->connectedDB[$dbIndex])) {

        // Enter Critical Section so no error below belowing code will cause error output, but the error still in log though
        facula::core('debug')->criticalSection(true);

        try {
            $dbh = new PDO($DBInfo['Driver'] . ':' . $DBInfo['Connection'] . '=' . $DBInfo['Host'] . ';dbname=' . $DBInfo['Database'], $DBInfo['Username'], $DBInfo['Password'], array( PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING, PDO::ATTR_TIMEOUT => $DBInfo['Timeout'] )); // ATTR_ERRMODE => PDO::ERRMODE_WARNING. or we will cannot get anything even error happens

            $dbh->facula_prefix = $DBInfo['Prefix'];
            $dbh->facula_index = $dbIndex;
            $dbh->facula_connection = $DBInfo; // In order you want to reconnect this specify database after connection lost etc, remove if you worry about the security issue.

            $successed = true;
        } catch (PDOException $e) {
            $error = $e->getMessage(); // If any error, catch it, to &$error.
        }

        // Exit Critical Section, restore error caught
        facula::core('debug')->criticalSection(false);

        if ($successed) {
            return $this->connectedDB[$dbIndex] = $dbh;
        }
    } else {
        return $this->connectedDB[$dbIndex];
    }

    return false;
}

因此,在您的情况下,您可以将我的facula :: core('debug') - > criticalSection替换为display_errors off / on以正确处理错误显示处理程序。

例如:

$display_error_status = ini_get('display_errors');

function criticalSection($entered) {
    global $display_error_status;

    if ($entered) {
        ini_set('display_errors', '0');
    } else {
        ini_set('display_errors', $display_error_status);
    }
}