TrackManiaControl/application/core/ErrorHandler.php

283 lines
7.9 KiB
PHP
Raw Normal View History

2014-01-27 20:28:37 +01:00
<?php
2014-02-10 22:04:09 +01:00
namespace ManiaControl;
2014-02-08 19:33:26 +01:00
use ManiaControl\Files\FileUtil;
2014-02-10 22:54:49 +01:00
use ManiaControl\Update\UpdateManager;
2014-01-27 20:28:37 +01:00
/**
* Error and Exception Manager Class
2014-05-02 17:40:47 +02:00
*
* @author ManiaControl Team <mail@maniacontrol.com>
* @copyright 2014 ManiaControl Team
* @license http://www.gnu.org/licenses/ GNU General Public License, Version 3
2014-01-27 20:28:37 +01:00
*/
class ErrorHandler {
/*
2014-02-17 12:54:31 +01:00
* Constants
*/
const MC_DEBUG_NOTICE = 'ManiaControl.DebugNotice';
const SETTING_RESTART_ON_EXCEPTION = 'Automatically restart on Exceptions';
2014-05-02 17:40:47 +02:00
/*
2014-01-27 21:56:49 +01:00
* Private Properties
*/
private $maniaControl = null;
private $reportErrors = true;
2014-01-27 21:56:49 +01:00
2014-01-27 20:28:37 +01:00
/**
* Construct Error Handler
*/
2014-01-27 21:56:49 +01:00
public function __construct(ManiaControl $maniaControl) {
$this->maniaControl = $maniaControl;
2014-05-03 22:21:57 +02:00
set_error_handler(array(&$this, 'handleError'), -1);
set_exception_handler(array(&$this, 'handleException'));
2014-01-27 20:28:37 +01:00
}
/**
* Initialize other Error Handler Features
*/
public function init() {
$this->maniaControl->settingManager->initSetting($this, self::SETTING_RESTART_ON_EXCEPTION, true);
}
2014-01-27 20:28:37 +01:00
/**
* ManiaControl Exception Handler
2014-05-02 17:40:47 +02:00
*
2014-02-10 22:54:49 +01:00
* @param \Exception $ex
2014-05-02 17:40:47 +02:00
* @param bool $shutdown
2014-01-27 20:28:37 +01:00
*/
2014-05-03 22:21:57 +02:00
public function handleException(\Exception $ex, $shutdown = true) {
$message = "[ManiaControl EXCEPTION]: {$ex->getMessage()}";
$exceptionClass = get_class($ex);
$traceString = $ex->getTraceAsString();
$logMessage = $message . PHP_EOL . 'Class: ' . $exceptionClass . PHP_EOL . 'Trace:' . PHP_EOL . $traceString;
logMessage($logMessage);
2014-05-02 17:40:47 +02:00
if ($this->reportErrors) {
2014-05-02 17:40:47 +02:00
$error = array();
$error['Type'] = 'Exception';
$error['Message'] = $message;
$error['Class'] = $exceptionClass;
2014-05-06 02:29:48 +02:00
$error['FileLine'] = $ex->getFile() . ': ' . $ex->getLine();
$error['Backtrace'] = $traceString;
$error['OperatingSystem'] = php_uname();
2014-05-02 17:40:47 +02:00
$error['PHPVersion'] = phpversion();
if ($this->maniaControl->server) {
$error['ServerLogin'] = $this->maniaControl->server->login;
}
2014-05-02 17:40:47 +02:00
if ($this->maniaControl->settingManager && $this->maniaControl->updateManager) {
2014-05-02 17:40:47 +02:00
$error['UpdateChannel'] = $this->maniaControl->settingManager->getSetting($this->maniaControl->updateManager, UpdateManager::SETTING_UPDATECHECK_CHANNEL);
2014-05-06 02:17:24 +02:00
$error['ManiaControlVersion'] = ManiaControl::VERSION . ' #' . $this->maniaControl->updateManager->getNightlyBuildDate();
2014-05-02 17:40:47 +02:00
} else {
$error['ManiaControlVersion'] = ManiaControl::VERSION;
}
2014-05-02 17:40:47 +02:00
$json = json_encode($error);
$info = base64_encode($json);
2014-05-02 17:40:47 +02:00
$url = ManiaControl::URL_WEBSERVICE . 'errorreport?error=' . urlencode($info);
$success = FileUtil::loadFile($url);
2014-05-02 17:40:47 +02:00
if (!json_decode($success)) {
logMessage('Exception-Report failed!');
2014-05-02 17:40:47 +02:00
} else {
logMessage('Exception successfully reported!');
}
2014-02-08 19:33:26 +01:00
}
2014-05-02 17:40:47 +02:00
if ($shutdown) {
if ($this->shouldRestart()) {
$this->maniaControl->restart();
}
exit();
}
2014-01-27 20:28:37 +01:00
}
2014-05-02 17:40:47 +02:00
/**
* Test if ManiaControl should restart automatically
*
* @return bool
*/
private function shouldRestart() {
if (!$this->maniaControl || !$this->maniaControl->settingManager) {
return false;
}
$setting = $this->maniaControl->settingManager->getSetting($this, self::SETTING_RESTART_ON_EXCEPTION, true);
return $setting;
}
/**
2014-05-03 22:26:49 +02:00
* Trigger a Debug Notice to the ManiaControl Website
2014-05-02 17:40:47 +02:00
*
2014-05-03 22:26:49 +02:00
* @param string $message
2014-05-02 17:40:47 +02:00
*/
public function triggerDebugNotice($message) {
2014-05-03 22:21:57 +02:00
$this->handleError(self::MC_DEBUG_NOTICE, $message);
2014-05-02 17:40:47 +02:00
}
2014-01-27 20:28:37 +01:00
/**
* ManiaControl Error Handler
2014-05-02 17:40:47 +02:00
*
2014-05-03 22:26:49 +02:00
* @param int $errorNumber
2014-05-03 22:21:57 +02:00
* @param string $errorString
* @param string $errorFile
2014-05-03 22:26:49 +02:00
* @param int $errorLine
2014-01-27 20:28:37 +01:00
* @return bool
*/
2014-05-03 22:21:57 +02:00
public function handleError($errorNumber, $errorString, $errorFile = null, $errorLine = -1) {
2014-05-06 02:29:48 +02:00
$userError = $this->isUserErrorNumber($errorNumber);
if (!$userError && error_reporting() === 0) {
return;
}
$errorTag = $this->getErrorTag($errorNumber);
$message = $errorTag . ': ' . $errorString;
$fileLine = $errorFile . ': ' . $errorLine;
$traceString = $this->parseBackTrace(debug_backtrace());
$logMessage = $message . PHP_EOL . 'File&Line: ' . $fileLine . PHP_EOL . 'Trace: ' . $traceString;
2014-05-02 05:12:47 +02:00
logMessage($logMessage);
2014-05-02 17:40:47 +02:00
if ($this->reportErrors && !$userError) {
2014-05-02 17:40:47 +02:00
$error = array();
$error['Type'] = 'Error';
$error['Message'] = $message;
$error['FileLine'] = $fileLine;
$error['Backtrace'] = $traceString;
2014-02-15 18:26:31 +01:00
$error['OperatingSystem'] = php_uname();
2014-05-02 17:40:47 +02:00
$error['PHPVersion'] = phpversion();
2014-02-15 19:19:03 +01:00
if ($this->maniaControl->server) {
2014-02-10 15:26:08 +01:00
$error['ServerLogin'] = $this->maniaControl->server->login;
2014-05-02 17:40:47 +02:00
} else {
2014-02-15 19:19:03 +01:00
$error['ServerLogin'] = '';
2014-02-10 15:26:08 +01:00
}
2014-05-02 17:40:47 +02:00
2014-02-15 19:19:03 +01:00
if ($this->maniaControl->settingManager && $this->maniaControl->updateManager) {
2014-05-02 17:40:47 +02:00
$error['UpdateChannel'] = $this->maniaControl->settingManager->getSetting($this->maniaControl->updateManager, UpdateManager::SETTING_UPDATECHECK_CHANNEL);
2014-05-02 05:12:47 +02:00
$error['ManiaControlVersion'] = ManiaControl::VERSION . '#' . $this->maniaControl->updateManager->getNightlyBuildDate();
2014-05-02 17:40:47 +02:00
} else {
$error['UpdateChannel'] = '';
2014-02-15 18:26:31 +01:00
$error['ManiaControlVersion'] = ManiaControl::VERSION;
}
2014-05-02 17:40:47 +02:00
2014-02-08 19:33:26 +01:00
$json = json_encode($error);
$info = base64_encode($json);
2014-05-02 17:40:47 +02:00
$url = ManiaControl::URL_WEBSERVICE . 'errorreport?error=' . urlencode($info);
2014-02-08 19:33:26 +01:00
$success = FileUtil::loadFile($url);
2014-05-02 17:40:47 +02:00
2014-02-08 19:33:26 +01:00
if (!json_decode($success)) {
logMessage('Error-Report failed!');
2014-05-02 17:40:47 +02:00
} else {
logMessage('Error successfully reported!');
2014-02-08 19:33:26 +01:00
}
2014-02-10 23:03:25 +01:00
}
2014-05-02 05:12:47 +02:00
if ($this->shouldStopExecution($errorNumber)) {
2014-01-27 20:28:37 +01:00
logMessage('Stopping execution...');
exit();
}
return false;
}
/**
2014-05-02 05:12:47 +02:00
* Get the Prefix for the given Error Level
2014-05-02 17:40:47 +02:00
*
2014-01-27 20:28:37 +01:00
* @param int $errorLevel
* @return string
*/
public function getErrorTag($errorLevel) {
2014-05-02 18:21:38 +02:00
switch ($errorLevel) {
case E_NOTICE:
return '[PHP NOTICE]';
case E_WARNING:
return '[PHP WARNING]';
case E_ERROR:
return '[PHP ERROR]';
case E_CORE_ERROR:
return '[PHP CORE ERROR]';
case E_COMPILE_ERROR:
return '[PHP COMPILE ERROR]';
case E_RECOVERABLE_ERROR:
return '[PHP RECOVERABLE ERROR]';
case E_USER_NOTICE:
return '[ManiaControl NOTICE]';
case E_USER_WARNING:
return '[ManiaControl WARNING]';
case E_USER_ERROR:
return '[ManiaControl ERROR]';
case self::MC_DEBUG_NOTICE:
return '[ManiaControl DEBUG]';
}
return "[PHP ERROR '{$errorLevel}']";
2014-01-27 20:28:37 +01:00
}
/**
* Parse the Debug Backtrace into a String for the Error Report
*
* @return string
*/
private function parseBackTrace(array $backtrace) {
$traceString = '';
2014-05-02 17:40:47 +02:00
$stepCount = 0;
foreach ($backtrace as $traceStep) {
$traceString .= PHP_EOL . '#' . $stepCount . ': ';
if (isset($traceStep['class'])) {
$traceString .= $traceStep['class'];
}
if (isset($traceStep['type'])) {
$traceString .= $traceStep['type'];
}
if (isset($traceStep['function'])) {
$traceString .= $traceStep['function'];
}
if (isset($traceStep['file'])) {
$traceString .= ' in File ';
$traceString .= $traceStep['file'];
}
if (isset($traceStep['line'])) {
$traceString .= ' on Line ';
$traceString .= $traceStep['line'];
}
$stepCount++;
}
return $traceString;
}
2014-05-02 17:40:47 +02:00
/**
* Check if the given Error Number is a User Error
*
* @param int $errorNumber
* @return bool
*/
private function isUserErrorNumber($errorNumber) {
return ($errorNumber === E_USER_ERROR || $errorNumber === E_USER_WARNING || $errorNumber === E_USER_NOTICE || $errorNumber === E_USER_DEPRECATED);
}
2014-05-02 17:40:47 +02:00
/**
* Test if ManiaControl should stop its Execution
*
* @param int $errorNumber
* @return bool
*/
private function shouldStopExecution($errorNumber) {
return ($errorNumber === E_ERROR || $errorNumber === E_USER_ERROR || $errorNumber === E_FATAL);
}
2014-05-03 22:26:49 +02:00
/**
* Check if the Shutdown was caused by a Fatal Error and report it
*/
public function handleShutdown() {
$error = error_get_last();
if ($error && ($error['type'] & E_FATAL)) {
$this->handleError($error['type'], $error['message'], $error['file'], $error['line']);
}
}
2014-01-27 20:28:37 +01:00
}