This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "quickfw".
The branch, master has been updated
via 4736419bdf19013a5a7aca28cc07ddb998910f04 (commit)
from 6c578872e8c8f59a141c01b87c78e214e96f7045 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 4736419bdf19013a5a7aca28cc07ddb998910f04
Author: Ivan1986 <iva...@li...>
Date: Tue May 25 17:05:03 2010 +0400
В качестве обработчика ошибок - Dklab_ErrorHook
diff --git a/QFW/Init.php b/QFW/Init.php
index 5ecfde7..3078def 100644
--- a/QFW/Init.php
+++ b/QFW/Init.php
@@ -92,8 +92,12 @@ class QFW
static public function modules()
{
//Включаем обработку фатальных ошибок, если в конфиге указано
- if (!empty(self::$config['QFW']['catchFE']))
- require QFWPATH.'/QuickFW/Error.php';
+ if (!empty(self::$config['error']))
+ {
+ require_once QFWPATH.'/QuickFW/Error.php';
+ foreach(self::$config['error'] as $handler)
+ QFW_Listener::addFromConfig($handler);
+ }
//автолоад
if (!empty(self::$config['QFW']['autoload']))
diff --git a/QFW/QuickFW/Error.php b/QFW/QuickFW/Error.php
index 7004293..d25e409 100644
--- a/QFW/QuickFW/Error.php
+++ b/QFW/QuickFW/Error.php
@@ -1,71 +1,44 @@
<?php
-/**
- * Функция - обработчик ошибок
- * На продакшене записывает в лог
- * На тестовом вылетает как эксепшн
- */
-function exception_error_handler($errno, $errstr, $errfile, $errline )
-{
- if (QFW::$config['QFW']['release'])
- {
- require_once LIBPATH.'/Log.php';
- Log::log($errstr.' in '.$errfile.' on line '.$errline,'debug');
- return false;
- }
- throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
-}
-set_error_handler("exception_error_handler");
+require_once LIBPATH.'/ErrorHook/Listener.php';
-/**
- * Обработка исключений
- * Обрабатывает исключение неавторизованности как нормальное - показом контента
- * Исключение 404 - показывает ошибку 404
- * Остальные - на продакшене 404 и в лог
- * в дебаге - на страницу
- */
-function exception_handler(Exception $exception)
+class QFW_Listener extends Debug_ErrorHook_Listener
{
- $GLOBALS['DONE'] = 1;
- if ($exception instanceof AuthException)
- echo $exception->getMessage();
- elseif ($exception instanceof S404Exception)
- QFW::$router->show404();
- elseif (QFW::$config['QFW']['release'])
+ private static $Instance;
+
+ /**
+ * Добавляет обработчик из конфига
+ *
+ * @param array $handler данные из конфига
+ */
+ public static function addFromConfig($handler)
{
- require_once LIBPATH.'/Log.php';
- Log::log("Uncaught exception: " . $exception->getMessage(),'debug');
- QFW::$router->show404();
- }
- else
- echo "Uncaught exception: " , $exception->getMessage(), "\n";
-}
-set_exception_handler('exception_handler');
+ if (!self::$Instance)
+ self::$Instance = new self();;
-/**
- * Классы исключений
- *
- */
-class AuthException extends Exception {}
-class S404Exception extends Exception {}
+ $name = ucfirst($handler['name']);
+ require_once LIBPATH.'/ErrorHook/'.$name.'Notifier.php';
+ //пока так, потом возможно придется переделать
+ if ($name == 'Mail')
+ {
+ $i = new Debug_ErrorHook_MailNotifier(
+ $handler['options']['to'], $handler['options']['whatToSend'],
+ $handler['options']['subjPrefix'], $handler['options']['charset']);
+ }
+ else
+ {
+ $class = 'Debug_ErrorHook_'.$name.'Notifier';
+ $i = new $class($handler['options']['whatToSend']);
+ }
+ if ($handler['RemoveDups'])
+ {
+ require_once LIBPATH.'/ErrorHook/RemoveDupsWrapper.php';
+ $i = new Debug_ErrorHook_RemoveDupsWrapper($i,
+ TMPPATH.'/errors', $handler['RemoveDups']);
+ }
+ self::$Instance->addNotifier($i);
-/**
- * Перехватчик фатальных ошибок
- * В случае фатальной ошибки может что-то сделать
- * TODO: Дописать коммент
- */
-function FatalErrorHandler($text)
-{
- //тут определим что жопа не случилась
- if ($GLOBALS['DONE'])
- return false;
- // Случилась жопа, начинаем обработку ошибок
- QFW::Init();
- require_once LIBPATH.'/Log.php';
- Log::log("Fatal Error" ,'critical');
- //TODO: Выдирать лог ошибок и отправлять последние куда-то
- return $text;
+ }
}
-ob_start('FatalErrorHandler');
?>
\ No newline at end of file
diff --git a/QFW/config.php b/QFW/config.php
index 186f569..2a2a486 100644
--- a/QFW/config.php
+++ b/QFW/config.php
@@ -42,6 +42,21 @@ $config['QFW'] = array(
);
/**
+ * Настройки обработчика ошибок
+ */
+$config['error'] = array();
+/*$config['error'][] = array(
+ 'name' => 'mail',
+ 'RemoveDups' => 300, //секунд или false
+ 'options' => array(
+ 'to' => 'user@localhost',
+ 'whatToSend' => 65535, // LOG_ALL (look in TextNotifier)
+ 'subjPrefix' => '[ERROR] ',
+ 'charset' => 'UTF-8',
+ ),
+);*/
+
+/**
* С этими параметрами вызывается функция
* session_set_cookie_params
* Менять порядок нельзя - отломается, дописывать можно
diff --git a/application/default.php b/application/default.php
index b6f670b..433c974 100644
--- a/application/default.php
+++ b/application/default.php
@@ -34,6 +34,21 @@ $config['redirection']=array(
);
/**
+ * Настройки обработчика ошибок
+ */
+$config['error'] = array();
+$config['error'][] = array(
+ 'name' => 'mail',
+ 'RemoveDups' => 300, //секунд или false
+ 'options' => array(
+ 'to' => 'ivan1986@localhost',
+ 'whatToSend' => 65535, // LOG_ALL (look in TextNotifier)
+ 'subjPrefix' => '[ERROR] ',
+ 'charset' => 'UTF-8',
+ ),
+);
+
+/**
* Настройки кешера (класс бекенда и дополнительные параметры, если есть)
*
* @deprecated лучше юзайте новый кешер
diff --git a/lib/ErrorHook/Catcher.php b/lib/ErrorHook/Catcher.php
new file mode 100644
index 0000000..b191d50
--- /dev/null
+++ b/lib/ErrorHook/Catcher.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * Auxilary class.
+ * It performs all work with notification catching.
+ */
+class Debug_ErrorHook_Catcher
+{
+ private $_notifiers = array();
+ private $_active = true;
+ private $_prevHdl = null;
+ private $_types = array(
+ "E_ERROR", "E_WARNING", "E_PARSE", "E_NOTICE", "E_CORE_ERROR",
+ "E_CORE_WARNING", "E_COMPILE_ERROR", "E_COMPILE_WARNING",
+ "E_USER_ERROR", "E_USER_WARNING", "E_USER_NOTICE", "E_STRICT",
+ "E_RECOVERABLE_ERROR"
+ );
+
+ public function __construct()
+ {
+ $this->_prevHdl = set_error_handler(array($this, "_handleNotice"));
+ register_shutdown_function(array($this, "_handleFatal"));
+ }
+
+ public function remove()
+ {
+ restore_error_handler();
+ $this->_prevHdl = null;
+ // There is no unregister_shutdown_function(), so we emulate it via flag.
+ $this->_active = false;
+ }
+
+ public function addNotifier(Debug_ErrorHook_INotifier $notifier)
+ {
+ $this->_notifiers[] = $notifier;
+ }
+
+ public function _handleNotice($errno, $errstr, $errfile, $errline)
+ {
+ if (!($errno & error_reporting())) {
+ return $this->_callPrevHdl($errno, $errstr, $errfile, $errline);
+ }
+ $trace = debug_backtrace();
+ array_shift($trace);
+ if ($this->_notify($errno, $errstr, $errfile, $errline, $trace) === false) {
+ return $this->_callPrevHdl($errno, $errstr, $errfile, $errline, $trace);
+ }
+ }
+
+ public function _handleFatal()
+ {
+ $error = error_get_last();
+ if (!$this->_active || !is_array($error) || !in_array($error['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR))) {
+ return;
+ }
+ $this->_notify($error['type'], $error['message'], $error['file'], $error['line'], null);
+ }
+
+ /**
+ * Processes a notification.
+ *
+ * @param mixed $errno
+ * @param string $errstr
+ * @param string $errfile
+ * @param int $errline
+ * @param array $trace
+ * @return bool True if we need to stop the processing.
+ */
+ private function _notify($errno, $errstr, $errfile, $errline, $trace)
+ {
+ // Translate error number to error name.
+ if (is_numeric($errno)) {
+ foreach ($this->_types as $t) {
+ $e = constant($t);
+ if ($errno == $e) {
+ $errno = $t;
+ break;
+ }
+ }
+ }
+ // Send data to all notifiers.
+ foreach ($this->_notifiers as $notifier) {
+ if ($notifier->notify($errno, $errstr, $errfile, $errline, $trace) === true) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private function _callPrevHdl()
+ {
+ if ($this->_prevHdl) {
+ $args = func_get_args();
+ return call_user_func_array($this->_prevHdl, $args);
+ }
+ return false;
+ }
+}
diff --git a/lib/ErrorHook/INotifier.php b/lib/ErrorHook/INotifier.php
new file mode 100644
index 0000000..f255275
--- /dev/null
+++ b/lib/ErrorHook/INotifier.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Notifier interface.
+ * Should be implemented by all notifiers in the stack.
+ */
+interface Debug_ErrorHook_INotifier
+{
+ /**
+ * Called when an error occurred.
+ *
+ * @param string $errno
+ * @param string $errstr
+ * @param string $errfile
+ * @param string $errline
+ * @param array $trace
+ * @return void
+ */
+ public function notify($errno, $errstr, $errfile, $errline, $trace);
+}
diff --git a/lib/ErrorHook/Listener.php b/lib/ErrorHook/Listener.php
new file mode 100644
index 0000000..25f7b16
--- /dev/null
+++ b/lib/ErrorHook/Listener.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Class to catch notices, warnings and even fatal errors
+ * and push them to a number of notifiers (e.g. - to email).
+ *
+ * A Listener object is kind of a guard object.
+ *
+ * @version 1.00
+ */
+
+require_once dirname(__FILE__).'/Catcher.php';
+require_once dirname(__FILE__).'/INotifier.php';
+
+class Debug_ErrorHook_Listener
+{
+ private $_catcher = null;
+
+ /**
+ * Creates a new listener object.
+ * When this object is destroyed, all hooks are removed.
+ *
+ * @return Debug_ErrorHook_Listener
+ */
+ public function __construct()
+ {
+ $this->_catcher = new Debug_ErrorHook_Catcher();
+ }
+
+ /**
+ * Destructor. Cancels all listenings.
+ *
+ * @return void
+ */
+ public function __destruct()
+ {
+ $this->_catcher->remove();
+ }
+
+ /**
+ * Adds a new notifier to the list. Notifiers are called in case
+ * of notices and even fatal errors.
+ *
+ * @param Debug_ErrorHook_INotifier $notifier
+ * @return void
+ */
+ public function addNotifier(Debug_ErrorHook_INotifier $notifier)
+ {
+ $this->_catcher->addNotifier($notifier);
+ }
+}
diff --git a/lib/ErrorHook/MailNotifier.php b/lib/ErrorHook/MailNotifier.php
new file mode 100644
index 0000000..f26f32b
--- /dev/null
+++ b/lib/ErrorHook/MailNotifier.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * Sends all notifications to a specified email.
+ *
+ * Consider using this class together with Debug_ErrorHook_RemoveDupsWrapper
+ * to avoid mail server flooding when a lot of errors arrives.
+ */
+
+require_once dirname(__FILE__).'/Util.php';
+require_once dirname(__FILE__).'/TextNotifier.php';
+
+class Debug_ErrorHook_MailNotifier extends Debug_ErrorHook_TextNotifier
+{
+ private $_to;
+ private $_charset;
+ private $_whatToSend;
+ private $_subjPrefix;
+
+ public function __construct($to, $whatToSend, $subjPrefix = "[ERROR] ", $charset = "UTF-8")
+ {
+ parent::__construct($whatToSend);
+ $this->_to = $to;
+ $this->_subjPrefix = $subjPrefix;
+ $this->_charset = $charset;
+ }
+
+ protected function _notifyText($subject, $body)
+ {
+ $this->_mail(
+ $this->_to,
+ $this->_encodeMailHeader($this->_subjPrefix . $subject),
+ $body,
+ join("\r\n", array(
+ "From: {$this->_to}",
+ "Content-Type: text/plain; charset={$this->_charset}"
+ ))
+ );
+ }
+
+ protected function _mail()
+ {
+ $args = func_get_args();
+ @call_user_func_array("mail", $args);
+ }
+
+ private function _encodeMailHeader($header)
+ {
+ return preg_replace_callback(
+ '/((?:^|>)\s*)([^<>]*?[^\w\s.][^<>]*?)(\s*(?:<|$))/s',
+ array(__CLASS__, '_encodeMailHeaderCallback'),
+ $header
+ );
+ }
+
+ private function _encodeMailHeaderCallback($p)
+ {
+ $encoding = $this->_charset;
+ return $p[1] . "=?$encoding?B?" . base64_encode($p[2]) . "?=" . $p[3];
+ }
+}
diff --git a/lib/ErrorHook/RemoveDupsWrapper.php b/lib/ErrorHook/RemoveDupsWrapper.php
new file mode 100644
index 0000000..4d223e9
--- /dev/null
+++ b/lib/ErrorHook/RemoveDupsWrapper.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Wrapper which denies duplicated notifications to be
+ * processed again and again. It is needed to lower the
+ * traffic to mail server in case the site is down.
+ *
+ * This class stores meta-informations in filesystem.
+ * It takes care about garbage collecting.
+ */
+
+require_once dirname(__FILE__).'/INotifier.php';
+
+class Debug_ErrorHook_RemoveDupsWrapper implements Debug_ErrorHook_INotifier
+{
+ const DEFAULT_PERIOD = 300;
+ const ERROR_FILE_SUFFIX = ".error";
+ const GC_PROBABILITY = 0.01;
+
+ private $_notifier;
+ private $_tmpPath;
+ private $_period;
+ private $_gcExecuted = false;
+
+ public function __construct(Debug_ErrorHook_INotifier $notifier, $tmpPath = null, $period = null)
+ {
+ $this->_tmpPath = $tmpPath? $tmpPath : $this->_getDefaultTmpPath();
+ $this->_period = $period? $period : self::DEFAULT_PERIOD;
+ $this->_notifier = $notifier;
+ if (!@is_dir($this->_tmpPath)) {
+ if (!@mkdir($this->_tmpPath, 0777, true)) {
+ $error = error_get_last();
+ throw new Exception("Cannot create '{$this->_tmpPath}': {$error['message']}");
+ }
+ }
+ }
+
+ public function notify($errno, $errstr, $errfile, $errline, $trace)
+ {
+ $hash = md5(join(":", array($errno, $errfile, $errline)));
+ if ($this->_isExpired($hash)) {
+ $this->_notifier->notify($errno, $errstr, $errfile, $errline, $trace);
+ }
+ // Touch always, even if we did not send anything. Else same errors will
+ // be mailed again and again after $period (e.g. once per 5 minutes).
+ $this->_touch($hash, $errfile, $errline);
+ }
+
+ protected function _getDefaultTmpPath()
+ {
+ return sys_get_temp_dir() . "/" . get_class($this);
+ }
+
+ protected function _getGcProbability()
+ {
+ return self::GC_PROBABILITY;
+ }
+
+ private function _getLockFname($hash)
+ {
+ return $this->_tmpPath . '/' . $hash . self::ERROR_FILE_SUFFIX;
+ }
+
+ private function _isExpired($hash)
+ {
+ $file = $this->_getLockFname($hash);
+ return !file_exists($file) || filemtime($file) < time() - $this->_period;
+ }
+
+ private function _touch($hash, $errfile, $errline)
+ {
+ $file = $this->_getLockFname($hash);
+ file_put_contents($file, "$errfile:$errline");
+ chmod($file, 0777);
+ $this->_gc();
+ }
+
+ private function _gc()
+ {
+ if ($this->_gcExecuted || mt_rand(0, 10000) >= $this->_getGcProbability() * 10000) {
+ return;
+ }
+ foreach (glob("{$this->_tmpPath}/*" . self::ERROR_FILE_SUFFIX) as $file) {
+ if (filemtime($file) <= time() - $this->_period * 2) {
+ @unlink($file);
+ }
+ }
+ $this->_gcExecuted = true;
+ }
+}
diff --git a/lib/ErrorHook/TextNotifier.php b/lib/ErrorHook/TextNotifier.php
new file mode 100644
index 0000000..a02e670
--- /dev/null
+++ b/lib/ErrorHook/TextNotifier.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Generic notifier wrapper. Converts notification
+ * to a human-readable text representation.
+ */
+
+require_once dirname(__FILE__).'/Util.php';
+require_once dirname(__FILE__).'/INotifier.php';
+
+abstract class Debug_ErrorHook_TextNotifier implements Debug_ErrorHook_INotifier
+{
+ const LOG_SERVER = 1;
+ const LOG_TRACE = 2;
+ const LOG_COOKIE = 4;
+ const LOG_GET = 8;
+ const LOG_POST = 16;
+ const LOG_SESSION = 32;
+ const LOG_ALL = 65535;
+
+ private $_whatToLog;
+ private $_bodySuffix;
+
+ public function __construct($whatToLog)
+ {
+ $this->_whatToLog = $whatToLog;
+ }
+
+ public function setBodySuffixTest($text)
+ {
+ $this->_bodySuffix = $text;
+ }
+
+ public function notify($errno, $errstr, $errfile, $errline, $trace)
+ {
+ $body = array();
+ $body[] = $this->_makeSection(
+ "",
+ join("\n", array(
+ (@$_SERVER['GATEWAY_INTERFACE']? "//{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}" : ""),
+ "$errno: $errstr",
+ "at $errfile on line $errline",
+ ))
+ );
+ if ($this->_whatToLog & self::LOG_TRACE && $trace) {
+ $body[] = $this->_makeSection("TRACE", Debug_ErrorHook_Util::backtraceToString($trace));
+ }
+ if ($this->_whatToLog & self::LOG_SERVER) {
+ $body[] = $this->_makeSection("SERVER", Debug_ErrorHook_Util::varExport($_SERVER));
+ }
+ if ($this->_whatToLog & self::LOG_COOKIE) {
+ $body[] = $this->_makeSection("COOKIES", Debug_ErrorHook_Util::varExport($_COOKIE));
+ }
+ if ($this->_whatToLog & self::LOG_GET) {
+ $body[] = $this->_makeSection("GET", Debug_ErrorHook_Util::varExport($_GET));
+ }
+ if ($this->_whatToLog & self::LOG_POST) {
+ $body[] = $this->_makeSection("POST", Debug_ErrorHook_Util::varExport($_POST));
+ }
+ if ($this->_whatToLog & self::LOG_SESSION) {
+ $body[] = $this->_makeSection("SESSION", Debug_ErrorHook_Util::varExport(@$_SESSION));
+ }
+ // Append body suffix?
+ $suffix = $this->_bodySuffix && is_callable($this->_bodySuffix)? call_user_func($this->_bodySuffix) : $this->_bodySuffix;
+ if ($suffix) {
+ $body[] = $this->_makeSection("ADDITIONAL INFO", $suffix);
+ }
+ // Remain only 1st line for subject.
+ $errstr = preg_replace("/\r?\n.*/s", '', $errstr);
+ $this->_notifyText("$errno: $errstr at $errfile on line $errline", join("\n", $body));
+ }
+
+ private function _makeSection($name, $body)
+ {
+ $body = rtrim($body);
+ if ($name) $body = preg_replace('/^/m', ' ', $body);
+ $body = preg_replace('/^([ \t\r]*\n)+/s', '', $body);
+ return ($name? $name . ":\n" : "") . $body . "\n";
+ }
+
+ abstract protected function _notifyText($subject, $body);
+}
diff --git a/lib/ErrorHook/Util.php b/lib/ErrorHook/Util.php
new file mode 100644
index 0000000..02f35ce
--- /dev/null
+++ b/lib/ErrorHook/Util.php
@@ -0,0 +1,102 @@
+<?php
+class Debug_ErrorHook_Util
+{
+ /**
+ * var_export clone, without using output buffering.
+ * (For calls in ob_handler)
+ *
+ * @param mixed $var to be exported
+ * @param integer $maxLevel (recursion protect)
+ * @param integer $level of current indent
+ * @return string
+ */
+ public static function varExport($var, $maxLevel = 10, $level = 0)
+ {
+ $escapes = "\"\r\t\x00\$";
+ $tab = ' ';
+
+ if (is_bool($var)) {
+ return $var ? 'TRUE' : 'FALSE';
+ } elseif (is_string($var)) {
+ return '"' . addcslashes($var, $escapes) . '"';
+ } elseif (is_float($var) || is_int($var)) {
+ return $var;
+ } elseif (is_null($var)) {
+ return 'NULL';
+ } elseif (is_resource($var)) {
+ return 'NULL /* ' . $var . ' */';
+ }
+
+ if ($maxLevel < $level) {
+ return 'NULL /* ' . (string) $var . ' MAX LEVEL ' . $maxLevel . " REACHED*/";
+ }
+
+ if (is_array($var)) {
+ $return = "array(\n";
+ } else {
+ $return = get_class($var) . "::__set_state(array(\n";
+ }
+
+ $offset = str_repeat($tab, $level + 1);
+
+ foreach ((array) $var as $key => $value) {
+ $return .= $offset;
+ if (is_int($key)) {
+ $return .= $key;
+ } else {
+ $return .= '"' . addcslashes($key, $escapes). '"';
+ }
+ $return .= ' => ' . self::varExport($value, $maxLevel, $level + 1) . ",\n";
+ }
+
+ return $return
+ . str_repeat($tab, $level)
+ . (is_array($var) ? ')' : '))');
+ }
+
+ /**
+ * Analog for debug_print_backtrace(), but returns string.
+ *
+ * @return string
+ */
+ public static function backtraceToString($backtrace)
+ {
+ // Iterate backtrace
+ $calls = array();
+ foreach ($backtrace as $i => $call) {
+ if (!isset($call['file'])) {
+ $call['file'] = '(null)';
+ }
+ if (!isset($call['line'])) {
+ $call['line'] = '0';
+ }
+ $location = $call['file'] . ':' . $call['line'];
+ $function = (isset($call['class'])) ?
+ $call['class'] . (isset($call['type']) ? $call['type'] : '.') . $call['function'] :
+ $call['function'];
+
+ $params = '';
+ if (isset($call['args']) && is_array($call['args'])) {
+ $args = array();
+ foreach ($call['args'] as $arg) {
+ if (is_array($arg)) {
+ $args[] = "Array(...)";
+ } elseif (is_object($arg)) {
+ $args[] = get_class($arg);
+ } else {
+ $args[] = $arg;
+ }
+ }
+ $params = implode(', ', $args);
+ }
+
+ $calls[] = sprintf('#%d %s(%s) called at [%s]',
+ $i,
+ $function,
+ $params,
+ $location);
+ }
+
+ return implode("\n", $calls) . "\n";
+ }
+}
-----------------------------------------------------------------------
Summary of changes:
QFW/Init.php | 8 ++-
QFW/QuickFW/Error.php | 95 ++++++++++++---------------------
QFW/config.php | 15 +++++
application/default.php | 15 +++++
lib/ErrorHook/Catcher.php | 97 +++++++++++++++++++++++++++++++++
lib/ErrorHook/INotifier.php | 19 +++++++
lib/ErrorHook/Listener.php | 50 +++++++++++++++++
lib/ErrorHook/MailNotifier.php | 60 ++++++++++++++++++++
lib/ErrorHook/RemoveDupsWrapper.php | 89 ++++++++++++++++++++++++++++++
lib/ErrorHook/TextNotifier.php | 81 +++++++++++++++++++++++++++
lib/ErrorHook/Util.php | 102 +++++++++++++++++++++++++++++++++++
11 files changed, 568 insertions(+), 63 deletions(-)
create mode 100644 lib/ErrorHook/Catcher.php
create mode 100644 lib/ErrorHook/INotifier.php
create mode 100644 lib/ErrorHook/Listener.php
create mode 100644 lib/ErrorHook/MailNotifier.php
create mode 100644 lib/ErrorHook/RemoveDupsWrapper.php
create mode 100644 lib/ErrorHook/TextNotifier.php
create mode 100644 lib/ErrorHook/Util.php
hooks/post-receive
--
quickfw
|