PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.5.1
Defender Security – Malware Scanner, Login Security & Firewall v5.5.1
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / src / model / class-audit-log.php

class-audit-log.php in Defender Security – Malware Scanner, Login Security & Firewall 5.5.1, at src/model/class-audit-log.php

336 lines 7.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles interactions with the database table for audit logs.
4 *
5 * @package WP_Defender\Model
6 */
7
8 namespace WP_Defender\Model;
9
10 use WP_Defender\DB;
11 use ReflectionException;
12
13 /**
14 * Model for the audit log table.
15 */
16 class Audit_Log extends DB {
17
18 public const EVENT_TYPE_USER = 'user', EVENT_TYPE_SYSTEM = 'system', EVENT_TYPE_COMMENT = 'comment',
19 EVENT_TYPE_MEDIA = 'media', EVENT_TYPE_SETTINGS = 'settings', EVENT_TYPE_CONTENT = 'content',
20 EVENT_TYPE_MENU = 'menu';
21
22 /**
23 * Table name.
24 *
25 * @var string
26 */
27 protected $table = 'defender_audit_log';
28
29 /**
30 * Primary key column.
31 *
32 * @var int
33 * @defender_property
34 */
35 public $id;
36 /**
37 * Table column for timestamp.
38 *
39 * @var int
40 * @defender_property
41 */
42 public $timestamp;
43 /**
44 * Table column for event type.
45 *
46 * @var string
47 * @defender_property
48 */
49 public $event_type;
50 /**
51 * Table column for action type.
52 *
53 * @var string
54 * @defender_property
55 */
56 public $action_type;
57 /**
58 * Table column for site url.
59 *
60 * @var string
61 * @defender_property
62 */
63 public $site_url;
64 /**
65 * Table column for user id.
66 *
67 * @var int
68 * @defender_property
69 */
70 public $user_id;
71 /**
72 * Table column for context.
73 *
74 * @var string
75 * @defender_property
76 */
77 public $context;
78 /**
79 * Table column for ip.
80 *
81 * @var string
82 * @defender_property
83 */
84 public $ip;
85 /**
86 * Table column for message.
87 *
88 * @var string
89 * @defender_property
90 */
91 public $msg;
92 /**
93 * Table column for blog id.
94 *
95 * @var int
96 * @defender_property
97 */
98 public $blog_id;
99 /**
100 * Table column for synced flag.
101 *
102 * @var bool
103 * @defender_property
104 */
105 public $synced;
106 /**
107 * Table column for ttl.
108 *
109 * @var int
110 * @defender_property
111 */
112 public $ttl;
113 /**
114 * Safe columns.
115 *
116 * @var array
117 */
118 public $safe = array(
119 'id',
120 'timestamp',
121 'event_type',
122 'action_type',
123 'site_url',
124 'user_id',
125 'context',
126 'ip',
127 'msg',
128 'blog_id',
129 'synced',
130 'ttl',
131 );
132
133 /**
134 * Truncate the table, as this is mostly use for cache, when we fetch new data, old data should be removed for
135 * consistent sync with API side.
136 */
137 public static function truncate() {
138 $orm = self::get_orm();
139 $orm->get_repository( self::class )->truncate();
140 }
141
142 /**
143 * Get the very last item, mostly use for testing.
144 *
145 * @return self|null
146 */
147 public static function get_last() {
148 $orm = self::get_orm();
149
150 return $orm->get_repository( self::class )
151 ->where( 'synced', 'in', array( 0, 1 ) )
152 ->order_by( 'id', 'desc' )
153 ->first();
154 }
155
156 /**
157 * Sometimes we need the pre of last, for testing.
158 *
159 * @return self|null
160 */
161 public static function get_pre_last() {
162 $orm = self::get_orm();
163 $model = $orm->get_repository( self::class )
164 ->where( 'synced', 'in', array( 0, 1 ) )
165 ->order_by( 'id', 'desc' )
166 ->limit( 2, 0 )
167 ->get();
168
169 return array_pop( $model );
170 }
171
172 /**
173 * Get logs that need to be flushed.
174 *
175 * @return self[]
176 */
177 public static function get_logs_need_flush() {
178 $orm = self::get_orm();
179
180 return $orm->get_repository( self::class )->where( 'synced', 0 )->limit( 50 )->get();
181 }
182
183 /**
184 * Query logs from internal cache.
185 *
186 * @param int $date_from The start date we want to query, in timestamp format.
187 * @param int $date_to The date end for the query, in timestamp format.
188 * @param array $events Type of the event, e.g. comment, user, system.
189 * @param string $user_id Who trigger this event, if it 0, will be guest.
190 * @param string $ip IP of who trigger this.
191 * @param int|bool $paged Current page.
192 *
193 * @return array
194 */
195 public static function query(
196 $date_from,
197 $date_to,
198 $events = array(),
199 $user_id = '',
200 $ip = '',
201 $paged = 1
202 ): array {
203 $orm = self::get_orm();
204 $builder = $orm->get_repository( self::class );
205 $builder->where( 'timestamp', '>=', $date_from )
206 ->where( 'timestamp', '<=', $date_to );
207
208 if ( is_array( $events )
209 && count( $events )
210 && count( array_diff( $events, self::allowed_events() ) ) === 0 ) {
211 $builder->where( 'event_type', 'in', $events );
212 }
213
214 if ( ! empty( $user_id ) ) {
215 $builder->where( 'user_id', $user_id );
216 }
217
218 if ( ! empty( $ip ) ) {
219 $builder->where( 'ip', 'like', "%$ip%" );
220 }
221 $builder->order_by( 'timestamp', 'desc' );
222
223 if ( false !== $paged ) {
224 // If paged == false, then it will be no paging.
225 $per_page = 20;
226 $offset = ( $paged - 1 ) * $per_page;
227 $builder->limit( $per_page, $offset );
228 }
229
230 return $builder->get();
231 }
232
233 /**
234 * Clean up the old logs depending on the storage settings.
235 *
236 * @param int $date_from The start date we want to query, in timestamp format.
237 * @param int $date_to The date end for the query, in timestamp format.
238 * @param int|null $limit Limit.
239 *
240 * @return void
241 */
242 public static function delete_old_logs( $date_from, $date_to, $limit = null ) {
243 $orm = self::get_orm();
244 $builder = $orm->get_repository( self::class );
245 $builder->where( 'timestamp', '>=', $date_from )
246 ->where( 'timestamp', '<=', $date_to );
247
248 if ( null === $limit ) {
249 $builder->delete_all();
250 } else {
251 $builder->order_by( 'id' )
252 ->limit( $limit )
253 ->delete_by_limit();
254 }
255 }
256
257 /**
258 * Counts the number of records in the database table that match the given criteria.
259 *
260 * @param int $date_from The start date to filter records by.
261 * @param int $date_to The end date to filter records by.
262 * @param array $events (optional) An array of event types to filter records by.
263 * @param string $user_id (optional) The user ID to filter records by.
264 * @param string $ip (optional) The IP address to filter records by.
265 *
266 * @return int The number of records that match the given criteria.
267 */
268 public static function count( $date_from, $date_to, $events = array(), $user_id = '', $ip = '' ) {
269 $orm = self::get_orm();
270 $builder = $orm->get_repository( self::class );
271 $builder->where( 'timestamp', '>=', $date_from )
272 ->where( 'timestamp', '<=', $date_to );
273 if ( count( $events ) && count( array_diff( $events, self::allowed_events() ) ) === 0 ) {
274 $builder->where( 'event_type', 'in', $events );
275 }
276
277 if ( ! empty( $user_id ) ) {
278 $builder->where( 'user_id', $user_id );
279 }
280
281 if ( ! empty( $ip ) ) {
282 $builder->where( 'ip', 'like', "%$ip%" );
283 }
284
285 return $builder->count();
286 }
287
288 /**
289 * Mass insert logs, usually fetched from API.
290 *
291 * @param array $data An array of data to be inserted into the Audit_Log table.
292 *
293 * @return void
294 * @throws ReflectionException If the import method of the Audit_Log class throws a ReflectionException.
295 */
296 public static function mass_insert( $data ) {
297 // Use raw sql for faster.
298 foreach ( $data as $datum ) {
299 $item = new Audit_Log();
300 $item->import( $datum );
301 $item->synced = 1;
302 $item->save();
303 }
304 }
305
306 /**
307 * Retrieves a record from the database by its ID.
308 *
309 * @param int $id The ID of the record to retrieve.
310 *
311 * @return mixed The retrieved record, or null if not found.
312 */
313 public static function get_by_id( $id ) {
314 $orm = self::get_orm();
315
316 return $orm->get_repository( self::class )->find_by_id( $id );
317 }
318
319 /**
320 * Get allowed types.
321 *
322 * @return array
323 */
324 public static function allowed_events(): array {
325 return array(
326 self::EVENT_TYPE_USER,
327 self::EVENT_TYPE_SYSTEM,
328 self::EVENT_TYPE_COMMENT,
329 self::EVENT_TYPE_MEDIA,
330 self::EVENT_TYPE_SETTINGS,
331 self::EVENT_TYPE_CONTENT,
332 self::EVENT_TYPE_MENU,
333 );
334 }
335 }
336