Completed
Branch 09branch (946dde)
by Anton
05:16
created

ExceptionWrapper::findIp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Spiral\Http\Middlewares;
10
11
use Psr\Http\Message\ResponseInterface as Response;
12
use Psr\Http\Message\ServerRequestInterface;
13
use Psr\Http\Message\ServerRequestInterface as Request;
14
use Psr\Log\LoggerAwareInterface;
15
use Spiral\Core\Component;
16
use Spiral\Core\ContainerInterface;
17
use Spiral\Debug\Traits\LoggerTrait;
18
use Spiral\Http\Configs\HttpConfig;
19
use Spiral\Http\ErrorWriter;
20
use Spiral\Http\Exceptions\ClientException;
21
use Spiral\Http\MiddlewareInterface;
22
23
/**
24
 * Isolates ClientException(s) into response.
25
 *
26
 * Attention, middleware requests ViewsInterface on demand!
27
 */
28
class ExceptionWrapper extends Component implements MiddlewareInterface, LoggerAwareInterface
29
{
30
    use LoggerTrait;
31
32
    /**
33
     * Format to be used for log messages in cases where http error caused by client request.
34
     */
35
    const LOG_FORMAT = "{scheme}://{host}{path} caused the error {code} ({message}) by client {remote}.";
36
37
    /**
38
     * Contain list of error pages.
39
     *
40
     * @var HttpConfig
41
     */
42
    protected $httpConfig = null;
43
44
    /**
45
     * Required to get ErrorWriter on demand and fetch proper logger.
46
     *
47
     * @invisible
48
     * @var ContainerInterface
49
     */
50
    protected $container = null;
51
52
    /**
53
     * @param HttpConfig         $httpConfig
54
     * @param ContainerInterface $container
55
     */
56
    public function __construct(HttpConfig $httpConfig, ContainerInterface $container)
57
    {
58
        $this->httpConfig = $httpConfig;
59
        $this->container = $container;
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65
    public function __invoke(Request $request, Response $response, callable $next)
66
    {
67
        try {
68
            //Debug: ClientExceptions are isolated in this middleware.
69
            return $next($request, $response);
70
        } catch (ClientException $exception) {
71
            //Logging client error
72
            $this->logError($request, $exception);
73
74
            //Writing nice error into response
75
            return $this->errorWriter()->writeException($request, $response, $exception);
76
        }
77
    }
78
79
    /**
80
     * Add error to error log.
81
     *
82
     * @param Request         $request
83
     * @param ClientException $exception
84
     */
85
    private function logError(Request $request, ClientException $exception)
86
    {
87
        $this->logger()->error(\Spiral\interpolate(static::LOG_FORMAT, [
88
            'scheme'  => $request->getUri()->getScheme(),
89
            'host'    => $request->getUri()->getHost(),
90
            'path'    => $request->getUri()->getPath(),
91
            'code'    => $exception->getCode(),
92
            'message' => $exception->getMessage() ?: '-not specified-',
93
            'remote'  => $this->findIp($request)
94
        ]));
95
    }
96
97
    /**
98
     * Instance of ErrorWriter.
99
     *
100
     * @return ErrorWriter
101
     */
102
    protected function errorWriter(): ErrorWriter
103
    {
104
        return $this->container->get(ErrorWriter::class);
105
    }
106
107
    /**
108
     * Try to locate client ip. To be used for debug purposes only!
109
     *
110
     * @param \Psr\Http\Message\ServerRequestInterface $request
111
     *
112
     * @return string
113
     */
114
    private function findIp(ServerRequestInterface $request): string
115
    {
116
        return $request->getServerParams()['REMOTE_ADDR'] ?? '127.0.0.1';
117
    }
118
}
119