PDO error handling [duplicate]

2020-04-10 04:12发布

From a tutorial on the intertubes I learned a bit about doing PDO queries. The tutorial used try/catch and the queries are basically structured like so:

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();
}

This of course echos mysql errors on the screen. Not that I intend on having bad queries, but I do not like the idea of echoing out errors right on the screen, figuring what if an attacker tries to induce said errors and try to learn something from them.

Is there a better way to do this so that any errors go to a log file instead, or do I in actuality have nothing to fear in this regard since the bound parameters eliminate the risk of any sql injection?

标签: pdo
3条回答
Luminary・发光体
2楼-- · 2020-04-10 04:51

The tutorial is correct in that you want to use try..catch blocks to catch code that will possibly cause an error and bring down whatever you're loading. So, if you have some code that is dependent on this code executing you'd want to include it in your try section. If you absolutely need this code to execute for whatever you're creating to work, then you'll probably want to catch the error and redirect the user to some type of error page.

If you use the php error log function then instead of

echo $e->getMessage();

You can use

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

to send the error message from PDO directly to your php error log. If you don't know where the error log is, you can check out this link for a couple pointers to it if you're running a *nix system. If you're running windows there should be a config file somewhere that will tell you. Or you can check the php ini file for the location it's pointing to for a surefire way to find the log.

查看更多
够拽才男人
3楼-- · 2020-04-10 05:05

Well, my answer probably not in the best practice, so please leave it to the last option. But for my case, it works perfectly.

PDO::__construct however will give you an exception anyway no matter what you set in PDO::ATTR_ERRMODE. I don't know why they design it to behave like that.

My way to solve this problem is to create a code area i call it Debug Critical Section (means you need very careful about the codes in the section), any errors in this section will not directly output to user.

Here is the code i made for my framework:

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;
}

So in your case, you may replace my facula::core('debug')->criticalSection to display_errors off/on to handle the error display handler correctly.

For example:

$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);
    }
}
查看更多
Deceive 欺骗
4楼-- · 2020-04-10 05:11

Is there a better way to do this

Yes, sure!

That's apparently wrong way of handling PDO errors this tutorial taught you.
So, just get rid of these try..catch commands - that's all.

This way you'll have PDO exceptions handled the same way as other PHP errors. Thus, in case of query error your script will be halted and error will be logged (if you tell PHP so).
To tell PHP so, you have to set log_errors ini directive to 1 To tell PHP not to show errors on-screen, set display_errors ini directive to 0 (on a development server you may wish to reverse them though)

查看更多
登录 后发表回答