Passed
Pull Request — master (#1119)
by Tarmo
08:41
created

determineParameters()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 1
dl 0
loc 22
rs 9.9666
c 0
b 0
f 0
ccs 9
cts 9
cp 1
crap 3
1
<?php
2
declare(strict_types = 1);
3
/**
4
 * /src/Entity/Traits/LogRequestProcessRequestTrait.php
5
 *
6
 * @author TLe, Tarmo Leppänen <[email protected]>
7
 */
8
9
namespace App\Entity\Traits;
10
11
use App\Utils\JSON;
12
use Doctrine\ORM\Mapping as ORM;
13
use JsonException;
14
use Symfony\Component\HttpFoundation\Request;
15
use Symfony\Component\Serializer\Annotation\Groups;
16
use function array_key_exists;
17
use function array_map;
18
use function array_walk;
19
use function basename;
20
use function explode;
21
use function is_array;
22
use function mb_strtolower;
23
use function parse_str;
24
use function preg_replace;
25
use function strpos;
26
27
/**
28
 * Trait LogRequestProcessRequestTrait
29
 *
30
 * @package App\Entity\Traits
31
 * @author TLe, Tarmo Leppänen <[email protected]>
32
 *
33
 * @method array getSensitiveProperties();
34
 */
35
trait LogRequestProcessRequestTrait
36
{
37
    private string $replaceValue = '*** REPLACED ***';
38
39
    /**
40
     * @var array<string, string>
41
     *
42
     * @ORM\Column(
43
     *      name="headers",
44
     *      type="array",
45
     *  )
46
     */
47
    #[Groups([
48
        'LogRequest',
49
        'LogRequest.headers',
50
    ])]
51
    private array $headers = [];
52
53
    /**
54
     * @ORM\Column(
55
     *      name="method",
56
     *      type="string",
57
     *      length=255,
58
     *      nullable=false,
59
     *  )
60
     */
61
    #[Groups([
62
        'LogRequest',
63
        'LogRequest.method',
64
    ])]
65
    private string $method = '';
66
67
    /**
68
     * @ORM\Column(
69
     *      name="scheme",
70
     *      type="string",
71
     *      length=5,
72
     *      nullable=false,
73
     *  )
74
     */
75
    #[Groups([
76
        'LogRequest',
77
        'LogRequest.scheme',
78
    ])]
79
    private string $scheme = '';
80
81
    /**
82
     * @ORM\Column(
83
     *      name="base_path",
84
     *      type="string",
85
     *      length=255,
86
     *      nullable=false,
87
     *  )
88
     */
89
    #[Groups([
90
        'LogRequest',
91
        'LogRequest.basePath',
92
    ])]
93
    private string $basePath = '';
94
95
    /**
96
     * @ORM\Column(
97
     *      name="script",
98
     *      type="string",
99
     *      length=255,
100
     *      nullable=false,
101
     *  )
102
     */
103
    #[Groups([
104
        'LogRequest',
105
        'LogRequest.script',
106
    ])]
107
    private string $script = '';
108
109
    /**
110
     * @ORM\Column(
111
     *      name="path",
112
     *      type="string",
113
     *      length=255,
114
     *      nullable=true,
115
     *  )
116
     */
117
    #[Groups([
118
        'LogRequest',
119
        'LogRequest.path',
120
    ])]
121
    private string $path = '';
122
123
    /**
124
     * @ORM\Column(
125
     *      name="query_string",
126
     *      type="text",
127
     *      nullable=true,
128
     *  )
129
     */
130
    #[Groups([
131
        'LogRequest',
132
        'LogRequest.queryString',
133
    ])]
134
    private string $queryString = '';
135
136
    /**
137
     * @ORM\Column(
138
     *      name="uri",
139
     *      type="text",
140
     *      nullable=false,
141
     *  )
142
     */
143
    #[Groups([
144
        'LogRequest',
145
        'LogRequest.uri',
146
    ])]
147
    private string $uri = '';
148
149
    /**
150
     * @ORM\Column(
151
     *      name="controller",
152
     *      type="string",
153
     *      length=255,
154
     *      nullable=true,
155
     *  )
156
     */
157
    #[Groups([
158
        'LogRequest',
159
        'LogRequest.controller',
160
    ])]
161
    private string $controller = '';
162
163
    /**
164
     * @ORM\Column(
165
     *      name="content_type",
166
     *      type="string",
167
     *      length=255,
168
     *      nullable=true,
169
     *  )
170
     */
171
    #[Groups([
172
        'LogRequest',
173
        'LogRequest.contentType',
174
    ])]
175
    private string $contentType = '';
176
177
    /**
178
     * @ORM\Column(
179
     *      name="content_type_short",
180
     *      type="string",
181
     *      length=255,
182
     *      nullable=true,
183
     *  )
184
     */
185
    #[Groups([
186
        'LogRequest',
187
        'LogRequest.contentTypeShort',
188
    ])]
189
    private string $contentTypeShort = '';
190
191
    /**
192
     * @ORM\Column(
193
     *      name="is_xml_http_request",
194
     *      type="boolean",
195
     *      nullable=false,
196
     *  )
197
     */
198
    #[Groups([
199
        'LogRequest',
200
        'LogRequest.isXmlHttpRequest',
201
    ])]
202
    private bool $xmlHttpRequest = false;
203
204
    /**
205
     * @ORM\Column(
206
     *      name="action",
207
     *      type="string",
208
     *      length=255,
209
     *      nullable=true,
210
     *  )
211
     */
212
    #[Groups([
213
        'LogRequest',
214
        'LogRequest.action',
215
    ])]
216
    private string $action = '';
217
218
    /**
219
     * @ORM\Column(
220
     *      name="content",
221
     *      type="text",
222
     *      nullable=true,
223
     *  )
224
     */
225
    #[Groups([
226
        'LogRequest',
227
        'LogRequest.content',
228
    ])]
229
    private string $content = '';
230
231
    /**
232
     * @var array<string, string>
233
     *
234
     * @ORM\Column(
235
     *      name="parameters",
236
     *      type="array",
237
     *  )
238
     */
239
    #[Groups([
240
        'LogRequest',
241
        'LogRequest.parameters',
242
    ])]
243
    private array $parameters = [];
244
245 1
    public function getUri(): string
246
    {
247 1
        return $this->uri;
248
    }
249
250 1
    public function getMethod(): string
251
    {
252 1
        return $this->method;
253
    }
254
255 1
    public function getScheme(): string
256
    {
257 1
        return $this->scheme;
258
    }
259
260 1
    public function getBasePath(): string
261
    {
262 1
        return $this->basePath;
263
    }
264
265 1
    public function getQueryString(): ?string
266
    {
267 1
        return $this->queryString;
268
    }
269
270
    /**
271
     * @return array<string, string>
272
     */
273 6
    public function getHeaders(): array
274
    {
275 6
        return $this->headers;
276
    }
277
278
    /**
279
     * @return array<string, string>
280
     */
281 6
    public function getParameters(): array
282
    {
283 6
        return $this->parameters;
284
    }
285
286 1
    public function isXmlHttpRequest(): bool
287
    {
288 1
        return $this->xmlHttpRequest;
289
    }
290
291 1
    public function getController(): ?string
292
    {
293 1
        return $this->controller;
294
    }
295
296 1
    public function getAction(): ?string
297
    {
298 1
        return $this->action;
299
    }
300
301 1
    public function getPath(): ?string
302
    {
303 1
        return $this->path;
304
    }
305
306 1
    public function getScript(): string
307
    {
308 1
        return $this->script;
309
    }
310
311 1
    public function getContent(): string
312
    {
313 1
        return $this->content;
314
    }
315
316 1
    public function getContentType(): ?string
317
    {
318 1
        return $this->contentType;
319
    }
320
321 1
    public function getContentTypeShort(): ?string
322
    {
323 1
        return $this->contentTypeShort;
324
    }
325
326 439
    protected function processRequest(Request $request): void
327
    {
328 439
        $this->processRequestBaseInfo($request);
329 439
        $this->processHeadersAndParameters($request);
330
331 439
        $this->action = $this->determineAction($request);
332 439
        $this->content = $this->cleanContent($request->getContent());
333 439
    }
334
335 439
    private function processHeadersAndParameters(Request $request): void
336
    {
337 439
        $rawHeaders = $request->headers->all();
338
339
        // Clean possible sensitive data from parameters
340 439
        array_walk(
341 439
            $rawHeaders,
342 439
            fn (mixed & $value, string $key) => $this->cleanParameters($value, $key),
343
        );
344
345 439
        $this->headers = $rawHeaders;
346
347 439
        $rawParameters = $this->determineParameters($request);
348
349
        // Clean possible sensitive data from parameters
350 439
        array_walk(
351 439
            $rawParameters,
352 439
            fn (mixed & $value, string $key) => $this->cleanParameters($value, $key),
353
        );
354
355 439
        $this->parameters = $rawParameters;
356 439
    }
357
358 439
    private function processRequestBaseInfo(Request $request): void
359
    {
360 439
        $this->method = $request->getRealMethod();
361 439
        $this->scheme = $request->getScheme();
362 439
        $this->basePath = $request->getBasePath();
363 439
        $this->script = '/' . basename($request->getScriptName());
364 439
        $this->path = $request->getPathInfo();
365 439
        $this->queryString = $request->getRequestUri();
366 439
        $this->uri = $request->getUri();
367 439
        $this->controller = (string)$request->get('_controller', '');
368 439
        $this->contentType = (string)$request->getMimeType($request->getContentType() ?? '');
369 439
        $this->contentTypeShort = (string)$request->getContentType();
370 439
        $this->xmlHttpRequest = $request->isXmlHttpRequest();
371 439
    }
372
373 439
    private function determineAction(Request $request): string
374
    {
375 439
        $rawAction = $request->get('_controller', '');
376 439
        $rawAction = (array)explode(strpos($rawAction, '::') ? '::' : ':', $rawAction);
377
378 439
        return (string)($rawAction[1] ?? '');
379
    }
380
381
    /**
382
     * Getter method to convert current request parameters to array.
383
     *
384
     * @return mixed[]
385
     */
386 439
    private function determineParameters(Request $request): array
387
    {
388 439
        $rawContent = $request->getContent();
389
390
        // By default just get whole parameter bag
391 439
        $output = $request->request->all();
392
393
        // Content given so parse it
394 439
        if ($rawContent) {
395
            // First try to convert content to array from JSON
396
            try {
397
                /** @var array<string, mixed> $output */
398 43
                $output = JSON::decode($rawContent, true);
399 1
            } catch (JsonException) {
400
                // Oh noes content isn't JSON so just parse it
401 1
                $output = [];
402
403 1
                parse_str($rawContent, $output);
404
            }
405
        }
406
407 439
        return $output;
408
    }
409
410
    /**
411
     * Helper method to clean parameters / header array of any sensitive data.
412
     */
413 437
    private function cleanParameters(mixed &$value, string $key): void
414
    {
415
        // What keys we should replace so that any sensitive data is not logged
416 437
        $replacements = array_fill_keys($this->sensitiveProperties, $this->replaceValue);
417
418
        // Normalize current key
419 437
        $key = mb_strtolower($key);
420
421
        // Replace current value
422 437
        if (array_key_exists($key, $replacements)) {
423 321
            $value = $this->cleanContent($replacements[$key]);
424
        }
425
426
        // Recursive call
427 437
        if (is_array($value)) {
428 432
            array_walk(
429 432
                $value,
430 432
                fn (mixed & $value, string $key) => $this->cleanParameters($value, $key),
431
            );
432
        }
433 437
    }
434
435
    /**
436
     * Method to clean raw request content of any sensitive data.
437
     */
438 439
    private function cleanContent(string $inputContent): string
439
    {
440 439
        $iterator = static function (string $search) use (&$inputContent): void {
441 410
            $inputContent = (string)preg_replace(
442 410
                '/(' . $search . '":)\s*"(.*)"/',
443 410
                '$1"*** REPLACED ***"',
444 410
                $inputContent
445
            );
446 410
        };
447
448 439
        array_map($iterator, $this->getSensitiveProperties());
449
450 439
        return $inputContent;
451
    }
452
}
453