Completed
Push — rbac ( 1ec5d5...5c33ef )
by Simon
04:39
created

ExceptionHandler::getExceptionData()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 1
dl 0
loc 13
ccs 8
cts 8
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
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 1
    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 1
        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 1
<link href="{$siteConfiguration->getBaseUrl()}/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet">
38
<style>
39
  body {
40
    padding-top: 60px;
41
  }
42
</style>
43 1
<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 1
</div></body></html>
50 1
HTML;
51
52 1
        $errorData = self::getExceptionData($exception);
53 1
        $errorData['server'] = $_SERVER;
54 1
        $errorData['get'] = $_GET;
55 1
        $errorData['post'] = $_POST;
56
57 1
        $state = serialize($errorData);
58 1
        $errorId = sha1($state);
59
60
        // Save the error for later analysis
61 1
        file_put_contents($siteConfiguration->getErrorLog() . '/' . $errorId . '.log', $state);
62
63
        // clear and discard any content that's been saved to the output buffer
64 1
        if (ob_get_level() > 0) {
65 1
            ob_end_clean();
66 1
        }
67
68
        // push error ID into the document.
69 1
        $message = str_replace('$1$', $errorId, $errorDocument);
70
71 1
        if ($siteConfiguration->getDebuggingTraceEnabled()) {
72
            ob_start();
73
            var_dump($errorData);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($errorData); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
74
            $textErrorData = ob_get_contents();
75
            ob_end_clean();
76
77
            $message = str_replace('$2$', $textErrorData, $message);
78
        }
79
        else {
80 1
            $message = str_replace('$2$', "", $message);
81
        }
82
83
        // While we *shouldn't* have sent headers by now due to the output buffering, PHPUnit does weird things.
84
        // This is "only" needed for the tests, but it's a good idea to wrap this anyway.
85 1
        if (!headers_sent()) {
86
            header('HTTP/1.1 500 Internal Server Error');
87
        }
88
89
        // output the document
90 1
        print $message;
91 1
    }
92
93
    /**
94
     * @param int    $errorSeverity The severity level of the exception.
95
     * @param string $errorMessage  The Exception message to throw.
96
     * @param string $errorFile     The filename where the exception is thrown.
97
     * @param int    $errorLine     The line number where the exception is thrown.
98
     *
99
     * @throws ErrorException
100
     */
101 1
    public static function errorHandler($errorSeverity, $errorMessage, $errorFile, $errorLine)
102
    {
103
        // call into the main exception handler above
104 1
        throw new ErrorException($errorMessage, 0, $errorSeverity, $errorFile, $errorLine);
105
    }
106
107
    /**
108
     * @param Exception $exception
109
     *
110
     * @return null|array
111
     */
112 1
    private static function getExceptionData($exception)
113
    {
114 1
        if ($exception == null) {
115 1
            return null;
116
        }
117
118
        return array(
119 1
            'exception' => get_class($exception),
120 1
            'message'   => $exception->getMessage(),
121 1
            'stack'     => $exception->getTraceAsString(),
122 1
            'previous'  => self::getExceptionData($exception->getPrevious()),
123 1
        );
124
    }
125
}