php - 使用 PDO 处理错误的最佳实践

标签 php mysql pdo error-handling database-connection

问题:

寻找使用 PDO 进行错误处理的最佳实践。我在网站、SO、书籍等上找到的选项。

  1. 许多网站表示您应该在 catch block 中回显错误消息。
  2. SO 上的大量用户表示,出于安全风险,您永远不应该回显错误消息。
  3. 其他人建议将其记录到文档根目录之外的日志文件中。
  4. 有些使用错误处理将其记录到 SQL 表中。

由于有多种选项,您很容易陷入应该使用哪个选项的困境。当然,您可以使用 MVC 框架并让它为您处理错误日志记录,但如果您不使用 MVC,它会是什么样子。

据我了解,开发环境中的错误处理应如下所示:

display_errors = On
display_startup_errors = On
error_reporting = -1
log_errors = On

或者如果无法访问 php.ini 文件:

error_reporting(-1);
ini_set("display_errors", 1);

生产环境中:

display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
log_errors = On

或者如果无法访问 php.ini 文件:

error_reporting(0);

生产环境中的数据库连接为例。

代码:

<?php
  // Error handling
  error_reporting(0);

  // Get credentials from outside document root
  require_once('../settings.php');

  // Tests connection to database
  try {
    $dbh = new PDO(
            sprintf(
              'mysql:host=%s;dbname=%s;port=%s;charset=%s',
              $settings['host'],
              $settings['name'],
              $settings['port'],
              $settings['charset']
            ),
            $settings['username'],
            $settings['password']
    );
    // Prevents emulated prepares and activates error handling
    // PDO::ERRMODE_EXCEPTION
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  }
  // Catches errors raised by PDO
  catch (PDOException $e) {
    // Prints error messages to file
    file_put_contents('/home/ubuntu/errors.log', 'Error: ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
    // Shows generic error message to user
    header('Location: 404.php');
    exit;
  }
?>

问题:

  • 在 PHP 中处理一般错误的最佳实践是什么?
  • 处理 catch block 中的错误的最佳实践是什么?

最佳答案

这是一个非常好的问题,但一开始就有一个错误的前提:您将 PDO 的错误报告与站点范围的错误报告分开。这毫无意义:PDO 错误在各个方面都与其他错误相同 - 文件系统错误、HTTP 错误等等。因此,没有理由建立仅 PDO 的错误报告。您所需要的只是正确设置站点范围的错误报告。

关于 php.ini 不可访问性,还有一个错误的假设:您始终可以使用 ini_set() 函数设置任何配置指令。因此,这里并不是将 error_reporting 设置为灾难性级别 0 的唯一原因。

要回答您的其余问题,您所需要的只是一点常识。

A great number of websites say you should echo your error messages in your catch block. A large number of users on SO say that you should never echo error messages due to security risks.

你自己怎么想?向用户显示系统错误消息有什么好处吗?向恶意用户展示系统内部结构有什么好处吗?

Others are recommending logging it to a log file outside the document root.

您对此有何异议?

Some use error handling to log it to a SQL table.

您不认为将数据库错误记录到数据库中是非常矛盾的想法吗?

What is the best practice for handling errors in general in PHP?

您已经显示了:在 dev 中显示并登录 prod。一切都通过几个简单的配置选项在站点范围内进行控制。

What is the best practice for handling errors in the catch-block?

根本不要使用 try-catch block 进行错误报告。您不会为应用中的每个查询编写带有友好错误消息的 catch block strong>,正如其他答案中所建议的那样,你是吗?

因此你的代码必须是

<?php
  // Error handling
  error_reporting(-1);
  ini_set('display_errors',0);
  ini_set('log_errors',1);

  // Get credentials from outside document root
  require_once('../settings.php');

  // Tests connection to database
    $dbh = new PDO(
            sprintf(
              'mysql:host=%s;dbname=%s;port=%s;charset=%s',
              $settings['host'],
              $settings['name'],
              $settings['port'],
              $settings['charset']
            ),
            $settings['username'],
            $settings['password']
    );
    // Prevents emulated prepares and activates error handling
    // PDO::ERRMODE_EXCEPTION
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

现在回答您在评论中提出的问题。

自定义错误屏幕是完全不同的事情,您的代码尤其糟糕。它既不应该是 404 错误,也不应该使用 HTTP 重定向(这对 SEO 非常不利)。

要创建自定义错误页面,您必须使用 Web 服务器功能(首选)或 PHP 脚本中的错误处理程序。

当遇到 fatal error (未捕获的异常就是其中之一)时,PHP 不会以 200 OK HTTP 状态响应,而是以 5xx 状态响应。每个网络服务器都可以捕获此状态并显示相应的错误页面。例如。对于 Apache 来说是

ErrorDocument 503 server_error.html

您可以在其中写下任何您想要的借口。

或者您可以在 PHP 中设置一个自定义错误处理程序,它也可以处理所有 PHP 错误,我在有关此事的文章中可以看到一个示例:The (im)proper use of try..catch.

关于php - 使用 PDO 处理错误的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33192547/

相关文章:

mysql - 从 mysql 中导出表,导入到具有不同名称的表中

php - 使用 MSSQL 的 PDO 返回无效游标

JavaScript Date 对象的月份索引从 0 开始

php - 根据用户 IP 时区报告日期/时间值

c# - 该请求缺少身份验证 key (FCM token )

javascript - 表单上的 AJAX 引用错误

mysql - MySQL中使用保留字作为表名或列名导致的语法错误

php - 为什么我的网站可以连接到本地服务器上的数据库,但无法连接到大学域?

php - Mysql 中的报告 - man 子表

php - 通过 PHP mysql PDO 根据下拉列表选择的值更新表