2008-09-25 100 views
28

我熟悉一些基础知识,但是我想知道更多关于什么时候以及为什么应该在PHP中使用错误处理(包括抛出异常),特别是在活动网站或Web上应用程序。是否可以过度使用,如果是这样,过度使用是什么样子?有没有不应该使用它的情况?另外,在错误处理方面有哪些常见的安全问题?在PHP中处理错误

回答

29

有一件事要说,已经说了什么是最重要的是,你在你的web应用程序中记录任何错误到日志中。这样,正如杰夫“编码恐怖”阿特伍德所建议的那样,您会知道用户何时遇到了应用程序问题(而不是“问他们出了什么问题”)。

要做到这一点,我建议以下类型的基础设施:

  • 在数据库中创建一个“崩溃”表和报告错误一组包装类。我建议设置崩溃类别(“阻塞”,“安全”,“PHP错误/警告”(与例外)等)。
  • 在所有错误处理代码中,请确保记录错误。一直这样做取决于你如何建立API(上面的步骤) - 它应该是微不足道的记录崩溃,如果做得对。

附加题:有时候,你的崩溃将是数据库级的崩溃:即DB服务器关闭等,如果是这样的话,你的错误日志基础设施(上图)将失败(您不能崩溃日志以因为日志会尝试写入数据库)。在这种情况下,我会写故障转移逻辑在你崩溃包装类要么

  • 发送电子邮件给管理员和/或
  • 记录崩溃的细节,一个纯文本文件

所有这些听起来都像是过火,但相信我,这会影响您的应用程序是否被接受为“稳定”或“片状”。这种差异来自于所有应用程序始终如故/崩溃的事实,但那些了解应用程序所有问题的开发人员有机会实际修复它。

2

无影响的错误会停止脚本,这是一个很好的理由来处理它们。

一般来说,你可以使用try-catch块来处理错误

try 
{ 
    // Code that may error 
} 
catch (Exception $e) 
{ 
    // Do other stuff if there's an error 
} 

如果你想停止出现在页面上的错误或警告消息,那么你可以像这样一个@符号前缀通话。

@mysql_query($query); 

使用查询但它通常是一个好主意,做这样的事情,所以你有什么事情的一个更好的主意。

@mysql_query($query) 
    or die('Invalid query: ' . mysql_error() . '<br />Line: ' . __LINE__ . '<br />File: ' . __FILE__ . '<br /><br />'); 
+2

虽然没有使用mysql_error()函数存在安全风险? – VirtuosiMedia 2008-09-25 16:39:49

+1

向用户输出mysql_error有潜在的风险。 – 2008-09-25 16:47:54

+0

您可以在您的Web应用程序中设置一个标志,以确定您处于测试环境还是生产环境中;在生产中,不要显示错误,只需记录它。在测试中,做两个。 – 2008-09-25 19:19:29

1

不是输出mysql_error,而是将其存储在日志中。这样您就可以跟踪错误(并且您不依赖用户报告错误),并且可以进入并清除问题。

最好的错误处理是对用户透明的那种,让你的代码理清问题,不需要涉及那个用户家伙。

2

如果您没有显式控制脚本正在处理的数据,则应该使用错误处理。我倾向于经常在例如表单验证等地方使用它。知道如何在代码中发现容易出错的地方需要一些练习:一些常见的是在函数调用之后返回一个值,或者在处理来自数据库查询的结果时。你绝不应该假设函数的返回将会是你的期望,你应该确保按照预期编写代码。你不必使用try/catch块,尽管它们很有用。很多时候你可以通过简单的if/else检查来获得。

错误处理与安全编码实践密切相关,因为存在大量“错误”,不会导致脚本简单崩溃。尽管本身并不严格处理错误处理,但增加的字节有很多关于安全PHP编程基础知识的4篇文章系列,您可以找到HERE。在这里,还有很多其他的问题在关于如mysql_real_escape_stringRegular Expressions这些主题的stackoverflow,这可以非常强大的确认用户输入的数据的内容。

1

除了处理错误,在你的代码的时候了,你还可以利用

http://us.php.net/manual/en/function.set-exception-handler.php

http://us.php.net/manual/en/function.set-error-handler.php

我发现,设置自己的异常处理程序特别有用。发生异常时,您可以根据异常类型执行不同的操作。

例如:当mysql_connet调用返回FALSE我抛出一个new DBConnectionException(mysql_error())和处理这是一个“特殊”的方式:记录错误,数据库连接信息(主机,用户名,密码)等,甚至电子邮件的开发团队,通知他们那些数据库可能真的有问题

我使用它来补充标准错误处理。我不会推荐过度使用这种方法

2

最好的做法恕我直言是使用以下方法:1。 创建错误/异常处理程序 2,开始它在应用程序从内有

<?php 
启动 3.处理所有的错误

类调​​试{

public static setAsErrorHandler() { 
     set_error_handler(array(__CLASS__, '__error_handler')); 
    } 

public static function __error_handler($errcode, $errmsg, $errfile, $errline) { 
     if (IN DEV) { 
       print on screen 
      } 
      else if (IN PRO) { 
       log and mail 
      } 
    } 

}

调试:: setAsErrorHandler();

?>

22

粗略地说,错误是在PHP中的遗留问题,而例外的是对待错误的现代生活方式。最简单的事情就是设置一个错误处理程序,它会抛出一个异常。这样所有的错误都被转换为异常,然后你可以简单地处理一个错误处理方案。以下代码将为您的错误转换为例外:

function exceptions_error_handler($severity, $message, $filename, $lineno) { 
    if (error_reporting() == 0) { 
    return; 
    } 
    if (error_reporting() & $severity) { 
    throw new ErrorException($message, 0, $severity, $filename, $lineno); 
    } 
} 
set_error_handler('exceptions_error_handler'); 
error_reporting(E_ALL^E_STRICT); 

尽管有几种情况,其中代码是专门设计用于处理错误的。例如,在验证文档时,schemaValidate method of DomDocument会引发警告。如果您将错误转换为异常,它将在第一次失败后停止验证。有时这是你想要的,但是在验证文档时,你可能实际上想要全部失败。在这种情况下,您可以临时安装收集错误的错误处理程序。这里有一个小片段,我已经用于上述用途:

class errorhandler_LoggingCaller { 
    protected $errors = array(); 
    function call($callback, $arguments = array()) { 
    set_error_handler(array($this, "onError")); 
    $orig_error_reporting = error_reporting(E_ALL); 
    try { 
     $result = call_user_func_array($callback, $arguments); 
    } catch (Exception $ex) { 
     restore_error_handler(); 
     error_reporting($orig_error_reporting); 
     throw $ex; 
    } 
    restore_error_handler(); 
    error_reporting($orig_error_reporting); 
    return $result; 
    } 
    function onError($severity, $message, $file = null, $line = null) { 
    $this->errors[] = $message; 
    } 
    function getErrors() { 
    return $this->errors; 
    } 
    function hasErrors() { 
    return count($this->errors) > 0; 
    } 
} 

和用例:

$doc = new DomDocument(); 
$doc->load($xml_filename); 
$validation = new errorhandler_LoggingCaller(); 
$validation->call(
    array($doc, 'schemaValidate'), 
    array($xsd_filename)); 
if ($validation->hasErrors()) { 
    var_dump($validation->getErrors()); 
} 
1

用@屏蔽错误是非常缓慢的。

0

您还可以使用Google表单来捕获和分析异常,而无需维护数据库或公共可访问的服务器。有一个教程here,解释过程。