Completed
Push — master ( 00ed35...63fbb3 )
by Oscar
10:20
created

AccessLog::logger()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4286
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace Psr7Middlewares\Middleware;
4
5
use Psr7Middlewares\Middleware;
6
use Psr\Http\Message\ServerRequestInterface;
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Log\LoggerInterface;
9
use RuntimeException;
10
11
class AccessLog
12
{
13
    /**
14
     * @var LoggerInterface The router container
15
     */
16
    private $logger;
17
18
    /**
19
     * @var bool
20
     */
21
    private $combined = false;
22
23
    /**
24
     * Set the LoggerInterface instance.
25
     *
26
     * @param LoggerInterface $logger
27
     */
28
    public function __construct(LoggerInterface $logger)
29
    {
30
        $this->logger = $logger;
31
    }
32
33
    /**
34
     * Whether use the combined log format instead the common log format.
35
     *
36
     * @param bool $combined
37
     *
38
     * @return self
39
     */
40
    public function combined($combined = true)
41
    {
42
        $this->combined = $combined;
43
44
        return $this;
45
    }
46
47
    /**
48
     * Execute the middleware.
49
     *
50
     * @param ServerRequestInterface $request
51
     * @param ResponseInterface      $response
52
     * @param callable               $next
53
     *
54
     * @return ResponseInterface
55
     */
56
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
57
    {
58
        if (!Middleware::hasAttribute($request, ClientIp::KEY)) {
59
            throw new RuntimeException('AccessLog middleware needs ClientIp executed before');
60
        }
61
62
        $message = $this->combined ? self::combinedFormat($request, $response) : self::commonFormat($request, $response);
63
64
        if ($response->getStatusCode() >= 400 && $response->getStatusCode() < 600) {
65
            $this->logger->error($message);
66
        } else {
67
            $this->logger->info($message);
68
        }
69
70
        return $next($request, $response);
71
    }
72
73
    /**
74
     * Generates a message using the Apache's Common Log format
75
     * https://httpd.apache.org/docs/2.4/logs.html#accesslog.
76
     * 
77
     * Note: The user identifier (identd) is ommited intentionally
78
     * 
79
     * @param ServerRequestInterface $request
80
     * @param ResponseInterface      $response
81
     * 
82
     * @return string
83
     */
84
    private static function commonFormat(ServerRequestInterface $request, ResponseInterface $response)
85
    {
86
        return sprintf('%s %s [%s] "%s %s %s/%s" %d %d',
87
            ClientIp::getIp($request),
88
            $request->getUri()->getUserInfo() ?: '-',
89
            strftime('%d/%b/%Y:%H:%M:%S %z'),
90
            strtoupper($request->getMethod()),
91
            $request->getUri()->getPath(),
92
            strtoupper($request->getUri()->getScheme()),
93
            $request->getProtocolVersion(),
94
            $response->getStatusCode(),
95
            $response->getBody()->getSize()
96
        );
97
    }
98
99
    /**
100
     * Generates a message using the Apache's Combined Log format
101
     * This is exactly the same than Common Log, with the addition of two more fields: Referer and User-Agent headers.
102
     * 
103
     * @param ServerRequestInterface $request
104
     * @param ResponseInterface      $response
105
     * 
106
     * @return string
107
     */
108
    private static function combinedFormat(ServerRequestInterface $request, ResponseInterface $response)
109
    {
110
        return sprintf('%s "%s" "%s"',
111
            self::commonFormat($request, $response),
112
            $request->getHeaderLine('Referer'),
113
            $request->getHeaderLine('User-Agent')
114
        );
115
    }
116
}
117