Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
16 / 16
CRAP
100.00% covered (success)
100.00%
1 / 1
AdminLog
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
16 / 16
17
100.00% covered (success)
100.00%
1 / 1
 getId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setId
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getTime
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setTime
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getUserId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setUserId
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getText
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setText
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getIp
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setIp
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getHash
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setHash
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getPreviousHash
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setPreviousHash
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 calculateHash
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 verifyIntegrity
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3/**
4 * Admin log entity class.
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public License,
7 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
8 * obtain one at https://mozilla.org/MPL/2.0/.
9 *
10 * @package   phpMyFAQ
11 * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
12 * @copyright 2024-2026 phpMyFAQ Team
13 * @license   https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
14 * @link      https://www.phpmyfaq.de
15 * @since     2024-03-24
16 */
17
18declare(strict_types=1);
19
20namespace phpMyFAQ\Entity;
21
22class AdminLog
23{
24    private int $id = 0;
25
26    private int $time = 0;
27
28    private int $userId = 0;
29
30    private string $text = '';
31
32    private string $ip = '';
33
34    private ?string $hash = null;
35    private ?string $previousHash = null;
36
37    public function getId(): int
38    {
39        return $this->id;
40    }
41
42    public function setId(int $id): AdminLog
43    {
44        $this->id = $id;
45        return $this;
46    }
47
48    public function getTime(): int
49    {
50        return $this->time;
51    }
52
53    public function setTime(int $time): AdminLog
54    {
55        $this->time = $time;
56        return $this;
57    }
58
59    public function getUserId(): int
60    {
61        return $this->userId;
62    }
63
64    public function setUserId(int $userId): AdminLog
65    {
66        $this->userId = $userId;
67        return $this;
68    }
69
70    public function getText(): string
71    {
72        return $this->text;
73    }
74
75    public function setText(string $text): AdminLog
76    {
77        $this->text = $text;
78        return $this;
79    }
80
81    public function getIp(): string
82    {
83        return $this->ip;
84    }
85
86    public function setIp(string $ip): AdminLog
87    {
88        $this->ip = $ip;
89        return $this;
90    }
91
92    public function getHash(): ?string
93    {
94        return $this->hash;
95    }
96
97    public function setHash(?string $hash): AdminLog
98    {
99        $this->hash = $hash;
100        return $this;
101    }
102
103    public function getPreviousHash(): ?string
104    {
105        return $this->previousHash;
106    }
107
108    public function setPreviousHash(?string $previousHash): AdminLog
109    {
110        $this->previousHash = $previousHash;
111        return $this;
112    }
113
114    /**
115     * Calculates SHA-256 hash over all log data.
116     * Note: ID is not included because it's auto-generated after INSERT
117     * @return string 64-character hex hash
118     */
119    public function calculateHash(): string
120    {
121        $data = implode('|', [
122            (string) $this->time,
123            (string) $this->userId,
124            $this->ip,
125            $this->text,
126            $this->previousHash ?? '',
127        ]);
128
129        return hash('sha256', $data);
130    }
131
132    /**
133     * Verifies if the stored hash matches the calculated hash.
134     * @return bool True if the hash is valid, false if tampered
135     */
136    public function verifyIntegrity(): bool
137    {
138        $storedHash = $this->hash;
139        if ($storedHash === null) {
140            return false;
141        }
142
143        $calculatedHash = $this->calculateHash();
144
145        return hash_equals($storedHash, $calculatedHash);
146    }
147}