PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.2.4
Defender Security – Malware Scanner, Login Security & Firewall v6.2.4
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 6.2.4, at src/model/class-audit-log.php

339 lines 7.6 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 * @param int $per_page Number of logs per page.
193 *
194 * @return array
195 */
196 public static function query(
197 $date_from,
198 $date_to,
199 $events = array(),
200 $user_id = '',
201 $ip = '',
202 $paged = 1,
203 $per_page = 10
204 ): array {
205 $orm = self::get_orm();
206 $builder = $orm->get_repository( self::class );
207 $builder->where( 'timestamp', '>=', $date_from )
208 ->where( 'timestamp', '<=', $date_to );
209
210 if ( is_array( $events )
211 && count( $events )
212 && count( array_diff( $events, self::allowed_events() ) ) === 0 ) {
213 $builder->where( 'event_type', 'in', $events );
214 }
215
216 if ( is_numeric( $user_id ) && $user_id > 0 ) {
217 $builder->where( 'user_id', $user_id );
218 }
219
220 if ( is_string( $ip ) && '' !== trim( $ip ) ) {
221 $builder->where( 'ip', 'like', "%$ip%" );
222 }
223 $builder->order_by( 'timestamp', 'desc' );
224
225 if ( false !== $paged ) {
226 // If paged == false, then it will be no paging.
227 $per_page = max( 1, (int) $per_page );
228 $offset = ( $paged - 1 ) * $per_page;
229 $builder->limit( $per_page, $offset );
230 }
231
232 return $builder->get();
233 }
234
235 /**
236 * Clean up the old logs depending on the storage settings.
237 *
238 * @param int $date_from The start date we want to query, in timestamp format.
239 * @param int $date_to The date end for the query, in timestamp format.
240 * @param int|null $limit Limit.
241 *
242 * @return void
243 */
244 public static function delete_old_logs( $date_from, $date_to, $limit = null ) {
245 $orm = self::get_orm();
246 $builder = $orm->get_repository( self::class );
247 $builder->where( 'timestamp', '>=', $date_from )
248 ->where( 'timestamp', '<=', $date_to );
249
250 if ( null === $limit ) {
251 $builder->delete_all();
252 } else {
253 $builder->order_by( 'id' )
254 ->limit( $limit )
255 ->delete_by_limit();
256 }
257 }
258
259 /**
260 * Counts the number of records in the database table that match the given criteria.
261 *
262 * @param int $date_from The start date to filter records by.
263 * @param int $date_to The end date to filter records by.
264 * @param array $events (optional) An array of event types to filter records by.
265 * @param string $user_id (optional) The user ID to filter records by.
266 * @param string $ip (optional) The IP address to filter records by.
267 *
268 * @return int The number of records that match the given criteria.
269 */
270 public static function count( $date_from, $date_to, $events = array(), $user_id = '', $ip = '' ) {
271 $orm = self::get_orm();
272 $builder = $orm->get_repository( self::class );
273 $builder->where( 'timestamp', '>=', $date_from )
274 ->where( 'timestamp', '<=', $date_to );
275 if ( count( $events ) && count( array_diff( $events, self::allowed_events() ) ) === 0 ) {
276 $builder->where( 'event_type', 'in', $events );
277 }
278
279 if ( is_numeric( $user_id ) && $user_id > 0 ) {
280 $builder->where( 'user_id', $user_id );
281 }
282
283 if ( is_string( $ip ) && '' !== trim( $ip ) ) {
284 $builder->where( 'ip', 'like', "%$ip%" );
285 }
286
287 return (int) $builder->count();
288 }
289
290 /**
291 * Mass insert logs, usually fetched from API.
292 *
293 * @param array $data An array of data to be inserted into the Audit_Log table.
294 * @param int $synced Whether the logs have already been synced.
295 *
296 * @return void
297 * @throws ReflectionException If the import method of the Audit_Log class throws a ReflectionException.
298 */
299 public static function mass_insert( $data, $synced = 1 ) {
300 // Use raw sql for faster.
301 foreach ( $data as $datum ) {
302 $item = new Audit_Log();
303 $item->import( $datum );
304 $item->synced = $synced;
305 $item->save();
306 }
307 }
308
309 /**
310 * Retrieves a record from the database by its ID.
311 *
312 * @param int $id The ID of the record to retrieve.
313 *
314 * @return mixed The retrieved record, or null if not found.
315 */
316 public static function get_by_id( $id ) {
317 $orm = self::get_orm();
318
319 return $orm->get_repository( self::class )->find_by_id( $id );
320 }
321
322 /**
323 * Get allowed types.
324 *
325 * @return array
326 */
327 public static function allowed_events(): array {
328 return array(
329 self::EVENT_TYPE_USER,
330 self::EVENT_TYPE_SYSTEM,
331 self::EVENT_TYPE_COMMENT,
332 self::EVENT_TYPE_MEDIA,
333 self::EVENT_TYPE_SETTINGS,
334 self::EVENT_TYPE_CONTENT,
335 self::EVENT_TYPE_MENU,
336 );
337 }
338 }
339