使用PDO进行错误处理的最佳实践

时间:2015-09-06 08:46:53

标签: php mysql pdo error-handling database-connection

问题:

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

  1. 许多网站都说您应该在catch区块中回显您的错误消息。
  2. SO上的大量用户表示,由于安全风险,您不应该回复错误消息。
  3. 其他人建议将其记录到文档根目录之外的日志文件中。
  4. 有些人使用错误处理将其记录到SQL表中。
  5. 通过众多选项,您可以轻松地淹没到应该使用的选项中。当然,您可以使用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中处理错误的最佳做法是什么?

1 个答案:

答案 0 :(得分:2)

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

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

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

  

许多网站都说您应该在catch块中回显您的错误消息。   SO上的大量用户表示,由于安全风险,您不应该回复错误消息。

你认为自己是什么?向用户显示系统错误消息是否有用?向恶意用户显示系统内部是否有用?

  

其他人建议将其记录到文档根目录之外的日志文件中。

你对此有任何异议吗?

  

有些人使用错误处理将其记录到SQL表中。

难道你认为将数据库错误记录到数据库中是不是很矛盾?

  

在PHP中处理错误的最佳做法是什么?

您已经展示过:在开发中显示并登录prod。所有这些都通过几个简单的配置选项在站点范围内进行控制。

  

处理catch块中的错误的最佳做法是什么?

根本不使用try-catch块进行错误报告。您不会为应用中的每个查询编写带有友好错误消息的catch块,正如在另一个答案中建议的那样,是吗?

因此你的代码必须是

<?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脚本中的错误处理程序。

当遇到致命错误(并且未捕获的异常为1)时,PHP不响应200 OK HTTP状态但具有5xx状态。每个Web服务器都可以捕获此状态并显示相应的错误页面。例如。对于Apache,它将是

ErrorDocument 503 server_error.html

你可以写任何你想要的借口。

或者你可以在PHP中设置一个自定义错误处理程序来处理所有PHP错误,我在这篇文章中写的一个例子可以看到:The (im)proper use of try..catch.