使用 PDO 处理错误的最佳实践
Posted
技术标签:
【中文标题】使用 PDO 处理错误的最佳实践【英文标题】:Best practice for error handling using PDO 【发布时间】:2015-09-06 08:46:53 【问题描述】:问题:
寻找。我在网站、SO、书籍等上找到的选项。
-
很多网站说您应该在
catch
块中回显错误消息。
SO 上的大量用户表示,出于安全风险,您永远不应回显错误消息。
其他人建议将其记录到文档根目录之外的日志文件中。
有些使用错误处理将其记录到 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 中处理错误的最佳做法是什么?【问题讨论】:
【参考方案1】:这是一个非常好的问题,但一开始就有一个错误的前提:您将 PDO 的错误报告与站点范围的错误报告分开。这几乎没有什么意义:PDO 错误在各个方面都与其他错误相同——文件系统错误、HTTP 错误等等。因此,没有理由建立仅 PDO 的错误报告。您只需要正确设置站点范围的错误报告即可。
关于 php.ini 不可访问性还有一个错误假设:您始终可以使用 ini_set() 函数设置任何配置指令。因此,将 error_reporting 设置为灾难性级别 0 的原因不止一个。
要回答您的其余问题,您只需要一点常识即可。
很多网站都说你应该在你的 catch 块中回显你的错误消息。 SO 上的大量用户表示,出于安全风险,您永远不应回显错误消息。
你自己怎么看?向用户显示系统错误消息有什么好处吗?向恶意用户展示系统内部有什么好处?
其他人建议将其记录到文档根目录之外的日志文件中。
您对此有异议吗?
有些使用错误处理将其记录到 SQL 表中。
您不认为将数据库错误记录到数据库中很矛盾吗?
在 PHP 中处理一般错误的最佳实践是什么?
您已经展示过了:在 dev 中显示并登录 prod。通过几个简单的配置选项,所有这些都在站点范围内进行控制。
在 catch-block 中处理错误的最佳做法是什么?
根本不使用 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 脚本中的错误处理程序。
当遇到致命错误(未捕获的异常是一个)时,PHP 响应的不是 200 OK HTTP 状态,而是 5xx 状态。每个网络服务器都可以捕捉到这种状态并显示相应的错误页面。例如。对于 Apache 它会是
ErrorDocument 503 server_error.html
你可以写任何你想要的借口。
或者您可以在 PHP 中设置一个自定义错误处理程序,它也可以处理所有 PHP 错误,可以在我写的文章中看到一个示例:The (im)proper use of try..catch.
【讨论】:
不向用户显示错误消息听起来不太优雅。我的意思是,即使是 Facebook 在发生错误时也会显示一般错误。在您的示例中,没有显示此类通用错误。这真的是一种处理错误的优雅方式吗? 感谢您的更新!您能否举例说明自定义错误处理程序的外观,以便了解应该如何实施?如果没有,您能否提供讨论此问题的文章的链接?只是试图充实一种合理的错误处理方法。我对这样的处理程序如何处理显示自定义错误消息特别感兴趣。 感谢您的链接,信息量很大。我沿着set_error_handler()
和set_exception_handler()
的路径前进,它把我带到了一个有趣的世界。但是有一件事让我很困惑,为什么你在一个处理程序中使用 include() 而在另一个处理程序中使用 readfile()?
这只是一个复制粘贴错误。在原始代码中包含一个 php 文件,即使在错误页面上也能显示广告。
感谢您的澄清。我采纳了您的所有建议并编写了三个函数,希望您在有时间时继续考虑审查:codereview.stackexchange.com/questions/103954/…以上是关于使用 PDO 处理错误的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章
使用 NSURLSession 处理 HTTP 错误的最佳实践?