506 lines
18 KiB
PHP
506 lines
18 KiB
PHP
<?php
|
|
/**
|
|
* FuzeWorks.
|
|
*
|
|
* The FuzeWorks MVC PHP FrameWork
|
|
*
|
|
* Copyright (C) 2015 TechFuze
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* @author TechFuze
|
|
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
|
|
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
|
|
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
|
|
*
|
|
* @link http://fuzeworks.techfuze.net
|
|
* @since Version 0.0.1
|
|
*
|
|
* @version Version 0.0.1
|
|
*/
|
|
|
|
namespace FuzeWorks;
|
|
|
|
/**
|
|
* Logger Class.
|
|
*
|
|
* The main tool to handle errors and exceptions. Provides some tools for debugging and tracking where errors take place
|
|
* All fatal errors get catched by this class and get displayed if configured to do so.
|
|
*
|
|
* @author Abel Hoogeveen <abel@techfuze.net>
|
|
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
|
|
*/
|
|
class Logger
|
|
{
|
|
/**
|
|
* Log entries which display information entries.
|
|
*
|
|
* @var array
|
|
*/
|
|
public static $infoErrors = array();
|
|
|
|
/**
|
|
* Log entries which display critical error entries.
|
|
*
|
|
* @var array
|
|
*/
|
|
public static $criticalErrors = array();
|
|
|
|
/**
|
|
* Log entries which display warning entries.
|
|
*
|
|
* @var array
|
|
*/
|
|
public static $warningErrors = array();
|
|
|
|
/**
|
|
* All log entries, unsorted.
|
|
*
|
|
* @var array
|
|
*/
|
|
public static $Logs = array();
|
|
|
|
/**
|
|
* whether to output the log after FuzeWorks has run.
|
|
*
|
|
* @var bool
|
|
*/
|
|
private static $print_to_screen = false;
|
|
|
|
/**
|
|
* whether to output the log after FuzeWorks has run, regardless of conditions.
|
|
*
|
|
* @var bool
|
|
*/
|
|
public static $debug = false;
|
|
|
|
/**
|
|
* Initiates the Logger.
|
|
*
|
|
* Registers the error and exception handler, when required to do so by configuration
|
|
*/
|
|
public static function init()
|
|
{
|
|
// Register the error handler
|
|
if (Config::get('error')->error_reporting == true) {
|
|
set_error_handler(array('\FuzeWorks\Logger', 'errorHandler'), E_ALL);
|
|
set_Exception_handler(array('\FuzeWorks\Logger', 'exceptionHandler'));
|
|
error_reporting(false);
|
|
}
|
|
self::$debug = Config::get('error')->debug;
|
|
self::newLevel('Logger Initiated');
|
|
}
|
|
|
|
/**
|
|
* Function to be run upon FuzeWorks shutdown.
|
|
*
|
|
* Logs a fatal error and outputs the log when configured or requested to do so
|
|
*/
|
|
public static function shutdown()
|
|
{
|
|
// Load last error if thrown
|
|
$errfile = 'Unknown file';
|
|
$errstr = 'shutdown';
|
|
$errno = E_CORE_ERROR;
|
|
$errline = 0;
|
|
|
|
$error = error_get_last();
|
|
if ($error !== null) {
|
|
$errno = $error['type'];
|
|
$errfile = $error['file'];
|
|
$errline = $error['line'];
|
|
$errstr = $error['message'];
|
|
|
|
// Log it!
|
|
self::errorHandler($errno, $errstr, $errfile, $errline);
|
|
self::logInfo(self::backtrace());
|
|
}
|
|
|
|
// And finally stop the Logging
|
|
self::stopLevel();
|
|
|
|
if (self::$debug == true || self::$print_to_screen) {
|
|
self::log('Parsing debug log');
|
|
echo self::logToScreen();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* System that redirects the errors to the appropriate logging method.
|
|
*
|
|
* @param int $type Error-type, Pre defined PHP Constant
|
|
* @param string error. The error itself
|
|
* @param string File. The absolute path of the file
|
|
* @param int Line. The line on which the error occured.
|
|
* @param array context. Some of the error's relevant variables
|
|
*/
|
|
public static function errorHandler($type = E_USER_NOTICE, $error = 'Undefined Error', $errFile = null, $errLine = null, $context = null)
|
|
{
|
|
// Check type
|
|
$thisType = self::getType($type);
|
|
$LOG = array('type' => (!is_null($thisType) ? $thisType : 'ERROR'),
|
|
'message' => (!is_null($error) ? $error : ''),
|
|
'logFile' => (!is_null($errFile) ? $errFile : ''),
|
|
'logLine' => (!is_null($errLine) ? $errLine : ''),
|
|
'context' => (!is_null($context) ? $context : ''),
|
|
'runtime' => round(self::getRelativeTime(), 4), );
|
|
self::$Logs[] = $LOG;
|
|
}
|
|
|
|
/**
|
|
* Exception handler
|
|
* Will be triggered when an uncaught exception occures. This function shows the error-message, and shuts down the script.
|
|
* Please note that most of the user-defined exceptions will be caught in the router, and handled with the error-controller.
|
|
*
|
|
* @param Exception $exception The occured exception.
|
|
*/
|
|
public static function exceptionHandler($exception)
|
|
{
|
|
$message = $exception->getMessage();
|
|
$code = $exception->getCode();
|
|
$file = $exception->getFile();
|
|
$line = $exception->getLine();
|
|
$context = $exception->getTraceAsString();
|
|
|
|
self::logError('Exception thrown: '.$message.' | '.$code, null, $file, $line);
|
|
}
|
|
|
|
/**
|
|
* Output the entire log to the screen. Used for debugging problems with your code.
|
|
*
|
|
* @return string Output of the log
|
|
*/
|
|
public static function logToScreen()
|
|
{
|
|
// Send a screenLogEvent, allows for new screen log designs
|
|
$event = Events::fireEvent('screenLogEvent');
|
|
if ($event->isCancelled()) {
|
|
return false;
|
|
}
|
|
|
|
// Otherwise just load it
|
|
$string = '<h3>FuzeWorks debug log</h3>';
|
|
$layer = 0;
|
|
for ($i = 0; $i < count(self::$Logs); ++$i) {
|
|
$log = self::$Logs[$i];
|
|
if ($log['type'] == 'LEVEL_START') {
|
|
++$layer;
|
|
$color = 255 - ($layer * 25);
|
|
$string .= '<div style="background: rgb(188 , 232 ,'.$color.');border: 1px black solid;margin: 5px 0;padding: 5px 20px;">';
|
|
$string .= '<div style="font-weight: bold; font-size: 11pt;">'.$log['message'].'<span style="float: right">'.(!empty($log['runtime']) ? '('.round($log['runtime'] * 1000, 4).'ms)' : '').'</span></div>';
|
|
} elseif ($log['type'] == 'LEVEL_STOP') {
|
|
--$layer;
|
|
$string .= '</div>';
|
|
} elseif ($log['type'] == 'ERROR') {
|
|
$string .= '<div style="'.($layer == 0 ? 'padding-left: 21px;' : '').'font-size: 11pt; background-color:#f56954;">['.$log['type'].']'.(!empty($log['context']) && is_string($log['context']) ? '<u>['.$log['context'].']</u>' : '').' '.$log['message'].'
|
|
<span style="float: right">'.(!empty($log['logFile']) ? $log['logFile'] : '').' : '.(!empty($log['logLine']) ? $log['logLine'] : '').'('.round($log['runtime'] * 1000, 4).' ms)</span></div>';
|
|
} elseif ($log['type'] == 'WARNING') {
|
|
$string .= '<div style="'.($layer == 0 ? 'padding-left: 21px;' : '').'font-size: 11pt; background-color:#f39c12;">['.$log['type'].']'.(!empty($log['context']) && is_string($log['context']) ? '<u>['.$log['context'].']</u>' : '').' '.$log['message'].'
|
|
<span style="float: right">'.(!empty($log['logFile']) ? $log['logFile'] : '').' : '.(!empty($log['logLine']) ? $log['logLine'] : '').'('.round($log['runtime'] * 1000, 4).' ms)</span></div>';
|
|
} elseif ($log['type'] == 'INFO') {
|
|
$string .= '<div style="'.($layer == 0 ? 'padding-left: 21px;' : '').'font-size: 11pt;">'.(!empty($log['context']) ? '<u>['.$log['context'].']</u>' : '').' '.$log['message'].'<span style="float: right">('.round($log['runtime'] * 1000, 4).' ms)</span></div>';
|
|
}
|
|
}
|
|
|
|
return $string;
|
|
}
|
|
|
|
/**
|
|
* Backtrace a problem to the source using the trace of an Exception.
|
|
*
|
|
* @return string HTML backtrace
|
|
*/
|
|
public static function backtrace()
|
|
{
|
|
$e = new Exception();
|
|
$trace = explode("\n", $e->getTraceAsString());
|
|
// reverse array to make steps line up chronologically
|
|
$trace = array_reverse($trace);
|
|
array_shift($trace); // remove {main}
|
|
array_pop($trace); // remove call to this method
|
|
$length = count($trace);
|
|
$result = array();
|
|
|
|
for ($i = 0; $i < $length; ++$i) {
|
|
$result[] = ($i + 1).')'.substr($trace[$i], strpos($trace[$i], ' ')); // replace '#someNum' with '$i)', set the right ordering
|
|
}
|
|
|
|
return "<b>BACKTRACE: <br/>\t".implode('<br/>', $result).'</b>';
|
|
}
|
|
|
|
/* =========================================LOGGING METHODS==============================================================*/
|
|
|
|
/**
|
|
* Create a information log entry.
|
|
*
|
|
* @param string $msg The information to be logged
|
|
* @param string $mod The name of the module
|
|
* @param string $file The file where the log occured
|
|
* @param int $line The line where the log occured
|
|
*/
|
|
public static function log($msg, $mod = null, $file = 0, $line = 0)
|
|
{
|
|
self::logInfo($msg, $mod, $file, $line);
|
|
}
|
|
|
|
/**
|
|
* Create a information log entry.
|
|
*
|
|
* @param string $msg The information to be logged
|
|
* @param string $mod The name of the module
|
|
* @param string $file The file where the log occured
|
|
* @param int $line The line where the log occured
|
|
*/
|
|
public static function logInfo($msg, $mod = null, $file = 0, $line = 0)
|
|
{
|
|
$LOG = array('type' => 'INFO',
|
|
'message' => (!is_null($msg) ? $msg : ''),
|
|
'logFile' => (!is_null($file) ? $file : ''),
|
|
'logLine' => (!is_null($line) ? $line : ''),
|
|
'context' => (!is_null($mod) ? $mod : ''),
|
|
'runtime' => round(self::getRelativeTime(), 4), );
|
|
|
|
self::$infoErrors[] = $LOG;
|
|
self::$Logs[] = $LOG;
|
|
}
|
|
|
|
/**
|
|
* Create a error log entry.
|
|
*
|
|
* @param string $msg The information to be logged
|
|
* @param string $mod The name of the module
|
|
* @param string $file The file where the log occured
|
|
* @param int $line The line where the log occured
|
|
*/
|
|
public static function logError($msg, $mod = null, $file = 0, $line = 0)
|
|
{
|
|
$LOG = array('type' => 'ERROR',
|
|
'message' => (!is_null($msg) ? $msg : ''),
|
|
'logFile' => (!is_null($file) ? $file : ''),
|
|
'logLine' => (!is_null($line) ? $line : ''),
|
|
'context' => (!is_null($mod) ? $mod : ''),
|
|
'runtime' => round(self::getRelativeTime(), 4), );
|
|
|
|
self::$criticalErrors[] = $LOG;
|
|
self::$Logs[] = $LOG;
|
|
}
|
|
|
|
/**
|
|
* Create a warning log entry.
|
|
*
|
|
* @param string $msg The information to be logged
|
|
* @param string $mod The name of the module
|
|
* @param string $file The file where the log occured
|
|
* @param int $line The line where the log occured
|
|
*/
|
|
public static function logWarning($msg, $mod = null, $file = 0, $line = 0)
|
|
{
|
|
$LOG = array('type' => 'WARNING',
|
|
'message' => (!is_null($msg) ? $msg : ''),
|
|
'logFile' => (!is_null($file) ? $file : ''),
|
|
'logLine' => (!is_null($line) ? $line : ''),
|
|
'context' => (!is_null($mod) ? $mod : ''),
|
|
'runtime' => round(self::getRelativeTime(), 4), );
|
|
|
|
self::$warningErrors[] = $LOG;
|
|
self::$Logs[] = $LOG;
|
|
}
|
|
|
|
/**
|
|
* Create a new Level log entry. Used to categorise logs.
|
|
*
|
|
* @param string $msg The name of the new level
|
|
* @param string $mod The name of the module
|
|
* @param string $file The file where the log occured
|
|
* @param int $line The line where the log occured
|
|
*/
|
|
public static function newLevel($msg, $mod = null, $file = null, $line = null)
|
|
{
|
|
$LOG = array('type' => 'LEVEL_START',
|
|
'message' => (!is_null($msg) ? $msg : ''),
|
|
'logFile' => (!is_null($file) ? $file : ''),
|
|
'logLine' => (!is_null($line) ? $line : ''),
|
|
'context' => (!is_null($mod) ? $mod : ''),
|
|
'runtime' => round(self::getRelativeTime(), 4), );
|
|
|
|
self::$Logs[] = $LOG;
|
|
}
|
|
|
|
/**
|
|
* Create a stop Level log entry. Used to close log categories.
|
|
*
|
|
* @param string $msg The name of the new level
|
|
* @param string $mod The name of the module
|
|
* @param string $file The file where the log occured
|
|
* @param int $line The line where the log occured
|
|
*/
|
|
public static function stopLevel($msg = null, $mod = null, $file = null, $line = null)
|
|
{
|
|
$LOG = array('type' => 'LEVEL_STOP',
|
|
'message' => (!is_null($msg) ? $msg : ''),
|
|
'logFile' => (!is_null($file) ? $file : ''),
|
|
'logLine' => (!is_null($line) ? $line : ''),
|
|
'context' => (!is_null($mod) ? $mod : ''),
|
|
'runtime' => round(self::getRelativeTime(), 4), );
|
|
|
|
self::$Logs[] = $LOG;
|
|
}
|
|
|
|
/* =========================================OTHER METHODS==============================================================*/
|
|
|
|
/**
|
|
* Returns a string representation of an error
|
|
* Turns a PHP error-constant (or integer) into a string representation.
|
|
*
|
|
* @param int $type PHP-constant errortype (e.g. E_NOTICE).
|
|
*
|
|
* @return string String representation
|
|
*/
|
|
public static function getType($type)
|
|
{
|
|
switch ($type) {
|
|
case E_ERROR:
|
|
return 'ERROR';
|
|
case E_WARNING:
|
|
return 'WARNING';
|
|
case E_PARSE:
|
|
return 'ERROR';
|
|
case E_NOTICE:
|
|
return 'WARNING';
|
|
case E_CORE_ERROR:
|
|
return 'ERROR';
|
|
case E_CORE_WARNING:
|
|
return 'WARNING';
|
|
case E_COMPILE_ERROR:
|
|
return 'ERROR';
|
|
case E_COMPILE_WARNING:
|
|
return 'WARNING';
|
|
case E_USER_ERROR:
|
|
return 'ERROR';
|
|
case E_USER_WARNING:
|
|
return 'WARNING';
|
|
case E_USER_NOTICE:
|
|
return 'WARNING';
|
|
case E_USER_DEPRECATED:
|
|
return 'WARNING';
|
|
case E_STRICT:
|
|
return 'ERROR';
|
|
case E_RECOVERABLE_ERROR:
|
|
return 'ERROR';
|
|
case E_DEPRECATED:
|
|
return 'WARNING';
|
|
}
|
|
|
|
return $type = 'Unknown error: '.$type;
|
|
}
|
|
|
|
/**
|
|
* Calls an HTTP error, sends it as a header, and loads a template if required to do so.
|
|
*
|
|
* @param int $errno HTTP error code
|
|
* @param bool $view true to view error on website
|
|
*/
|
|
public static function http_error($errno = 500, $view = true)
|
|
{
|
|
$http_codes = array(
|
|
|
|
400 => 'Bad Request',
|
|
401 => 'Unauthorized',
|
|
402 => 'Payment Required',
|
|
403 => 'Forbidden',
|
|
404 => 'Not Found',
|
|
405 => 'Method Not Allowed',
|
|
406 => 'Not Acceptable',
|
|
407 => 'Proxy Authentication Required',
|
|
408 => 'Request Timeout',
|
|
409 => 'Conflict',
|
|
410 => 'Gone',
|
|
411 => 'Length Required',
|
|
412 => 'Precondition Failed',
|
|
413 => 'Request Entity Too Large',
|
|
414 => 'Request-URI Too Long',
|
|
415 => 'Unsupported Media Type',
|
|
416 => 'Requested Range Not Satisfiable',
|
|
417 => 'Expectation Failed',
|
|
418 => 'I\'m a teapot',
|
|
426 => 'Upgrade Required',
|
|
428 => 'Precondition Required',
|
|
429 => 'Too Many Requests',
|
|
431 => 'Request Header Fields Too Large',
|
|
500 => 'Internal Server Error',
|
|
501 => 'Not Implemented',
|
|
502 => 'Bad Gateway',
|
|
503 => 'Service Unavailable',
|
|
504 => 'Gateway Timeout',
|
|
505 => 'HTTP Version Not Supported',
|
|
506 => 'Variant Also Negotiates',
|
|
509 => 'Bandwidth Limit Exceeded',
|
|
510 => 'Not Extended',
|
|
511 => 'Network Authentication Required',
|
|
);
|
|
|
|
self::logError('HTTP-error '.$errno.' called');
|
|
self::log('Sending header HTTP/1.1 '.$errno.' '.$http_codes[$errno]);
|
|
header('HTTP/1.1 '.$errno.' '.$http_codes[$errno]);
|
|
|
|
// Do we want the error-view with it?
|
|
if ($view == false) {
|
|
return;
|
|
}
|
|
|
|
// Load the view
|
|
$view = 'errors/'.$errno;
|
|
self::log('Loading view '.$view);
|
|
|
|
// Try and load the view, if impossible, load HTTP code instead.
|
|
try {
|
|
Layout::view($view);
|
|
} catch (LayoutException $exception) {
|
|
// No error page could be found, just echo the result
|
|
echo "<h1>$errno</h1><h3>".$http_codes[$errno].'</h3>';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enable error to screen logging.
|
|
*/
|
|
public static function enable()
|
|
{
|
|
self::$print_to_screen = true;
|
|
}
|
|
|
|
/**
|
|
* Disable error to screen logging.
|
|
*/
|
|
public static function disable()
|
|
{
|
|
self::$print_to_screen = false;
|
|
}
|
|
|
|
/**
|
|
* Get the relative time since the framework started.
|
|
*
|
|
* Used for debugging timings in FuzeWorks
|
|
*
|
|
* @return int Time passed since FuzeWorks init
|
|
*/
|
|
private static function getRelativeTime()
|
|
{
|
|
$startTime = STARTTIME;
|
|
$time = microtime(true) - $startTime;
|
|
|
|
return $time;
|
|
}
|
|
}
|