Zend数据库适配器 - 未捕获的异常 - 堆栈跟踪显示用户名和密码

时间:2012-02-14 14:49:10

标签: php mysql zend-framework pdo

我正在使用Zend_Db_Adapter,特别是Zend_Db_Adapter_Pdo_Abstract。我想这个问题也扩展到其他适配器。当抛出PDOException时,它被“未被捕获”,并且在许多情况下,堆栈跟踪显示用户名和密码。

我已经验证以下PDO异常都显示堆栈跟踪中的凭据:

  • SQLSTATE [HY000] [2005]未知的MySQL服务器主机 ... snip ...
  • SQLSTATE [HY000] [2013]在'阅读授权数据包'
  • 时失去与MySQL服务器的连接
  • SQLSTATE [1040]连接太多
  • SQLSTATE [28000] [1045]拒绝用户访问 ... snip ... (使用密码:是)

我的生产网站在出现错误时没有显示堆栈跟踪,我仍然希望在我的开发环境中看到这些错误的堆栈跟踪,我只是不希望用户名和密码以明文形式显示。

2 个答案:

答案 0 :(得分:3)

我会通过不解决它来解决这个问题......让我解释一下:

目前无法从未捕获的异常中禁用堆栈跟踪。 PHP不允许你这样做。

所以,不要试图禁用它,我只是不要让一个例外没有被删除......我会安装一个exception handler然后记录后跟踪信息。我不会在屏幕上显示它。我不会检查它所在的环境。我不会检查请求信息。我只是将它记录到一个文件,并显示一个通用的500服务器错误页面。

现在,在您的处理程序中,您可以有选择地显示呼叫信息,以便您可以选择是否记录参数信息:

set_exception_handler(function($exception) {
    $log = array(
        'message' => $exception->getMessage(),
        'trace' => array(),
    );
    foreach ($exception->getTrace() as $item) {
        $trace = isset($item['class']) ? $item['class'] . $item['type'] : '';
        $trace .= $item['function'] . '()';
        $log['trace'][] = $trace;
    }
    save_to_log($log);
});

但是我将未被捕获的异常视为应用程序中的错误的标志。你应该找到它们并修复它们。如果你得到足够的,你担心在页面中显示参数,那么你真的需要解决这个事实,即首先存在未捕获的异常......

编辑以下是对所发生情况的演示:

class Foo {
    public function doSomething($user, $password) {
        throw new Exception('Something Went Wrong!');
    }
}

$f = new Foo();

$f->doSomething('user', 'passw');

on CodePad导致:

<br />
<b>Fatal error</b>:  Uncaught exception 'Exception' with message 'Something Went Wrong!' in /code/MxH9Ls:4
Stack trace:
#0 /code/MxH9Ls(10): Foo-&gt;doSomething('user', 'passw')
#1 {main}
  thrown in <b>/code/MxH9Ls</b> on line <b>4</b><br />

但是,使用异常处理程序(修改为打印而不是日志):

set_exception_handler(function($exception) {
    $log = array(
        'message' => $exception->getMessage(),
        'trace' => array(),
    );
    foreach ($exception->getTrace() as $item) {
        $trace = isset($item['class']) ? $item['class'] . $item['type'] : '';
        $trace .= $item['function'] . '()';
        $log['trace'][] = $trace;
    }
    echo $log['message'] . "\n";
    foreach ($log['trace'] as $trace) {
        echo " - $trace\n";
    }
});

class Foo {
    public function doSomething($user, $password) {
        throw new Exception('Something Went Wrong!');
    }
}

$f = new Foo();

$f->doSomething('user', 'passw');

On CodePad产生:

Something Went Wrong!
 - Foo->doSomething()

答案 1 :(得分:1)

您可以尝试两种方法,第一种也许是最好的解决方案是捕获异常并将它们传递给自定义异常类。该类还将采用适配器的实例:

未经测试的示例

class myPDOException extends Exception
{
     public function __construct($message = '', $code = 0, Exception $previous = null, Zend_Db_Adapter_Abstract $adapter) {
        $config = $adapter->getConfig();
        $message = str_replace(array($config['username'], $config['password']), array('--user--', '--pass--'));
        parent::__construct($message, $code, $previous);
     }         
}

另一个选择是在检查引导程序后使用set_exception_handler,如果env是开发,那么你可以执行以下操作;

function exception_handler($exception) {
    if ($exception instanceof PDOException) {
        //load your configuration
        //replace the user pass in the message
        //rethrow the exceptio with the updated message
    }
}

set_exception_handler('exception_handler');

我处理不可见异常的方法是将它们保存到队列中,然后通过电子邮件向我发送所有必要信息,我们可以解决异常原因。

希望有所帮助