Completed
Push — master ( e15c58...b150a8 )
by Changwan
07:08
created

DefaultHttpErrorHandler::handle()   C

Complexity

Conditions 8
Paths 15

Size

Total Lines 37
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 9.728

Importance

Changes 0
Metric Value
cc 8
eloc 26
nc 15
nop 2
dl 0
loc 37
ccs 21
cts 30
cp 0.7
crap 9.728
rs 5.3846
c 0
b 0
f 0
1
<?php
2
namespace Wandu\Foundation\Error;
3
4
use Psr\Http\Message\ServerRequestInterface;
5
use Psr\Log\LoggerInterface;
6
use Wandu\Config\Contracts\ConfigInterface;
7
use Wandu\Foundation\Contracts\HttpErrorHandlerInterface;
8
use Wandu\Http\Exception\HttpException;
9
use Wandu\Router\Exception\MethodNotAllowedException as RouteMethodException;
10
use Wandu\Router\Exception\RouteNotFoundException;
11
use Whoops\Handler\JsonResponseHandler;
12
use Whoops\Handler\PlainTextHandler;
13
use Whoops\Handler\PrettyPageHandler;
14
use Whoops\Run;
15
use function Wandu\Http\Response\create;
16
use function Wandu\Http\Response\json;
17
18
class DefaultHttpErrorHandler implements HttpErrorHandlerInterface
19
{
20
    /** @var \Psr\Log\LoggerInterface */
21
    protected $logger;
22
    
23
    /** @var \Wandu\Config\Contracts\ConfigInterface */
24
    protected $config;
25
    
26
    /**
27
     * @param \Wandu\Config\Contracts\ConfigInterface $config
28
     * @param \Psr\Log\LoggerInterface $logger
29
     */
30 4
    public function __construct(ConfigInterface $config, LoggerInterface $logger = null)
31
    {
32 4
        $this->config = $config;
33 4
        $this->logger = $logger;
34 4
    }
35
36
    /**
37
     * {@inheritdoc}
38
     */
39 4
    public function handle(ServerRequestInterface $request, $exception)
40 1
    {
41 4
        if ($exception instanceof HttpException) {
42 2
            if ($this->logger) {
43 2
                $this->logger->notice($this->prettifyRequest($request));
44 2
                $this->logger->notice($exception);
45 2
            }
46 2
            return $exception;
47
        }
48 2
        if ($this->config->get('debug', true)) {
49 1
            $whoops = $this->getWhoops($request);
50 1
            return create($whoops->handleException($exception), 500);
0 ignored issues
show
Bug introduced by
It seems like $exception defined by parameter $exception on line 39 can also be of type object<Exception>; however, Whoops\Run::handleException() does only seem to accept object<Throwable>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Security Bug introduced by
It seems like $whoops->handleException($exception) targeting Whoops\Run::handleException() can also be of type false; however, Wandu\Http\Response\create() does only seem to accept string|null, did you maybe forget to handle an error condition?
Loading history...
51
        }
52
53 1
        $statusCode = 500;
54 1
        $reasonPhrase = 'Internal Server Error';
55
56 1
        if ($exception instanceof RouteNotFoundException) {
57
            $statusCode = 404;
58
            $reasonPhrase = "Not Found";
59 1
        } elseif ($exception instanceof RouteMethodException) {
60
            $statusCode = 405;
61
            $reasonPhrase = 'Method Not Allowed';
62
        }
63 1
        if ($this->logger) {
64 1
            $this->logger->error($this->prettifyRequest($request));
65 1
            $this->logger->error($exception);
0 ignored issues
show
Bug introduced by
It seems like $exception defined by parameter $exception on line 39 can also be of type object<Exception>; however, Psr\Log\LoggerInterface::error() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
66 1
        }
67
68 1
        if ($this->isAjax($request)) {
69
            return json([
70
                'status' => $statusCode,
71
                'reason' => $reasonPhrase,
72
            ], $statusCode);
73
        }
74 1
        return create("{$statusCode} {$reasonPhrase}", $statusCode);
75
    }
76
77
    /**
78
     * @param \Psr\Http\Message\ServerRequestInterface $request
79
     * @return bool
80
     */
81 1
    protected function isAjax(ServerRequestInterface $request)
82
    {
83 1
        return $request->hasHeader('x-requested-with') &&
84 1
            $request->getHeaderLine('x-requested-with') === 'XMLHttpRequest';
85
    }
86
87
    /**
88
     * @param \Psr\Http\Message\ServerRequestInterface $request
89
     * @return string
90
     */
91 3
    protected function prettifyRequest(ServerRequestInterface $request)
92
    {
93 3
        $contents = "{$request->getMethod()} : {$request->getUri()->__toString()}\n";
94 3
        $contents .= "HEADERS\n";
95 3
        foreach ($request->getHeaders() as $name => $value) {
96
            $contents .= "    {$name} : {$request->getHeaderLine($name)}\n";
97 3
        }
98 3
        if ($body = $request->getBody()) {
99
            $contents .= "BODY\n";
100
            $contents .= "\"{$body->__toString()}\"\n";
101
        }
102 3
        return $contents;
103
    }
104
    
105 1
    protected function getWhoops(ServerRequestInterface $request)
106
    {
107 1
        $whoops = new Run();
108
109 1
        switch ($this->getAcceptType($request)) {
110 1
            case 'html':
111
                $whoops->pushHandler(new PrettyPageHandler());
0 ignored issues
show
Documentation introduced by
new \Whoops\Handler\PrettyPageHandler() is of type object<Whoops\Handler\PrettyPageHandler>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
112
                break;
113 1
            case 'json':
114
                $whoops->pushHandler(new JsonResponseHandler());
0 ignored issues
show
Documentation introduced by
new \Whoops\Handler\JsonResponseHandler() is of type object<Whoops\Handler\JsonResponseHandler>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
115
                break;
116 1
            default:
117 1
                $whoops->pushHandler(new PlainTextHandler());
0 ignored issues
show
Documentation introduced by
new \Whoops\Handler\PlainTextHandler() is of type object<Whoops\Handler\PlainTextHandler>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
118 1
        }
119
120 1
        $whoops->allowQuit(false);
121 1
        $whoops->writeToOutput(false);
122 1
        $whoops->sendHttpCode(false);
123
124 1
        return $whoops;
125
    }
126
127
    /**
128
     * @ref github.com/oscarotero/psr7-middlewares/blob/master/src/Middleware/FormatNegotiator.php
129
     *
130
     * @param \Psr\Http\Message\ServerRequestInterface $request
131
     * @return string
132
     */
133 1
    protected function getAcceptType(ServerRequestInterface $request)
134
    {
135 1
        $accept = $request->getHeaderLine('Accept');
136
        if (
137 1
            strpos($accept, 'text/html') !== false ||
138 1
            strpos($accept, 'application/xhtml+xml') !== false
139 1
        ) {
140
            return 'html';
141
        }
142
        if (
143 1
            strpos($accept, 'application/json') !== false ||
144 1
            strpos($accept, 'text/json') !== false ||
145 1
            strpos($accept, 'application/x-json') !== false
146 1
        ) {
147
            return 'json';
148
        }
149 1
        return 'text';
150
    }
151
}
152