WP Security Audit Log - Version 2.5.9

Version Description

(2017-01-03) =

  • Support for new features in External DB Add-on:
    • Mirroring of audit trail to Syslog
    • Mirroring of audit trail to Papertrail
    • Support for archiving alerts from the audit trail in an external database.
Download this release

Release Info

Developer WPWhiteSecurity
Plugin Icon 128x128 WP Security Audit Log
Version 2.5.9
Comparing to
See all releases

Code changes from version 2.5.8 to 2.5.9

classes/Adapters/MySQL/ActiveRecordAdapter.php CHANGED
@@ -361,13 +361,31 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
361
  return 'DROP TABLE ' . $this->GetTable();
362
  }
363
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  /**
365
  * Function used in WSAL reporting extension
366
  */
367
  public function GetReporting($_siteId, $_userId, $_roleName, $_alertCode, $_startTimestamp, $_endTimestamp, $_nextDate = null, $_limit = 0)
368
  {
369
  global $wpdb;
370
- $tableUsers = $wpdb->users;
371
  $_wpdb = $this->connection;
372
  $_wpdb->set_charset($_wpdb->dbh, 'utf8mb4', 'utf8mb4_general_ci');
373
  // tables
@@ -376,17 +394,8 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
376
  $occurrence = new WSAL_Adapters_MySQL_Occurrence($this->connection);
377
  $tableOcc = $occurrence->GetTable(); // occurrences
378
 
379
- $user_names = '0';
380
- if (!empty($_userId) && $_userId != "null") {
381
- $sql = 'SELECT user_login FROM '.$tableUsers.' WHERE find_in_set(ID, @userId) > 0';
382
- $wpdb->query("SET @userId = $_userId");
383
- $result = $wpdb->get_results($sql, ARRAY_A);
384
- $aUsers = array();
385
- foreach ($result as $item) {
386
- $aUsers[] = '"'.$item['user_login'].'"';
387
- }
388
- $user_names = implode(', ', $aUsers);
389
- }
390
  $conditionDate = !empty($_nextDate) ? ' AND occ.created_on < '.$_nextDate : '';
391
 
392
  $sql = "SELECT DISTINCT
@@ -432,18 +441,72 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
432
  $sql .= " LIMIT {$_limit}";
433
  }
434
  $results = $_wpdb->get_results($sql);
435
-
436
- foreach ($results as $row) {
437
- $sql = "SELECT t6.ID FROM $tableUsers AS t6 WHERE t6.user_login = \"$row->user_id\"";
438
- $userId = $wpdb->get_var($sql);
439
- if ($userId == null) {
440
- $sql = "SELECT t4.ID FROM $tableUsers AS t4 WHERE t4.ID = \"$row->user_id\"";
441
  $userId = $wpdb->get_var($sql);
 
 
 
 
 
 
442
  }
443
- $row->user_id = $userId;
444
- $results['lastDate'] = $row->created_on;
445
  }
446
 
447
  return $results;
448
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
  }
361
  return 'DROP TABLE ' . $this->GetTable();
362
  }
363
 
364
+ private function GetUserNames($_userId)
365
+ {
366
+ global $wpdb;
367
+
368
+ $user_names = '0';
369
+ if (!empty($_userId) && $_userId != "null") {
370
+ $sql = 'SELECT user_login FROM '. $wpdb->users .' WHERE find_in_set(ID, @userId) > 0';
371
+ $wpdb->query("SET @userId = $_userId");
372
+ $result = $wpdb->get_results($sql, ARRAY_A);
373
+ $aUsers = array();
374
+ foreach ($result as $item) {
375
+ $aUsers[] = '"'.$item['user_login'].'"';
376
+ }
377
+ $user_names = implode(', ', $aUsers);
378
+ }
379
+ return $user_names;
380
+ }
381
+
382
  /**
383
  * Function used in WSAL reporting extension
384
  */
385
  public function GetReporting($_siteId, $_userId, $_roleName, $_alertCode, $_startTimestamp, $_endTimestamp, $_nextDate = null, $_limit = 0)
386
  {
387
  global $wpdb;
388
+
389
  $_wpdb = $this->connection;
390
  $_wpdb->set_charset($_wpdb->dbh, 'utf8mb4', 'utf8mb4_general_ci');
391
  // tables
394
  $occurrence = new WSAL_Adapters_MySQL_Occurrence($this->connection);
395
  $tableOcc = $occurrence->GetTable(); // occurrences
396
 
397
+ $user_names = $this->GetUserNames($_userId);
398
+
 
 
 
 
 
 
 
 
 
399
  $conditionDate = !empty($_nextDate) ? ' AND occ.created_on < '.$_nextDate : '';
400
 
401
  $sql = "SELECT DISTINCT
441
  $sql .= " LIMIT {$_limit}";
442
  }
443
  $results = $_wpdb->get_results($sql);
444
+ if (!empty($results)) {
445
+ foreach ($results as $row) {
446
+ $sql = "SELECT t6.ID FROM $wpdb->users AS t6 WHERE t6.user_login = \"$row->user_id\"";
 
 
 
447
  $userId = $wpdb->get_var($sql);
448
+ if ($userId == null) {
449
+ $sql = "SELECT t4.ID FROM $wpdb->users AS t4 WHERE t4.ID = \"$row->user_id\"";
450
+ $userId = $wpdb->get_var($sql);
451
+ }
452
+ $row->user_id = $userId;
453
+ $results['lastDate'] = $row->created_on;
454
  }
 
 
455
  }
456
 
457
  return $results;
458
  }
459
+
460
+ /**
461
+ * Function used in WSAL reporting extension
462
+ * Check if criteria are matching in the DB
463
+ */
464
+ public function CheckMatchReportCriteria($criteria)
465
+ {
466
+ $_siteId = $criteria['siteId'];
467
+ $_userId = $criteria['userId'];
468
+ $_roleName = $criteria['roleName'];
469
+ $_alertCode = $criteria['alertCode'];
470
+ $_startTimestamp = $criteria['startTimestamp'];
471
+ $_endTimestamp = $criteria['endTimestamp'];
472
+ $_ipAddress = $criteria['ipAddress'];
473
+
474
+ $_wpdb = $this->connection;
475
+ $_wpdb->set_charset($_wpdb->dbh, 'utf8mb4', 'utf8mb4_general_ci');
476
+ // tables
477
+ $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
478
+ $tableMeta = $meta->GetTable(); // metadata
479
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence($this->connection);
480
+ $tableOcc = $occurrence->GetTable(); // occurrences
481
+
482
+ $user_names = $this->GetUserNames($_userId);
483
+
484
+ $sql = "SELECT COUNT(DISTINCT occ.id) FROM $tableOcc AS occ
485
+ JOIN $tableMeta AS meta ON meta.occurrence_id = occ.id
486
+ WHERE
487
+ (@siteId is NULL OR find_in_set(occ.site_id, @siteId) > 0)
488
+ AND (@userId is NULL OR (
489
+ (meta.name = 'CurrentUserID' AND find_in_set(meta.value, @userId) > 0)
490
+ OR (meta.name = 'Username' AND replace(meta.value, '\"', '') IN ($user_names))
491
+ ))
492
+ AND (@roleName is NULL OR (meta.name = 'CurrentUserRoles'
493
+ AND replace(replace(replace(meta.value, ']', ''), '[', ''), '\\'', '') REGEXP @roleName
494
+ ))
495
+ AND (@alertCode is NULL OR find_in_set(occ.alert_id, @alertCode) > 0)
496
+ AND (@startTimestamp is NULL OR occ.created_on >= @startTimestamp)
497
+ AND (@endTimestamp is NULL OR occ.created_on <= @endTimestamp)
498
+ AND (@ipAddress is NULL OR (meta.name = 'ClientIP' AND find_in_set(meta.value, @ipAddress) > 0))
499
+ ";
500
+
501
+ $_wpdb->query("SET @siteId = $_siteId");
502
+ $_wpdb->query("SET @userId = $_userId");
503
+ $_wpdb->query("SET @roleName = $_roleName");
504
+ $_wpdb->query("SET @alertCode = $_alertCode");
505
+ $_wpdb->query("SET @startTimestamp = $_startTimestamp");
506
+ $_wpdb->query("SET @endTimestamp = $_endTimestamp");
507
+ $_wpdb->query("SET @ipAddress = $_ipAddress");
508
+
509
+ $count = (int)$_wpdb->get_var($sql);
510
+ return $count;
511
+ }
512
  }
classes/AuditLogListView.php CHANGED
@@ -29,6 +29,10 @@ class WSAL_AuditLogListView extends WP_List_Table
29
  'ajax' => true,
30
  'screen' => 'interval-list',
31
  ));
 
 
 
 
32
  }
33
 
34
  public function no_items()
@@ -80,6 +84,20 @@ class WSAL_AuditLogListView extends WP_List_Table
80
  <?php } ?>
81
  </div><?php
82
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  }
84
 
85
  /**
@@ -89,14 +107,11 @@ class WSAL_AuditLogListView extends WP_List_Table
89
  public function get_sites($limit = null)
90
  {
91
  global $wpdb;
92
-
93
  // build query
94
  $sql = 'SELECT blog_id, domain FROM ' . $wpdb->blogs;
95
  if (!is_null($limit)) $sql .= ' LIMIT ' . $limit;
96
-
97
  // execute query
98
  $res = $wpdb->get_results($sql);
99
-
100
  // modify result
101
  foreach ($res as $row) {
102
  $row->blogname = get_blog_option($row->blog_id, 'blogname');
@@ -396,6 +411,13 @@ class WSAL_AuditLogListView extends WP_List_Table
396
 
397
  public function prepare_items()
398
  {
 
 
 
 
 
 
 
399
  $per_page = $this->_plugin->settings->GetViewPerPage();
400
 
401
  $columns = $this->get_columns();
29
  'ajax' => true,
30
  'screen' => 'interval-list',
31
  ));
32
+
33
+ if (!session_id()) {
34
+ @session_start();
35
+ }
36
  }
37
 
38
  public function no_items()
84
  <?php } ?>
85
  </div><?php
86
  }
87
+
88
+ // switch to live or archive DB
89
+ if ($this->_plugin->settings->IsArchivingEnabled()) {
90
+ $selected = 'live';
91
+ if (isset($_SESSION['selected_db']) && $_SESSION['selected_db'] == 'archive') {
92
+ $selected = 'archive';
93
+ }
94
+ ?><div class="wsal-ssa wsal-db">
95
+ <select class="wsal-db" onchange="WsalDBChange(value);">
96
+ <option value="live" <?php if ($selected == 'live') echo 'selected="selected"'; ?>><?php _e('Live Database', 'wp-security-audit-log'); ?></option>
97
+ <option value="archive" <?php if ($selected == 'archive') echo 'selected="selected"'; ?>><?php _e('Archive Database', 'wp-security-audit-log'); ?></option>
98
+ </select>
99
+ </div><?php
100
+ }
101
  }
102
 
103
  /**
107
  public function get_sites($limit = null)
108
  {
109
  global $wpdb;
 
110
  // build query
111
  $sql = 'SELECT blog_id, domain FROM ' . $wpdb->blogs;
112
  if (!is_null($limit)) $sql .= ' LIMIT ' . $limit;
 
113
  // execute query
114
  $res = $wpdb->get_results($sql);
 
115
  // modify result
116
  foreach ($res as $row) {
117
  $row->blogname = get_blog_option($row->blog_id, 'blogname');
411
 
412
  public function prepare_items()
413
  {
414
+ if ($this->_plugin->settings->IsArchivingEnabled()) {
415
+ // Switch to Archive DB
416
+ if (isset($_SESSION['selected_db']) && $_SESSION['selected_db'] == 'archive') {
417
+ $this->_plugin->settings->SwitchToArchiveDB();
418
+ }
419
+ }
420
+
421
  $per_page = $this->_plugin->settings->GetViewPerPage();
422
 
423
  $columns = $this->get_columns();
classes/Connector/ConnectorFactory.php CHANGED
@@ -20,7 +20,7 @@ abstract class WSAL_Connector_ConnectorFactory
20
  * Returns a connector singleton
21
  * @return WSAL_Connector_ConnectorInterface
22
  */
23
- public static function GetConnector($config = null)
24
  {
25
  if (!empty($config)) {
26
  $connectionConfig = $config;
@@ -29,7 +29,7 @@ abstract class WSAL_Connector_ConnectorFactory
29
  }
30
 
31
  //TO DO: Load connection config
32
- if (self::$connector == null || !empty($config)) {
33
  switch (strtolower($connectionConfig['type'])) {
34
  //TO DO: Add other connectors
35
  case 'mysql':
20
  * Returns a connector singleton
21
  * @return WSAL_Connector_ConnectorInterface
22
  */
23
+ public static function GetConnector($config = null, $reset = false)
24
  {
25
  if (!empty($config)) {
26
  $connectionConfig = $config;
29
  }
30
 
31
  //TO DO: Load connection config
32
+ if (self::$connector == null || !empty($config) || $reset) {
33
  switch (strtolower($connectionConfig['type'])) {
34
  //TO DO: Add other connectors
35
  case 'mysql':
classes/Connector/ConnectorInterface.php CHANGED
@@ -4,6 +4,7 @@ interface WSAL_Connector_ConnectorInterface
4
  {
5
  public function getAdapter($class_name);
6
  public function getConnection();
 
7
  public function isInstalled();
8
  public function canMigrate();
9
  public function installAll();
4
  {
5
  public function getAdapter($class_name);
6
  public function getConnection();
7
+ public function closeConnection();
8
  public function isInstalled();
9
  public function canMigrate();
10
  public function installAll();
classes/Connector/MySQLDB.php CHANGED
@@ -54,6 +54,16 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
54
  }
55
  }
56
 
 
 
 
 
 
 
 
 
 
 
57
  /**
58
  * Gets an adapter for the specified model
59
  */
@@ -164,7 +174,7 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
164
  $sql = 'INSERT INTO ' . $metaNew->GetTable() . ' (occurrence_id, name, value) VALUES ' ;
165
  foreach ($metadata as $entry) {
166
  $occurrence_id = intval($entry['occurrence_id']) + $increase_occurrence_id;
167
- $sql .= '('.$occurrence_id.', \''.$entry['name'].'\', \''.str_replace("'", "\'", $entry['value']).'\'), ';
168
  }
169
  $sql = rtrim($sql, ", ");
170
  $_wpdb->query($sql);
@@ -274,7 +284,7 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
274
  $index++;
275
  $sql = 'INSERT INTO ' . $metaWP->GetWPTable() . ' (occurrence_id, name, value) VALUES ' ;
276
  foreach ($metadata as $entry) {
277
- $sql .= '('.$entry['occurrence_id'].', \''.$entry['name'].'\', \''.str_replace("'", "\'", $entry['value']).'\'), ';
278
  }
279
  $sql = rtrim($sql, ", ");
280
  $wpdb->query($sql);
@@ -319,6 +329,157 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
319
  return rtrim($plaintext_dec, "\0");
320
  }
321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  private function truncateKey()
323
  {
324
  if (!defined('AUTH_KEY')) {
54
  }
55
  }
56
 
57
+ /**
58
+ * Close DB connection
59
+ */
60
+ public function closeConnection()
61
+ {
62
+ $currentWpdb = $this->getConnection();
63
+ $result = $currentWpdb->close();
64
+ return $result;
65
+ }
66
+
67
  /**
68
  * Gets an adapter for the specified model
69
  */
174
  $sql = 'INSERT INTO ' . $metaNew->GetTable() . ' (occurrence_id, name, value) VALUES ' ;
175
  foreach ($metadata as $entry) {
176
  $occurrence_id = intval($entry['occurrence_id']) + $increase_occurrence_id;
177
+ $sql .= '('.$occurrence_id.', \''.$entry['name'].'\', \''.str_replace(array("'", "\'"), "\'", $entry['value']).'\'), ';
178
  }
179
  $sql = rtrim($sql, ", ");
180
  $_wpdb->query($sql);
284
  $index++;
285
  $sql = 'INSERT INTO ' . $metaWP->GetWPTable() . ' (occurrence_id, name, value) VALUES ' ;
286
  foreach ($metadata as $entry) {
287
+ $sql .= '('.$entry['occurrence_id'].', \''.$entry['name'].'\', \''.str_replace(array("'", "\'"), "\'", $entry['value']).'\'), ';
288
  }
289
  $sql = rtrim($sql, ", ");
290
  $wpdb->query($sql);
329
  return rtrim($plaintext_dec, "\0");
330
  }
331
 
332
+ public function MirroringAlertsToDB($args)
333
+ {
334
+ $last_created_on = null;
335
+ $first_occurrence_id = null;
336
+ $_wpdb = $this->getConnection();
337
+ $mirroring_db = $args['mirroring_db'];
338
+
339
+ // Load data Occurrences from WP
340
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence($_wpdb);
341
+ if (!$occurrence->IsInstalled()) {
342
+ return null;
343
+ }
344
+
345
+ $sql = 'SELECT * FROM ' . $occurrence->GetTable() . ' WHERE created_on > ' . $args['last_created_on'];
346
+ $occurrences = $_wpdb->get_results($sql, ARRAY_A);
347
+
348
+ if (!empty($occurrences)) {
349
+ $occurrenceNew = new WSAL_Adapters_MySQL_Occurrence($mirroring_db);
350
+
351
+ $sql = 'INSERT INTO ' . $occurrenceNew->GetTable() . ' (id, site_id, alert_id, created_on, is_read) VALUES ' ;
352
+ foreach ($occurrences as $entry) {
353
+ $sql .= '('.$entry['id'].', '.$entry['site_id'].', '.$entry['alert_id'].', '.$entry['created_on'].', '.$entry['is_read'].'), ';
354
+ $last_created_on = $entry['created_on'];
355
+ // save the first id
356
+ if (empty($first_occurrence_id)) {
357
+ $first_occurrence_id = $entry['id'];
358
+ }
359
+ }
360
+ $sql = rtrim($sql, ", ");
361
+ $mirroring_db->query($sql);
362
+ }
363
+
364
+ // Load data Meta from WP
365
+ $meta = new WSAL_Adapters_MySQL_Meta($_wpdb);
366
+ if (!$meta->IsInstalled()) {
367
+ return null;
368
+ }
369
+ if (!empty($first_occurrence_id)) {
370
+ $sql = 'SELECT * FROM ' . $meta->GetTable() . ' WHERE occurrence_id >= ' . $first_occurrence_id;
371
+ $metadata = $_wpdb->get_results($sql, ARRAY_A);
372
+
373
+ if (!empty($metadata)) {
374
+ $metaNew = new WSAL_Adapters_MySQL_Meta($mirroring_db);
375
+
376
+ $sql = 'INSERT INTO ' . $metaNew->GetTable() . ' (occurrence_id, name, value) VALUES ' ;
377
+ foreach ($metadata as $entry) {
378
+ $sql .= '('.$entry['occurrence_id'].', \''.$entry['name'].'\', \''.str_replace(array("'", "\'"), "\'", $entry['value']).'\'), ';
379
+ }
380
+ $sql = rtrim($sql, ", ");
381
+ $mirroring_db->query($sql);
382
+ }
383
+ }
384
+ return $last_created_on;
385
+ }
386
+
387
+ public function ArchiveOccurrence($args)
388
+ {
389
+ $_wpdb = $this->getConnection();
390
+ $archive_db = $args['archive_db'];
391
+
392
+ // Load data Occurrences from WP
393
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence($_wpdb);
394
+ if (!$occurrence->IsInstalled()) {
395
+ return null;
396
+ }
397
+ if (!empty($args['by_date'])) {
398
+ $sql = 'SELECT * FROM ' . $occurrence->GetTable() . ' WHERE created_on <= ' . $args['by_date'];
399
+ }
400
+
401
+ if (!empty($args['by_limit'])) {
402
+ $sql = 'SELECT occ.* FROM ' . $occurrence->GetTable() . ' occ
403
+ LEFT JOIN (SELECT id FROM ' . $occurrence->GetTable() . ' order by created_on DESC limit ' . $args['by_limit'] . ') as ids
404
+ on ids.id = occ.id
405
+ WHERE ids.id IS NULL';
406
+ }
407
+ if (!empty($args['last_created_on'])) {
408
+ $sql .= ' AND created_on > ' . $args['last_created_on'];
409
+ }
410
+ $sql .= ' ORDER BY created_on ASC';
411
+ if (!empty($args['limit'])) {
412
+ $sql .= ' LIMIT ' . $args['limit'];
413
+ }
414
+ $occurrences = $_wpdb->get_results($sql, ARRAY_A);
415
+
416
+ // Insert data to Archive DB
417
+ if (!empty($occurrences)) {
418
+ $last = end($occurrences);
419
+ $args['last_created_on'] = $last['created_on'];
420
+ $args['occurence_ids'] = array();
421
+
422
+ $occurrenceNew = new WSAL_Adapters_MySQL_Occurrence($archive_db);
423
+
424
+ $sql = 'INSERT INTO ' . $occurrenceNew->GetTable() . ' (id, site_id, alert_id, created_on, is_read) VALUES ' ;
425
+ foreach ($occurrences as $entry) {
426
+ $sql .= '('.$entry['id'].', '.$entry['site_id'].', '.$entry['alert_id'].', '.$entry['created_on'].', '.$entry['is_read'].'), ';
427
+ $args['occurence_ids'][] = $entry['id'];
428
+ }
429
+ $sql = rtrim($sql, ", ");
430
+ $archive_db->query($sql);
431
+ return $args;
432
+ } else {
433
+ return false;
434
+ }
435
+ }
436
+
437
+ public function ArchiveMeta($args)
438
+ {
439
+ $_wpdb = $this->getConnection();
440
+ $archive_db = $args['archive_db'];
441
+
442
+ // Load data Meta from WP
443
+ $meta = new WSAL_Adapters_MySQL_Meta($_wpdb);
444
+ if (!$meta->IsInstalled()) {
445
+ return null;
446
+ }
447
+ $sOccurenceIds = implode(", ", $args["occurence_ids"]);
448
+ $sql = 'SELECT * FROM ' . $meta->GetTable() . ' WHERE occurrence_id IN (' . $sOccurenceIds . ')';
449
+ $metadata = $_wpdb->get_results($sql, ARRAY_A);
450
+
451
+ // Insert data to Archive DB
452
+ if (!empty($metadata)) {
453
+ $metaNew = new WSAL_Adapters_MySQL_Meta($archive_db);
454
+
455
+ $sql = 'INSERT INTO ' . $metaNew->GetTable() . ' (occurrence_id, name, value) VALUES ' ;
456
+ foreach ($metadata as $entry) {
457
+ $sql .= '('.$entry['occurrence_id'].', \''.$entry['name'].'\', \''.str_replace(array("'", "\'"), "\'", $entry['value']).'\'), ';
458
+ }
459
+ $sql = rtrim($sql, ", ");
460
+ $archive_db->query($sql);
461
+ return $args;
462
+ } else {
463
+ return false;
464
+ }
465
+ }
466
+
467
+ public function DeleteAfterArchive($args)
468
+ {
469
+ $_wpdb = $this->getConnection();
470
+ $archive_db = $args['archive_db'];
471
+
472
+ $sOccurenceIds = implode(", ", $args["occurence_ids"]);
473
+
474
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence($_wpdb);
475
+ $sql = 'DELETE FROM ' . $occurrence->GetTable() . ' WHERE id IN (' . $sOccurenceIds . ')';
476
+ $_wpdb->query($sql);
477
+
478
+ $meta = new WSAL_Adapters_MySQL_Meta($_wpdb);
479
+ $sql = 'DELETE FROM ' . $meta->GetTable() . ' WHERE occurrence_id IN (' . $sOccurenceIds . ')';
480
+ $_wpdb->query($sql);
481
+ }
482
+
483
  private function truncateKey()
484
  {
485
  if (!defined('AUTH_KEY')) {
classes/Settings.php CHANGED
@@ -29,7 +29,7 @@ class WSAL_Settings {
29
  * @return boolean If option is enabled or not.
30
  */
31
  public function IsDevOptionEnabled($option){
32
- if(is_null($this->_devoption)){
33
  $this->_devoption = $this->_plugin->GetGlobalOption(
34
  'dev-options',
35
  implode(',', $this->GetDefaultDevOptions())
@@ -53,11 +53,13 @@ class WSAL_Settings {
53
  // make sure options have been loaded
54
  $this->IsDevOptionEnabled('');
55
  // remove option if it exists
56
- while(($p = array_search($option, $this->_devoption)) !== false)
57
  unset($this->_devoption[$p]);
 
58
  // add option if callee wants it enabled
59
- if($enabled)
60
  $this->_devoption[] = $option;
 
61
  // commit option
62
  $this->_plugin->SetGlobalOption(
63
  'dev-options',
@@ -146,10 +148,11 @@ class WSAL_Settings {
146
  * @return string The current pruning date.
147
  */
148
  public function GetPruningDate(){
149
- if(!$this->_pruning){
150
  $this->_pruning = $this->_plugin->GetGlobalOption('pruning-date');
151
- if(!strtotime($this->_pruning))
152
  $this->_pruning = $this->GetDefaultPruningDate();
 
153
  }
154
  return $this->_pruning;
155
  }
@@ -157,7 +160,7 @@ class WSAL_Settings {
157
  * @param string $newvalue The new pruning date.
158
  */
159
  public function SetPruningDate($newvalue){
160
- if(strtotime($newvalue)){
161
  $this->_plugin->SetGlobalOption('pruning-date', $newvalue);
162
  $this->_pruning = $newvalue;
163
  }
@@ -188,6 +191,7 @@ class WSAL_Settings {
188
  public function IsPruningLimitEnabled(){
189
  return $this->_plugin->GetGlobalOption('pruning-limit-e');
190
  }
 
191
  public function IsRestrictAdmins(){
192
  return $this->_plugin->GetGlobalOption('restrict-admins', false);
193
  }
@@ -211,7 +215,7 @@ class WSAL_Settings {
211
  * @return array IDs of disabled alerts.
212
  */
213
  public function GetDisabledAlerts(){
214
- if(!$this->_disabled){
215
  $this->_disabled = implode(',', $this->GetDefaultDisabledAlerts());
216
  $this->_disabled = $this->_plugin->GetGlobalOption('disabled-alerts', $this->_disabled);
217
  $this->_disabled = ($this->_disabled == '') ? array() : explode(',', $this->_disabled);
@@ -263,7 +267,7 @@ class WSAL_Settings {
263
  $this->_plugin->SetGlobalOption('plugin-viewers', implode(',', $this->_viewers));
264
  }
265
  public function GetAllowedPluginViewers(){
266
- if(is_null($this->_viewers)){
267
  $this->_viewers = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('plugin-viewers'))));
268
  }
269
  return $this->_viewers;
@@ -274,7 +278,7 @@ class WSAL_Settings {
274
  $this->_plugin->SetGlobalOption('plugin-editors', implode(',', $this->_editors));
275
  }
276
  public function GetAllowedPluginEditors(){
277
- if(is_null($this->_editors)){
278
  $this->_editors = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('plugin-editors'))));
279
  }
280
  return $this->_editors;
@@ -285,8 +289,8 @@ class WSAL_Settings {
285
  $this->_plugin->SetGlobalOption('items-per-page', $this->_perpage);
286
  }
287
  public function GetViewPerPage(){
288
- if(is_null($this->_perpage)){
289
- $this->_perpage = (int)$this->_plugin->GetGlobalOption('items-per-page', 10);
290
  }
291
  return $this->_perpage;
292
  }
@@ -307,7 +311,7 @@ class WSAL_Settings {
307
  * @return string[] List of admin usernames.
308
  */
309
  protected function GetAdmins(){
310
- if($this->_plugin->IsMultisite()){
311
  // see: https://gist.github.com/1508426/65785a15b8638d43a9905effb59e4d97319ef8f8
312
  global $wpdb;
313
  $cap = $wpdb->prefix."capabilities";
@@ -317,7 +321,7 @@ class WSAL_Settings {
317
  . " WHERE $wpdb->usermeta.meta_key = '$cap'"
318
  . " AND CAST($wpdb->usermeta.meta_value AS CHAR) LIKE '%\"administrator\"%'";
319
  return $wpdb->get_col($sql);
320
- }else{
321
  $result = array();
322
  $query = 'role=administrator&fields[]=user_login';
323
  foreach (get_users($query) as $user) $result[] = $user->user_login;
@@ -433,11 +437,10 @@ class WSAL_Settings {
433
  $this->SetLicenses($data);
434
  }
435
  public function ClearLicenses(){
436
- $this->SetLicenses(array());
437
  }
438
 
439
  // </editor-fold>
440
-
441
  // <editor-fold desc="Client IP Retrieval">
442
 
443
  public function IsMainIPFromProxy(){
@@ -475,9 +478,11 @@ class WSAL_Settings {
475
  foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key) {
476
  if (isset($_SERVER[$key])) {
477
  $ips[$key] = array();
478
- foreach (explode(',', $_SERVER[$key]) as $ip)
479
- if ($this->ValidateIP($ip = $this->NormalizeIP($ip)))
480
  $ips[$key][] = $ip;
 
 
481
  }
482
  }
483
  return $ips;
@@ -485,11 +490,11 @@ class WSAL_Settings {
485
 
486
  protected function NormalizeIP($ip){
487
  $ip = trim($ip);
488
- if(strpos($ip, ':') !== false && substr_count($ip, '.') == 3 && strpos($ip, '[') === false){
489
  // IPv4 with a port (eg: 11.22.33.44:80)
490
  $ip = explode(':', $ip);
491
  $ip = $ip[0];
492
- }else{
493
  // IPv6 with a port (eg: [::1]:80)
494
  $ip = explode(']', $ip);
495
  $ip = ltrim($ip[0], '[');
@@ -526,7 +531,7 @@ class WSAL_Settings {
526
  }
527
  public function GetExcludedMonitoringUsers()
528
  {
529
- if(empty($this->_excluded_users)){
530
  $this->_excluded_users = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-users'))));
531
  }
532
  return $this->_excluded_users;
@@ -541,7 +546,7 @@ class WSAL_Settings {
541
  $this->_plugin->SetGlobalOption('excluded-roles', esc_html(implode(',', $this->_excluded_roles)));
542
  }
543
  public function GetExcludedMonitoringRoles(){
544
- if(empty($this->_excluded_roles)){
545
  $this->_excluded_roles = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-roles'))));
546
  }
547
  return $this->_excluded_roles;
@@ -556,7 +561,7 @@ class WSAL_Settings {
556
  $this->_plugin->SetGlobalOption('excluded-custom', esc_html(implode(',', $this->_excluded_custom)));
557
  }
558
  public function GetExcludedMonitoringCustom(){
559
- if(empty($this->_excluded_custom)){
560
  $this->_excluded_custom = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-custom'))));
561
  asort($this->_excluded_custom);
562
  }
@@ -572,7 +577,7 @@ class WSAL_Settings {
572
  $this->_plugin->SetGlobalOption('excluded-ip', esc_html(implode(',', $this->_excluded_ip)));
573
  }
574
  public function GetExcludedMonitoringIP(){
575
- if(empty($this->_excluded_ip)){
576
  $this->_excluded_ip = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-ip'))));
577
  }
578
  return $this->_excluded_ip;
@@ -690,12 +695,35 @@ class WSAL_Settings {
690
  return $this->_plugin->GetGlobalOption('display-name');
691
  }
692
 
693
- public function Set404LogLimit($value){
694
  return $this->_plugin->SetGlobalOption('log-404-limit', abs($value));
695
  }
696
 
697
  public function Get404LogLimit(){
698
- return $this->_plugin->GetGlobalOption('log-404-limit', 99);;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
699
  }
700
  // </editor-fold>
701
  }
29
  * @return boolean If option is enabled or not.
30
  */
31
  public function IsDevOptionEnabled($option){
32
+ if (is_null($this->_devoption)) {
33
  $this->_devoption = $this->_plugin->GetGlobalOption(
34
  'dev-options',
35
  implode(',', $this->GetDefaultDevOptions())
53
  // make sure options have been loaded
54
  $this->IsDevOptionEnabled('');
55
  // remove option if it exists
56
+ while (($p = array_search($option, $this->_devoption)) !== false) {
57
  unset($this->_devoption[$p]);
58
+ }
59
  // add option if callee wants it enabled
60
+ if ($enabled) {
61
  $this->_devoption[] = $option;
62
+ }
63
  // commit option
64
  $this->_plugin->SetGlobalOption(
65
  'dev-options',
148
  * @return string The current pruning date.
149
  */
150
  public function GetPruningDate(){
151
+ if (!$this->_pruning) {
152
  $this->_pruning = $this->_plugin->GetGlobalOption('pruning-date');
153
+ if (!strtotime($this->_pruning)) {
154
  $this->_pruning = $this->GetDefaultPruningDate();
155
+ }
156
  }
157
  return $this->_pruning;
158
  }
160
  * @param string $newvalue The new pruning date.
161
  */
162
  public function SetPruningDate($newvalue){
163
+ if (strtotime($newvalue)) {
164
  $this->_plugin->SetGlobalOption('pruning-date', $newvalue);
165
  $this->_pruning = $newvalue;
166
  }
191
  public function IsPruningLimitEnabled(){
192
  return $this->_plugin->GetGlobalOption('pruning-limit-e');
193
  }
194
+
195
  public function IsRestrictAdmins(){
196
  return $this->_plugin->GetGlobalOption('restrict-admins', false);
197
  }
215
  * @return array IDs of disabled alerts.
216
  */
217
  public function GetDisabledAlerts(){
218
+ if (!$this->_disabled) {
219
  $this->_disabled = implode(',', $this->GetDefaultDisabledAlerts());
220
  $this->_disabled = $this->_plugin->GetGlobalOption('disabled-alerts', $this->_disabled);
221
  $this->_disabled = ($this->_disabled == '') ? array() : explode(',', $this->_disabled);
267
  $this->_plugin->SetGlobalOption('plugin-viewers', implode(',', $this->_viewers));
268
  }
269
  public function GetAllowedPluginViewers(){
270
+ if (is_null($this->_viewers)) {
271
  $this->_viewers = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('plugin-viewers'))));
272
  }
273
  return $this->_viewers;
278
  $this->_plugin->SetGlobalOption('plugin-editors', implode(',', $this->_editors));
279
  }
280
  public function GetAllowedPluginEditors(){
281
+ if (is_null($this->_editors)) {
282
  $this->_editors = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('plugin-editors'))));
283
  }
284
  return $this->_editors;
289
  $this->_plugin->SetGlobalOption('items-per-page', $this->_perpage);
290
  }
291
  public function GetViewPerPage(){
292
+ if (is_null($this->_perpage)) {
293
+ $this->_perpage = (int)$this->_plugin->GetGlobalOption('items-per-page', 10);
294
  }
295
  return $this->_perpage;
296
  }
311
  * @return string[] List of admin usernames.
312
  */
313
  protected function GetAdmins(){
314
+ if ($this->_plugin->IsMultisite()) {
315
  // see: https://gist.github.com/1508426/65785a15b8638d43a9905effb59e4d97319ef8f8
316
  global $wpdb;
317
  $cap = $wpdb->prefix."capabilities";
321
  . " WHERE $wpdb->usermeta.meta_key = '$cap'"
322
  . " AND CAST($wpdb->usermeta.meta_value AS CHAR) LIKE '%\"administrator\"%'";
323
  return $wpdb->get_col($sql);
324
+ } else {
325
  $result = array();
326
  $query = 'role=administrator&fields[]=user_login';
327
  foreach (get_users($query) as $user) $result[] = $user->user_login;
437
  $this->SetLicenses($data);
438
  }
439
  public function ClearLicenses(){
440
+ $this->SetLicenses(array());
441
  }
442
 
443
  // </editor-fold>
 
444
  // <editor-fold desc="Client IP Retrieval">
445
 
446
  public function IsMainIPFromProxy(){
478
  foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key) {
479
  if (isset($_SERVER[$key])) {
480
  $ips[$key] = array();
481
+ foreach (explode(',', $_SERVER[$key]) as $ip) {
482
+ if ($this->ValidateIP($ip = $this->NormalizeIP($ip))) {
483
  $ips[$key][] = $ip;
484
+ }
485
+ }
486
  }
487
  }
488
  return $ips;
490
 
491
  protected function NormalizeIP($ip){
492
  $ip = trim($ip);
493
+ if (strpos($ip, ':') !== false && substr_count($ip, '.') == 3 && strpos($ip, '[') === false) {
494
  // IPv4 with a port (eg: 11.22.33.44:80)
495
  $ip = explode(':', $ip);
496
  $ip = $ip[0];
497
+ } else {
498
  // IPv6 with a port (eg: [::1]:80)
499
  $ip = explode(']', $ip);
500
  $ip = ltrim($ip[0], '[');
531
  }
532
  public function GetExcludedMonitoringUsers()
533
  {
534
+ if (empty($this->_excluded_users)) {
535
  $this->_excluded_users = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-users'))));
536
  }
537
  return $this->_excluded_users;
546
  $this->_plugin->SetGlobalOption('excluded-roles', esc_html(implode(',', $this->_excluded_roles)));
547
  }
548
  public function GetExcludedMonitoringRoles(){
549
+ if (empty($this->_excluded_roles)) {
550
  $this->_excluded_roles = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-roles'))));
551
  }
552
  return $this->_excluded_roles;
561
  $this->_plugin->SetGlobalOption('excluded-custom', esc_html(implode(',', $this->_excluded_custom)));
562
  }
563
  public function GetExcludedMonitoringCustom(){
564
+ if (empty($this->_excluded_custom)) {
565
  $this->_excluded_custom = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-custom'))));
566
  asort($this->_excluded_custom);
567
  }
577
  $this->_plugin->SetGlobalOption('excluded-ip', esc_html(implode(',', $this->_excluded_ip)));
578
  }
579
  public function GetExcludedMonitoringIP(){
580
+ if (empty($this->_excluded_ip)) {
581
  $this->_excluded_ip = array_unique(array_filter(explode(',', $this->_plugin->GetGlobalOption('excluded-ip'))));
582
  }
583
  return $this->_excluded_ip;
695
  return $this->_plugin->GetGlobalOption('display-name');
696
  }
697
 
698
+ public function Set404LogLimit($value){
699
  return $this->_plugin->SetGlobalOption('log-404-limit', abs($value));
700
  }
701
 
702
  public function Get404LogLimit(){
703
+ return $this->_plugin->GetGlobalOption('log-404-limit', 99);
704
+ }
705
+
706
+ /*============================== Support Archive Database ==============================*/
707
+
708
+ public function IsArchivingEnabled(){
709
+ return $this->_plugin->GetGlobalOption('archiving-e');
710
+ }
711
+
712
+ /**
713
+ * Switch to Archive DB if is enabled
714
+ */
715
+ public function SwitchToArchiveDB()
716
+ {
717
+ if ($this->IsArchivingEnabled()) {
718
+ $archiveType = $this->_plugin->GetGlobalOption('archive-type');
719
+ $archiveUser = $this->_plugin->GetGlobalOption('archive-user');
720
+ $password = $this->_plugin->GetGlobalOption('archive-password');
721
+ $archiveName = $this->_plugin->GetGlobalOption('archive-name');
722
+ $archiveHostname = $this->_plugin->GetGlobalOption('archive-hostname');
723
+ $archiveBasePrefix = $this->_plugin->GetGlobalOption('archive-base-prefix');
724
+ $config = WSAL_Connector_ConnectorFactory::GetConfigArray($archiveType, $archiveUser, $password, $archiveName, $archiveHostname, $archiveBasePrefix);
725
+ $this->_plugin->getConnector($config)->getAdapter('Occurrence');
726
+ }
727
  }
728
  // </editor-fold>
729
  }
classes/Views/AuditLog.php CHANGED
@@ -15,12 +15,17 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
15
  add_action('wp_ajax_AjaxRefresh', array($this, 'AjaxRefresh'));
16
  add_action('wp_ajax_AjaxSetIpp', array($this, 'AjaxSetIpp'));
17
  add_action('wp_ajax_AjaxSearchSite', array($this, 'AjaxSearchSite'));
 
18
  add_action('all_admin_notices', array($this, 'AdminNoticesPremium'));
19
  // Check plugin version for to dismiss the notice only until upgrade
20
  $plugin_file = trailingslashit(WP_PLUGIN_DIR) . plugin_basename(__FILE__);
21
  $data = get_plugin_data($plugin_file, false, false);
22
  $this->_version = isset($data['Version']) ? $data['Version'] : '0.0.0';
23
  $this->RegisterNotice('premium-wsal-'.$this->_version);
 
 
 
 
24
  }
25
 
26
  public function AdminNoticesPremium()
@@ -65,7 +70,9 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
65
  }
66
 
67
  protected function GetListView() {
68
- if (is_null($this->_listview)) $this->_listview = new WSAL_AuditLogListView($this->_plugin);
 
 
69
  return $this->_listview;
70
  }
71
 
@@ -106,10 +113,12 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
106
  }
107
 
108
  public function AjaxInspector() {
109
- if(!$this->_plugin->settings->CurrentUserCan('view'))
110
  die('Access Denied.');
111
- if(!isset($_REQUEST['occurrence']))
 
112
  die('Occurrence parameter expected.');
 
113
  $occ = new WSAL_Models_Occurrence();
114
  $occ->Load('id = %d', array((int)$_REQUEST['occurrence']));
115
 
@@ -129,56 +138,74 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
129
  }
130
 
131
  public function AjaxRefresh() {
132
- if(!$this->_plugin->settings->CurrentUserCan('view'))
133
  die('Access Denied.');
134
- if(!isset($_REQUEST['logcount']))
 
135
  die('Log count parameter expected.');
 
136
 
137
  $old = (int)$_REQUEST['logcount'];
138
  $max = 40; // 40*500msec = 20sec
139
-
 
 
 
 
140
  session_write_close(); // fixes session lock issue
141
 
142
- do{
143
  $occ = new WSAL_Models_Occurrence();
144
  $new = $occ->Count();
145
  usleep(500000); // 500msec
146
- }while(($old == $new) && (--$max > 0));
147
 
148
- echo $old == $new ? 'false' : $new;
 
 
 
 
149
  die;
150
  }
151
 
152
- public function AjaxSetIpp(){
153
- if(!$this->_plugin->settings->CurrentUserCan('view'))
154
  die('Access Denied.');
155
- if(!isset($_REQUEST['count']))
 
156
  die('Count parameter expected.');
 
157
  $this->_plugin->settings->SetViewPerPage((int)$_REQUEST['count']);
158
  die;
159
  }
160
 
161
- public function AjaxSearchSite(){
162
- if(!$this->_plugin->settings->CurrentUserCan('view'))
163
  die('Access Denied.');
164
- if(!isset($_REQUEST['search']))
 
165
  die('Search parameter expected.');
166
-
167
  $grp1 = array();
168
  $grp2 = array();
169
 
170
  $search = $_REQUEST['search'];
171
 
172
- foreach($this->GetListView()->get_sites() as $site){
173
- if(stripos($site->blogname, $search) !== false)
174
  $grp1[] = $site;
175
- else
176
- if(stripos($site->domain, $search) !== false)
177
- $grp2[] = $site;
178
  }
179
-
180
  die(json_encode(array_slice($grp1 + $grp2, 0, 7)));
181
  }
 
 
 
 
 
 
182
 
183
  public function Header() {
184
  add_thickbox();
15
  add_action('wp_ajax_AjaxRefresh', array($this, 'AjaxRefresh'));
16
  add_action('wp_ajax_AjaxSetIpp', array($this, 'AjaxSetIpp'));
17
  add_action('wp_ajax_AjaxSearchSite', array($this, 'AjaxSearchSite'));
18
+ add_action('wp_ajax_AjaxSwitchDB', array($this, 'AjaxSwitchDB'));
19
  add_action('all_admin_notices', array($this, 'AdminNoticesPremium'));
20
  // Check plugin version for to dismiss the notice only until upgrade
21
  $plugin_file = trailingslashit(WP_PLUGIN_DIR) . plugin_basename(__FILE__);
22
  $data = get_plugin_data($plugin_file, false, false);
23
  $this->_version = isset($data['Version']) ? $data['Version'] : '0.0.0';
24
  $this->RegisterNotice('premium-wsal-'.$this->_version);
25
+
26
+ if (!session_id()) {
27
+ @session_start();
28
+ }
29
  }
30
 
31
  public function AdminNoticesPremium()
70
  }
71
 
72
  protected function GetListView() {
73
+ if (is_null($this->_listview)) {
74
+ $this->_listview = new WSAL_AuditLogListView($this->_plugin);
75
+ }
76
  return $this->_listview;
77
  }
78
 
113
  }
114
 
115
  public function AjaxInspector() {
116
+ if (!$this->_plugin->settings->CurrentUserCan('view')) {
117
  die('Access Denied.');
118
+ }
119
+ if (!isset($_REQUEST['occurrence'])) {
120
  die('Occurrence parameter expected.');
121
+ }
122
  $occ = new WSAL_Models_Occurrence();
123
  $occ->Load('id = %d', array((int)$_REQUEST['occurrence']));
124
 
138
  }
139
 
140
  public function AjaxRefresh() {
141
+ if (!$this->_plugin->settings->CurrentUserCan('view')) {
142
  die('Access Denied.');
143
+ }
144
+ if (!isset($_REQUEST['logcount'])) {
145
  die('Log count parameter expected.');
146
+ }
147
 
148
  $old = (int)$_REQUEST['logcount'];
149
  $max = 40; // 40*500msec = 20sec
150
+
151
+ $is_archive = false;
152
+ if (isset($_SESSION['selected_db']) && $_SESSION['selected_db'] == 'archive') {
153
+ $is_archive = true;
154
+ }
155
  session_write_close(); // fixes session lock issue
156
 
157
+ do {
158
  $occ = new WSAL_Models_Occurrence();
159
  $new = $occ->Count();
160
  usleep(500000); // 500msec
161
+ } while (($old == $new) && (--$max > 0));
162
 
163
+ if ($is_archive) {
164
+ echo 'false';
165
+ } else {
166
+ echo $old == $new ? 'false' : $new;
167
+ }
168
  die;
169
  }
170
 
171
+ public function AjaxSetIpp() {
172
+ if (!$this->_plugin->settings->CurrentUserCan('view')) {
173
  die('Access Denied.');
174
+ }
175
+ if (!isset($_REQUEST['count'])) {
176
  die('Count parameter expected.');
177
+ }
178
  $this->_plugin->settings->SetViewPerPage((int)$_REQUEST['count']);
179
  die;
180
  }
181
 
182
+ public function AjaxSearchSite() {
183
+ if (!$this->_plugin->settings->CurrentUserCan('view')) {
184
  die('Access Denied.');
185
+ }
186
+ if (!isset($_REQUEST['search'])) {
187
  die('Search parameter expected.');
188
+ }
189
  $grp1 = array();
190
  $grp2 = array();
191
 
192
  $search = $_REQUEST['search'];
193
 
194
+ foreach ($this->GetListView()->get_sites() as $site) {
195
+ if (stripos($site->blogname, $search) !== false) {
196
  $grp1[] = $site;
197
+ } elseif (stripos($site->domain, $search) !== false) {
198
+ $grp2[] = $site;
199
+ }
200
  }
 
201
  die(json_encode(array_slice($grp1 + $grp2, 0, 7)));
202
  }
203
+
204
+ public function AjaxSwitchDB() {
205
+ if (isset($_REQUEST['selected_db'])) {
206
+ $_SESSION['selected_db'] = $_REQUEST['selected_db'];
207
+ }
208
+ }
209
 
210
  public function Header() {
211
  add_thickbox();
classes/Views/Settings.php CHANGED
@@ -355,6 +355,17 @@ class WSAL_Views_Settings extends WSAL_AbstractView
355
  <table class="form-table wsal-tab widefat" id="tab-audit-log">
356
  <tbody>
357
  <!-- Security Alerts Pruning -->
 
 
 
 
 
 
 
 
 
 
 
358
  <tr>
359
  <th><label for="delete1"><?php _e('Security Alerts Pruning', 'wp-security-audit-log'); ?></label></th>
360
  <td>
@@ -362,7 +373,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView
362
  <?php $text = __('(eg: 1 month)', 'wp-security-audit-log'); ?>
363
  <?php $nbld = !($this->_plugin->settings->IsPruningDateEnabled() || $this->_plugin->settings->IsPruningLimitEnabled()); ?>
364
  <label for="delete0">
365
- <input type="radio" id="delete0" name="PruneBy" value="" <?php if ($nbld) echo 'checked="checked"'; ?>/>
366
  <?php echo __('None', 'wp-security-audit-log'); ?>
367
  </label>
368
  </fieldset>
@@ -370,24 +381,24 @@ class WSAL_Views_Settings extends WSAL_AbstractView
370
  <?php $text = __('(eg: 1 month)', 'wp-security-audit-log'); ?>
371
  <?php $nbld = $this->_plugin->settings->IsPruningDateEnabled(); ?>
372
  <label for="delete1">
373
- <input type="radio" id="delete1" name="PruneBy" value="date" <?php if($nbld)echo 'checked="checked"'; ?>/>
374
  <?php echo __('Delete alerts older than', 'wp-security-audit-log'); ?>
375
  </label>
376
  <input type="text" id="PruningDate" name="PruningDate" placeholder="<?php echo $text; ?>"
377
  value="<?php echo esc_attr($this->_plugin->settings->GetPruningDate()); ?>"
378
- onfocus="jQuery('#delete1').attr('checked', true);"/>
379
  <span> <?php echo $text; ?></span>
380
  </fieldset>
381
  <fieldset>
382
  <?php $text = __('(eg: 80)', 'wp-security-audit-log'); ?>
383
  <?php $nbld = $this->_plugin->settings->IsPruningLimitEnabled(); ?>
384
  <label for="delete2">
385
- <input type="radio" id="delete2" name="PruneBy" value="limit" <?php if($nbld)echo 'checked="checked"'; ?>/>
386
  <?php echo __('Keep up to', 'wp-security-audit-log'); ?>
387
  </label>
388
  <input type="text" id="PruningLimit" name="PruningLimit" placeholder="<?php echo $text;?>"
389
  value="<?php echo esc_attr($this->_plugin->settings->GetPruningLimit()); ?>"
390
- onfocus="jQuery('#delete2').attr('checked', true);"/>
391
  <?php echo __('alerts', 'wp-security-audit-log'); ?>
392
  <span><?php echo $text; ?></span>
393
  </fieldset>
@@ -397,7 +408,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView
397
  echo '<!-- ' . date('dMy H:i:s', $next) . ' --> ';
398
  echo sprintf(
399
  __('(or %s)', 'wp-security-audit-log'),
400
- '<a href="' . admin_url('admin-ajax.php?action=AjaxRunCleanup') . '">' . __('Run Manually', 'wp-security-audit-log') . '</a>'
401
  );
402
  ?></p>
403
  </td>
355
  <table class="form-table wsal-tab widefat" id="tab-audit-log">
356
  <tbody>
357
  <!-- Security Alerts Pruning -->
358
+ <?php
359
+ $disabled = '';
360
+ if ($this->_plugin->settings->IsArchivingEnabled()) {
361
+ $disabled = 'disabled';
362
+ ?>
363
+ <tr>
364
+ <td colspan="2">
365
+ <?php _e('The options below are disabled because you enabled archiving of alerts to the archiving table from', 'wp-security-audit-log'); ?>&nbsp;<a href="<?php echo admin_url('admin.php?page=wsal-ext-settings#mirroring'); ?>" target="_blank">here</a>
366
+ </td>
367
+ </tr>
368
+ <?php } ?>
369
  <tr>
370
  <th><label for="delete1"><?php _e('Security Alerts Pruning', 'wp-security-audit-log'); ?></label></th>
371
  <td>
373
  <?php $text = __('(eg: 1 month)', 'wp-security-audit-log'); ?>
374
  <?php $nbld = !($this->_plugin->settings->IsPruningDateEnabled() || $this->_plugin->settings->IsPruningLimitEnabled()); ?>
375
  <label for="delete0">
376
+ <input type="radio" id="delete0" name="PruneBy" value="" <?php if ($nbld) echo 'checked="checked"'; ?> <?php echo $disabled; ?>/>
377
  <?php echo __('None', 'wp-security-audit-log'); ?>
378
  </label>
379
  </fieldset>
381
  <?php $text = __('(eg: 1 month)', 'wp-security-audit-log'); ?>
382
  <?php $nbld = $this->_plugin->settings->IsPruningDateEnabled(); ?>
383
  <label for="delete1">
384
+ <input type="radio" id="delete1" name="PruneBy" value="date" <?php if($nbld)echo 'checked="checked"'; ?> <?php echo $disabled; ?>/>
385
  <?php echo __('Delete alerts older than', 'wp-security-audit-log'); ?>
386
  </label>
387
  <input type="text" id="PruningDate" name="PruningDate" placeholder="<?php echo $text; ?>"
388
  value="<?php echo esc_attr($this->_plugin->settings->GetPruningDate()); ?>"
389
+ onfocus="jQuery('#delete1').attr('checked', true);" <?php echo $disabled; ?>/>
390
  <span> <?php echo $text; ?></span>
391
  </fieldset>
392
  <fieldset>
393
  <?php $text = __('(eg: 80)', 'wp-security-audit-log'); ?>
394
  <?php $nbld = $this->_plugin->settings->IsPruningLimitEnabled(); ?>
395
  <label for="delete2">
396
+ <input type="radio" id="delete2" name="PruneBy" value="limit" <?php if($nbld)echo 'checked="checked"'; ?> <?php echo $disabled; ?>/>
397
  <?php echo __('Keep up to', 'wp-security-audit-log'); ?>
398
  </label>
399
  <input type="text" id="PruningLimit" name="PruningLimit" placeholder="<?php echo $text;?>"
400
  value="<?php echo esc_attr($this->_plugin->settings->GetPruningLimit()); ?>"
401
+ onfocus="jQuery('#delete2').attr('checked', true);" <?php echo $disabled; ?>/>
402
  <?php echo __('alerts', 'wp-security-audit-log'); ?>
403
  <span><?php echo $text; ?></span>
404
  </fieldset>
408
  echo '<!-- ' . date('dMy H:i:s', $next) . ' --> ';
409
  echo sprintf(
410
  __('(or %s)', 'wp-security-audit-log'),
411
+ '<a class="' .$disabled.'" href="' . admin_url('admin-ajax.php?action=AjaxRunCleanup') . '">' . __('Run Manually', 'wp-security-audit-log') . '</a>'
412
  );
413
  ?></p>
414
  </td>
css/settings.css CHANGED
@@ -139,3 +139,8 @@ input.switch[type="radio"]:disabled:checked + label {
139
  box-shadow: none;
140
  cursor: default;
141
  }
 
 
 
 
 
139
  box-shadow: none;
140
  cursor: default;
141
  }
142
+ a.disabled {
143
+ pointer-events: none;
144
+ cursor: default;
145
+ opacity: 0.6;
146
+ }
js/auditlog.js CHANGED
@@ -147,4 +147,19 @@ function WsalDisableCustom(link, meta_key){
147
  jQuery("h2:first").after(notice);
148
  }
149
  });
150
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  jQuery("h2:first").after(notice);
148
  }
149
  });
150
+ }
151
+
152
+ function WsalDBChange(value){
153
+ jQuery.ajax({
154
+ type: 'POST',
155
+ url: ajaxurl,
156
+ async: true,
157
+ data: {
158
+ action: 'AjaxSwitchDB',
159
+ selected_db: value
160
+ },
161
+ success: function() {
162
+ location.reload();
163
+ }
164
+ });
165
+ }
readme.txt CHANGED
@@ -7,7 +7,7 @@ License URI: http://www.gnu.org/licenses/gpl.html
7
  Tags: wordpress security plugin, wordpress security audit log, audit log, wordpress log, event log wordpress, wordpress user tracking, wordpress activity log, wordpress audit, security event log, audit trail, security audit trail, wordpress security alerts, wordpress monitor, wordpress security monitor, wordpress admin, wordpress admin monitoring, analytics, activity, admin, multisite, wordpress multisite, actions, dashboard, log, notification, wordpress monitoring, email notification, wordpress email alerts, tracking, user tracking, user activity report, wordpress audit trail
8
  Requires at least: 3.6
9
  Tested up to: 4.7
10
- Stable tag: 2.5.8
11
 
12
  Keep an audit trail of all changes and under the hood WordPress activity to ensure productivity and thwart possible WordPress hacker attacks.
13
 
@@ -113,6 +113,7 @@ WP Security Audit Log plugin also has a number of features that make WordPress a
113
 
114
  = As Featured On: =
115
 
 
116
  * [WP SmackDown](https://wpsmackdown.com/wp-plugins/wp-security-audit-log/)
117
  * [WPKube](http://www.wpkube.com/improve-wordpress-security-wp-security-audit-log/)
118
  * [ManageWP Plugins of the month](https://managewp.com/free-wordpress-plugins-june-2014)
@@ -122,7 +123,6 @@ WP Security Audit Log plugin also has a number of features that make WordPress a
122
  * [Pagely](https://pagely.com/blog/2015/01/log-wordpress-dashboard-activity-improved-security-auditing/)
123
  * [Design Wall](http://www.designwall.com/blog/10-wordpress-multisite-plugins-you-shouldnt-live-without/)
124
  * [WP Mayor](http://www.wpmayor.com/wp-security-audit-log-plugin-review-user-activity-logging-wordpress/)
125
- * [WPLift](http://wplift.com/wordpress-event-tracking)
126
  * [Tourqe News](http://torquemag.io/5-awesome-wordpress-plugins-you-may-not-have-heard-of/)
127
  * [Shout Me Loud](http://www.shoutmeloud.com/how-to-monitor-user-activities-wordpress-dashboard.html)
128
  * [Monster Post](http://blog.templatemonster.com/2015/12/15/wp-security-audit-log-plugin-review/)
@@ -179,9 +179,17 @@ Please refer to the [FAQs page](https://www.wpsecurityauditlog.com/documentation
179
  8. The Audit Log Viewer of a Super Admin in a WordPress multisite network installation with the Site selection drop down menu.
180
  9. If there are more than 15 sites in a multisite, an auto complete site search shows up instead of the drop down menu (see [screenshots](https://wordpress.org/plugins/wp-security-audit-log/screenshots/) for reference)
181
  10. WP Security Audit Log is integrated with the built-in revision system of WordPress, thus allowing you to see what content changes users make on your WordPress posts, pages and custom post types. For more information read [Keep Record of All WordPress Content Changes with WP Security Audit Log Plugin](http://www.wpsecurityauditlog.com/wordpress-user-monitoring-plugin-releases/record-all-wordpress-content-changes-wp-security-audit-log-plugin/)
 
182
 
183
  == Changelog ==
184
 
 
 
 
 
 
 
 
185
  = 2.5.8 (2016-11-09) =
186
 
187
  * **Plugin Improvement (Standardized all date & time formats and timezone)**
7
  Tags: wordpress security plugin, wordpress security audit log, audit log, wordpress log, event log wordpress, wordpress user tracking, wordpress activity log, wordpress audit, security event log, audit trail, security audit trail, wordpress security alerts, wordpress monitor, wordpress security monitor, wordpress admin, wordpress admin monitoring, analytics, activity, admin, multisite, wordpress multisite, actions, dashboard, log, notification, wordpress monitoring, email notification, wordpress email alerts, tracking, user tracking, user activity report, wordpress audit trail
8
  Requires at least: 3.6
9
  Tested up to: 4.7
10
+ Stable tag: 2.5.9
11
 
12
  Keep an audit trail of all changes and under the hood WordPress activity to ensure productivity and thwart possible WordPress hacker attacks.
13
 
113
 
114
  = As Featured On: =
115
 
116
+ * [WPLift](http://wplift.com/audit-wordpress-security-logs) - Review by Ahmad Awais
117
  * [WP SmackDown](https://wpsmackdown.com/wp-plugins/wp-security-audit-log/)
118
  * [WPKube](http://www.wpkube.com/improve-wordpress-security-wp-security-audit-log/)
119
  * [ManageWP Plugins of the month](https://managewp.com/free-wordpress-plugins-june-2014)
123
  * [Pagely](https://pagely.com/blog/2015/01/log-wordpress-dashboard-activity-improved-security-auditing/)
124
  * [Design Wall](http://www.designwall.com/blog/10-wordpress-multisite-plugins-you-shouldnt-live-without/)
125
  * [WP Mayor](http://www.wpmayor.com/wp-security-audit-log-plugin-review-user-activity-logging-wordpress/)
 
126
  * [Tourqe News](http://torquemag.io/5-awesome-wordpress-plugins-you-may-not-have-heard-of/)
127
  * [Shout Me Loud](http://www.shoutmeloud.com/how-to-monitor-user-activities-wordpress-dashboard.html)
128
  * [Monster Post](http://blog.templatemonster.com/2015/12/15/wp-security-audit-log-plugin-review/)
179
  8. The Audit Log Viewer of a Super Admin in a WordPress multisite network installation with the Site selection drop down menu.
180
  9. If there are more than 15 sites in a multisite, an auto complete site search shows up instead of the drop down menu (see [screenshots](https://wordpress.org/plugins/wp-security-audit-log/screenshots/) for reference)
181
  10. WP Security Audit Log is integrated with the built-in revision system of WordPress, thus allowing you to see what content changes users make on your WordPress posts, pages and custom post types. For more information read [Keep Record of All WordPress Content Changes with WP Security Audit Log Plugin](http://www.wpsecurityauditlog.com/wordpress-user-monitoring-plugin-releases/record-all-wordpress-content-changes-wp-security-audit-log-plugin/)
182
+ 11. Mirror the WordPress audit trail to an external solution such as Syslog or Papertrail to centralize logging, ensure logs are always available and cannot be tampered with in the unfortunate case of a hack attack.
183
 
184
  == Changelog ==
185
 
186
+ = 2.5.9 (2017-01-03) =
187
+
188
+ * **Support for new features in External DB Add-on:**
189
+ * [Mirroring of audit trail to Syslog](https://www.wpsecurityauditlog.com/wordpress-user-monitoring-plugin-documentation/faq-mirroring-wordpress-audit-trail-syslog/)
190
+ * [Mirroring of audit trail to Papertrail](https://www.wpsecurityauditlog.com/wordpress-user-monitoring-plugin-documentation/faq-mirroring-wordpress-audit-trail-papertrail/)
191
+ * Support for [archiving alerts from the audit trail in an external database](https://www.wpsecurityauditlog.com/wordpress-user-monitoring-plugin-documentation/faq-archiving-wordpress-audit-trail/).
192
+
193
  = 2.5.8 (2016-11-09) =
194
 
195
  * **Plugin Improvement (Standardized all date & time formats and timezone)**
wp-security-audit-log.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: WP Security Audit Log
4
  Plugin URI: http://www.wpsecurityauditlog.com/
5
  Description: Identify WordPress security issues before they become a problem. Keep track of everything happening on your WordPress including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Security Audit Log generates a security alert for everything that happens on your WordPress blogs and websites. Use the Audit Log Viewer included in the plugin to see all the security alerts.
6
  Author: WP White Security
7
- Version: 2.5.8
8
  Text Domain: wp-security-audit-log
9
  Author URI: http://www.wpsecurityauditlog.com/
10
  License: GPL2
@@ -576,9 +576,9 @@ class WpSecurityAuditLog {
576
  unset($this->_cleanup_hooks[$pos]);
577
  }
578
 
579
- public static function getConnector($config = null)
580
  {
581
- return WSAL_Connector_ConnectorFactory::getConnector($config);
582
  }
583
 
584
  /**
4
  Plugin URI: http://www.wpsecurityauditlog.com/
5
  Description: Identify WordPress security issues before they become a problem. Keep track of everything happening on your WordPress including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Security Audit Log generates a security alert for everything that happens on your WordPress blogs and websites. Use the Audit Log Viewer included in the plugin to see all the security alerts.
6
  Author: WP White Security
7
+ Version: 2.5.9
8
  Text Domain: wp-security-audit-log
9
  Author URI: http://www.wpsecurityauditlog.com/
10
  License: GPL2
576
  unset($this->_cleanup_hooks[$pos]);
577
  }
578
 
579
+ public static function getConnector($config = null, $reset = false)
580
  {
581
+ return WSAL_Connector_ConnectorFactory::getConnector($config, $reset);
582
  }
583
 
584
  /**