Completed
Branch newinternal (4dede1)
by Simon
03:45
created

ExceptionHandler   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 108
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 0

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 6
c 1
b 0
f 0
lcom 0
cbo 0
dl 0
loc 108
ccs 0
cts 63
cp 0
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A exceptionHandler() 0 62 3
A errorHandler() 0 5 1
A getExceptionData() 0 13 2
1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 *                                                                            *
5
 * All code in this file is released into the public domain by the ACC        *
6
 * Development Team. Please see team.json for a list of contributors.         *
7
 ******************************************************************************/
8
9
namespace Waca;
10
11
use ErrorException;
12
use Exception;
13
14
class ExceptionHandler
15
{
16
	/**
17
	 * Global exception handler
18
	 *
19
	 * Smarty would be nice to use, but it COULD BE smarty that throws the errors.
20
	 * Let's build something ourselves, and hope it works.
21
	 *
22
	 * @param $exception
23
	 *
24
	 * @category Security-Critical - has the potential to leak data when exception is thrown.
25
	 */
26
	public static function exceptionHandler(Exception $exception)
0 ignored issues
show
Coding Style introduced by
exceptionHandler uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
exceptionHandler uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
exceptionHandler uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
27
	{
28
		/** @global $siteConfiguration SiteConfiguration */
29
		global $siteConfiguration;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
30
31
		$errorDocument = <<<HTML
32
<!DOCTYPE html>
33
<html lang="en"><head>
34
<meta charset="utf-8">
35
<title>Oops! Something went wrong!</title>
36
<meta name="viewport" content="width=device-width, initial-scale=1.0">
37
<link href="{$siteConfiguration->getBaseUrl()}/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet">
38
<style>
39
  body {
40
    padding-top: 60px;
41
  }
42
</style>
43
<link href="{$siteConfiguration->getBaseUrl()}/lib/bootstrap/css/bootstrap-responsive.min.css" rel="stylesheet">
44
</head><body><div class="container">
45
<h1>Oops! Something went wrong!</h1>
46
<p>We'll work on fixing this for you, so why not come back later?</p>
47
<p class="muted">If our trained monkeys ask, tell them this error ID: <code>$1$</code></p>
48
$2$
49
</div></body></html>
50
HTML;
51
52
		$errorData = self::getExceptionData($exception);
53
		$errorData['server'] = $_SERVER;
54
		$errorData['get'] = $_GET;
55
		$errorData['post'] = $_POST;
56
57
		$state = serialize($errorData);
58
		$errorId = sha1($state);
59
60
		// Save the error for later analysis
61
		file_put_contents($siteConfiguration->getErrorLog() . '/' . $errorId . '.log', $state);
62
63
		// clear and discard any content that's been saved to the output buffer
64
		if (ob_get_level() > 0) {
65
			ob_end_clean();
66
		}
67
68
		// push error ID into the document.
69
		$message = str_replace('$1$', $errorId, $errorDocument);
70
71
		if ($siteConfiguration->getDebuggingTraceEnabled()) {
72
			ob_start();
73
			var_dump($errorData);
74
			$textErrorData = ob_get_contents();
75
			ob_end_clean();
76
77
			$message = str_replace('$2$', $textErrorData, $message);
78
		}
79
		else {
80
			$message = str_replace('$2$', "", $message);
81
		}
82
83
		header('HTTP/1.1 500 Internal Server Error');
84
85
		// output the document
86
		print $message;
87
	}
88
89
	/**
90
	 * @param int    $errorSeverity The severity level of the exception.
91
	 * @param string $errorMessage  The Exception message to throw.
92
	 * @param string $errorFile     The filename where the exception is thrown.
93
	 * @param int    $errorLine     The line number where the exception is thrown.
94
	 *
95
	 * @throws ErrorException
96
	 */
97
	public static function errorHandler($errorSeverity, $errorMessage, $errorFile, $errorLine)
98
	{
99
		// call into the main exception handler above
100
		throw new ErrorException($errorMessage, 0, $errorSeverity, $errorFile, $errorLine);
101
	}
102
103
	/**
104
	 * @param Exception $exception
105
	 *
106
	 * @return null|array
107
	 */
108
	private static function getExceptionData($exception)
109
	{
110
		if ($exception == null) {
111
			return null;
112
		}
113
114
		return array(
115
			'exception' => get_class($exception),
116
			'message'   => $exception->getMessage(),
117
			'stack'     => $exception->getTraceAsString(),
118
			'previous'  => self::getExceptionData($exception->getPrevious()),
119
		);
120
	}
121
}