Failed Conditions
Pull Request — master (#10)
by Adrien
04:59 queued 01:35
created

EventCompleter::removeSensitiveData()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.072

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 9
ccs 4
cts 5
cp 0.8
crap 3.072
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ecodev\Felix\Log;
6
7
use Ecodev\Felix\Model\CurrentUser;
8
use Laminas\Log\Processor\ProcessorInterface;
9
10
class EventCompleter implements ProcessorInterface
11
{
12
    private string $baseUrl;
13
14 5
    public function __construct(string $baseUrl)
15
    {
16 5
        $this->baseUrl = $baseUrl;
17 5
    }
18
19
    /**
20
     * Complete a log event with extra data, including stacktrace and any global stuff relevant to the app.
21
     */
22 4
    public function process(array $event): array
23
    {
24 4
        $envData = $this->getEnvData();
25 4
        $event = array_merge($event, $envData);
26
27
        // If we are logging PHP errors, then we include all known information in message
28 4
        if ($event['extra']['errno'] ?? false) {
29 1
            $event['message'] .= "\nStacktrace:\n" . $this->getStacktrace();
30
        }
31
32
        // Security hide clear text password
33 4
        unset($event['extra']['password']);
34
35 4
        return $event;
36
    }
37
38
    /**
39
     * Retrieve dynamic information from environment to be logged.
40
     */
41 4
    private function getEnvData(): array
42
    {
43 4
        $user = CurrentUser::get();
44
45 4
        if (PHP_SAPI === 'cli') {
46
            global $argv;
47 4
            $request = $argv;
48 4
            $ip = !empty(getenv('REMOTE_ADDR')) ? getenv('REMOTE_ADDR') : 'script';
49 4
            $url = implode(' ', $argv);
50 4
            $referer = '';
51
        } else {
52
            $request = $_REQUEST;
53
            $ip = $_SERVER['REMOTE_ADDR'] ?? '';
54
            $url = $this->baseUrl . $_SERVER['REQUEST_URI'];
55
            $referer = $_SERVER['HTTP_REFERER'] ?? '';
56
        }
57
58 4
        $request = $this->removeSensitiveData($request);
59
60
        $envData = [
61 4
            'creator_id' => $user ? $user->getId() : null,
62 4
            'login' => $user ? $user->getLogin() : null,
63 4
            'url' => $url,
64 4
            'referer' => $referer,
65 4
            'request' => json_encode($request, JSON_PRETTY_PRINT),
66 4
            'ip' => $ip,
67
        ];
68
69 4
        return $envData;
70
    }
71
72
    /**
73
     * Remove password value from GraphQL variables well-known structure.
74
     */
75 4
    protected function removeSensitiveData(array $request): array
76
    {
77 4
        foreach ($request as &$r) {
78 4
            if (is_array($r)) {
79
                unset($r['variables']['password']);
80
            }
81
        }
82
83 4
        return $request;
84
    }
85
86
    /**
87
     * Returns the backtrace excluding the most recent calls to this function so we only get the interesting parts.
88
     */
89 1
    private function getStacktrace(): string
90
    {
91 1
        ob_start();
92 1
        @debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
93 1
        $trace = ob_get_contents();
94 1
        ob_end_clean();
95
96 1
        if ($trace === false) {
97
            return 'Could not get stacktrace';
98
        }
99
100
        // Remove first items from backtrace as it's this function and previous logging functions which is not interesting
101 1
        $shortenTrace = preg_replace('/^#[0-4]\s+[^\n]*\n/m', '', $trace);
102
103 1
        if ($shortenTrace === null) {
104
            return $trace;
105
        }
106
107
        // Renumber backtrace items.
108 1
        $renumberedTrace = preg_replace_callback('/^#(\d+)/m', fn ($matches) => '#' . ((int) $matches[1] - 5), $shortenTrace);
109
110 1
        if ($renumberedTrace === null) {
111
            return $shortenTrace;
112
        }
113
114 1
        return $renumberedTrace;
115
    }
116
}
117