RequestDumpListener::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1.125

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
ccs 2
cts 4
cp 0.5
crap 1.125
1
<?php
2
3
namespace Eccube\EventListener;
4
5
use Eccube\Application;
6
use Monolog\Logger;
7
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
8
use Symfony\Component\HttpFoundation\Request;
9
use Symfony\Component\HttpFoundation\Response;
10
use Symfony\Component\HttpFoundation\Session\SessionInterface;
11
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
12
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
13
use Symfony\Component\HttpKernel\KernelEvents;
14
15
/**
16
 * リクエストログ出力ため Listener
17
 *
18
 * ログ出力を除外したいキーは log.yml の exclude_keys で設定します.
19
 * addExcludeKey(), removeExcludeKey() でも設定できます.
20
 *
21
 * @author Kentaro Ohkouchi
22
 */
23
class RequestDumpListener implements EventSubscriberInterface
24
{
25
    private $app;
26
    private $excludeKeys;
27
28
    /**
29
     * Constructor function.
30
     *
31
     * @param Application $app
32
     */
33 629
    public function __construct(Application $app)
34
    {
35 629
        $this->app = $app;
36
        $this->excludeKeys = $app['config']['log']['exclude_keys'];
37
    }
38
39
    /**
40
     * Kernel request listener callback.
41
     *
42
     * @param GetResponseEvent $event
43
     */
44 58
    public function onKernelRequest(GetResponseEvent $event)
45
    {
46 58
        if (!$event->isMasterRequest()) {
47
            return;
48
        }
49
        $log = '** before *****************************************:'.PHP_EOL;
50
        $request = $event->getRequest();
51
        $log .= $this->logRequest($request);
52
        $Session = $request->getSession();
53
        if ($request->hasSession()) {
54
            $log .= $this->logSession($Session);
0 ignored issues
show
Bug introduced by
It seems like $Session defined by $request->getSession() on line 52 can be null; however, Eccube\EventListener\Req...pListener::logSession() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
55
        }
56
        $this->app->log($log, array(), Logger::DEBUG);
57
        log_debug($log);
58
    }
59
60
    /**
61 58
     * Kernel response listener callback.
62
     *
63 58
     * @param FilterResponseEvent $event
64
     */
65
    public function onResponse(FilterResponseEvent $event)
66
    {
67
        if (!$event->isMasterRequest()) {
68
            return;
69
        }
70
        $log = '** after *****************************************:'.PHP_EOL;
71
        $response = $event->getResponse();
72
        $log .= $this->logResponse($response);
73
        $request = $event->getRequest();
74
        $log .= $this->logRequest($request);
75
        $Session = $request->getSession();
76
        if ($request->hasSession()) {
77
            $log .= $this->logSession($Session);
0 ignored issues
show
Bug introduced by
It seems like $Session defined by $request->getSession() on line 75 can be null; however, Eccube\EventListener\Req...pListener::logSession() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
78
        }
79
        $this->app->log($log, array(), Logger::DEBUG);
80 629
        log_debug($log);
81
    }
82
83 629
    /**
84 629
     * Return the events to subscribe to.
85
     *
86
     * @return array
87
     */
88
    public static function getSubscribedEvents()
89
    {
90
        return array(
91
            KernelEvents::REQUEST => 'onKernelRequest',
92
            KernelEvents::RESPONSE => 'onResponse',
93
        );
94
    }
95
96
    /**
97
     * ログ出力を除外するキーを追加します.
98
     *
99
     * @param string $key 除外対象のキー
100
     */
101
    protected function addExcludeKey($key)
102
    {
103
        $this->excludeKeys[] = $key;
104
    }
105
106
    /**
107
     * ログ出力を除外するキーを削除します.
108
     *
109
     * @param string $key 削除対象のキー
110
     */
111
    protected function removeExcludeKey($key)
112
    {
113
        if (array_key_exists($key, $this->excludeKeys)) {
114
            unset($this->excludeKeys[$key]);
115
        }
116 2
    }
117
118 2
    /**
119
     * Request のログを出力する.
120
     *
121
     * @param Request $request
122
     * @return string Request のログ
123
     */
124
    protected function logRequest(Request $request)
125
    {
126
        $log = '';
127
        $log .= $this->logKeyValuePair('REMOTE_ADDR', $request->getClientIp());
128
        $log .= $this->logKeyValuePair('SCRIPT_NAME', $request->getScriptName());
129
        $log .= $this->logKeyValuePair('PATH_INFO', $request->getPathInfo());
130
        $log .= $this->logKeyValuePair('BASE_PATH', $request->getBasePath());
131
        $log .= $this->logKeyValuePair('BASE_URL', $request->getBaseUrl());
132
        $log .= $this->logKeyValuePair('SCHEME', $request->getScheme());
133
        $log .= $this->logKeyValuePair('REMOTE_USER', $request->getUser());
134
        $log .= $this->logKeyValuePair('HTTP_HOST', $request->getSchemeAndHttpHost());
135
        $log .= $this->logKeyValuePair('REQUEST_URI', $request->getRequestUri());
136
        $log .= $this->logKeyValuePair('METHOD', $request->getRealMethod());
137
        $log .= $this->logKeyValuePair('LOCALE', $request->getLocale());
138 2
        // $log .= $this->logArray($request->server->all(), '[server]'); // 大量にログ出力される...
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
139 2
        $log .= $this->logArray($request->headers->all(), '[header]');
140
        $log .= $this->logArray($request->query->all(), '[get]');
141
        $log .= $this->logArray($request->request->all(), '[post]');
142
        $log .= $this->logArray($request->attributes->all(), '[attributes]');
143
        $log .= $this->logArray($request->cookies->all(), '[cookie]');
144
        $log .= $this->logArray($request->files->all(), '[files]');
145
146
        return $log;
147 58
    }
148
149 58
    /**
150
     * Response のログを出力する.
151
     *
152 58
     * @param Response $response
153 58
     * @return string Response のログ
154
     */
155
    protected function logResponse(Response $response)
156
    {
157
        $log = '';
158
        $log .= $this->logKeyValuePair('HTTP_STATUS', $response->getStatusCode());
159
160
        return $log;
161
    }
162
163
    /**
164
     * Session のログを出力する.
165
     */
166
    protected function logSession(SessionInterface $Session)
167
    {
168
        return $this->logArray($Session->all(), '[session]');
169
    }
170
171
    /**
172
     * 配列をログ出力する.
173
     */
174
    protected function logArray(array $values, $prefix = '')
175
    {
176
        $log = '';
177
        foreach ($values as $key => $val) {
178
            $log .= $this->logKeyValuePair($key, $val, $prefix);
179
        }
180
181 57
        return $log;
182
    }
183
184 57
    /**
185
     * キーと値のペアをログ出力する.
186
     *
187
     * 除外キーに該当する値は, マスクをかける
188
     */
189
    protected function logKeyValuePair($key, $value, $prefix = '')
190 2
    {
191
        if (in_array($key, $this->excludeKeys)) {
192
            return '';
193 8
        }
194
        if (is_null($value) || is_scalar($value) || (is_object($value) && method_exists($value, '__toString'))) {
195
            $copy_value = $value;
196
        } elseif (is_object($value)) {
197
            try {
198
                $copy_value = '[object '.serialize($value).']';
199
            } catch (\Exception $e) {
200
                return $e->getMessage().PHP_EOL;
201
            }
202
        } else {
203
            $copy_value = $value;
204
            if (is_array($copy_value)) {
205
                foreach ($copy_value as $key => &$val) {
206
                    if (in_array($key, $this->excludeKeys)
207
                        && $prefix != '[header]') { // XXX header にもマスクがかかってしまう
208
                        $val = '******';
209
                    }
210
                }
211
            }
212
            try {
213
                $copy_value = '['.serialize($copy_value).']';
214
            } catch (\Exception $e) {
215
                return $e->getMessage().PHP_EOL;
216
            }
217
        }
218
219
        return '  '.$prefix.' '.$key.'='.$copy_value.PHP_EOL;
220
    }
221
}
222