Passed
Push — master ( d76f9c...e93f22 )
by Adrien
02:31
created

DbWriter::completeEvent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
c 2
b 0
f 0
nc 2
nop 1
dl 0
loc 14
ccs 0
cts 9
cp 0
crap 6
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 Ecodev\Felix\Repository\LogRepository;
9
use Laminas\Log\Writer\AbstractWriter;
10
11
class DbWriter extends AbstractWriter
12
{
13
    /**
14
     * @var LogRepository
15
     */
16
    private $logRepository;
17
18
    /**
19
     * @var string
20
     */
21
    private $baseUrl;
22
23
    public function __construct(LogRepository $logRepository, string $baseUrl, $options = null)
24
    {
25
        parent::__construct($options);
26
        $this->logRepository = $logRepository;
27
        $this->baseUrl = $baseUrl;
28
    }
29
30
    /**
31
     * Write a message to the log
32
     *
33
     * @param array $event log data event
34
     */
35
    final protected function doWrite(array $event): void
36
    {
37
        $completedEvent = $this->completeEvent($event);
38
        $this->logRepository->log($completedEvent);
39
    }
40
41
    protected function completeEvent(array $event): array
42
    {
43
        $envData = $this->getEnvData();
44
        $event = array_merge($event, $envData);
45
46
        // If we are logging PHP errors, then we include all known information in message
47
        if ($event['extra']['errno'] ?? false) {
48
            $event['message'] .= "\nStacktrace:\n" . $this->getStacktrace();
49
        }
50
51
        // Security hide clear text password
52
        unset($event['extra']['password']);
53
54
        return $event;
55
    }
56
57
    /**
58
     * Retrieve dynamic information from environment to be logged.
59
     */
60
    private function getEnvData(): array
61
    {
62
        $user = CurrentUser::get();
63
64
        if (PHP_SAPI === 'cli') {
65
            global $argv;
66
            $request = $argv;
67
            $ip = 'script';
68
            $url = implode(' ', $argv);
69
            $referer = '';
70
        } else {
71
            $request = $_REQUEST;
72
            $ip = $_SERVER['REMOTE_ADDR'] ?? '';
73
            $url = $this->baseUrl . $_SERVER['REQUEST_URI'];
74
            $referer = $_SERVER['HTTP_REFERER'] ?? '';
75
        }
76
77
        $request = $this->removeSensitiveData($request);
78
79
        $envData = [
80
            'creator_id' => $user ? $user->getId() : null,
81
            'url' => $url,
82
            'referer' => $referer,
83
            'request' => json_encode($request, JSON_PRETTY_PRINT),
84
            'ip' => $ip,
85
        ];
86
87
        return $envData;
88
    }
89
90
    protected function removeSensitiveData(array $request): array
91
    {
92
        return $request;
93
    }
94
95
    /**
96
     * Returns the backtrace excluding the most recent calls to this function so we only get the interesting parts
97
     */
98
    private function getStacktrace(): string
99
    {
100
        ob_start();
101
        @debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
102
        $trace = ob_get_contents();
103
        ob_end_clean();
104
105
        if ($trace === false) {
106
            return 'Could not get stacktrace';
107
        }
108
109
        // Remove first items from backtrace as it's this function and previous logging functions which is not interesting
110
        $shortenTrace = preg_replace('/^#[0-4]\s+[^\n]*\n/m', '', $trace);
111
112
        if ($shortenTrace === null) {
113
            return $trace;
114
        }
115
116
        // Renumber backtrace items.
117
        $renumberedTrace = preg_replace_callback('/^#(\d+)/m', function ($matches) {
118
            return '#' . ($matches[1] - 5);
119
        }, $shortenTrace);
120
121
        if ($renumberedTrace === null) {
122
            return $shortenTrace;
123
        }
124
125
        return $renumberedTrace;
126
    }
127
}
128