WP Security Audit Log - Version 2.4

Version Description

(2016-03-28) =

Read the WP Security Audit Log 2.4 release notes for a detailed overview of what is new.

  • New Features

    • Monitoring of WordPress menus changes from both admin pages and theme customizer.
    • New hook that allows users to create their own custom alerts. Read the WP Security Audit Log Custom Alerts documentation for more information.
    • New alerts for when a either a post, a post or a custom post type is scheduled.
  • New WordPress Security Alerts for Menus

    • 2078: User created a new menu
    • 2079: User added objects to menu
    • 2080: User removed object from menu
    • 2081: User deleted a menu
    • 2082: User changed menu settings
    • 2083: USer modified an object in menu
    • 2084: User renamed a menu
    • 2085: User changed the order of the objects in menu
  • New WordPress Security Alerts for Scheduled Items

    • 2074: User scheduled a post for publishing
    • 2075: User scheduled a page for publishing
    • 2076: User scheduled a custom post type for publishing
  • Bug Fixes

    • Fixed an issue where WordPress updated alerts were begin generated repeatedly upon accessing the updates page. Support Ticket
    • Fixed an issue where WordPress pruning was not working in an out of the box installation. Support Ticket
    • Fixed a conflict with Migrate DB. Support Ticket
Download this release

Release Info

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

Code changes from version 2.3.3 to 2.4

Files changed (43) hide show
  1. classes/AbstractSensor.php +37 -29
  2. classes/AlertManager.php +32 -14
  3. classes/Connector/AbstractConnector.php +36 -36
  4. classes/Connector/ConnectorFactory.php +87 -87
  5. classes/Connector/ConnectorInterface.php +11 -11
  6. classes/Connector/MySQLDBConnector.php +304 -257
  7. classes/Connector/wp-db-custom.php +36 -36
  8. classes/EDD_SL_Plugin_Updater.php +170 -170
  9. classes/Helpers/DataHelper.php +22 -22
  10. classes/Loggers/Database.php +7 -5
  11. classes/Models/ActiveRecord.php +267 -267
  12. classes/Models/Adapters/ActiveRecordInterface.php +15 -15
  13. classes/Models/Adapters/MetaInterface.php +13 -13
  14. classes/Models/Adapters/MySQL/ActiveRecordAdapter.php +448 -438
  15. classes/Models/Adapters/MySQL/MetaAdapter.php +53 -53
  16. classes/Models/Adapters/MySQL/OccurrenceAdapter.php +187 -187
  17. classes/Models/Adapters/MySQL/OptionAdapter.php +79 -79
  18. classes/Models/Adapters/MySQL/QueryAdapter.php +219 -219
  19. classes/Models/Adapters/OccurrenceInterface.php +11 -11
  20. classes/Models/Adapters/QueryInterface.php +8 -8
  21. classes/Models/Meta.php +34 -34
  22. classes/Models/Occurrence.php +199 -198
  23. classes/Models/OccurrenceQuery.php +29 -29
  24. classes/Models/Option.php +80 -80
  25. classes/Models/Query.php +187 -187
  26. classes/Sensors/BBPress.php +412 -410
  27. classes/Sensors/Content.php +34 -5
  28. classes/Sensors/CustomHooks.php +49 -0
  29. classes/Sensors/Database.php +132 -130
  30. classes/Sensors/LogInOut.php +0 -8
  31. classes/Sensors/Menus.php +416 -0
  32. classes/Sensors/MetaData.php +37 -38
  33. classes/Sensors/System.php +11 -9
  34. classes/Sensors/UserProfile.php +0 -5
  35. css/install-error.css +41 -41
  36. css/settings.css +70 -70
  37. defaults.php +21 -3
  38. js/auditlog.js +149 -149
  39. js/common.js +17 -17
  40. js/nice_r.js +11 -11
  41. js/settings.js +73 -73
  42. readme.txt +34 -2
  43. wp-security-audit-log.php +3 -3
classes/AbstractSensor.php CHANGED
@@ -1,35 +1,43 @@
1
  <?php
2
 
3
  abstract class WSAL_AbstractSensor {
4
- /**
5
- * @var WpSecurityAuditLog
6
- */
7
- protected $plugin;
8
 
9
- public function __construct(WpSecurityAuditLog $plugin){
10
- $this->plugin = $plugin;
11
- }
12
-
13
- abstract function HookEvents();
14
-
15
- protected function Log($type, $message, $args){
16
- $this->plugin->alerts->Trigger($type, array(
17
- 'Message' => $message,
18
- 'Context' => $args,
19
- 'Trace' => debug_backtrace(),
20
- ));
21
- }
22
-
23
- protected function LogError($message, $args){
24
- $this->Log(0001, $message, $args);
25
- }
26
-
27
- protected function LogWarn($message, $args){
28
- $this->Log(0002, $message, $args);
29
- }
30
-
31
- protected function LogInfo($message, $args){
32
- $this->Log(0003, $message, $args);
33
- }
 
 
 
 
 
 
 
 
34
 
35
  }
1
  <?php
2
 
3
  abstract class WSAL_AbstractSensor {
4
+ /**
5
+ * @var WpSecurityAuditLog
6
+ */
7
+ protected $plugin;
8
 
9
+ public function __construct(WpSecurityAuditLog $plugin){
10
+ $this->plugin = $plugin;
11
+ }
12
+
13
+ /**
14
+ * @return boolean Whether we are running on multisite or not.
15
+ */
16
+ protected function IsMultisite()
17
+ {
18
+ return function_exists('is_multisite') && is_multisite();
19
+ }
20
+
21
+ abstract function HookEvents();
22
+
23
+ protected function Log($type, $message, $args){
24
+ $this->plugin->alerts->Trigger($type, array(
25
+ 'Message' => $message,
26
+ 'Context' => $args,
27
+ 'Trace' => debug_backtrace(),
28
+ ));
29
+ }
30
+
31
+ protected function LogError($message, $args){
32
+ $this->Log(0001, $message, $args);
33
+ }
34
+
35
+ protected function LogWarn($message, $args){
36
+ $this->Log(0002, $message, $args);
37
+ }
38
+
39
+ protected function LogInfo($message, $args){
40
+ $this->Log(0003, $message, $args);
41
+ }
42
 
43
  }
classes/AlertManager.php CHANGED
@@ -253,25 +253,43 @@ final class WSAL_AlertManager {
253
  * @param integer $type Alert type.
254
  * @param array $data Misc alert data.
255
  */
256
- protected function Log($type, $data = array()){
257
- if(!isset($data['ClientIP']))
258
- $data['ClientIP'] = $this->plugin->settings->GetMainClientIP();
259
- if(!isset($data['OtherIPs']) && $this->plugin->settings->IsMainIPFromProxy())
260
- $data['OtherIPs'] = $this->plugin->settings->GetClientIPs();
261
- if(!isset($data['UserAgent']))
262
- $data['UserAgent'] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
263
- if(!isset($data['Username']) && !isset($data['CurrentUserID']))
264
- $data['CurrentUserID'] = function_exists('get_current_user_id') ? get_current_user_id() : 0;
265
- if(!isset($data['CurrentUserRoles']) && function_exists('is_user_logged_in') && is_user_logged_in())
266
- $data['CurrentUserRoles'] = $this->plugin->settings->GetCurrentUserRoles();
267
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  //if(isset($_SERVER['REMOTE_HOST']) && $_SERVER['REMOTE_HOST'] != $data['ClientIP'])
269
  // $data['ClientHost'] = $_SERVER['REMOTE_HOST'];
270
-
271
  //$data['OtherIPs'] = $_SERVER['REMOTE_HOST'];
272
 
273
- foreach($this->_loggers as $logger)
274
  $logger->Log($type, $data);
 
275
  }
276
 
277
  /**
253
  * @param integer $type Alert type.
254
  * @param array $data Misc alert data.
255
  */
256
+ protected function Log($type, $data = array())
257
+ {
258
+ if (!isset($data['ClientIP'])) {
259
+ $clientIP = $this->plugin->settings->GetMainClientIP();
260
+ if (!empty($clientIP)) {
261
+ $data['ClientIP'] = $clientIP;
262
+ }
263
+ }
264
+ if (!isset($data['OtherIPs']) && $this->plugin->settings->IsMainIPFromProxy()) {
265
+ $otherIPs = $this->plugin->settings->GetClientIPs();
266
+ if (!empty($otherIPs)) {
267
+ $data['OtherIPs'] = $otherIPs;
268
+ }
269
+ }
270
+ if (!isset($data['UserAgent'])) {
271
+ if (isset($_SERVER['HTTP_USER_AGENT'])) {
272
+ $data['UserAgent'] = $_SERVER['HTTP_USER_AGENT'];
273
+ }
274
+ }
275
+ if (!isset($data['Username']) && !isset($data['CurrentUserID'])) {
276
+ if (function_exists('get_current_user_id')) {
277
+ $data['CurrentUserID'] = get_current_user_id();
278
+ }
279
+ }
280
+ if (!isset($data['CurrentUserRoles']) && function_exists('is_user_logged_in') && is_user_logged_in()) {
281
+ $currentUserRoles = $this->plugin->settings->GetCurrentUserRoles();
282
+ if (!empty($currentUserRoles)) {
283
+ $data['CurrentUserRoles'] = $currentUserRoles;
284
+ }
285
+ }
286
  //if(isset($_SERVER['REMOTE_HOST']) && $_SERVER['REMOTE_HOST'] != $data['ClientIP'])
287
  // $data['ClientHost'] = $_SERVER['REMOTE_HOST'];
 
288
  //$data['OtherIPs'] = $_SERVER['REMOTE_HOST'];
289
 
290
+ foreach ($this->_loggers as $logger) {
291
  $logger->Log($type, $data);
292
+ }
293
  }
294
 
295
  /**
classes/Connector/AbstractConnector.php CHANGED
@@ -1,36 +1,36 @@
1
- <?php
2
- require_once('ConnectorInterface.php');
3
-
4
- abstract class WSAL_Connector_AbstractConnector
5
- {
6
- protected $connection = null;
7
- protected $adaptersBasePath = null;
8
- protected $adaptersDirName = null;
9
-
10
- public function __construct($adaptersDirName = null)
11
- {
12
- $this->adaptersBasePath = __DIR__ . DIRECTORY_SEPARATOR .'..'. DIRECTORY_SEPARATOR .'Models'. DIRECTORY_SEPARATOR .'Adapters'. DIRECTORY_SEPARATOR;
13
-
14
- require_once($this->adaptersBasePath . 'ActiveRecordInterface.php');
15
- require_once($this->adaptersBasePath . 'MetaInterface.php');
16
- require_once($this->adaptersBasePath . 'OccurrenceInterface.php');
17
- require_once($this->adaptersBasePath . 'QueryInterface.php');
18
-
19
- if (!empty($adaptersDirName)) {
20
- $this->adaptersDirName = $adaptersDirName;
21
- require_once($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'ActiveRecordAdapter.php');
22
- require_once($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'MetaAdapter.php');
23
- require_once($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'OccurrenceAdapter.php');
24
- require_once($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'QueryAdapter.php');
25
- }
26
- }
27
-
28
- public function getAdaptersDirectory()
29
- {
30
- if (!empty($this->adaptersBasePath) && !empty($this->adaptersDirName)) {
31
- return $this->adaptersBasePath . $this->adaptersDirName;
32
- } else {
33
- return false;
34
- }
35
- }
36
- }
1
+ <?php
2
+ require_once('ConnectorInterface.php');
3
+
4
+ abstract class WSAL_Connector_AbstractConnector
5
+ {
6
+ protected $connection = null;
7
+ protected $adaptersBasePath = null;
8
+ protected $adaptersDirName = null;
9
+
10
+ public function __construct($adaptersDirName = null)
11
+ {
12
+ $this->adaptersBasePath = __DIR__ . DIRECTORY_SEPARATOR .'..'. DIRECTORY_SEPARATOR .'Models'. DIRECTORY_SEPARATOR .'Adapters'. DIRECTORY_SEPARATOR;
13
+
14
+ require_once($this->adaptersBasePath . 'ActiveRecordInterface.php');
15
+ require_once($this->adaptersBasePath . 'MetaInterface.php');
16
+ require_once($this->adaptersBasePath . 'OccurrenceInterface.php');
17
+ require_once($this->adaptersBasePath . 'QueryInterface.php');
18
+
19
+ if (!empty($adaptersDirName)) {
20
+ $this->adaptersDirName = $adaptersDirName;
21
+ require_once($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'ActiveRecordAdapter.php');
22
+ require_once($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'MetaAdapter.php');
23
+ require_once($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'OccurrenceAdapter.php');
24
+ require_once($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'QueryAdapter.php');
25
+ }
26
+ }
27
+
28
+ public function getAdaptersDirectory()
29
+ {
30
+ if (!empty($this->adaptersBasePath) && !empty($this->adaptersDirName)) {
31
+ return $this->adaptersBasePath . $this->adaptersDirName;
32
+ } else {
33
+ return false;
34
+ }
35
+ }
36
+ }
classes/Connector/ConnectorFactory.php CHANGED
@@ -1,87 +1,87 @@
1
- <?php
2
- require_once(__DIR__ . DIRECTORY_SEPARATOR .'..'. DIRECTORY_SEPARATOR .'Settings.php');
3
- require_once('MySQLDBConnector.php');
4
-
5
- abstract class WSAL_Connector_ConnectorFactory
6
- {
7
- public static $connector;
8
- public static $defaultConnector;
9
- public static $adapter;
10
-
11
- /**
12
- * Returns the a default WPDB connector for saving options
13
- */
14
- public static function GetDefaultConnector()
15
- {
16
- return new WSAL_Connector_MySQLDB();
17
- }
18
-
19
- /**
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;
27
- } else {
28
- $connectionConfig = self::GetConfig();
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':
36
- default:
37
- //use config
38
- self::$connector = new WSAL_Connector_MySQLDB($connectionConfig);
39
- }
40
- }
41
- return self::$connector;
42
- }
43
-
44
- public static function GetConfig()
45
- {
46
- $conf = new WSAL_Settings(WpSecurityAuditLog::GetInstance());
47
- $type = $conf->GetAdapterConfig('adapter-type');
48
- if (empty($type)) {
49
- return null;
50
- } else {
51
- return array(
52
- 'type' => $conf->GetAdapterConfig('adapter-type'),
53
- 'user' => $conf->GetAdapterConfig('adapter-user'),
54
- 'password' => $conf->GetAdapterConfig('adapter-password'),
55
- 'name' => $conf->GetAdapterConfig('adapter-name'),
56
- 'hostname' => $conf->GetAdapterConfig('adapter-hostname'),
57
- 'base_prefix' => $conf->GetAdapterConfig('adapter-base-prefix')
58
- );
59
- }
60
- }
61
-
62
- public static function CheckConfig($type, $user, $password, $name, $hostname, $base_prefix)
63
- {
64
- $result = false;
65
- $config = self::GetConfigArray($type, $user, $password, $name, $hostname, $base_prefix);
66
- switch (strtolower($type)) {
67
- //TO DO: Add other connectors
68
- case 'mysql':
69
- default:
70
- $test = new WSAL_Connector_MySQLDB($config);
71
- $result = $test->TestConnection();
72
- }
73
- return $result;
74
- }
75
-
76
- public static function GetConfigArray($type, $user, $password, $name, $hostname, $base_prefix)
77
- {
78
- return array(
79
- 'type' => $type,
80
- 'user' => $user,
81
- 'password' => $password,
82
- 'name' => $name,
83
- 'hostname' => $hostname,
84
- 'base_prefix' => $base_prefix
85
- );
86
- }
87
- }
1
+ <?php
2
+ require_once(__DIR__ . DIRECTORY_SEPARATOR .'..'. DIRECTORY_SEPARATOR .'Settings.php');
3
+ require_once('MySQLDBConnector.php');
4
+
5
+ abstract class WSAL_Connector_ConnectorFactory
6
+ {
7
+ public static $connector;
8
+ public static $defaultConnector;
9
+ public static $adapter;
10
+
11
+ /**
12
+ * Returns the a default WPDB connector for saving options
13
+ */
14
+ public static function GetDefaultConnector()
15
+ {
16
+ return new WSAL_Connector_MySQLDB();
17
+ }
18
+
19
+ /**
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;
27
+ } else {
28
+ $connectionConfig = self::GetConfig();
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':
36
+ default:
37
+ //use config
38
+ self::$connector = new WSAL_Connector_MySQLDB($connectionConfig);
39
+ }
40
+ }
41
+ return self::$connector;
42
+ }
43
+
44
+ public static function GetConfig()
45
+ {
46
+ $conf = new WSAL_Settings(WpSecurityAuditLog::GetInstance());
47
+ $type = $conf->GetAdapterConfig('adapter-type');
48
+ if (empty($type)) {
49
+ return null;
50
+ } else {
51
+ return array(
52
+ 'type' => $conf->GetAdapterConfig('adapter-type'),
53
+ 'user' => $conf->GetAdapterConfig('adapter-user'),
54
+ 'password' => $conf->GetAdapterConfig('adapter-password'),
55
+ 'name' => $conf->GetAdapterConfig('adapter-name'),
56
+ 'hostname' => $conf->GetAdapterConfig('adapter-hostname'),
57
+ 'base_prefix' => $conf->GetAdapterConfig('adapter-base-prefix')
58
+ );
59
+ }
60
+ }
61
+
62
+ public static function CheckConfig($type, $user, $password, $name, $hostname, $base_prefix)
63
+ {
64
+ $result = false;
65
+ $config = self::GetConfigArray($type, $user, $password, $name, $hostname, $base_prefix);
66
+ switch (strtolower($type)) {
67
+ //TO DO: Add other connectors
68
+ case 'mysql':
69
+ default:
70
+ $test = new WSAL_Connector_MySQLDB($config);
71
+ $result = $test->TestConnection();
72
+ }
73
+ return $result;
74
+ }
75
+
76
+ public static function GetConfigArray($type, $user, $password, $name, $hostname, $base_prefix)
77
+ {
78
+ return array(
79
+ 'type' => $type,
80
+ 'user' => $user,
81
+ 'password' => $password,
82
+ 'name' => $name,
83
+ 'hostname' => $hostname,
84
+ 'base_prefix' => $base_prefix
85
+ );
86
+ }
87
+ }
classes/Connector/ConnectorInterface.php CHANGED
@@ -1,11 +1,11 @@
1
- <?php
2
-
3
- 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();
10
- public function uninstallAll();
11
- }
1
+ <?php
2
+
3
+ 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();
10
+ public function uninstallAll();
11
+ }
classes/Connector/MySQLDBConnector.php CHANGED
@@ -1,257 +1,304 @@
1
- <?php
2
- require_once('ConnectorInterface.php');
3
- require_once('AbstractConnector.php');
4
- require_once('wp-db-custom.php');
5
-
6
- class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements WSAL_Connector_ConnectorInterface
7
- {
8
- protected $connectionConfig = null;
9
-
10
- public function __construct($connectionConfig = null)
11
- {
12
- $this->connectionConfig = $connectionConfig;
13
- parent::__construct("MySQL");
14
- require_once($this->getAdaptersDirectory() . '/OptionAdapter.php');
15
- }
16
-
17
- public function TestConnection()
18
- {
19
- error_reporting(E_ALL ^ E_WARNING);
20
- $connectionConfig = $this->connectionConfig;
21
- $password = $this->decryptString($connectionConfig['password']);
22
- $newWpdb = new wpdbCustom($connectionConfig['user'], $password, $connectionConfig['name'], $connectionConfig['hostname']);
23
- if (!$newWpdb->has_connected) { // Database Error
24
- throw new Exception("Connection failed. Please check your connection details.");
25
- }
26
- }
27
-
28
- /**
29
- * Creates a connection and returns it
30
- * @return Instance of WPDB
31
- */
32
- private function createConnection()
33
- {
34
- if (!empty($this->connectionConfig)) {
35
- //TO DO: Use the provided connection config
36
- $connectionConfig = $this->connectionConfig;
37
- $password = $this->decryptString($connectionConfig['password']);
38
- $newWpdb = new wpdb($connectionConfig['user'], $password, $connectionConfig['name'], $connectionConfig['hostname']);
39
- $newWpdb->set_prefix($connectionConfig['base_prefix']);
40
- return $newWpdb;
41
- } else {
42
- global $wpdb;
43
- return $wpdb;
44
- }
45
- }
46
-
47
- /**
48
- * Returns a wpdb instance
49
- */
50
- public function getConnection()
51
- {
52
- if (!empty($this->connection)) {
53
- return $this->connection;
54
- } else {
55
- $this->connection = $this->createConnection();
56
- return $this->connection;
57
- }
58
- }
59
-
60
- /**
61
- * Gets an adapter for the specified model
62
- */
63
- public function getAdapter($class_name)
64
- {
65
- $objName = $this->getAdapterClassName($class_name);
66
- return new $objName($this->getConnection());
67
- }
68
-
69
- protected function getAdapterClassName($class_name)
70
- {
71
- return 'WSAL_Adapters_MySQL_'.$class_name;
72
- }
73
-
74
- /**
75
- * Checks if the necessary tables are available
76
- */
77
- public function isInstalled()
78
- {
79
- global $wpdb;
80
- $table = $wpdb->base_prefix . 'wsal_occurrences';
81
- return ($wpdb->get_var('SHOW TABLES LIKE "'.$table.'"') == $table);
82
- }
83
-
84
- /**
85
- * Checks if old version tables are available
86
- */
87
- public function canMigrate()
88
- {
89
- $wpdb = $this->getConnection();
90
- $table = $wpdb->base_prefix . 'wordpress_auditlog_events';
91
- return ($wpdb->get_var('SHOW TABLES LIKE "'.$table.'"') == $table);
92
- }
93
-
94
- /**
95
- * Install all DB tables.
96
- */
97
- public function installAll($excludeOptions = false)
98
- {
99
- $plugin = WpSecurityAuditLog::GetInstance();
100
-
101
- foreach (glob($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . '*.php') as $file) {
102
- $filePath = explode(DIRECTORY_SEPARATOR, $file);
103
- $fileName = $filePath[count($filePath) - 1];
104
- $className = $this->getAdapterClassName(str_replace("Adapter.php", "", $fileName));
105
-
106
- $class = new $className($this->getConnection());
107
- if ($excludeOptions && $class instanceof WSAL_Adapters_MySQL_Option) {
108
- continue;
109
- }
110
-
111
- if (is_subclass_of($class, "WSAL_Adapters_MySQL_ActiveRecord")) {
112
- $class->Install();
113
- }
114
- }
115
- }
116
-
117
- /**
118
- * Uninstall all DB tables.
119
- */
120
- public function uninstallAll()
121
- {
122
- $plugin = WpSecurityAuditLog::GetInstance();
123
-
124
- foreach (glob($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . '*.php') as $file) {
125
- $filePath = explode(DIRECTORY_SEPARATOR, $file);
126
- $fileName = $filePath[count($filePath) - 1];
127
- $className = $this->getAdapterClassName(str_replace("Adapter.php", "", $fileName));
128
-
129
- $class = new $className($this->getConnection());
130
- if (is_subclass_of($class, "WSAL_Adapters_MySQL_ActiveRecord")) {
131
- $class->Uninstall();
132
- }
133
- }
134
- }
135
-
136
- public function Migrate()
137
- {
138
- global $wpdb;
139
- $_wpdb = $this->getConnection();
140
-
141
- // Load data Occurrences from WP
142
- $occurrence = new WSAL_Adapters_MySQL_Occurrence($wpdb);
143
- if (!$occurrence->IsInstalled()) die("No alerts to import");
144
- $sql = 'SELECT * FROM ' . $occurrence->GetWPTable();
145
- $occurrences = $wpdb->get_results($sql, ARRAY_A);
146
-
147
- // Insert data to External DB
148
- $occurrenceNew = new WSAL_Adapters_MySQL_Occurrence($_wpdb);
149
- $increase_id = 0;
150
- $sql = 'SELECT MAX(id) FROM ' . $occurrenceNew->GetTable();
151
- $increase_id = (int)$_wpdb->get_var($sql);
152
-
153
- $sql = 'INSERT INTO ' . $occurrenceNew->GetTable() . ' (site_id, alert_id, created_on, is_read, is_migrated) VALUES ' ;
154
- foreach ($occurrences as $entry) {
155
- $sql .= '('.$entry['site_id'].', '.$entry['alert_id'].', '.$entry['created_on'].', '.$entry['is_read'].', 1), ';
156
- }
157
- $sql = rtrim($sql, ", ");
158
- $_wpdb->query($sql);
159
-
160
- // Load data Meta from WP
161
- $meta = new WSAL_Adapters_MySQL_Meta($wpdb);
162
- if (!$meta->IsInstalled()) die("No alerts to import");
163
- $sql = 'SELECT * FROM ' . $meta->GetWPTable();
164
- $metadata = $wpdb->get_results($sql, ARRAY_A);
165
-
166
- // Insert data to External DB
167
- $metaNew = new WSAL_Adapters_MySQL_Meta($_wpdb);
168
- $sql = 'INSERT INTO ' . $metaNew->GetTable() . ' (occurrence_id, name, value) VALUES ' ;
169
- foreach ($metadata as $entry) {
170
- $occurrence_id = $entry['occurrence_id'] + $increase_id;
171
- $sql .= '('.$occurrence_id.', \''.$entry['name'].'\', \''.$entry['value'].'\'), ';
172
- }
173
- $sql = rtrim($sql, ", ");
174
- $_wpdb->query($sql);
175
- $this->DeleteAfterMigrate($occurrence);
176
- $this->DeleteAfterMigrate($meta);
177
- }
178
-
179
- public function MigrateBack()
180
- {
181
- global $wpdb;
182
- $_wpdb = $this->getConnection();
183
-
184
- // Load data Occurrences from External DB
185
- $occurrence = new WSAL_Adapters_MySQL_Occurrence($_wpdb);
186
- if (!$occurrence->IsInstalled()) die("No alerts to import");
187
- $sql = 'SELECT * FROM ' . $occurrence->GetTable();
188
- $occurrences = $_wpdb->get_results($sql, ARRAY_A);
189
-
190
- // Insert data to WP
191
- $occurrenceWP = new WSAL_Adapters_MySQL_Occurrence($wpdb);
192
-
193
- $sql = 'INSERT INTO ' . $occurrenceWP->GetWPTable() . ' (site_id, alert_id, created_on, is_read, is_migrated) VALUES ' ;
194
- foreach ($occurrences as $entry) {
195
- $sql .= '('.$entry['site_id'].', '.$entry['alert_id'].', '.$entry['created_on'].', '.$entry['is_read'].', 1), ';
196
- }
197
- $sql = rtrim($sql, ", ");
198
- $wpdb->query($sql);
199
-
200
- // Load data Meta from External DB
201
- $meta = new WSAL_Adapters_MySQL_Meta($_wpdb);
202
- if (!$meta->IsInstalled()) die("No alerts to import");
203
- $sql = 'SELECT * FROM ' . $meta->GetTable();
204
- $metadata = $_wpdb->get_results($sql, ARRAY_A);
205
-
206
- // Insert data to WP
207
- $metaWP = new WSAL_Adapters_MySQL_Meta($wpdb);
208
- $sql = 'INSERT INTO ' . $metaWP->GetWPTable() . ' (occurrence_id, name, value) VALUES ' ;
209
- foreach ($metadata as $entry) {
210
- $sql .= '('.$entry['occurrence_id'].', \''.$entry['name'].'\', \''.$entry['value'].'\'), ';
211
- }
212
- $sql = rtrim($sql, ", ");
213
- $wpdb->query($sql);
214
- }
215
-
216
- private function DeleteAfterMigrate($record)
217
- {
218
- global $wpdb;
219
- $sql = 'DROP TABLE IF EXISTS ' . $record->GetTable();
220
- $wpdb->query($sql);
221
- }
222
-
223
- public function encryptString($plaintext)
224
- {
225
- $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
226
- $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
227
- $key = $this->truncateKey();
228
- $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv);
229
- $ciphertext = $iv . $ciphertext;
230
- $ciphertext_base64 = base64_encode($ciphertext);
231
-
232
- return $ciphertext_base64;
233
- }
234
-
235
- private function decryptString($ciphertext_base64)
236
- {
237
- $ciphertext_dec = base64_decode($ciphertext_base64);
238
- $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
239
-
240
- $iv_dec = substr($ciphertext_dec, 0, $iv_size);
241
- $ciphertext_dec = substr($ciphertext_dec, $iv_size);
242
- $key = $this->truncateKey();
243
- $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
244
-
245
- return rtrim($plaintext_dec, "\0");
246
- }
247
-
248
- private function truncateKey()
249
- {
250
- $key_size = strlen(AUTH_KEY);
251
- if ($key_size > 32) {
252
- return substr(AUTH_KEY, 0, 32);
253
- } else {
254
- return AUTH_KEY;
255
- }
256
- }
257
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once('ConnectorInterface.php');
3
+ require_once('AbstractConnector.php');
4
+ require_once('wp-db-custom.php');
5
+
6
+ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements WSAL_Connector_ConnectorInterface
7
+ {
8
+ protected $connectionConfig = null;
9
+
10
+ public function __construct($connectionConfig = null)
11
+ {
12
+ @ini_set('memory_limit', '256M');
13
+
14
+ $this->connectionConfig = $connectionConfig;
15
+ parent::__construct("MySQL");
16
+ require_once($this->getAdaptersDirectory() . '/OptionAdapter.php');
17
+ }
18
+
19
+ public function TestConnection()
20
+ {
21
+ error_reporting(E_ALL ^ E_WARNING);
22
+ $connectionConfig = $this->connectionConfig;
23
+ $password = $this->decryptString($connectionConfig['password']);
24
+ $newWpdb = new wpdbCustom($connectionConfig['user'], $password, $connectionConfig['name'], $connectionConfig['hostname']);
25
+ if (!$newWpdb->has_connected) { // Database Error
26
+ throw new Exception("Connection failed. Please check your connection details.");
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Creates a connection and returns it
32
+ * @return Instance of WPDB
33
+ */
34
+ private function createConnection()
35
+ {
36
+ if (!empty($this->connectionConfig)) {
37
+ //TO DO: Use the provided connection config
38
+ $connectionConfig = $this->connectionConfig;
39
+ $password = $this->decryptString($connectionConfig['password']);
40
+ $newWpdb = new wpdb($connectionConfig['user'], $password, $connectionConfig['name'], $connectionConfig['hostname']);
41
+ $newWpdb->set_prefix($connectionConfig['base_prefix']);
42
+ return $newWpdb;
43
+ } else {
44
+ global $wpdb;
45
+ return $wpdb;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Returns a wpdb instance
51
+ */
52
+ public function getConnection()
53
+ {
54
+ if (!empty($this->connection)) {
55
+ return $this->connection;
56
+ } else {
57
+ $this->connection = $this->createConnection();
58
+ return $this->connection;
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Gets an adapter for the specified model
64
+ */
65
+ public function getAdapter($class_name)
66
+ {
67
+ $objName = $this->getAdapterClassName($class_name);
68
+ return new $objName($this->getConnection());
69
+ }
70
+
71
+ protected function getAdapterClassName($class_name)
72
+ {
73
+ return 'WSAL_Adapters_MySQL_'.$class_name;
74
+ }
75
+
76
+ /**
77
+ * Checks if the necessary tables are available
78
+ */
79
+ public function isInstalled()
80
+ {
81
+ global $wpdb;
82
+ $table = $wpdb->base_prefix . 'wsal_occurrences';
83
+ return ($wpdb->get_var('SHOW TABLES LIKE "'.$table.'"') == $table);
84
+ }
85
+
86
+ /**
87
+ * Checks if old version tables are available
88
+ */
89
+ public function canMigrate()
90
+ {
91
+ $wpdb = $this->getConnection();
92
+ $table = $wpdb->base_prefix . 'wordpress_auditlog_events';
93
+ return ($wpdb->get_var('SHOW TABLES LIKE "'.$table.'"') == $table);
94
+ }
95
+
96
+ /**
97
+ * Install all DB tables.
98
+ */
99
+ public function installAll($excludeOptions = false)
100
+ {
101
+ $plugin = WpSecurityAuditLog::GetInstance();
102
+
103
+ foreach (glob($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . '*.php') as $file) {
104
+ $filePath = explode(DIRECTORY_SEPARATOR, $file);
105
+ $fileName = $filePath[count($filePath) - 1];
106
+ $className = $this->getAdapterClassName(str_replace("Adapter.php", "", $fileName));
107
+
108
+ $class = new $className($this->getConnection());
109
+ if ($excludeOptions && $class instanceof WSAL_Adapters_MySQL_Option) {
110
+ continue;
111
+ }
112
+
113
+ if (is_subclass_of($class, "WSAL_Adapters_MySQL_ActiveRecord")) {
114
+ $class->Install();
115
+ }
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Uninstall all DB tables.
121
+ */
122
+ public function uninstallAll()
123
+ {
124
+ $plugin = WpSecurityAuditLog::GetInstance();
125
+
126
+ foreach (glob($this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . '*.php') as $file) {
127
+ $filePath = explode(DIRECTORY_SEPARATOR, $file);
128
+ $fileName = $filePath[count($filePath) - 1];
129
+ $className = $this->getAdapterClassName(str_replace("Adapter.php", "", $fileName));
130
+
131
+ $class = new $className($this->getConnection());
132
+ if (is_subclass_of($class, "WSAL_Adapters_MySQL_ActiveRecord")) {
133
+ $class->Uninstall();
134
+ }
135
+ }
136
+ }
137
+
138
+ public function Migrate()
139
+ {
140
+ global $wpdb;
141
+ $_wpdb = $this->getConnection();
142
+
143
+ // Load data Occurrences from WP
144
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence($wpdb);
145
+ if (!$occurrence->IsInstalled()) die("No alerts to import");
146
+ $sql = 'SELECT * FROM ' . $occurrence->GetWPTable();
147
+ $occurrences = $wpdb->get_results($sql, ARRAY_A);
148
+
149
+ // Insert data to External DB
150
+ if (!empty($occurrences)) {
151
+ $occurrenceNew = new WSAL_Adapters_MySQL_Occurrence($_wpdb);
152
+ $increase_id = 0;
153
+ $sql = 'SELECT MAX(id) FROM ' . $occurrenceNew->GetTable();
154
+ $increase_id = (int)$_wpdb->get_var($sql);
155
+ // split data
156
+ $occurrences_splited = $this->array_split($occurrences, 3);
157
+ foreach ($occurrences_splited as $occurrences_partition) {
158
+ if (!empty($occurrences_partition)) {
159
+ $sql = 'INSERT INTO ' . $occurrenceNew->GetTable() . ' (site_id, alert_id, created_on, is_read) VALUES ' ;
160
+ foreach ($occurrences_partition as $entry) {
161
+ $sql .= '('.$entry['site_id'].', '.$entry['alert_id'].', '.$entry['created_on'].', '.$entry['is_read'].'), ';
162
+ }
163
+ $sql = rtrim($sql, ", ");
164
+ $_wpdb->query($sql);
165
+ }
166
+ }
167
+ }
168
+
169
+ // Load data Meta from WP
170
+ $meta = new WSAL_Adapters_MySQL_Meta($wpdb);
171
+ if (!$meta->IsInstalled()) die("No alerts to import");
172
+ $sql = 'SELECT * FROM ' . $meta->GetWPTable();
173
+ $metadata = $wpdb->get_results($sql, ARRAY_A);
174
+
175
+ // Insert data to External DB
176
+ if (!empty($metadata)) {
177
+ $metaNew = new WSAL_Adapters_MySQL_Meta($_wpdb);
178
+ // split data
179
+ $metadata_splited = $this->array_split($metadata, 3);
180
+ foreach ($metadata_splited as $metadata_partition) {
181
+ if (!empty($metadata_partition)) {
182
+ $sql = 'INSERT INTO ' . $metaNew->GetTable() . ' (occurrence_id, name, value) VALUES ' ;
183
+ foreach ($metadata_partition as $entry) {
184
+ $occurrence_id = $entry['occurrence_id'] + $increase_id;
185
+ $sql .= '('.$occurrence_id.', \''.$entry['name'].'\', \''.$entry['value'].'\'), ';
186
+ }
187
+ $sql = rtrim($sql, ", ");
188
+ $_wpdb->query($sql);
189
+ }
190
+ }
191
+ }
192
+ $this->DeleteAfterMigrate($occurrence);
193
+ $this->DeleteAfterMigrate($meta);
194
+ }
195
+
196
+ public function MigrateBack()
197
+ {
198
+ global $wpdb;
199
+ $_wpdb = $this->getConnection();
200
+
201
+ // Load data Occurrences from External DB
202
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence($_wpdb);
203
+ if (!$occurrence->IsInstalled()) die("No alerts to import");
204
+ $sql = 'SELECT * FROM ' . $occurrence->GetTable();
205
+ $occurrences = $_wpdb->get_results($sql, ARRAY_A);
206
+
207
+ // Insert data to WP
208
+ if (!empty($occurrences)) {
209
+ $occurrenceWP = new WSAL_Adapters_MySQL_Occurrence($wpdb);
210
+ // split data
211
+ $occurrences_splited = $this->array_split($occurrences, 3);
212
+ foreach ($occurrences_splited as $occurrences_partition) {
213
+ if (!empty($occurrences_partition)) {
214
+ $sql = 'INSERT INTO ' . $occurrenceWP->GetWPTable() . ' (id, site_id, alert_id, created_on, is_read) VALUES ' ;
215
+ foreach ($occurrences_partition as $entry) {
216
+ $sql .= '('.$entry['id'].', '.$entry['site_id'].', '.$entry['alert_id'].', '.$entry['created_on'].', '.$entry['is_read'].'), ';
217
+ }
218
+ $sql = rtrim($sql, ", ");
219
+ $wpdb->query($sql);
220
+ }
221
+ }
222
+ }
223
+
224
+ // Load data Meta from External DB
225
+ $meta = new WSAL_Adapters_MySQL_Meta($_wpdb);
226
+ if (!$meta->IsInstalled()) die("No alerts to import");
227
+ $sql = 'SELECT * FROM ' . $meta->GetTable();
228
+ $metadata = $_wpdb->get_results($sql, ARRAY_A);
229
+
230
+ // Insert data to WP
231
+ if (!empty($metadata)) {
232
+ $metaWP = new WSAL_Adapters_MySQL_Meta($wpdb);
233
+ // split data
234
+ $metadata_splited = $this->array_split($metadata, 3);
235
+ foreach ($metadata_splited as $metadata_partition) {
236
+ if (!empty($metadata_partition)) {
237
+ $sql = 'INSERT INTO ' . $metaWP->GetWPTable() . ' (occurrence_id, name, value) VALUES ' ;
238
+ foreach ($metadata_partition as $entry) {
239
+ $sql .= '('.$entry['occurrence_id'].', \''.$entry['name'].'\', \''.$entry['value'].'\'), ';
240
+ }
241
+ $sql = rtrim($sql, ", ");
242
+ $wpdb->query($sql);
243
+ }
244
+ }
245
+ }
246
+ }
247
+
248
+ private function DeleteAfterMigrate($record)
249
+ {
250
+ global $wpdb;
251
+ $sql = 'DROP TABLE IF EXISTS ' . $record->GetTable();
252
+ $wpdb->query($sql);
253
+ }
254
+
255
+ public function encryptString($plaintext)
256
+ {
257
+ $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
258
+ $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
259
+ $key = $this->truncateKey();
260
+ $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv);
261
+ $ciphertext = $iv . $ciphertext;
262
+ $ciphertext_base64 = base64_encode($ciphertext);
263
+
264
+ return $ciphertext_base64;
265
+ }
266
+
267
+ private function decryptString($ciphertext_base64)
268
+ {
269
+ $ciphertext_dec = base64_decode($ciphertext_base64);
270
+ $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
271
+
272
+ $iv_dec = substr($ciphertext_dec, 0, $iv_size);
273
+ $ciphertext_dec = substr($ciphertext_dec, $iv_size);
274
+ $key = $this->truncateKey();
275
+ $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
276
+
277
+ return rtrim($plaintext_dec, "\0");
278
+ }
279
+
280
+ private function truncateKey()
281
+ {
282
+ if (!defined('AUTH_KEY')) {
283
+ return 'x4>Tg@G-Kr6a]o-eJeP^?UO)KW;LbV)I';
284
+ }
285
+ $key_size = strlen(AUTH_KEY);
286
+ if ($key_size > 32) {
287
+ return substr(AUTH_KEY, 0, 32);
288
+ } else {
289
+ return AUTH_KEY;
290
+ }
291
+ }
292
+
293
+ // split the given array into n number of pieces
294
+ private function array_split($array, $pieces = 2)
295
+ {
296
+ if ($pieces < 2) {
297
+ return array($array);
298
+ }
299
+ $newCount = ceil(count($array)/$pieces);
300
+ $a = array_slice($array, 0, $newCount);
301
+ $b = $this->array_split(array_slice($array, $newCount), $pieces-1);
302
+ return array_merge(array($a), $b);
303
+ }
304
+ }
classes/Connector/wp-db-custom.php CHANGED
@@ -1,36 +1,36 @@
1
- <?php
2
-
3
- class wpdbCustom extends wpdb
4
- {
5
- /*
6
- * overwrite wpdb class for set $allow_bail to false
7
- * and hide the print of the error
8
- */
9
- public function __construct($dbuser, $dbpassword, $dbname, $dbhost)
10
- {
11
- register_shutdown_function(array($this, '__destruct'));
12
- if (WP_DEBUG && WP_DEBUG_DISPLAY) {
13
- $this->show_errors();
14
- }
15
- if (function_exists('mysqli_connect')) {
16
- if (defined('WP_USE_EXT_MYSQL')) {
17
- $this->use_mysqli = ! WP_USE_EXT_MYSQL;
18
- } elseif (version_compare(phpversion(), '5.5', '>=') || !function_exists('mysql_connect')) {
19
- $this->use_mysqli = true;
20
- } elseif (false !== strpos($GLOBALS['wp_version'], '-')) {
21
- $this->use_mysqli = true;
22
- }
23
- }
24
- $this->dbuser = $dbuser;
25
- $this->dbpassword = $dbpassword;
26
- $this->dbname = $dbname;
27
- $this->dbhost = $dbhost;
28
- // wp-config.php creation will manually connect when ready.
29
- if (defined('WP_SETUP_CONFIG')) {
30
- return;
31
- }
32
-
33
- $this->db_connect(false);
34
- }
35
-
36
- }
1
+ <?php
2
+
3
+ class wpdbCustom extends wpdb
4
+ {
5
+ /*
6
+ * overwrite wpdb class for set $allow_bail to false
7
+ * and hide the print of the error
8
+ */
9
+ public function __construct($dbuser, $dbpassword, $dbname, $dbhost)
10
+ {
11
+ register_shutdown_function(array($this, '__destruct'));
12
+ if (WP_DEBUG && WP_DEBUG_DISPLAY) {
13
+ $this->show_errors();
14
+ }
15
+ if (function_exists('mysqli_connect')) {
16
+ if (defined('WP_USE_EXT_MYSQL')) {
17
+ $this->use_mysqli = ! WP_USE_EXT_MYSQL;
18
+ } elseif (version_compare(phpversion(), '5.5', '>=') || !function_exists('mysql_connect')) {
19
+ $this->use_mysqli = true;
20
+ } elseif (false !== strpos($GLOBALS['wp_version'], '-')) {
21
+ $this->use_mysqli = true;
22
+ }
23
+ }
24
+ $this->dbuser = $dbuser;
25
+ $this->dbpassword = $dbpassword;
26
+ $this->dbname = $dbname;
27
+ $this->dbhost = $dbhost;
28
+ // wp-config.php creation will manually connect when ready.
29
+ if (defined('WP_SETUP_CONFIG')) {
30
+ return;
31
+ }
32
+
33
+ $this->db_connect(false);
34
+ }
35
+
36
+ }
classes/EDD_SL_Plugin_Updater.php CHANGED
@@ -1,170 +1,170 @@
1
- <?php
2
-
3
- // uncomment this line for testing
4
- //set_site_transient( 'update_plugins', null );
5
-
6
- /**
7
- * Allows plugins to use their own update API.
8
- *
9
- * @author Pippin Williamson
10
- * @version 1.2
11
- */
12
- class EDD_SL_Plugin_Updater {
13
- private $api_url = '';
14
- private $api_data = array();
15
- private $name = '';
16
- private $slug = '';
17
- private $do_check = false;
18
-
19
- /**
20
- * Class constructor.
21
- *
22
- * @uses plugin_basename()
23
- * @uses hook()
24
- *
25
- * @param string $_api_url The URL pointing to the custom API endpoint.
26
- * @param string $_plugin_file Path to the plugin file.
27
- * @param array $_api_data Optional data to send with API calls.
28
- * @return void
29
- */
30
- function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
31
- $this->api_url = trailingslashit( $_api_url );
32
- $this->api_data = urlencode_deep( $_api_data );
33
- $this->name = plugin_basename( $_plugin_file );
34
- $this->slug = basename( $_plugin_file, '.php');
35
- $this->version = $_api_data['version'];
36
-
37
- // Set up hooks.
38
- $this->hook();
39
- }
40
-
41
- /**
42
- * Set up WordPress filters to hook into WP's update process.
43
- *
44
- * @uses add_filter()
45
- *
46
- * @return void
47
- */
48
- private function hook() {
49
- add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'pre_set_site_transient_update_plugins_filter' ) );
50
- add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
51
- add_filter( 'http_request_args', array( $this, 'http_request_args' ), 10, 2 );
52
- }
53
-
54
- /**
55
- * Check for Updates at the defined API endpoint and modify the update array.
56
- *
57
- * This function dives into the update API just when WordPress creates its update array,
58
- * then adds a custom API call and injects the custom plugin data retrieved from the API.
59
- * It is reassembled from parts of the native WordPress plugin update code.
60
- * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
61
- *
62
- * @uses api_request()
63
- *
64
- * @param array $_transient_data Update array build by WordPress.
65
- * @return array Modified update array with custom plugin data.
66
- */
67
- function pre_set_site_transient_update_plugins_filter( $_transient_data ) {
68
-
69
- if( empty( $_transient_data ) || ! $this->do_check ) {
70
-
71
- // This ensures that the custom API request only runs on the second time that WP fires the update check
72
- $this->do_check = true;
73
-
74
- return $_transient_data;
75
- }
76
-
77
- $to_send = array( 'slug' => $this->slug );
78
-
79
- $api_response = $this->api_request( 'plugin_latest_version', $to_send );
80
-
81
- if( false !== $api_response && is_object( $api_response ) && isset( $api_response->new_version ) ) {
82
-
83
- if( version_compare( $this->version, $api_response->new_version, '<' ) ) {
84
- $_transient_data->response[$this->name] = $api_response;
85
- }
86
- }
87
- return $_transient_data;
88
- }
89
-
90
-
91
- /**
92
- * Updates information on the "View version x.x details" page with custom data.
93
- *
94
- * @uses api_request()
95
- *
96
- * @param mixed $_data
97
- * @param string $_action
98
- * @param object $_args
99
- * @return object $_data
100
- */
101
- function plugins_api_filter( $_data, $_action = '', $_args = null ) {
102
- if ( ( $_action != 'plugin_information' ) || !isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) return $_data;
103
-
104
- $to_send = array( 'slug' => $this->slug );
105
-
106
- $api_response = $this->api_request( 'plugin_information', $to_send );
107
- if ( false !== $api_response ) $_data = $api_response;
108
-
109
- return $_data;
110
- }
111
-
112
-
113
- /**
114
- * Disable SSL verification in order to prevent download update failures
115
- *
116
- * @param array $args
117
- * @param string $url
118
- * @return object $array
119
- */
120
- function http_request_args( $args, $url ) {
121
- // If it is an https request and we are performing a package download, disable ssl verification
122
- if( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
123
- $args['sslverify'] = false;
124
- }
125
- return $args;
126
- }
127
-
128
- /**
129
- * Calls the API and, if successfull, returns the object delivered by the API.
130
- *
131
- * @uses get_bloginfo()
132
- * @uses wp_remote_post()
133
- * @uses is_wp_error()
134
- *
135
- * @param string $_action The requested action.
136
- * @param array $_data Parameters for the API action.
137
- * @return false||object
138
- */
139
- private function api_request( $_action, $_data ) {
140
-
141
- global $wp_version;
142
-
143
- $data = array_merge( $this->api_data, $_data );
144
-
145
- if( $data['slug'] != $this->slug )
146
- return;
147
-
148
- if( empty( $data['license'] ) )
149
- return;
150
-
151
- $api_params = array(
152
- 'edd_action' => 'get_version',
153
- 'license' => $data['license'],
154
- 'name' => $data['item_name'],
155
- 'slug' => $this->slug,
156
- 'author' => $data['author'],
157
- 'url' => home_url()
158
- );
159
- $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => false, 'body' => $api_params ) );
160
-
161
- if ( ! is_wp_error( $request ) ):
162
- $request = json_decode( wp_remote_retrieve_body( $request ) );
163
- if( $request && isset( $request->sections ) )
164
- $request->sections = maybe_unserialize( $request->sections );
165
- return $request;
166
- else:
167
- return false;
168
- endif;
169
- }
170
- }
1
+ <?php
2
+
3
+ // uncomment this line for testing
4
+ //set_site_transient( 'update_plugins', null );
5
+
6
+ /**
7
+ * Allows plugins to use their own update API.
8
+ *
9
+ * @author Pippin Williamson
10
+ * @version 1.2
11
+ */
12
+ class EDD_SL_Plugin_Updater {
13
+ private $api_url = '';
14
+ private $api_data = array();
15
+ private $name = '';
16
+ private $slug = '';
17
+ private $do_check = false;
18
+
19
+ /**
20
+ * Class constructor.
21
+ *
22
+ * @uses plugin_basename()
23
+ * @uses hook()
24
+ *
25
+ * @param string $_api_url The URL pointing to the custom API endpoint.
26
+ * @param string $_plugin_file Path to the plugin file.
27
+ * @param array $_api_data Optional data to send with API calls.
28
+ * @return void
29
+ */
30
+ function __construct( $_api_url, $_plugin_file, $_api_data = null ) {
31
+ $this->api_url = trailingslashit( $_api_url );
32
+ $this->api_data = urlencode_deep( $_api_data );
33
+ $this->name = plugin_basename( $_plugin_file );
34
+ $this->slug = basename( $_plugin_file, '.php');
35
+ $this->version = $_api_data['version'];
36
+
37
+ // Set up hooks.
38
+ $this->hook();
39
+ }
40
+
41
+ /**
42
+ * Set up WordPress filters to hook into WP's update process.
43
+ *
44
+ * @uses add_filter()
45
+ *
46
+ * @return void
47
+ */
48
+ private function hook() {
49
+ add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'pre_set_site_transient_update_plugins_filter' ) );
50
+ add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
51
+ add_filter( 'http_request_args', array( $this, 'http_request_args' ), 10, 2 );
52
+ }
53
+
54
+ /**
55
+ * Check for Updates at the defined API endpoint and modify the update array.
56
+ *
57
+ * This function dives into the update API just when WordPress creates its update array,
58
+ * then adds a custom API call and injects the custom plugin data retrieved from the API.
59
+ * It is reassembled from parts of the native WordPress plugin update code.
60
+ * See wp-includes/update.php line 121 for the original wp_update_plugins() function.
61
+ *
62
+ * @uses api_request()
63
+ *
64
+ * @param array $_transient_data Update array build by WordPress.
65
+ * @return array Modified update array with custom plugin data.
66
+ */
67
+ function pre_set_site_transient_update_plugins_filter( $_transient_data ) {
68
+
69
+ if( empty( $_transient_data ) || ! $this->do_check ) {
70
+
71
+ // This ensures that the custom API request only runs on the second time that WP fires the update check
72
+ $this->do_check = true;
73
+
74
+ return $_transient_data;
75
+ }
76
+
77
+ $to_send = array( 'slug' => $this->slug );
78
+
79
+ $api_response = $this->api_request( 'plugin_latest_version', $to_send );
80
+
81
+ if( false !== $api_response && is_object( $api_response ) && isset( $api_response->new_version ) ) {
82
+
83
+ if( version_compare( $this->version, $api_response->new_version, '<' ) ) {
84
+ $_transient_data->response[$this->name] = $api_response;
85
+ }
86
+ }
87
+ return $_transient_data;
88
+ }
89
+
90
+
91
+ /**
92
+ * Updates information on the "View version x.x details" page with custom data.
93
+ *
94
+ * @uses api_request()
95
+ *
96
+ * @param mixed $_data
97
+ * @param string $_action
98
+ * @param object $_args
99
+ * @return object $_data
100
+ */
101
+ function plugins_api_filter( $_data, $_action = '', $_args = null ) {
102
+ if ( ( $_action != 'plugin_information' ) || !isset( $_args->slug ) || ( $_args->slug != $this->slug ) ) return $_data;
103
+
104
+ $to_send = array( 'slug' => $this->slug );
105
+
106
+ $api_response = $this->api_request( 'plugin_information', $to_send );
107
+ if ( false !== $api_response ) $_data = $api_response;
108
+
109
+ return $_data;
110
+ }
111
+
112
+
113
+ /**
114
+ * Disable SSL verification in order to prevent download update failures
115
+ *
116
+ * @param array $args
117
+ * @param string $url
118
+ * @return object $array
119
+ */
120
+ function http_request_args( $args, $url ) {
121
+ // If it is an https request and we are performing a package download, disable ssl verification
122
+ if( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) {
123
+ $args['sslverify'] = false;
124
+ }
125
+ return $args;
126
+ }
127
+
128
+ /**
129
+ * Calls the API and, if successfull, returns the object delivered by the API.
130
+ *
131
+ * @uses get_bloginfo()
132
+ * @uses wp_remote_post()
133
+ * @uses is_wp_error()
134
+ *
135
+ * @param string $_action The requested action.
136
+ * @param array $_data Parameters for the API action.
137
+ * @return false||object
138
+ */
139
+ private function api_request( $_action, $_data ) {
140
+
141
+ global $wp_version;
142
+
143
+ $data = array_merge( $this->api_data, $_data );
144
+
145
+ if( $data['slug'] != $this->slug )
146
+ return;
147
+
148
+ if( empty( $data['license'] ) )
149
+ return;
150
+
151
+ $api_params = array(
152
+ 'edd_action' => 'get_version',
153
+ 'license' => $data['license'],
154
+ 'name' => $data['item_name'],
155
+ 'slug' => $this->slug,
156
+ 'author' => $data['author'],
157
+ 'url' => home_url()
158
+ );
159
+ $request = wp_remote_post( $this->api_url, array( 'timeout' => 15, 'sslverify' => false, 'body' => $api_params ) );
160
+
161
+ if ( ! is_wp_error( $request ) ):
162
+ $request = json_decode( wp_remote_retrieve_body( $request ) );
163
+ if( $request && isset( $request->sections ) )
164
+ $request->sections = maybe_unserialize( $request->sections );
165
+ return $request;
166
+ else:
167
+ return false;
168
+ endif;
169
+ }
170
+ }
classes/Helpers/DataHelper.php CHANGED
@@ -1,23 +1,23 @@
1
- <?php
2
-
3
- class WSAL_Helpers_DataHelper
4
- {
5
-
6
- /**
7
- * A wrapper for JSON encoding that fixes potential issues.
8
- * @param mixed $data The data to encode.
9
- * @return string JSON string.
10
- */
11
- public static function JsonEncode($data){
12
- return @json_encode($data);
13
- }
14
-
15
- /**
16
- * A wrapper for JSON encoding that fixes potential issues.
17
- * @param string $data The JSON string to decode.
18
- * @return mixed Decoded data.
19
- */
20
- public static function JsonDecode($data){
21
- return @json_decode($data);
22
- }
23
  }
1
+ <?php
2
+
3
+ class WSAL_Helpers_DataHelper
4
+ {
5
+
6
+ /**
7
+ * A wrapper for JSON encoding that fixes potential issues.
8
+ * @param mixed $data The data to encode.
9
+ * @return string JSON string.
10
+ */
11
+ public static function JsonEncode($data){
12
+ return @json_encode($data);
13
+ }
14
+
15
+ /**
16
+ * A wrapper for JSON encoding that fixes potential issues.
17
+ * @param string $data The JSON string to decode.
18
+ * @return mixed Decoded data.
19
+ */
20
+ public static function JsonDecode($data){
21
+ return @json_decode($data);
22
+ }
23
  }
classes/Loggers/Database.php CHANGED
@@ -10,7 +10,7 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger
10
  }
11
 
12
  public function Log($type, $data = array(), $date = null, $siteid = null, $migrated = false)
13
- {
14
  // is this a php alert, and if so, are we logging such alerts?
15
  if ($type < 0010 && !$this->plugin->settings->IsPhpErrorLoggingEnabled()) return;
16
 
@@ -25,8 +25,11 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger
25
 
26
  // set up meta data
27
  $occ->SetMeta($data);
 
28
  // Inject for promoting the paid add-ons
29
- $this->AlertInject($occ);
 
 
30
  }
31
 
32
  public function CleanUp()
@@ -77,12 +80,12 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger
77
  private function AlertInject($occurrence)
78
  {
79
  $count = $this->CheckPromoToShow();
80
- if ($count) {
81
  if (($occurrence->getId() % $count) == 0) {
82
  $promoToSend = $this->GetPromoAlert();
83
  if (!empty($promoToSend)) {
84
  $link = '<a href="'.$promoToSend['link'].'" target="_blank">'.$promoToSend['name'].'</a>';
85
- $this->log(9999, array(
86
  'ClientIP' => '127.0.0.1',
87
  'Username' => 'Plugin',
88
  'PromoMessage' => sprintf($promoToSend['message'], $link),
@@ -211,5 +214,4 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger
211
  }
212
  return (count($promoToShow) == 4) ? 100 : 175;
213
  }
214
-
215
  }
10
  }
11
 
12
  public function Log($type, $data = array(), $date = null, $siteid = null, $migrated = false)
13
+ {
14
  // is this a php alert, and if so, are we logging such alerts?
15
  if ($type < 0010 && !$this->plugin->settings->IsPhpErrorLoggingEnabled()) return;
16
 
25
 
26
  // set up meta data
27
  $occ->SetMeta($data);
28
+
29
  // Inject for promoting the paid add-ons
30
+ if ($type != 9999) {
31
+ $this->AlertInject($occ);
32
+ }
33
  }
34
 
35
  public function CleanUp()
80
  private function AlertInject($occurrence)
81
  {
82
  $count = $this->CheckPromoToShow();
83
+ if ($count && $occurrence->getId() != 0) {
84
  if (($occurrence->getId() % $count) == 0) {
85
  $promoToSend = $this->GetPromoAlert();
86
  if (!empty($promoToSend)) {
87
  $link = '<a href="'.$promoToSend['link'].'" target="_blank">'.$promoToSend['name'].'</a>';
88
+ $this->Log(9999, array(
89
  'ClientIP' => '127.0.0.1',
90
  'Username' => 'Plugin',
91
  'PromoMessage' => sprintf($promoToSend['message'], $link),
214
  }
215
  return (count($promoToShow) == 4) ? 100 : 175;
216
  }
 
217
  }
classes/Models/ActiveRecord.php CHANGED
@@ -1,267 +1,267 @@
1
- <?php
2
- require_once(__DIR__ . '/../Connector/ConnectorFactory.php');
3
-
4
- abstract class WSAL_Models_ActiveRecord
5
- {
6
-
7
- /**
8
- * @var_$connector Data connector;
9
- */
10
- protected $connector;
11
-
12
- protected $id = false;
13
-
14
- protected $adapterName = null;
15
-
16
- protected $useDefaultAdapter = false;
17
-
18
- /**
19
- * @return array Returns this records' fields.
20
- */
21
- public function GetFields()
22
- {
23
- if(!isset($this->_column_cache)){
24
- $this->_column_cache = array();
25
- foreach(array_keys(get_object_vars($this)) as $col)
26
- if(trim($col) && $col[0] != '_')
27
- $this->_column_cache[] = $col;
28
- }
29
- return $this->_column_cache;
30
- }
31
-
32
- public function setId($id)
33
- {
34
- $this->id = $id;
35
- }
36
-
37
- public function getId()
38
- {
39
- return $this->id;
40
- }
41
-
42
- const STATE_UNKNOWN = 'unknown';
43
- const STATE_CREATED = 'created';
44
- const STATE_UPDATED = 'updated';
45
- const STATE_DELETED = 'deleted';
46
- const STATE_LOADED = 'loaded';
47
-
48
- protected $_state = self::STATE_UNKNOWN;
49
-
50
- public function __construct($data = null)
51
- {
52
- if (!$this->adapterName) {
53
- throw new Exception('Class "' . __CLASS__ . '" requires "adapterName" to be set.');
54
- }
55
- if (!is_null($data)) {
56
- $this->LoadData($data);
57
- $this->_state = self::STATE_LOADED;
58
- }
59
- }
60
-
61
- protected function getConnector()
62
- {
63
- if (!empty($this->connector)) {
64
- return $this->connector;
65
- }
66
- if ($this->useDefaultAdapter) {
67
- $this->connector = WSAL_Connector_ConnectorFactory::GetDefaultConnector();
68
- } else {
69
- $this->connector = WSAL_Connector_ConnectorFactory::GetConnector();
70
- }
71
- return $this->connector;
72
- }
73
-
74
- public function getAdapter()
75
- {
76
- return $this->getConnector()->getAdapter($this->adapterName);
77
- }
78
-
79
-
80
- /**
81
- * Load record from DB.
82
- * @param string $cond (Optional) Load condition.
83
- * @param array $args (Optional) Load condition arguments.
84
- */
85
- public function Load($cond = '%d', $args = array(1)){
86
- $this->_state = self::STATE_UNKNOWN;
87
-
88
- $data = $this->getAdapter()->Load($cond, $args);
89
- if(!is_null($data)){
90
- $this->LoadData($data);
91
- $this->_state = self::STATE_LOADED;
92
- }
93
- }
94
-
95
- /**
96
- * Load object data from variable.
97
- * @param array|object $data Data array or object.
98
- */
99
- public function LoadData($data){
100
- $copy = get_class($this);
101
- $copy = new $copy;
102
- foreach((array)$data as $key => $val){
103
- if(isset($copy->$key)){
104
- switch(true){
105
- case is_array($copy->$key):
106
- case is_object($copy->$key):
107
- $jsonDecodedVal = WSAL_Helpers_DataHelper::JsonDecode($val);
108
- $this->$key = ($jsonDecodedVal == null) ? $val : $jsonDecodedVal;
109
- break;
110
- case is_int($copy->$key):
111
- $this->$key = (int)$val;
112
- break;
113
- case is_float($copy->$key):
114
- $this->$key = (float)$val;
115
- break;
116
- case is_bool($copy->$key):
117
- $this->$key = (bool)$val;
118
- break;
119
- case is_string($copy->$key):
120
- $this->$key = (string)$val;
121
- break;
122
- default:
123
- throw new Exception('Unsupported type "'.gettype($copy->$key).'"');
124
- }
125
- }
126
- }
127
- return $this;
128
- }
129
-
130
- /**
131
- * Save this active record
132
- * @return integer|boolean Either the number of modified/inserted rows or false on failure.
133
- */
134
- public function Save()
135
- {
136
- $this->_state = self::STATE_UNKNOWN;
137
-
138
- // use today's date if not set up
139
- if (is_null($this->created_on)) {
140
- $this->created_on = $this->GetMicrotime();
141
- }
142
- $updateId = $this->getId();
143
- $result = $this->getAdapter()->Save($this);
144
-
145
- if ($result !== false) {
146
- $this->_state = (!empty($updateId))?self::STATE_UPDATED:self::STATE_CREATED;
147
- }
148
- return $result;
149
- }
150
-
151
- /**
152
- * Deletes this active record
153
- */
154
- public function Delete()
155
- {
156
- $this->_state = self::STATE_UNKNOWN;
157
- $result = $this->getAdapter()->Delete($this);
158
- if($result !== false)
159
- $this->_state = self::STATE_DELETED;
160
-
161
- return $result;
162
- }
163
-
164
- public function Count($cond = '%d', $args = array(1)) {
165
- $result = $this->getAdapter()->Count($cond, $args);
166
- return $result;
167
- }
168
-
169
- /**
170
- * @return boolean
171
- */
172
- public function IsLoaded(){
173
- return $this->_state == self::STATE_LOADED;
174
- }
175
-
176
- /**
177
- * @return boolean
178
- */
179
- public function IsSaved(){
180
- return $this->_state == self::STATE_CREATED
181
- || $this->_state == self::STATE_UPDATED;
182
- }
183
-
184
- /**
185
- * @return boolean
186
- */
187
- public function IsCreated(){
188
- return $this->_state == self::STATE_CREATED;
189
- }
190
-
191
- /**
192
- * @return boolean
193
- */
194
- public function IsUpdated()
195
- {
196
- return $this->_state == self::STATE_UPDATED;
197
- }
198
-
199
- /**
200
- * @return boolean
201
- */
202
- public function IsInstalled()
203
- {
204
- return $this->getAdapter()->IsInstalled();
205
- }
206
-
207
- public function Install()
208
- {
209
- return $this->getAdapter()->Install();
210
- }
211
-
212
- /**
213
- * @return boolean
214
- */
215
- public function IsDeleted()
216
- {
217
- return $this->_state == self::STATE_DELETED;
218
- }
219
-
220
- protected static $_cache = array();
221
-
222
- /**
223
- * Load ActiveRecord from DB or cache.
224
- * @param string $target ActiveRecord class name.
225
- * @param string $query Load condition.
226
- * @param array $args Arguments used in condition.
227
- * @return WSAL_Models_ActiveRecord
228
- */
229
- protected static function CacheLoad($target, $query, $args){
230
- $index = $target . '::' . vsprintf($query, $args);
231
- if(!isset(self::$_cache[$index])){
232
- self::$_cache[$index] = new $target();
233
- self::$_cache[$index]->Load($query, $args);
234
- }
235
- return self::$_cache[$index];
236
- }
237
-
238
- /**
239
- * Remove ActiveRecord cache.
240
- * @param string $target ActiveRecord class name.
241
- * @param string $query Load condition.
242
- * @param array $args Arguments used in condition.
243
- */
244
- protected static function CacheRemove($target, $query, $args){
245
- $index = $target . '::' . sprintf($query, $args);
246
- if(!isset(self::$_cache[$index])){
247
- unset(self::$_cache[$index]);
248
- }
249
- }
250
-
251
- /**
252
- * Clear the cache.
253
- */
254
- protected static function CacheClear()
255
- {
256
- self::$_cache = array();
257
- }
258
-
259
- /**
260
- * Function used in WSAL reporting extension
261
- */
262
- public function GetReporting($_siteId, $_userId, $_roleName, $_alertCode, $_startTimestamp, $_endTimestamp)
263
- {
264
- return $this->getAdapter()->GetReporting($_siteId, $_userId, $_roleName, $_alertCode, $_startTimestamp, $_endTimestamp);
265
- }
266
-
267
- }
1
+ <?php
2
+ require_once(__DIR__ . '/../Connector/ConnectorFactory.php');
3
+
4
+ abstract class WSAL_Models_ActiveRecord
5
+ {
6
+
7
+ /**
8
+ * @var_$connector Data connector;
9
+ */
10
+ protected $connector;
11
+
12
+ protected $id = false;
13
+
14
+ protected $adapterName = null;
15
+
16
+ protected $useDefaultAdapter = false;
17
+
18
+ /**
19
+ * @return array Returns this records' fields.
20
+ */
21
+ public function GetFields()
22
+ {
23
+ if(!isset($this->_column_cache)){
24
+ $this->_column_cache = array();
25
+ foreach(array_keys(get_object_vars($this)) as $col)
26
+ if(trim($col) && $col[0] != '_')
27
+ $this->_column_cache[] = $col;
28
+ }
29
+ return $this->_column_cache;
30
+ }
31
+
32
+ public function setId($id)
33
+ {
34
+ $this->id = $id;
35
+ }
36
+
37
+ public function getId()
38
+ {
39
+ return $this->id;
40
+ }
41
+
42
+ const STATE_UNKNOWN = 'unknown';
43
+ const STATE_CREATED = 'created';
44
+ const STATE_UPDATED = 'updated';
45
+ const STATE_DELETED = 'deleted';
46
+ const STATE_LOADED = 'loaded';
47
+
48
+ protected $_state = self::STATE_UNKNOWN;
49
+
50
+ public function __construct($data = null)
51
+ {
52
+ if (!$this->adapterName) {
53
+ throw new Exception('Class "' . __CLASS__ . '" requires "adapterName" to be set.');
54
+ }
55
+ if (!is_null($data)) {
56
+ $this->LoadData($data);
57
+ $this->_state = self::STATE_LOADED;
58
+ }
59
+ }
60
+
61
+ protected function getConnector()
62
+ {
63
+ if (!empty($this->connector)) {
64
+ return $this->connector;
65
+ }
66
+ if ($this->useDefaultAdapter) {
67
+ $this->connector = WSAL_Connector_ConnectorFactory::GetDefaultConnector();
68
+ } else {
69
+ $this->connector = WSAL_Connector_ConnectorFactory::GetConnector();
70
+ }
71
+ return $this->connector;
72
+ }
73
+
74
+ public function getAdapter()
75
+ {
76
+ return $this->getConnector()->getAdapter($this->adapterName);
77
+ }
78
+
79
+
80
+ /**
81
+ * Load record from DB.
82
+ * @param string $cond (Optional) Load condition.
83
+ * @param array $args (Optional) Load condition arguments.
84
+ */
85
+ public function Load($cond = '%d', $args = array(1)){
86
+ $this->_state = self::STATE_UNKNOWN;
87
+
88
+ $data = $this->getAdapter()->Load($cond, $args);
89
+ if(!is_null($data)){
90
+ $this->LoadData($data);
91
+ $this->_state = self::STATE_LOADED;
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Load object data from variable.
97
+ * @param array|object $data Data array or object.
98
+ */
99
+ public function LoadData($data){
100
+ $copy = get_class($this);
101
+ $copy = new $copy;
102
+ foreach((array)$data as $key => $val){
103
+ if(isset($copy->$key)){
104
+ switch(true){
105
+ case is_array($copy->$key):
106
+ case is_object($copy->$key):
107
+ $jsonDecodedVal = WSAL_Helpers_DataHelper::JsonDecode($val);
108
+ $this->$key = ($jsonDecodedVal == null) ? $val : $jsonDecodedVal;
109
+ break;
110
+ case is_int($copy->$key):
111
+ $this->$key = (int)$val;
112
+ break;
113
+ case is_float($copy->$key):
114
+ $this->$key = (float)$val;
115
+ break;
116
+ case is_bool($copy->$key):
117
+ $this->$key = (bool)$val;
118
+ break;
119
+ case is_string($copy->$key):
120
+ $this->$key = (string)$val;
121
+ break;
122
+ default:
123
+ throw new Exception('Unsupported type "'.gettype($copy->$key).'"');
124
+ }
125
+ }
126
+ }
127
+ return $this;
128
+ }
129
+
130
+ /**
131
+ * Save this active record
132
+ * @return integer|boolean Either the number of modified/inserted rows or false on failure.
133
+ */
134
+ public function Save()
135
+ {
136
+ $this->_state = self::STATE_UNKNOWN;
137
+
138
+ // use today's date if not set up
139
+ if (is_null($this->created_on)) {
140
+ $this->created_on = $this->GetMicrotime();
141
+ }
142
+ $updateId = $this->getId();
143
+ $result = $this->getAdapter()->Save($this);
144
+
145
+ if ($result !== false) {
146
+ $this->_state = (!empty($updateId))?self::STATE_UPDATED:self::STATE_CREATED;
147
+ }
148
+ return $result;
149
+ }
150
+
151
+ /**
152
+ * Deletes this active record
153
+ */
154
+ public function Delete()
155
+ {
156
+ $this->_state = self::STATE_UNKNOWN;
157
+ $result = $this->getAdapter()->Delete($this);
158
+ if($result !== false)
159
+ $this->_state = self::STATE_DELETED;
160
+
161
+ return $result;
162
+ }
163
+
164
+ public function Count($cond = '%d', $args = array(1)) {
165
+ $result = $this->getAdapter()->Count($cond, $args);
166
+ return $result;
167
+ }
168
+
169
+ /**
170
+ * @return boolean
171
+ */
172
+ public function IsLoaded(){
173
+ return $this->_state == self::STATE_LOADED;
174
+ }
175
+
176
+ /**
177
+ * @return boolean
178
+ */
179
+ public function IsSaved(){
180
+ return $this->_state == self::STATE_CREATED
181
+ || $this->_state == self::STATE_UPDATED;
182
+ }
183
+
184
+ /**
185
+ * @return boolean
186
+ */
187
+ public function IsCreated(){
188
+ return $this->_state == self::STATE_CREATED;
189
+ }
190
+
191
+ /**
192
+ * @return boolean
193
+ */
194
+ public function IsUpdated()
195
+ {
196
+ return $this->_state == self::STATE_UPDATED;
197
+ }
198
+
199
+ /**
200
+ * @return boolean
201
+ */
202
+ public function IsInstalled()
203
+ {
204
+ return $this->getAdapter()->IsInstalled();
205
+ }
206
+
207
+ public function Install()
208
+ {
209
+ return $this->getAdapter()->Install();
210
+ }
211
+
212
+ /**
213
+ * @return boolean
214
+ */
215
+ public function IsDeleted()
216
+ {
217
+ return $this->_state == self::STATE_DELETED;
218
+ }
219
+
220
+ protected static $_cache = array();
221
+
222
+ /**
223
+ * Load ActiveRecord from DB or cache.
224
+ * @param string $target ActiveRecord class name.
225
+ * @param string $query Load condition.
226
+ * @param array $args Arguments used in condition.
227
+ * @return WSAL_Models_ActiveRecord
228
+ */
229
+ protected static function CacheLoad($target, $query, $args){
230
+ $index = $target . '::' . vsprintf($query, $args);
231
+ if(!isset(self::$_cache[$index])){
232
+ self::$_cache[$index] = new $target();
233
+ self::$_cache[$index]->Load($query, $args);
234
+ }
235
+ return self::$_cache[$index];
236
+ }
237
+
238
+ /**
239
+ * Remove ActiveRecord cache.
240
+ * @param string $target ActiveRecord class name.
241
+ * @param string $query Load condition.
242
+ * @param array $args Arguments used in condition.
243
+ */
244
+ protected static function CacheRemove($target, $query, $args){
245
+ $index = $target . '::' . sprintf($query, $args);
246
+ if(!isset(self::$_cache[$index])){
247
+ unset(self::$_cache[$index]);
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Clear the cache.
253
+ */
254
+ protected static function CacheClear()
255
+ {
256
+ self::$_cache = array();
257
+ }
258
+
259
+ /**
260
+ * Function used in WSAL reporting extension
261
+ */
262
+ public function GetReporting($_siteId, $_userId, $_roleName, $_alertCode, $_startTimestamp, $_endTimestamp)
263
+ {
264
+ return $this->getAdapter()->GetReporting($_siteId, $_userId, $_roleName, $_alertCode, $_startTimestamp, $_endTimestamp);
265
+ }
266
+
267
+ }
classes/Models/Adapters/ActiveRecordInterface.php CHANGED
@@ -1,15 +1,15 @@
1
- <?php
2
-
3
- interface WSAL_Adapters_ActiveRecordInterface {
4
-
5
- public function IsInstalled();
6
- public function Install();
7
- public function Uninstall();
8
- public function Load($cond = '%d', $args = array(1));
9
- public function Save($activeRecord);
10
- public function Delete($activeRecord);
11
- public function LoadMulti($cond, $args = array());
12
- public function LoadAndCallForEach($callback, $cond = '%d', $args = array(1));
13
- public function Count($cond = '%d', $args = array(1));
14
- public function LoadMultiQuery($query, $args = array());
15
- }
1
+ <?php
2
+
3
+ interface WSAL_Adapters_ActiveRecordInterface {
4
+
5
+ public function IsInstalled();
6
+ public function Install();
7
+ public function Uninstall();
8
+ public function Load($cond = '%d', $args = array(1));
9
+ public function Save($activeRecord);
10
+ public function Delete($activeRecord);
11
+ public function LoadMulti($cond, $args = array());
12
+ public function LoadAndCallForEach($callback, $cond = '%d', $args = array(1));
13
+ public function Count($cond = '%d', $args = array(1));
14
+ public function LoadMultiQuery($query, $args = array());
15
+ }
classes/Models/Adapters/MetaInterface.php CHANGED
@@ -1,13 +1,13 @@
1
- <?php
2
-
3
- interface WSAL_Adapters_MetaInterface {
4
- /**
5
- * Create a meta object
6
- * @param $metaData Array of meta data
7
- * @return int ID of the new meta data
8
- */
9
- public function deleteByOccurenceIds($occurenceIds);
10
-
11
- public function loadByNameAndOccurenceId($metaName, $occurenceId);
12
-
13
- }
1
+ <?php
2
+
3
+ interface WSAL_Adapters_MetaInterface {
4
+ /**
5
+ * Create a meta object
6
+ * @param $metaData Array of meta data
7
+ * @return int ID of the new meta data
8
+ */
9
+ public function deleteByOccurenceIds($occurenceIds);
10
+
11
+ public function loadByNameAndOccurenceId($metaName, $occurenceId);
12
+
13
+ }
classes/Models/Adapters/MySQL/ActiveRecordAdapter.php CHANGED
@@ -1,438 +1,448 @@
1
- <?php
2
-
3
- class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInterface {
4
-
5
- protected $connection;
6
-
7
- /**
8
- * Contains the table name
9
- * @var string
10
- */
11
- protected $_table;
12
-
13
- /**
14
- * Contains primary key column name, override as required.
15
- * @var string
16
- */
17
- protected $_idkey = '';
18
-
19
- public function __construct($conn)
20
- {
21
- $this->connection = $conn;
22
- }
23
-
24
- public function GetModel()
25
- {
26
- return new WSAL_Models_ActiveRecord();
27
- }
28
-
29
- /**
30
- * @return string Returns table name.
31
- */
32
- public function GetTable()
33
- {
34
- $_wpdb = $this->connection;
35
- return $_wpdb->base_prefix . $this->_table;
36
- }
37
-
38
- /**
39
- * Used for WordPress prefix
40
- * @return string Returns table name of WordPress.
41
- */
42
- public function GetWPTable()
43
- {
44
- global $wpdb;
45
- return $wpdb->base_prefix . $this->_table;
46
- }
47
-
48
- /**
49
- * @return string SQL table options (constraints, foreign keys, indexes etc).
50
- */
51
- protected function GetTableOptions()
52
- {
53
- return ' PRIMARY KEY (' . $this->_idkey . ')';
54
- }
55
-
56
- /**
57
- * @return array Returns this records' columns.
58
- */
59
- public function GetColumns()
60
- {
61
- $model = $this->GetModel();
62
-
63
- if(!isset($this->_column_cache)){
64
- $this->_column_cache = array();
65
- foreach(array_keys(get_object_vars($model)) as $col)
66
- if(trim($col) && $col[0] != '_')
67
- $this->_column_cache[] = $col;
68
- }
69
- return $this->_column_cache;
70
- }
71
-
72
- /**
73
- * @deprecated
74
- * @return boolean Returns whether table structure is installed or not.
75
- */
76
- public function IsInstalled(){
77
- //global $wpdb;
78
- $_wpdb = $this->connection;
79
- $sql = 'SHOW TABLES LIKE "' . $this->GetTable() . '"';
80
- return strtolower($_wpdb->get_var($sql)) == strtolower($this->GetTable());
81
- }
82
-
83
- /**
84
- * Install this ActiveRecord structure into DB.
85
- */
86
- public function Install(){
87
- $_wpdb = $this->connection;
88
- $_wpdb->query($this->_GetInstallQuery());
89
- }
90
-
91
- /**
92
- * Install this ActiveRecord structure into DB WordPress.
93
- */
94
- public function InstallOriginal(){
95
- global $wpdb;
96
- $wpdb->query($this->_GetInstallQuery(true));
97
- }
98
-
99
- /**
100
- * Remove this ActiveRecord structure into DB.
101
- */
102
- public function Uninstall()
103
- {
104
- //global $wpdb;
105
- $_wpdb = $this->connection;
106
- $_wpdb->query($this->_GetUninstallQuery());
107
- }
108
-
109
- /**
110
- * Save an active record to DB.
111
- * @return integer|boolean Either the number of modified/inserted rows or false on failure.
112
- */
113
- public function Save($activeRecord)
114
- {
115
- //global $wpdb;
116
- $_wpdb = $this->connection;
117
- $copy = $activeRecord;
118
- $data = array();
119
- $format = array();
120
- foreach ($this->GetColumns() as $key) {
121
-
122
- $val = $copy->$key;
123
- $deffmt = '%s';
124
- if (is_int($copy->$key)) {
125
- $deffmt = '%d';
126
- }
127
- if (is_float($copy->$key)) {
128
- $deffmt = '%f';
129
- }
130
- if (is_array($copy->$key) || is_object($copy->$key)) {
131
- $data[$key] = WSAL_Helpers_DataHelper::JsonEncode($val);
132
- } else {
133
- $data[$key] = $val;
134
- }
135
- $format[] = $deffmt;
136
- }
137
- $result = $_wpdb->replace($this->GetTable(), $data, $format);
138
-
139
- if ($result !== false) {
140
- if ($_wpdb->insert_id) {
141
- $copy->setId($_wpdb->insert_id);
142
- }
143
- }
144
- return $result;
145
- }
146
-
147
- /**
148
- * Load record from DB.
149
- * @param string $cond (Optional) Load condition.
150
- * @param array $args (Optional) Load condition arguments.
151
- */
152
- public function Load($cond = '%d', $args = array(1))
153
- {
154
- //global $wpdb;
155
- $_wpdb = $this->connection;
156
-
157
- $sql = $_wpdb->prepare('SELECT * FROM '.$this->GetTable().' WHERE '. $cond, $args);
158
- $data = $_wpdb->get_row($sql, ARRAY_A);
159
-
160
- return $data;
161
- }
162
-
163
- public function LoadArray($cond, $args = array())
164
- {
165
- //global $wpdb;
166
- $_wpdb = $this->connection;
167
- $result = array();
168
- $sql = $_wpdb->prepare('SELECT * FROM '.$this->GetTable().' WHERE '. $cond, $args);
169
- foreach ($_wpdb->get_results($sql, ARRAY_A) as $data) {
170
- $result[] = $this->getModel()->LoadData($data);
171
- }
172
- return $result;
173
- }
174
-
175
- /**
176
- * Delete DB record.
177
- * @return int|boolean Either the amount of deleted rows or False on error.
178
- */
179
- public function Delete($activeRecord)
180
- {
181
- //global $wpdb;
182
- $_wpdb = $this->connection;
183
- $result = $_wpdb->delete(
184
- $this->GetTable(),
185
- $activeRecord->getId()
186
- );
187
- return $result;
188
- }
189
-
190
- /**
191
- * Delete records in DB matching a query.
192
- * @param string $query Full SQL query.
193
- * @param array $args (Optional) Query arguments.
194
- */
195
- public function DeleteQuery($query, $args = array())
196
- {
197
- $_wpdb = $this->connection;
198
- $sql = count($args) ? $_wpdb->prepare($query, $args) : $query;
199
- $result = $_wpdb->query($sql);
200
- return $result;
201
- }
202
-
203
- /**
204
- * Load multiple records from DB.
205
- * @param string $cond (Optional) Load condition (eg: 'some_id = %d' ).
206
- * @param array $args (Optional) Load condition arguments (rg: array(45) ).
207
- * @return self[] List of loaded records.
208
- */
209
- public function LoadMulti($cond, $args = array())
210
- {
211
- //global $wpdb;
212
- $_wpdb = $this->connection;
213
- $result = array();
214
- $sql = (!is_array($args) || !count($args)) // do we really need to prepare() or not?
215
- ? ($cond)
216
- : $_wpdb->prepare($cond, $args)
217
- ;
218
- foreach ($_wpdb->get_results($sql, ARRAY_A) as $data) {
219
- $result[] = $this->getModel()->LoadData($data);
220
- }
221
- return $result;
222
-
223
- }
224
-
225
- /**
226
- * Load multiple records from DB and call a callback for each record.
227
- * This function is very memory-efficient, it doesn't load records in bulk.
228
- * @param callable $callback The callback to invoke.
229
- * @param string $cond (Optional) Load condition.
230
- * @param array $args (Optional) Load condition arguments.
231
- */
232
- public function LoadAndCallForEach($callback, $cond = '%d', $args = array(1))
233
- {
234
- //global $wpdb;
235
- $_wpdb = $this->connection;
236
- $class = get_called_class();
237
- $sql = $_wpdb->prepare('SELECT * FROM ' . $this->GetTable() . ' WHERE '.$cond, $args);
238
- foreach ($_wpdb->get_results($sql, ARRAY_A) as $data) {
239
- call_user_func($callback, new $class($data));
240
- }
241
- }
242
-
243
- /**
244
- * Count records in the DB matching a condition.
245
- * If no parameters are given, this counts the number of records in the DB table.
246
- * @param string $cond (Optional) Query condition.
247
- * @param array $args (Optional) Condition arguments.
248
- * @return int Number of matching records.
249
- */
250
- public function Count($cond = '%d', $args = array(1))
251
- {
252
- //global $wpdb;
253
- $_wpdb = $this->connection;
254
- $class = get_called_class();
255
- $sql = $_wpdb->prepare('SELECT COUNT(*) FROM ' . $this->GetTable() . ' WHERE ' . $cond, $args);
256
- return (int)$_wpdb->get_var($sql);
257
- }
258
-
259
- /**
260
- * Count records in the DB matching a query.
261
- * @param string $query Full SQL query.
262
- * @param array $args (Optional) Query arguments.
263
- * @return int Number of matching records.
264
- */
265
- public function CountQuery($query, $args = array())
266
- {
267
- //global $wpdb;
268
- $_wpdb = $this->connection;
269
- $sql = count($args) ? $_wpdb->prepare($query, $args) : $query;
270
- return (int)$_wpdb->get_var($sql);
271
- }
272
-
273
- /**
274
- * Similar to LoadMulti but allows the use of a full SQL query.
275
- * @param string $query Full SQL query.
276
- * @param array $args (Optional) Query arguments.
277
- * @return self[] List of loaded records.
278
- */
279
- public function LoadMultiQuery($query, $args = array())
280
- {
281
- //global $wpdb;
282
- $_wpdb = $this->connection;
283
- $class = get_called_class();
284
- $result = array();
285
- $sql = count($args) ? $_wpdb->prepare($query, $args) : $query;
286
- foreach ($_wpdb->get_results($sql, ARRAY_A) as $data) {
287
- $result[] = $this->getModel()->LoadData($data);
288
- }
289
- return $result;
290
- }
291
-
292
- /**
293
- * @return string Must return SQL for creating table.
294
- */
295
- protected function _GetInstallQuery($prefix = false)
296
- {
297
- $_wpdb = $this->connection;
298
-
299
- $class = get_class($this);
300
- $copy = new $class($this->connection);
301
- $table_name = ($prefix) ? $this->GetWPTable() : $this->GetTable();
302
- $sql = 'CREATE TABLE IF NOT EXISTS ' . $table_name . ' (' . PHP_EOL;
303
-
304
- foreach ($this->GetColumns() as $key) {
305
- $sql .= ' ';
306
- switch (true) {
307
- case $key == $copy->_idkey:
308
- $sql .= $key . ' BIGINT NOT NULL AUTO_INCREMENT,' . PHP_EOL;
309
- break;
310
- case is_integer($copy->$key):
311
- $sql .= $key . ' BIGINT NOT NULL,' . PHP_EOL;
312
- break;
313
- case is_float($copy->$key):
314
- $sql .= $key . ' DOUBLE NOT NULL,' . PHP_EOL;
315
- break;
316
- case is_string($copy->$key):
317
- $maxlength = $key . '_maxlength';
318
- if (property_exists($class, $maxlength)) {
319
- $sql .= $key . ' VARCHAR(' . intval($class::$$maxlength) . ') NOT NULL,' . PHP_EOL;
320
- } else {
321
- $sql .= $key . ' TEXT NOT NULL,' . PHP_EOL;
322
- }
323
- break;
324
- case is_bool($copy->$key):
325
- $sql .= $key . ' BIT NOT NULL,' . PHP_EOL;
326
- break;
327
- case is_array($copy->$key):
328
- case is_object($copy->$key):
329
- $sql .= $key . ' LONGTEXT NOT NULL,' . PHP_EOL;
330
- break;
331
- }
332
- }
333
-
334
- $sql .= $this->GetTableOptions() . PHP_EOL;
335
-
336
- $sql .= ')';
337
-
338
- if (! empty($_wpdb->charset)) {
339
- $sql .= ' DEFAULT CHARACTER SET ' . $_wpdb->charset;
340
- }
341
-
342
- return $sql;
343
-
344
- }
345
-
346
- /**
347
- * @return string Must return SQL for removing table (at a minimum, it should be ` 'DROP TABLE ' . $this->_table `).
348
- */
349
- protected function _GetUninstallQuery(){
350
- return 'DROP TABLE ' . $this->GetTable();
351
- }
352
-
353
- /**
354
- * Function used in WSAL reporting extension
355
- */
356
- public function GetReporting($_siteId, $_userId, $_roleName, $_alertCode, $_startTimestamp, $_endTimestamp, $_nextDate = null, $_limit = 0)
357
- {
358
- global $wpdb;
359
- $tableUsers = $wpdb->users;
360
- $_wpdb = $this->connection;
361
- // tables
362
- $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
363
- $tableMeta = $meta->GetTable(); // metadata
364
- $occurrence = new WSAL_Adapters_MySQL_Occurrence($this->connection);
365
- $tableOcc = $occurrence->GetTable(); // occurrences
366
-
367
- $user_names = '0';
368
- if (!empty($_userId) && $_userId != "null") {
369
- $sql = 'SELECT user_login FROM '.$tableUsers.' WHERE find_in_set(ID, @userId) > 0';
370
- $wpdb->query("SET @userId = $_userId");
371
- $result = $wpdb->get_results($sql, ARRAY_A);
372
- $aUsers = array();
373
- foreach ($result as $item) {
374
- $aUsers[] = '"'.$item['user_login'].'"';
375
- }
376
- $user_names = implode(', ', $aUsers);
377
- }
378
- $conditionDate = !empty($_nextDate) ? ' AND occ.created_on < '.$_nextDate : '';
379
-
380
- $sql = "SELECT DISTINCT
381
- occ.id,
382
- occ.alert_id,
383
- occ.site_id,
384
- occ.created_on,
385
- replace(replace(replace((
386
- SELECT t1.value FROM $tableMeta AS t1 WHERE t1.name = 'CurrentUserRoles' AND t1.occurrence_id = occ.id), '[', ''), ']', ''), '\\'', '') AS roles,
387
- (SELECT replace(t2.value, '\"','') FROM $tableMeta as t2 WHERE t2.name = 'ClientIP' AND t2.occurrence_id = occ.id) AS ip,
388
- (SELECT replace(t3.value, '\"', '') FROM $tableMeta as t3 WHERE t3.name = 'UserAgent' AND t3.occurrence_id = occ.id) AS ua,
389
- COALESCE(
390
- (SELECT replace(t4.value, '\"', '') FROM $tableMeta as t4 WHERE t4.name = 'Username' AND t4.occurrence_id = occ.id),
391
- (SELECT replace(t5.value, '\"', '') FROM $tableMeta as t5 WHERE t5.name = 'CurrentUserID' AND t5.occurrence_id = occ.id)
392
- ) as user_id
393
- FROM $tableOcc AS occ
394
- JOIN $tableMeta AS meta ON meta.occurrence_id = occ.id
395
- WHERE
396
- (@siteId is NULL OR find_in_set(occ.site_id, @siteId) > 0)
397
- AND (@userId is NULL OR (
398
- (meta.name = 'CurrentUserID' AND find_in_set(meta.value, @userId) > 0)
399
- OR (meta.name = 'Username' AND replace(meta.value, '\"', '') IN ($user_names))
400
- ))
401
- AND (@roleName is NULL OR (meta.name = 'CurrentUserRoles'
402
- AND replace(replace(replace(meta.value, ']', ''), '[', ''), '\\'', '') REGEXP @roleName
403
- ))
404
- AND (@alertCode is NULL OR find_in_set(occ.alert_id, @alertCode) > 0)
405
- AND (@startTimestamp is NULL OR occ.created_on >= @startTimestamp)
406
- AND (@endTimestamp is NULL OR occ.created_on <= @endTimestamp)
407
- {$conditionDate}
408
- ORDER BY
409
- created_on DESC
410
- ";
411
-
412
- $_wpdb->query("SET @siteId = $_siteId");
413
- $_wpdb->query("SET @userId = $_userId");
414
- $_wpdb->query("SET @roleName = $_roleName");
415
- $_wpdb->query("SET @alertCode = $_alertCode");
416
- $_wpdb->query("SET @startTimestamp = $_startTimestamp");
417
- $_wpdb->query("SET @endTimestamp = $_endTimestamp");
418
-
419
- if (!empty($_limit)) {
420
- $sql .= " LIMIT {$_limit}";
421
- }
422
- $results = $_wpdb->get_results($sql);
423
-
424
- foreach ($results as $row) {
425
- $sql = "SELECT t6.ID FROM $tableUsers AS t6 WHERE t6.user_login = \"$row->user_id\"";
426
- $userId = $wpdb->get_var($sql);
427
- if ($userId == null) {
428
- $sql = "SELECT t4.ID FROM $tableUsers AS t4 WHERE t4.ID = \"$row->user_id\"";
429
- $userId = $wpdb->get_var($sql);
430
- }
431
- $row->user_id = $userId;
432
- $results['lastDate'] = $row->created_on;
433
- }
434
-
435
- return $results;
436
- }
437
-
438
- }
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInterface
4
+ {
5
+ protected $connection;
6
+
7
+ /**
8
+ * Contains the table name
9
+ * @var string
10
+ */
11
+ protected $_table;
12
+
13
+ /**
14
+ * Contains primary key column name, override as required.
15
+ * @var string
16
+ */
17
+ protected $_idkey = '';
18
+
19
+ public function __construct($conn)
20
+ {
21
+ $this->connection = $conn;
22
+ }
23
+
24
+ public function GetModel()
25
+ {
26
+ return new WSAL_Models_ActiveRecord();
27
+ }
28
+
29
+ /**
30
+ * @return string Returns table name.
31
+ */
32
+ public function GetTable()
33
+ {
34
+ $_wpdb = $this->connection;
35
+ return $_wpdb->base_prefix . $this->_table;
36
+ }
37
+
38
+ /**
39
+ * Used for WordPress prefix
40
+ * @return string Returns table name of WordPress.
41
+ */
42
+ public function GetWPTable()
43
+ {
44
+ global $wpdb;
45
+ return $wpdb->base_prefix . $this->_table;
46
+ }
47
+
48
+ /**
49
+ * @return string SQL table options (constraints, foreign keys, indexes etc).
50
+ */
51
+ protected function GetTableOptions()
52
+ {
53
+ return ' PRIMARY KEY (' . $this->_idkey . ')';
54
+ }
55
+
56
+ /**
57
+ * @return array Returns this records' columns.
58
+ */
59
+ public function GetColumns()
60
+ {
61
+ $model = $this->GetModel();
62
+
63
+ if (!isset($this->_column_cache)) {
64
+ $this->_column_cache = array();
65
+ foreach (array_keys(get_object_vars($model)) as $col)
66
+ if (trim($col) && $col[0] != '_')
67
+ $this->_column_cache[] = $col;
68
+ }
69
+ return $this->_column_cache;
70
+ }
71
+
72
+ /**
73
+ * @deprecated
74
+ * @return boolean Returns whether table structure is installed or not.
75
+ */
76
+ public function IsInstalled(){
77
+ //global $wpdb;
78
+ $_wpdb = $this->connection;
79
+ $sql = 'SHOW TABLES LIKE "' . $this->GetTable() . '"';
80
+ return strtolower($_wpdb->get_var($sql)) == strtolower($this->GetTable());
81
+ }
82
+
83
+ /**
84
+ * Install this ActiveRecord structure into DB.
85
+ */
86
+ public function Install(){
87
+ $_wpdb = $this->connection;
88
+ $_wpdb->query($this->_GetInstallQuery());
89
+ }
90
+
91
+ /**
92
+ * Install this ActiveRecord structure into DB WordPress.
93
+ */
94
+ public function InstallOriginal(){
95
+ global $wpdb;
96
+ $wpdb->query($this->_GetInstallQuery(true));
97
+ }
98
+
99
+ /**
100
+ * Remove this ActiveRecord structure into DB.
101
+ */
102
+ public function Uninstall()
103
+ {
104
+ //global $wpdb;
105
+ $_wpdb = $this->connection;
106
+ $_wpdb->query($this->_GetUninstallQuery());
107
+ }
108
+
109
+ /**
110
+ * Save an active record to DB.
111
+ * @return integer|boolean Either the number of modified/inserted rows or false on failure.
112
+ */
113
+ public function Save($activeRecord)
114
+ {
115
+ //global $wpdb;
116
+ $_wpdb = $this->connection;
117
+ $copy = $activeRecord;
118
+ $data = array();
119
+ $format = array();
120
+
121
+ foreach ($this->GetColumns() as $index => $key) {
122
+ if ($key == $this->_idkey) {
123
+ $_idIndex = $index;
124
+ }
125
+
126
+ $val = $copy->$key;
127
+ $deffmt = '%s';
128
+ if (is_int($copy->$key)) {
129
+ $deffmt = '%d';
130
+ }
131
+ if (is_float($copy->$key)) {
132
+ $deffmt = '%f';
133
+ }
134
+ if (is_array($copy->$key) || is_object($copy->$key)) {
135
+ $data[$key] = WSAL_Helpers_DataHelper::JsonEncode($val);
136
+ } else {
137
+ $data[$key] = $val;
138
+ }
139
+ $format[] = $deffmt;
140
+ }
141
+
142
+ if (isset($data[$this->_idkey]) && empty($data[$this->_idkey])) {
143
+ unset($data[$this->_idkey]);
144
+ unset($format[$_idIndex]);
145
+ }
146
+
147
+ $result = $_wpdb->replace($this->GetTable(), $data, $format);
148
+
149
+ if ($result !== false) {
150
+ if ($_wpdb->insert_id) {
151
+ $copy->setId($_wpdb->insert_id);
152
+ }
153
+ }
154
+ return $result;
155
+ }
156
+
157
+ /**
158
+ * Load record from DB.
159
+ * @param string $cond (Optional) Load condition.
160
+ * @param array $args (Optional) Load condition arguments.
161
+ */
162
+ public function Load($cond = '%d', $args = array(1))
163
+ {
164
+ //global $wpdb;
165
+ $_wpdb = $this->connection;
166
+
167
+ $sql = $_wpdb->prepare('SELECT * FROM '.$this->GetTable().' WHERE '. $cond, $args);
168
+ $data = $_wpdb->get_row($sql, ARRAY_A);
169
+
170
+ return $data;
171
+ }
172
+
173
+ public function LoadArray($cond, $args = array())
174
+ {
175
+ //global $wpdb;
176
+ $_wpdb = $this->connection;
177
+ $result = array();
178
+ $sql = $_wpdb->prepare('SELECT * FROM '.$this->GetTable().' WHERE '. $cond, $args);
179
+ foreach ($_wpdb->get_results($sql, ARRAY_A) as $data) {
180
+ $result[] = $this->getModel()->LoadData($data);
181
+ }
182
+ return $result;
183
+ }
184
+
185
+ /**
186
+ * Delete DB record.
187
+ * @return int|boolean Either the amount of deleted rows or False on error.
188
+ */
189
+ public function Delete($activeRecord)
190
+ {
191
+ //global $wpdb;
192
+ $_wpdb = $this->connection;
193
+ $result = $_wpdb->delete(
194
+ $this->GetTable(),
195
+ $activeRecord->getId()
196
+ );
197
+ return $result;
198
+ }
199
+
200
+ /**
201
+ * Delete records in DB matching a query.
202
+ * @param string $query Full SQL query.
203
+ * @param array $args (Optional) Query arguments.
204
+ */
205
+ public function DeleteQuery($query, $args = array())
206
+ {
207
+ $_wpdb = $this->connection;
208
+ $sql = count($args) ? $_wpdb->prepare($query, $args) : $query;
209
+ $result = $_wpdb->query($sql);
210
+ return $result;
211
+ }
212
+
213
+ /**
214
+ * Load multiple records from DB.
215
+ * @param string $cond (Optional) Load condition (eg: 'some_id = %d' ).
216
+ * @param array $args (Optional) Load condition arguments (rg: array(45) ).
217
+ * @return self[] List of loaded records.
218
+ */
219
+ public function LoadMulti($cond, $args = array())
220
+ {
221
+ //global $wpdb;
222
+ $_wpdb = $this->connection;
223
+ $result = array();
224
+ $sql = (!is_array($args) || !count($args)) // do we really need to prepare() or not?
225
+ ? ($cond)
226
+ : $_wpdb->prepare($cond, $args)
227
+ ;
228
+ foreach ($_wpdb->get_results($sql, ARRAY_A) as $data) {
229
+ $result[] = $this->getModel()->LoadData($data);
230
+ }
231
+ return $result;
232
+
233
+ }
234
+
235
+ /**
236
+ * Load multiple records from DB and call a callback for each record.
237
+ * This function is very memory-efficient, it doesn't load records in bulk.
238
+ * @param callable $callback The callback to invoke.
239
+ * @param string $cond (Optional) Load condition.
240
+ * @param array $args (Optional) Load condition arguments.
241
+ */
242
+ public function LoadAndCallForEach($callback, $cond = '%d', $args = array(1))
243
+ {
244
+ //global $wpdb;
245
+ $_wpdb = $this->connection;
246
+ $class = get_called_class();
247
+ $sql = $_wpdb->prepare('SELECT * FROM ' . $this->GetTable() . ' WHERE '.$cond, $args);
248
+ foreach ($_wpdb->get_results($sql, ARRAY_A) as $data) {
249
+ call_user_func($callback, new $class($data));
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Count records in the DB matching a condition.
255
+ * If no parameters are given, this counts the number of records in the DB table.
256
+ * @param string $cond (Optional) Query condition.
257
+ * @param array $args (Optional) Condition arguments.
258
+ * @return int Number of matching records.
259
+ */
260
+ public function Count($cond = '%d', $args = array(1))
261
+ {
262
+ //global $wpdb;
263
+ $_wpdb = $this->connection;
264
+ $class = get_called_class();
265
+ $sql = $_wpdb->prepare('SELECT COUNT(*) FROM ' . $this->GetTable() . ' WHERE ' . $cond, $args);
266
+ return (int)$_wpdb->get_var($sql);
267
+ }
268
+
269
+ /**
270
+ * Count records in the DB matching a query.
271
+ * @param string $query Full SQL query.
272
+ * @param array $args (Optional) Query arguments.
273
+ * @return int Number of matching records.
274
+ */
275
+ public function CountQuery($query, $args = array())
276
+ {
277
+ //global $wpdb;
278
+ $_wpdb = $this->connection;
279
+ $sql = count($args) ? $_wpdb->prepare($query, $args) : $query;
280
+ return (int)$_wpdb->get_var($sql);
281
+ }
282
+
283
+ /**
284
+ * Similar to LoadMulti but allows the use of a full SQL query.
285
+ * @param string $query Full SQL query.
286
+ * @param array $args (Optional) Query arguments.
287
+ * @return self[] List of loaded records.
288
+ */
289
+ public function LoadMultiQuery($query, $args = array())
290
+ {
291
+ //global $wpdb;
292
+ $_wpdb = $this->connection;
293
+ $class = get_called_class();
294
+ $result = array();
295
+ $sql = count($args) ? $_wpdb->prepare($query, $args) : $query;
296
+ foreach ($_wpdb->get_results($sql, ARRAY_A) as $data) {
297
+ $result[] = $this->getModel()->LoadData($data);
298
+ }
299
+ return $result;
300
+ }
301
+
302
+ /**
303
+ * @return string Must return SQL for creating table.
304
+ */
305
+ protected function _GetInstallQuery($prefix = false)
306
+ {
307
+ $_wpdb = $this->connection;
308
+
309
+ $class = get_class($this);
310
+ $copy = new $class($this->connection);
311
+ $table_name = ($prefix) ? $this->GetWPTable() : $this->GetTable();
312
+ $sql = 'CREATE TABLE IF NOT EXISTS ' . $table_name . ' (' . PHP_EOL;
313
+
314
+ foreach ($this->GetColumns() as $key) {
315
+ $sql .= ' ';
316
+ switch (true) {
317
+ case $key == $copy->_idkey:
318
+ $sql .= $key . ' BIGINT NOT NULL AUTO_INCREMENT,' . PHP_EOL;
319
+ break;
320
+ case is_integer($copy->$key):
321
+ $sql .= $key . ' BIGINT NOT NULL,' . PHP_EOL;
322
+ break;
323
+ case is_float($copy->$key):
324
+ $sql .= $key . ' DOUBLE NOT NULL,' . PHP_EOL;
325
+ break;
326
+ case is_string($copy->$key):
327
+ $maxlength = $key . '_maxlength';
328
+ if (property_exists($class, $maxlength)) {
329
+ $sql .= $key . ' VARCHAR(' . intval($class::$$maxlength) . ') NOT NULL,' . PHP_EOL;
330
+ } else {
331
+ $sql .= $key . ' TEXT NOT NULL,' . PHP_EOL;
332
+ }
333
+ break;
334
+ case is_bool($copy->$key):
335
+ $sql .= $key . ' BIT NOT NULL,' . PHP_EOL;
336
+ break;
337
+ case is_array($copy->$key):
338
+ case is_object($copy->$key):
339
+ $sql .= $key . ' LONGTEXT NOT NULL,' . PHP_EOL;
340
+ break;
341
+ }
342
+ }
343
+
344
+ $sql .= $this->GetTableOptions() . PHP_EOL;
345
+
346
+ $sql .= ')';
347
+
348
+ if (! empty($_wpdb->charset)) {
349
+ $sql .= ' DEFAULT CHARACTER SET ' . $_wpdb->charset;
350
+ }
351
+
352
+ return $sql;
353
+
354
+ }
355
+
356
+ /**
357
+ * @return string Must return SQL for removing table (at a minimum, it should be ` 'DROP TABLE ' . $this->_table `).
358
+ */
359
+ protected function _GetUninstallQuery()
360
+ {
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
+ // tables
373
+ $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
374
+ $tableMeta = $meta->GetTable(); // metadata
375
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence($this->connection);
376
+ $tableOcc = $occurrence->GetTable(); // occurrences
377
+
378
+ $user_names = '0';
379
+ if (!empty($_userId) && $_userId != "null") {
380
+ $sql = 'SELECT user_login FROM '.$tableUsers.' WHERE find_in_set(ID, @userId) > 0';
381
+ $wpdb->query("SET @userId = $_userId");
382
+ $result = $wpdb->get_results($sql, ARRAY_A);
383
+ $aUsers = array();
384
+ foreach ($result as $item) {
385
+ $aUsers[] = '"'.$item['user_login'].'"';
386
+ }
387
+ $user_names = implode(', ', $aUsers);
388
+ }
389
+ $conditionDate = !empty($_nextDate) ? ' AND occ.created_on < '.$_nextDate : '';
390
+
391
+ $sql = "SELECT DISTINCT
392
+ occ.id,
393
+ occ.alert_id,
394
+ occ.site_id,
395
+ occ.created_on,
396
+ replace(replace(replace((
397
+ SELECT t1.value FROM $tableMeta AS t1 WHERE t1.name = 'CurrentUserRoles' AND t1.occurrence_id = occ.id), '[', ''), ']', ''), '\\'', '') AS roles,
398
+ (SELECT replace(t2.value, '\"','') FROM $tableMeta as t2 WHERE t2.name = 'ClientIP' AND t2.occurrence_id = occ.id) AS ip,
399
+ (SELECT replace(t3.value, '\"', '') FROM $tableMeta as t3 WHERE t3.name = 'UserAgent' AND t3.occurrence_id = occ.id) AS ua,
400
+ COALESCE(
401
+ (SELECT replace(t4.value, '\"', '') FROM $tableMeta as t4 WHERE t4.name = 'Username' AND t4.occurrence_id = occ.id),
402
+ (SELECT replace(t5.value, '\"', '') FROM $tableMeta as t5 WHERE t5.name = 'CurrentUserID' AND t5.occurrence_id = occ.id)
403
+ ) as user_id
404
+ FROM $tableOcc AS occ
405
+ JOIN $tableMeta AS meta ON meta.occurrence_id = occ.id
406
+ WHERE
407
+ (@siteId is NULL OR find_in_set(occ.site_id, @siteId) > 0)
408
+ AND (@userId is NULL OR (
409
+ (meta.name = 'CurrentUserID' AND find_in_set(meta.value, @userId) > 0)
410
+ OR (meta.name = 'Username' AND replace(meta.value, '\"', '') IN ($user_names))
411
+ ))
412
+ AND (@roleName is NULL OR (meta.name = 'CurrentUserRoles'
413
+ AND replace(replace(replace(meta.value, ']', ''), '[', ''), '\\'', '') REGEXP @roleName
414
+ ))
415
+ AND (@alertCode is NULL OR find_in_set(occ.alert_id, @alertCode) > 0)
416
+ AND (@startTimestamp is NULL OR occ.created_on >= @startTimestamp)
417
+ AND (@endTimestamp is NULL OR occ.created_on <= @endTimestamp)
418
+ {$conditionDate}
419
+ ORDER BY
420
+ created_on DESC
421
+ ";
422
+
423
+ $_wpdb->query("SET @siteId = $_siteId");
424
+ $_wpdb->query("SET @userId = $_userId");
425
+ $_wpdb->query("SET @roleName = $_roleName");
426
+ $_wpdb->query("SET @alertCode = $_alertCode");
427
+ $_wpdb->query("SET @startTimestamp = $_startTimestamp");
428
+ $_wpdb->query("SET @endTimestamp = $_endTimestamp");
429
+
430
+ if (!empty($_limit)) {
431
+ $sql .= " LIMIT {$_limit}";
432
+ }
433
+ $results = $_wpdb->get_results($sql);
434
+
435
+ foreach ($results as $row) {
436
+ $sql = "SELECT t6.ID FROM $tableUsers AS t6 WHERE t6.user_login = \"$row->user_id\"";
437
+ $userId = $wpdb->get_var($sql);
438
+ if ($userId == null) {
439
+ $sql = "SELECT t4.ID FROM $tableUsers AS t4 WHERE t4.ID = \"$row->user_id\"";
440
+ $userId = $wpdb->get_var($sql);
441
+ }
442
+ $row->user_id = $userId;
443
+ $results['lastDate'] = $row->created_on;
444
+ }
445
+
446
+ return $results;
447
+ }
448
+ }
classes/Models/Adapters/MySQL/MetaAdapter.php CHANGED
@@ -1,53 +1,53 @@
1
- <?php
2
-
3
- class WSAL_Adapters_MySQL_Meta extends WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_MetaInterface {
4
-
5
- protected $_table = 'wsal_metadata';
6
- protected $_idkey = 'id';
7
-
8
- public $id = 0;
9
- public $occurrence_id = 0;
10
- public $name = '';
11
- public static $name_maxlength = 100;
12
- public $value = array(); // force mixed type
13
-
14
- public function GetModel()
15
- {
16
- return new WSAL_Models_Meta();
17
- }
18
-
19
- public function __construct($conn)
20
- {
21
- parent::__construct($conn);
22
- }
23
-
24
- protected function GetTableOptions(){
25
- return parent::GetTableOptions() . ',' . PHP_EOL
26
- . ' KEY occurrence_name (occurrence_id,name)';
27
- }
28
-
29
- public function DeleteByOccurenceIds($occurenceIds)
30
- {
31
- if (!empty($occurenceIds)) {
32
- $sql = 'DELETE FROM ' . $this->GetTable() . ' WHERE occurrence_id IN (' . implode(',', $occurenceIds) . ')';
33
- // execute query
34
- parent::DeleteQuery($sql);
35
- }
36
- }
37
-
38
- public function LoadByNameAndOccurenceId($metaName, $occurenceId)
39
- {
40
- return $this->Load('occurrence_id = %d AND name = %s', array($occurenceId, $metaName));
41
- }
42
-
43
- public function GetMatchingIPs()
44
- {
45
- $_wpdb = $this->connection;
46
- $ips = $_wpdb->get_col("SELECT DISTINCT value FROM {$this->GetTable()} WHERE name = \"ClientIP\"");
47
- foreach ($ips as $key => $ip) {
48
- $ips[$key] = str_replace('"', '', $ip);
49
- }
50
- return array_unique($ips);
51
- }
52
-
53
- }
1
+ <?php
2
+
3
+ class WSAL_Adapters_MySQL_Meta extends WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_MetaInterface {
4
+
5
+ protected $_table = 'wsal_metadata';
6
+ protected $_idkey = 'id';
7
+
8
+ public $id = 0;
9
+ public $occurrence_id = 0;
10
+ public $name = '';
11
+ public static $name_maxlength = 100;
12
+ public $value = array(); // force mixed type
13
+
14
+ public function GetModel()
15
+ {
16
+ return new WSAL_Models_Meta();
17
+ }
18
+
19
+ public function __construct($conn)
20
+ {
21
+ parent::__construct($conn);
22
+ }
23
+
24
+ protected function GetTableOptions(){
25
+ return parent::GetTableOptions() . ',' . PHP_EOL
26
+ . ' KEY occurrence_name (occurrence_id,name)';
27
+ }
28
+
29
+ public function DeleteByOccurenceIds($occurenceIds)
30
+ {
31
+ if (!empty($occurenceIds)) {
32
+ $sql = 'DELETE FROM ' . $this->GetTable() . ' WHERE occurrence_id IN (' . implode(',', $occurenceIds) . ')';
33
+ // execute query
34
+ parent::DeleteQuery($sql);
35
+ }
36
+ }
37
+
38
+ public function LoadByNameAndOccurenceId($metaName, $occurenceId)
39
+ {
40
+ return $this->Load('occurrence_id = %d AND name = %s', array($occurenceId, $metaName));
41
+ }
42
+
43
+ public function GetMatchingIPs()
44
+ {
45
+ $_wpdb = $this->connection;
46
+ $ips = $_wpdb->get_col("SELECT DISTINCT value FROM {$this->GetTable()} WHERE name = \"ClientIP\"");
47
+ foreach ($ips as $key => $ip) {
48
+ $ips[$key] = str_replace('"', '', $ip);
49
+ }
50
+ return array_unique($ips);
51
+ }
52
+
53
+ }
classes/Models/Adapters/MySQL/OccurrenceAdapter.php CHANGED
@@ -1,187 +1,187 @@
1
- <?php
2
-
3
- class WSAL_Adapters_MySQL_Occurrence extends WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_OccurrenceInterface {
4
-
5
- protected $_table = 'wsal_occurrences';
6
- protected $_idkey = 'id';
7
- protected $_meta;
8
-
9
- public $id = 0;
10
- public $site_id = 0;
11
- public $alert_id = 0;
12
- public $created_on = 0.0;
13
- public $is_read = false;
14
- public $is_migrated = false;
15
-
16
- public function __construct($conn) {
17
- parent::__construct($conn);
18
- }
19
-
20
- protected function GetTableOptions(){
21
- return parent::GetTableOptions() . ',' . PHP_EOL
22
- . ' KEY site_alert_created (site_id,alert_id,created_on)';
23
- }
24
-
25
- public function GetModel()
26
- {
27
- return new WSAL_Models_Occurrence();
28
- }
29
- /**
30
- * Returns all meta data related to this event.
31
- * @return WSAL_Meta[]
32
- */
33
- public function GetMeta($occurence){
34
- if(!isset($this->_meta)){
35
- $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
36
- $this->_meta = $meta->Load('occurrence_id = %d', array($occurence->id));
37
- }
38
- return $this->_meta;
39
- }
40
-
41
- public function GetMultiMeta($occurence){
42
- if(!isset($this->_meta)){
43
- $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
44
- $this->_meta = $meta->LoadArray('occurrence_id = %d', array($occurence->id));
45
- }
46
- return $this->_meta;
47
- }
48
-
49
- /**
50
- * Loads a meta item given its name.
51
- * @param string $name Meta name.
52
- * @return WSAL_Meta The meta item, be sure to checked if it was loaded successfully.
53
- */
54
- public function GetNamedMeta($occurence, $name){
55
- $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
56
- $this->_meta = $meta->Load('occurrence_id = %d AND name = %s', array($occurence->id, $name));
57
-
58
- return $this->_meta;
59
- }
60
-
61
- /**
62
- * Returns the first meta value from a given set of names. Useful when you have a mix of items that could provide a particular detail.
63
- * @param array $names List of meta names.
64
- * @return WSAL_Meta The first meta item that exists.
65
- */
66
- public function GetFirstNamedMeta($occurence, $names){
67
- $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
68
- $query = '(' . str_repeat('name = %s OR ', count($names)).'0)';
69
- $query = 'occurrence_id = %d AND ' . $query . ' ORDER BY name DESC LIMIT 1';
70
- array_unshift($names, $occurence->id); // prepend args with occurrence id
71
-
72
- $this->_meta = $meta->Load($query, $names);
73
- return $meta->getModel()->LoadData($this->_meta);
74
-
75
- //TO DO: Do we want to reintroduce is loaded check/logic?
76
- //return $meta->IsLoaded() ? $meta : null;
77
- }
78
-
79
- /**
80
- * Returns newest unique occurrences.
81
- * @param integer $limit Maximum limit.
82
- * @return WSAL_Occurrence[]
83
- */
84
- public static function GetNewestUnique($limit = PHP_INT_MAX){
85
- $temp = new self();
86
- return self::LoadMultiQuery('
87
- SELECT *, COUNT(alert_id) as count
88
- FROM (
89
- SELECT *
90
- FROM ' . $temp->GetTable() . '
91
- ORDER BY created_on DESC
92
- ) AS temp_table
93
- GROUP BY alert_id
94
- LIMIT %d
95
- ', array($limit));
96
- }
97
-
98
- /**
99
- * Gets occurences of the same type by IP and Username within specified time frame
100
- * @param string $ipAddress
101
- * @param string $username
102
- * @param int $alertId Alert type we are lookign for
103
- * @param int $siteId
104
- * @param $startTime mktime
105
- * @param $endTime mktime
106
- */
107
- public function CheckKnownUsers($args = array())
108
- {
109
- $tt2 = new WSAL_Adapters_MySQL_Meta($this->connection);
110
- return self::LoadMultiQuery(
111
- 'SELECT occurrence.* FROM `' . $this->GetTable() . '` occurrence
112
- INNER JOIN `' . $tt2->GetTable() . '` ipMeta on ipMeta.occurrence_id = occurrence.id
113
- and ipMeta.name = "ClientIP"
114
- and ipMeta.value = %s
115
- INNER JOIN `' . $tt2->GetTable() . '` usernameMeta on usernameMeta.occurrence_id = occurrence.id
116
- and usernameMeta.name = "Username"
117
- and usernameMeta.value = %s
118
- WHERE occurrence.alert_id = %d AND occurrence.site_id = %d
119
- AND (created_on BETWEEN %d AND %d)
120
- GROUP BY occurrence.id',
121
- $args
122
- );
123
- }
124
-
125
- public function CheckUnKnownUsers($args = array())
126
- {
127
- $tt2 = new WSAL_Adapters_MySQL_Meta($this->connection);
128
- return self::LoadMultiQuery(
129
- 'SELECT occurrence.* FROM `' . $this->GetTable() . '` occurrence
130
- INNER JOIN `' . $tt2->GetTable() . '` ipMeta on ipMeta.occurrence_id = occurrence.id
131
- and ipMeta.name = "ClientIP" and ipMeta.value = %s
132
- WHERE occurrence.alert_id = %d AND occurrence.site_id = %d
133
- AND (created_on BETWEEN %d AND %d)
134
- GROUP BY occurrence.id',
135
- $args
136
- );
137
- }
138
-
139
- protected function prepareOccurrenceQuery($query)
140
- {
141
- $searchQueryParameters = array();
142
- $searchConditions = array();
143
- $conditions = $query->getConditions();
144
-
145
- //BUG: not all conditions are occurence related. maybe it's just a field site_id. need seperate arrays
146
- if (!empty($conditions)) {
147
- $tmp = new WSAL_Adapters_MySQL_Meta($this->connection);
148
- $sWhereClause = "";
149
- foreach ($conditions as $field => $value) {
150
- if (!empty($sWhereClause)) {
151
- $sWhereClause .= " AND ";
152
- }
153
- $sWhereClause .= "name = %s AND value = %s";
154
- $searchQueryParameters[] = $field;
155
- $searchQueryParameters[] = $value;
156
- }
157
-
158
- $searchConditions[] = 'id IN (
159
- SELECT DISTINCT occurrence_id
160
- FROM ' . $tmp->GetTable() . '
161
- WHERE ' . $sWhereClause . '
162
- )';
163
- }
164
-
165
- //do something with search query parameters and search conditions - give them to the query adapter?
166
- return $searchConditions;
167
- }
168
-
169
- /**
170
- * Gets occurrence by Post_id
171
- * @param int $post_id
172
- */
173
- public function GetByPostID($post_id)
174
- {
175
- $tt2 = new WSAL_Adapters_MySQL_Meta($this->connection);
176
- return self::LoadMultiQuery(
177
- 'SELECT occurrence.* FROM `' . $this->GetTable() . '`AS occurrence
178
- INNER JOIN `' . $tt2->GetTable() . '`AS postMeta ON postMeta.occurrence_id = occurrence.id
179
- and postMeta.name = "PostID"
180
- and postMeta.value = %d
181
- GROUP BY occurrence.id
182
- ORDER BY created_on DESC',
183
- array($post_id)
184
- );
185
- }
186
-
187
- }
1
+ <?php
2
+
3
+ class WSAL_Adapters_MySQL_Occurrence extends WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_OccurrenceInterface {
4
+
5
+ protected $_table = 'wsal_occurrences';
6
+ protected $_idkey = 'id';
7
+ protected $_meta;
8
+
9
+ public $id = 0;
10
+ public $site_id = 0;
11
+ public $alert_id = 0;
12
+ public $created_on = 0.0;
13
+ public $is_read = false;
14
+ public $is_migrated = false;
15
+
16
+ public function __construct($conn) {
17
+ parent::__construct($conn);
18
+ }
19
+
20
+ protected function GetTableOptions(){
21
+ return parent::GetTableOptions() . ',' . PHP_EOL
22
+ . ' KEY site_alert_created (site_id,alert_id,created_on)';
23
+ }
24
+
25
+ public function GetModel()
26
+ {
27
+ return new WSAL_Models_Occurrence();
28
+ }
29
+ /**
30
+ * Returns all meta data related to this event.
31
+ * @return WSAL_Meta[]
32
+ */
33
+ public function GetMeta($occurence){
34
+ if(!isset($this->_meta)){
35
+ $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
36
+ $this->_meta = $meta->Load('occurrence_id = %d', array($occurence->id));
37
+ }
38
+ return $this->_meta;
39
+ }
40
+
41
+ public function GetMultiMeta($occurence){
42
+ if(!isset($this->_meta)){
43
+ $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
44
+ $this->_meta = $meta->LoadArray('occurrence_id = %d', array($occurence->id));
45
+ }
46
+ return $this->_meta;
47
+ }
48
+
49
+ /**
50
+ * Loads a meta item given its name.
51
+ * @param string $name Meta name.
52
+ * @return WSAL_Meta The meta item, be sure to checked if it was loaded successfully.
53
+ */
54
+ public function GetNamedMeta($occurence, $name){
55
+ $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
56
+ $this->_meta = $meta->Load('occurrence_id = %d AND name = %s', array($occurence->id, $name));
57
+
58
+ return $this->_meta;
59
+ }
60
+
61
+ /**
62
+ * Returns the first meta value from a given set of names. Useful when you have a mix of items that could provide a particular detail.
63
+ * @param array $names List of meta names.
64
+ * @return WSAL_Meta The first meta item that exists.
65
+ */
66
+ public function GetFirstNamedMeta($occurence, $names){
67
+ $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
68
+ $query = '(' . str_repeat('name = %s OR ', count($names)).'0)';
69
+ $query = 'occurrence_id = %d AND ' . $query . ' ORDER BY name DESC LIMIT 1';
70
+ array_unshift($names, $occurence->id); // prepend args with occurrence id
71
+
72
+ $this->_meta = $meta->Load($query, $names);
73
+ return $meta->getModel()->LoadData($this->_meta);
74
+
75
+ //TO DO: Do we want to reintroduce is loaded check/logic?
76
+ //return $meta->IsLoaded() ? $meta : null;
77
+ }
78
+
79
+ /**
80
+ * Returns newest unique occurrences.
81
+ * @param integer $limit Maximum limit.
82
+ * @return WSAL_Occurrence[]
83
+ */
84
+ public static function GetNewestUnique($limit = PHP_INT_MAX){
85
+ $temp = new self();
86
+ return self::LoadMultiQuery('
87
+ SELECT *, COUNT(alert_id) as count
88
+ FROM (
89
+ SELECT *
90
+ FROM ' . $temp->GetTable() . '
91
+ ORDER BY created_on DESC
92
+ ) AS temp_table
93
+ GROUP BY alert_id
94
+ LIMIT %d
95
+ ', array($limit));
96
+ }
97
+
98
+ /**
99
+ * Gets occurences of the same type by IP and Username within specified time frame
100
+ * @param string $ipAddress
101
+ * @param string $username
102
+ * @param int $alertId Alert type we are lookign for
103
+ * @param int $siteId
104
+ * @param $startTime mktime
105
+ * @param $endTime mktime
106
+ */
107
+ public function CheckKnownUsers($args = array())
108
+ {
109
+ $tt2 = new WSAL_Adapters_MySQL_Meta($this->connection);
110
+ return self::LoadMultiQuery(
111
+ 'SELECT occurrence.* FROM `' . $this->GetTable() . '` occurrence
112
+ INNER JOIN `' . $tt2->GetTable() . '` ipMeta on ipMeta.occurrence_id = occurrence.id
113
+ and ipMeta.name = "ClientIP"
114
+ and ipMeta.value = %s
115
+ INNER JOIN `' . $tt2->GetTable() . '` usernameMeta on usernameMeta.occurrence_id = occurrence.id
116
+ and usernameMeta.name = "Username"
117
+ and usernameMeta.value = %s
118
+ WHERE occurrence.alert_id = %d AND occurrence.site_id = %d
119
+ AND (created_on BETWEEN %d AND %d)
120
+ GROUP BY occurrence.id',
121
+ $args
122
+ );
123
+ }
124
+
125
+ public function CheckUnKnownUsers($args = array())
126
+ {
127
+ $tt2 = new WSAL_Adapters_MySQL_Meta($this->connection);
128
+ return self::LoadMultiQuery(
129
+ 'SELECT occurrence.* FROM `' . $this->GetTable() . '` occurrence
130
+ INNER JOIN `' . $tt2->GetTable() . '` ipMeta on ipMeta.occurrence_id = occurrence.id
131
+ and ipMeta.name = "ClientIP" and ipMeta.value = %s
132
+ WHERE occurrence.alert_id = %d AND occurrence.site_id = %d
133
+ AND (created_on BETWEEN %d AND %d)
134
+ GROUP BY occurrence.id',
135
+ $args
136
+ );
137
+ }
138
+
139
+ protected function prepareOccurrenceQuery($query)
140
+ {
141
+ $searchQueryParameters = array();
142
+ $searchConditions = array();
143
+ $conditions = $query->getConditions();
144
+
145
+ //BUG: not all conditions are occurence related. maybe it's just a field site_id. need seperate arrays
146
+ if (!empty($conditions)) {
147
+ $tmp = new WSAL_Adapters_MySQL_Meta($this->connection);
148
+ $sWhereClause = "";
149
+ foreach ($conditions as $field => $value) {
150
+ if (!empty($sWhereClause)) {
151
+ $sWhereClause .= " AND ";
152
+ }
153
+ $sWhereClause .= "name = %s AND value = %s";
154
+ $searchQueryParameters[] = $field;
155
+ $searchQueryParameters[] = $value;
156
+ }
157
+
158
+ $searchConditions[] = 'id IN (
159
+ SELECT DISTINCT occurrence_id
160
+ FROM ' . $tmp->GetTable() . '
161
+ WHERE ' . $sWhereClause . '
162
+ )';
163
+ }
164
+
165
+ //do something with search query parameters and search conditions - give them to the query adapter?
166
+ return $searchConditions;
167
+ }
168
+
169
+ /**
170
+ * Gets occurrence by Post_id
171
+ * @param int $post_id
172
+ */
173
+ public function GetByPostID($post_id)
174
+ {
175
+ $tt2 = new WSAL_Adapters_MySQL_Meta($this->connection);
176
+ return self::LoadMultiQuery(
177
+ 'SELECT occurrence.* FROM `' . $this->GetTable() . '`AS occurrence
178
+ INNER JOIN `' . $tt2->GetTable() . '`AS postMeta ON postMeta.occurrence_id = occurrence.id
179
+ and postMeta.name = "PostID"
180
+ and postMeta.value = %d
181
+ GROUP BY occurrence.id
182
+ ORDER BY created_on DESC',
183
+ array($post_id)
184
+ );
185
+ }
186
+
187
+ }
classes/Models/Adapters/MySQL/OptionAdapter.php CHANGED
@@ -1,79 +1,79 @@
1
- <?php
2
-
3
- class WSAL_Adapters_MySQL_Option extends WSAL_Adapters_MySQL_ActiveRecord
4
- {
5
-
6
- protected $_table = 'wsal_options';
7
- protected $_idkey = 'id';
8
-
9
- public $id = 0;
10
- public $option_name = '';
11
- public static $option_name_maxlength = 100;
12
- public $option_value = '';
13
-
14
- public function __construct($conn)
15
- {
16
- parent::__construct($conn);
17
- }
18
-
19
- public function GetModel()
20
- {
21
- return new WSAL_Models_Option();
22
- }
23
-
24
- public function GetNamedOption($name)
25
- { if ($this->IsInstalled()) {
26
- return $this->Load('option_name = %s', array($name));
27
- } else {
28
- return null;
29
- }
30
- }
31
-
32
- public function GetNotificationsSetting($opt_prefix)
33
- {
34
- if ($this->IsInstalled()) {
35
- return $this->LoadArray('option_name LIKE %s', array($opt_prefix."%"));
36
- } else {
37
- return null;
38
- }
39
- }
40
-
41
- public function GetNotification($id)
42
- {
43
- if ($this->IsInstalled()) {
44
- return $this->Load('id = %d', array($id));
45
- } else {
46
- return null;
47
- }
48
- }
49
-
50
- public function DeleteByName($name)
51
- {
52
- if (!empty($name)) {
53
- $sql = "DELETE FROM " . $this->GetTable() . " WHERE option_name = '". $name ."'";
54
- // execute query
55
- return parent::DeleteQuery($sql);
56
- } else {
57
- return false;
58
- }
59
- }
60
-
61
- public function DeleteByPrefix($opt_prefix)
62
- {
63
- if (!empty($opt_prefix)) {
64
- $sql = "DELETE FROM " . $this->GetTable() . " WHERE option_name LIKE '". $opt_prefix ."%'";
65
- // execute query
66
- return parent::DeleteQuery($sql);
67
- } else {
68
- return false;
69
- }
70
- }
71
-
72
- public function CountNotifications($opt_prefix)
73
- {
74
- $_wpdb = $this->connection;
75
- $sql = "SELECT COUNT(id) FROM " . $this->GetTable() . " WHERE option_name LIKE '". $opt_prefix ."%'";
76
- return (int)$_wpdb->get_var($sql);
77
- }
78
-
79
- }
1
+ <?php
2
+
3
+ class WSAL_Adapters_MySQL_Option extends WSAL_Adapters_MySQL_ActiveRecord
4
+ {
5
+
6
+ protected $_table = 'wsal_options';
7
+ protected $_idkey = 'id';
8
+
9
+ public $id = 0;
10
+ public $option_name = '';
11
+ public static $option_name_maxlength = 100;
12
+ public $option_value = '';
13
+
14
+ public function __construct($conn)
15
+ {
16
+ parent::__construct($conn);
17
+ }
18
+
19
+ public function GetModel()
20
+ {
21
+ return new WSAL_Models_Option();
22
+ }
23
+
24
+ public function GetNamedOption($name)
25
+ { if ($this->IsInstalled()) {
26
+ return $this->Load('option_name = %s', array($name));
27
+ } else {
28
+ return null;
29
+ }
30
+ }
31
+
32
+ public function GetNotificationsSetting($opt_prefix)
33
+ {
34
+ if ($this->IsInstalled()) {
35
+ return $this->LoadArray('option_name LIKE %s', array($opt_prefix."%"));
36
+ } else {
37
+ return null;
38
+ }
39
+ }
40
+
41
+ public function GetNotification($id)
42
+ {
43
+ if ($this->IsInstalled()) {
44
+ return $this->Load('id = %d', array($id));
45
+ } else {
46
+ return null;
47
+ }
48
+ }
49
+
50
+ public function DeleteByName($name)
51
+ {
52
+ if (!empty($name)) {
53
+ $sql = "DELETE FROM " . $this->GetTable() . " WHERE option_name = '". $name ."'";
54
+ // execute query
55
+ return parent::DeleteQuery($sql);
56
+ } else {
57
+ return false;
58
+ }
59
+ }
60
+
61
+ public function DeleteByPrefix($opt_prefix)
62
+ {
63
+ if (!empty($opt_prefix)) {
64
+ $sql = "DELETE FROM " . $this->GetTable() . " WHERE option_name LIKE '". $opt_prefix ."%'";
65
+ // execute query
66
+ return parent::DeleteQuery($sql);
67
+ } else {
68
+ return false;
69
+ }
70
+ }
71
+
72
+ public function CountNotifications($opt_prefix)
73
+ {
74
+ $_wpdb = $this->connection;
75
+ $sql = "SELECT COUNT(id) FROM " . $this->GetTable() . " WHERE option_name LIKE '". $opt_prefix ."%'";
76
+ return (int)$_wpdb->get_var($sql);
77
+ }
78
+
79
+ }
classes/Models/Adapters/MySQL/QueryAdapter.php CHANGED
@@ -1,219 +1,219 @@
1
- <?php
2
-
3
- class WSAL_Adapters_MySQL_Query implements WSAL_Adapters_QueryInterface
4
- {
5
- protected $connection;
6
-
7
- public function __construct($conn)
8
- {
9
- $this->connection = $conn;
10
- }
11
-
12
- /**
13
- * @return string Generated sql.
14
- */
15
- protected function GetSql($query, &$args = array())
16
- {
17
- $conditions = $query->getConditions();
18
- $searchCondition = $this->SearchCondition($query);
19
-
20
- $sWhereClause = "";
21
- foreach ($conditions as $fieldName => $fieldValue) {
22
- if (empty($sWhereClause)) {
23
- $sWhereClause .= " WHERE ";
24
- } else {
25
- $sWhereClause .= " AND ";
26
- }
27
-
28
- if (is_array($fieldValue)) {
29
- $subWhereClause = "(";
30
- foreach($fieldValue as $orFieldName => $orFieldValue) {
31
- if ($subWhereClause != '(') {
32
- $subWhereClause .= " OR ";
33
- }
34
- $subWhereClause .= $orFieldName;
35
- $args[] = $orFieldValue;
36
- }
37
- $subWhereClause .= ")";
38
- $sWhereClause .= $subWhereClause;
39
- } else {
40
- $sWhereClause .= $fieldName;
41
- $args[] = $fieldValue;
42
- }
43
- }
44
-
45
- $fromDataSets = $query->getFrom();
46
- $columns = $query->getColumns();
47
- $orderBys = $query->getOrderBy();
48
-
49
- $sLimitClause = "";
50
- if ($query->getLimit()) {
51
- $sLimitClause .= " LIMIT ";
52
- if ($query->getOffset()) {
53
- $sLimitClause .= $query->getOffset() . ", ";
54
- }
55
- $sLimitClause .= $query->getLimit();
56
- }
57
- $joinClause = '';
58
- if ($query->hasMetaJoin()) {
59
- $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
60
- $occurrence = new WSAL_Adapters_MySQL_Occurrence($this->connection);
61
- $joinClause = ' LEFT JOIN '. $meta->GetTable() .' AS meta ON meta.occurrence_id = '. $occurrence->GetTable() .'.id ';
62
- }
63
- $fields = (empty($columns))? $fromDataSets[0] . '.*' : implode(',', $columns);
64
- if (!empty($searchCondition)) {
65
- $args[] = $searchCondition['args'];
66
- }
67
- return 'SELECT ' . $fields
68
- . ' FROM ' . implode(',', $fromDataSets)
69
- . $joinClause
70
- . $sWhereClause
71
- . (!empty($searchCondition) ? (empty($sWhereClause) ? " WHERE ".$searchCondition['sql'] : " AND ".$searchCondition['sql']) : '')
72
- // @todo GROUP BY goes here
73
- . (!empty($orderBys) ? (' ORDER BY ' . implode(', ', array_keys($orderBys)) . ' ' . implode(', ', array_values($orderBys))) : '')
74
- . $sLimitClause;
75
- }
76
-
77
- protected function getActiveRecordAdapter()
78
- {
79
- return new WSAL_Adapters_MySQL_ActiveRecord($this->connection);
80
- }
81
-
82
- /**
83
- * @return WSAL_Models_ActiveRecord[] Execute query and return data as $ar_cls objects.
84
- */
85
- public function Execute($query)
86
- {
87
- $args = array();
88
- $sql = $this->GetSql($query, $args);
89
-
90
- $occurenceAdapter = $query->getConnector()->getAdapter("Occurrence");
91
-
92
- if (in_array($occurenceAdapter->GetTable(), $query->getFrom())) {
93
- return $occurenceAdapter->LoadMulti($sql, $args);
94
- } else {
95
- return $this->getActiveRecordAdapter()->LoadMulti($sql, $args);
96
- }
97
- }
98
-
99
- /**
100
- * @return int Use query for counting records.
101
- */
102
- public function Count($query)
103
- {
104
- // back up columns, use COUNT as default column and generate sql
105
- $cols = $query->getColumns();
106
- $query->clearColumns();
107
- $query->addColumn('COUNT(*)');
108
-
109
- $args = array();
110
- $sql = $this->GetSql($query, $args);
111
-
112
- // restore columns
113
- $query->setColumns($cols);
114
- // execute query and return result
115
- return $this->getActiveRecordAdapter()->CountQuery($sql, $args);
116
- }
117
-
118
- public function CountDelete($query)
119
- {
120
- $result = $this->GetSqlDelete($query, true);
121
- // execute query and return result
122
- return $this->getActiveRecordAdapter()->CountQuery($result['sql'], $result['args']);
123
- }
124
-
125
- /**
126
- * Use query for deleting records.
127
- */
128
- public function Delete($query)
129
- {
130
- $result = $this->GetSqlDelete($query);
131
- $this->DeleteMetas($query, $result['args']);
132
- return $this->getActiveRecordAdapter()->DeleteQuery($result['sql'], $result['args']);
133
- }
134
-
135
- public function DeleteMetas($query, $args)
136
- {
137
- // back up columns, use COUNT as default column and generate sql
138
- $cols = $query->getColumns();
139
- $query->clearColumns();
140
- $query->addColumn('id');
141
- $sql = $this->GetSql($query);
142
- // restore columns
143
- $query->setColumns($cols);
144
-
145
- $_wpdb = $this->connection;
146
- $occ_ids = array();
147
- $sql = (!empty($args) ? $_wpdb->prepare($sql, $args) : $sql);
148
- foreach ($_wpdb->get_results($sql, ARRAY_A) as $data) {
149
- $occ_ids[] = $data['id'];
150
- }
151
- $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
152
- $meta->DeleteByOccurenceIds($occ_ids);
153
- }
154
-
155
- public function GetSqlDelete($query, $getCount = false)
156
- {
157
- $result = array();
158
- $args = array();
159
- // back up columns, remove them for DELETE and generate sql
160
- $cols = $query->getColumns();
161
- $query->clearColumns();
162
-
163
- $conditions = $query->getConditions();
164
-
165
- $sWhereClause = "";
166
- foreach ($conditions as $fieldName => $fieldValue) {
167
- if (empty($sWhereClause)) {
168
- $sWhereClause .= " WHERE ";
169
- } else {
170
- $sWhereClause .= " AND ";
171
- }
172
- $sWhereClause .= $fieldName;
173
- $args[] = $fieldValue;
174
- }
175
-
176
- $fromDataSets = $query->getFrom();
177
- $orderBys = $query->getOrderBy();
178
-
179
- $sLimitClause = "";
180
- if ($query->getLimit()) {
181
- $sLimitClause .= " LIMIT ";
182
- if ($query->getOffset()) {
183
- $sLimitClause .= $query->getOffset() . ", ";
184
- }
185
- $sLimitClause .= $query->getLimit();
186
- }
187
- $result['sql'] = ($getCount ? 'SELECT COUNT(*) FROM ' : 'DELETE FROM ')
188
- . implode(',', $fromDataSets)
189
- . $sWhereClause
190
- . (!empty($orderBys) ? (' ORDER BY ' . implode(', ', array_keys($orderBys)) . ' ' . implode(', ', array_values($orderBys))) : '')
191
- . $sLimitClause;
192
- $result['args'] = $args;
193
- //restore columns
194
- $query->setColumns($cols);
195
-
196
- return $result;
197
- }
198
-
199
- public function SearchCondition($query)
200
- {
201
- $condition = $query->getSearchCondition();
202
- if (empty($condition)) return null;
203
- $searchConditions = array();
204
- $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
205
- $occurrence = new WSAL_Adapters_MySQL_Occurrence($this->connection);
206
- if (is_numeric($condition) && strlen($condition) == 4) {
207
- $searchConditions['sql'] = $occurrence->GetTable() .'.alert_id LIKE %s';
208
- } else {
209
- $searchConditions['sql'] = $occurrence->GetTable() .'.id IN (
210
- SELECT DISTINCT occurrence_id
211
- FROM ' . $meta->GetTable() . '
212
- WHERE TRIM(BOTH "\"" FROM value) LIKE %s
213
- )';
214
- }
215
- $searchConditions['args'] = "%". $condition. "%";
216
- return $searchConditions;
217
- }
218
-
219
- }
1
+ <?php
2
+
3
+ class WSAL_Adapters_MySQL_Query implements WSAL_Adapters_QueryInterface
4
+ {
5
+ protected $connection;
6
+
7
+ public function __construct($conn)
8
+ {
9
+ $this->connection = $conn;
10
+ }
11
+
12
+ /**
13
+ * @return string Generated sql.
14
+ */
15
+ protected function GetSql($query, &$args = array())
16
+ {
17
+ $conditions = $query->getConditions();
18
+ $searchCondition = $this->SearchCondition($query);
19
+
20
+ $sWhereClause = "";
21
+ foreach ($conditions as $fieldName => $fieldValue) {
22
+ if (empty($sWhereClause)) {
23
+ $sWhereClause .= " WHERE ";
24
+ } else {
25
+ $sWhereClause .= " AND ";
26
+ }
27
+
28
+ if (is_array($fieldValue)) {
29
+ $subWhereClause = "(";
30
+ foreach($fieldValue as $orFieldName => $orFieldValue) {
31
+ if ($subWhereClause != '(') {
32
+ $subWhereClause .= " OR ";
33
+ }
34
+ $subWhereClause .= $orFieldName;
35
+ $args[] = $orFieldValue;
36
+ }
37
+ $subWhereClause .= ")";
38
+ $sWhereClause .= $subWhereClause;
39
+ } else {
40
+ $sWhereClause .= $fieldName;
41
+ $args[] = $fieldValue;
42
+ }
43
+ }
44
+
45
+ $fromDataSets = $query->getFrom();
46
+ $columns = $query->getColumns();
47
+ $orderBys = $query->getOrderBy();
48
+
49
+ $sLimitClause = "";
50
+ if ($query->getLimit()) {
51
+ $sLimitClause .= " LIMIT ";
52
+ if ($query->getOffset()) {
53
+ $sLimitClause .= $query->getOffset() . ", ";
54
+ }
55
+ $sLimitClause .= $query->getLimit();
56
+ }
57
+ $joinClause = '';
58
+ if ($query->hasMetaJoin()) {
59
+ $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
60
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence($this->connection);
61
+ $joinClause = ' LEFT JOIN '. $meta->GetTable() .' AS meta ON meta.occurrence_id = '. $occurrence->GetTable() .'.id ';
62
+ }
63
+ $fields = (empty($columns))? $fromDataSets[0] . '.*' : implode(',', $columns);
64
+ if (!empty($searchCondition)) {
65
+ $args[] = $searchCondition['args'];
66
+ }
67
+ return 'SELECT ' . $fields
68
+ . ' FROM ' . implode(',', $fromDataSets)
69
+ . $joinClause
70
+ . $sWhereClause
71
+ . (!empty($searchCondition) ? (empty($sWhereClause) ? " WHERE ".$searchCondition['sql'] : " AND ".$searchCondition['sql']) : '')
72
+ // @todo GROUP BY goes here
73
+ . (!empty($orderBys) ? (' ORDER BY ' . implode(', ', array_keys($orderBys)) . ' ' . implode(', ', array_values($orderBys))) : '')
74
+ . $sLimitClause;
75
+ }
76
+
77
+ protected function getActiveRecordAdapter()
78
+ {
79
+ return new WSAL_Adapters_MySQL_ActiveRecord($this->connection);
80
+ }
81
+
82
+ /**
83
+ * @return WSAL_Models_ActiveRecord[] Execute query and return data as $ar_cls objects.
84
+ */
85
+ public function Execute($query)
86
+ {
87
+ $args = array();
88
+ $sql = $this->GetSql($query, $args);
89
+
90
+ $occurenceAdapter = $query->getConnector()->getAdapter("Occurrence");
91
+
92
+ if (in_array($occurenceAdapter->GetTable(), $query->getFrom())) {
93
+ return $occurenceAdapter->LoadMulti($sql, $args);
94
+ } else {
95
+ return $this->getActiveRecordAdapter()->LoadMulti($sql, $args);
96
+ }
97
+ }
98
+
99
+ /**
100
+ * @return int Use query for counting records.
101
+ */
102
+ public function Count($query)
103
+ {
104
+ // back up columns, use COUNT as default column and generate sql
105
+ $cols = $query->getColumns();
106
+ $query->clearColumns();
107
+ $query->addColumn('COUNT(*)');
108
+
109
+ $args = array();
110
+ $sql = $this->GetSql($query, $args);
111
+
112
+ // restore columns
113
+ $query->setColumns($cols);
114
+ // execute query and return result
115
+ return $this->getActiveRecordAdapter()->CountQuery($sql, $args);
116
+ }
117
+
118
+ public function CountDelete($query)
119
+ {
120
+ $result = $this->GetSqlDelete($query, true);
121
+ // execute query and return result
122
+ return $this->getActiveRecordAdapter()->CountQuery($result['sql'], $result['args']);
123
+ }
124
+
125
+ /**
126
+ * Use query for deleting records.
127
+ */
128
+ public function Delete($query)
129
+ {
130
+ $result = $this->GetSqlDelete($query);
131
+ $this->DeleteMetas($query, $result['args']);
132
+ return $this->getActiveRecordAdapter()->DeleteQuery($result['sql'], $result['args']);
133
+ }
134
+
135
+ public function DeleteMetas($query, $args)
136
+ {
137
+ // back up columns, use COUNT as default column and generate sql
138
+ $cols = $query->getColumns();
139
+ $query->clearColumns();
140
+ $query->addColumn('id');
141
+ $sql = $this->GetSql($query);
142
+ // restore columns
143
+ $query->setColumns($cols);
144
+
145
+ $_wpdb = $this->connection;
146
+ $occ_ids = array();
147
+ $sql = (!empty($args) ? $_wpdb->prepare($sql, $args) : $sql);
148
+ foreach ($_wpdb->get_results($sql, ARRAY_A) as $data) {
149
+ $occ_ids[] = $data['id'];
150
+ }
151
+ $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
152
+ $meta->DeleteByOccurenceIds($occ_ids);
153
+ }
154
+
155
+ public function GetSqlDelete($query, $getCount = false)
156
+ {
157
+ $result = array();
158
+ $args = array();
159
+ // back up columns, remove them for DELETE and generate sql
160
+ $cols = $query->getColumns();
161
+ $query->clearColumns();
162
+
163
+ $conditions = $query->getConditions();
164
+
165
+ $sWhereClause = "";
166
+ foreach ($conditions as $fieldName => $fieldValue) {
167
+ if (empty($sWhereClause)) {
168
+ $sWhereClause .= " WHERE ";
169
+ } else {
170
+ $sWhereClause .= " AND ";
171
+ }
172
+ $sWhereClause .= $fieldName;
173
+ $args[] = $fieldValue;
174
+ }
175
+
176
+ $fromDataSets = $query->getFrom();
177
+ $orderBys = $query->getOrderBy();
178
+
179
+ $sLimitClause = "";
180
+ if ($query->getLimit()) {
181
+ $sLimitClause .= " LIMIT ";
182
+ if ($query->getOffset()) {
183
+ $sLimitClause .= $query->getOffset() . ", ";
184
+ }
185
+ $sLimitClause .= $query->getLimit();
186
+ }
187
+ $result['sql'] = ($getCount ? 'SELECT COUNT(*) FROM ' : 'DELETE FROM ')
188
+ . implode(',', $fromDataSets)
189
+ . $sWhereClause
190
+ . (!empty($orderBys) ? (' ORDER BY ' . implode(', ', array_keys($orderBys)) . ' ' . implode(', ', array_values($orderBys))) : '')
191
+ . $sLimitClause;
192
+ $result['args'] = $args;
193
+ //restore columns
194
+ $query->setColumns($cols);
195
+
196
+ return $result;
197
+ }
198
+
199
+ public function SearchCondition($query)
200
+ {
201
+ $condition = $query->getSearchCondition();
202
+ if (empty($condition)) return null;
203
+ $searchConditions = array();
204
+ $meta = new WSAL_Adapters_MySQL_Meta($this->connection);
205
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence($this->connection);
206
+ if (is_numeric($condition) && strlen($condition) == 4) {
207
+ $searchConditions['sql'] = $occurrence->GetTable() .'.alert_id LIKE %s';
208
+ } else {
209
+ $searchConditions['sql'] = $occurrence->GetTable() .'.id IN (
210
+ SELECT DISTINCT occurrence_id
211
+ FROM ' . $meta->GetTable() . '
212
+ WHERE TRIM(BOTH "\"" FROM value) LIKE %s
213
+ )';
214
+ }
215
+ $searchConditions['args'] = "%". $condition. "%";
216
+ return $searchConditions;
217
+ }
218
+
219
+ }
classes/Models/Adapters/OccurrenceInterface.php CHANGED
@@ -1,11 +1,11 @@
1
- <?php
2
-
3
- interface WSAL_Adapters_OccurrenceInterface
4
- {
5
- public function GetMeta($occurence);
6
- public function GetNamedMeta($occurence, $name);
7
- public function GetFirstNamedMeta($occurence, $names);
8
- public static function GetNewestUnique($limit = PHP_INT_MAX);
9
- public function CheckKnownUsers($args = array());
10
- public function CheckUnKnownUsers($args = array());
11
- }
1
+ <?php
2
+
3
+ interface WSAL_Adapters_OccurrenceInterface
4
+ {
5
+ public function GetMeta($occurence);
6
+ public function GetNamedMeta($occurence, $name);
7
+ public function GetFirstNamedMeta($occurence, $names);
8
+ public static function GetNewestUnique($limit = PHP_INT_MAX);
9
+ public function CheckKnownUsers($args = array());
10
+ public function CheckUnKnownUsers($args = array());
11
+ }
classes/Models/Adapters/QueryInterface.php CHANGED
@@ -1,8 +1,8 @@
1
- <?php
2
-
3
- interface WSAL_Adapters_QueryInterface
4
- {
5
- public function Execute($query);
6
- public function Count($query);
7
- public function Delete($query);
8
- }
1
+ <?php
2
+
3
+ interface WSAL_Adapters_QueryInterface
4
+ {
5
+ public function Execute($query);
6
+ public function Count($query);
7
+ public function Delete($query);
8
+ }
classes/Models/Meta.php CHANGED
@@ -1,34 +1,34 @@
1
- <?php
2
-
3
- class WSAL_Models_Meta extends WSAL_Models_ActiveRecord {
4
-
5
- protected $adapterName = "Meta";
6
-
7
- public $id = 0;
8
- public $occurrence_id = 0;
9
- public $name = '';
10
- public $value = array(); // force mixed type
11
-
12
- public function SaveMeta()
13
- {
14
- $this->_state = self::STATE_UNKNOWN;
15
- $updateId = $this->getId();
16
- $result = $this->getAdapter()->Save($this);
17
-
18
- if ($result !== false) {
19
- $this->_state = (!empty($updateId))?self::STATE_UPDATED:self::STATE_CREATED;
20
- }
21
- return $result;
22
- }
23
-
24
- public function UpdateByNameAndOccurenceId($name, $value, $occurrenceId)
25
- {
26
- $meta = $this->getAdapter()->LoadByNameAndOccurenceId($name, $occurrenceId);
27
- $this->id = $meta['id'];
28
- $this->occurrence_id = $meta['occurrence_id'];
29
- $this->name = $meta['name'];
30
- $this->value = $value;
31
- $this->saveMeta();
32
- }
33
-
34
- }
1
+ <?php
2
+
3
+ class WSAL_Models_Meta extends WSAL_Models_ActiveRecord {
4
+
5
+ protected $adapterName = "Meta";
6
+
7
+ public $id = 0;
8
+ public $occurrence_id = 0;
9
+ public $name = '';
10
+ public $value = array(); // force mixed type
11
+
12
+ public function SaveMeta()
13
+ {
14
+ $this->_state = self::STATE_UNKNOWN;
15
+ $updateId = $this->getId();
16
+ $result = $this->getAdapter()->Save($this);
17
+
18
+ if ($result !== false) {
19
+ $this->_state = (!empty($updateId))?self::STATE_UPDATED:self::STATE_CREATED;
20
+ }
21
+ return $result;
22
+ }
23
+
24
+ public function UpdateByNameAndOccurenceId($name, $value, $occurrenceId)
25
+ {
26
+ $meta = $this->getAdapter()->LoadByNameAndOccurenceId($name, $occurrenceId);
27
+ $this->id = $meta['id'];
28
+ $this->occurrence_id = $meta['occurrence_id'];
29
+ $this->name = $meta['name'];
30
+ $this->value = $value;
31
+ $this->saveMeta();
32
+ }
33
+
34
+ }
classes/Models/Occurrence.php CHANGED
@@ -1,198 +1,199 @@
1
- <?php
2
-
3
- class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord
4
- {
5
-
6
- public $id = 0;
7
- public $site_id = 0;
8
- public $alert_id = 0;
9
- public $created_on = 0.0;
10
- public $is_read = false;
11
- public $is_migrated = false;
12
- protected $adapterName = "Occurrence";
13
-
14
- /**
15
- * Returns the alert related to this occurrence.
16
- * @return WSAL_Alert
17
- */
18
- public function GetAlert()
19
- {
20
- return WpSecurityAuditLog::GetInstance()->alerts->GetAlert($this->alert_id);
21
- }
22
-
23
- /**
24
- * Returns the value of a meta item.
25
- * @param string $name Name of meta item.
26
- * @param mixed $default Default value returned when meta does not exist.
27
- * @return mixed The value, if meta item does not exist $default returned.
28
- */
29
- public function GetMetaValue($name, $default = array())
30
- {
31
- //get meta adapter
32
- //call the function ($name, $this->getId())
33
- $meta = $this->getAdapter()->GetNamedMeta($this, $name);
34
- return maybe_unserialize($meta['value']);
35
-
36
- //TO DO: re-introduce add is loaded check before running query
37
- //return $meta->IsLoaded() ? $meta->value : $default;
38
- }
39
-
40
- /**
41
- * Set the value of a meta item (creates or updates meta item).
42
- * @param string $name Meta name.
43
- * @param mixed $value Meta value.
44
- */
45
- public function SetMetaValue($name, $value)
46
- {
47
- //get meta adapter
48
- $model = new WSAL_Models_Meta();
49
- $model->occurrence_id = $this->getId();
50
- $model->name = $name;
51
- $model->value = maybe_serialize($value);
52
- $model->SaveMeta();
53
- }
54
-
55
- public function UpdateMetaValue($name, $value)
56
- {
57
- $model = new WSAL_Models_Meta();
58
- $model->UpdateByNameAndOccurenceId($name, $value, $this->getId());
59
- }
60
-
61
- /**
62
- * Returns a key-value pair of meta data.
63
- * @return array
64
- */
65
- public function GetMetaArray()
66
- {
67
- $result = array();
68
- $metas = $this->getAdapter()->GetMultiMeta($this);
69
- foreach ($metas as $meta) {
70
- $result[$meta->name] = maybe_unserialize($meta->value);
71
- }
72
- return $result;
73
- }
74
-
75
- /**
76
- * Creates or updates all meta data passed as an array of meta-key/meta-value pairs.
77
- * @param array $data New meta data.
78
- */
79
- public function SetMeta($data)
80
- {
81
- foreach ((array)$data as $key => $val) {
82
- $this->SetMetaValue($key, $val);
83
- }
84
- }
85
-
86
- /**
87
- * @param callable|null $metaFormatter (Optional) Meta formatter callback.
88
- * @return string Full-formatted message.
89
- */
90
- public function GetMessage($metaFormatter = null)
91
- {
92
- if (!isset($this->_cachedmessage)) {
93
- // get correct message entry
94
- if ($this->is_migrated) {
95
- $this->_cachedmessage = $this->GetMetaValue('MigratedMesg', false);
96
- }
97
- if (!$this->is_migrated || !$this->_cachedmessage) {
98
- $this->_cachedmessage = $this->GetAlert()->mesg;
99
- }
100
- // fill variables in message
101
- $this->_cachedmessage = $this->GetAlert()->GetMessage($this->GetMetaArray(), $metaFormatter, $this->_cachedmessage);
102
- }
103
- return $this->_cachedmessage;
104
- }
105
-
106
- /**
107
- * Delete occurrence as well as associated meta data.
108
- * @return boolean True on success, false on failure.
109
- */
110
- public function Delete()
111
- {
112
- foreach ($this->getAdapter()->GetMeta() as $meta) {
113
- $meta->Delete();
114
- }
115
- return parent::Delete();
116
- }
117
-
118
- /**
119
- * @return string User's username.
120
- */
121
- public function GetUsername()
122
- {
123
- $meta = $this->getAdapter()->GetFirstNamedMeta($this, array('Username', 'CurrentUserID'));
124
- if ($meta) {
125
- switch(true){
126
- case $meta->name == 'Username':
127
- return $meta->value;
128
- case $meta->name == 'CurrentUserID':
129
- return ($data = get_userdata($meta->value)) ? $data->user_login : null;
130
- }
131
- }
132
- return null;
133
- }
134
-
135
- /**
136
- * @return string IP address of request.
137
- */
138
- public function GetSourceIP()
139
- {
140
- return $this->GetMetaValue('ClientIP', '');
141
- }
142
-
143
- /**
144
- * @return string IP address of request (from proxies etc).
145
- */
146
- public function GetOtherIPs()
147
- {
148
- $result = array();
149
- $data = (array)$this->GetMetaValue('OtherIPs', array());
150
- foreach ($data as $ips) {
151
- foreach ($ips as $ip) {
152
- $result[] = $ip;
153
- }
154
- }
155
- return array_unique($result);
156
- }
157
-
158
- /**
159
- * @return array Array of user roles.
160
- */
161
- public function GetUserRoles()
162
- {
163
- return $this->GetMetaValue('CurrentUserRoles', array());
164
- }
165
-
166
- /**
167
- * @return float Number of seconds (and microseconds as fraction) since unix Day 0.
168
- * @todo This needs some caching.
169
- */
170
- protected function GetMicrotime()
171
- {
172
- return microtime(true);// + get_option('gmt_offset') * HOUR_IN_SECONDS;
173
- }
174
-
175
- /**
176
- * Finds occurences of the same type by IP and Username within specified time frame
177
- * @param string $ipAddress
178
- * @param string $username
179
- * @param int $alertId Alert type we are lookign for
180
- * @param int $siteId
181
- * @param $startTime mktime
182
- * @param $endTime mktime
183
- */
184
- public function CheckKnownUsers($args = array())
185
- {
186
- return $this->getAdapter()->CheckKnownUsers($args);
187
- }
188
-
189
- public function CheckUnKnownUsers($args = array())
190
- {
191
- return $this->getAdapter()->CheckUnKnownUsers($args);
192
- }
193
-
194
- public function GetByPostID($post_id)
195
- {
196
- return $this->getAdapter()->GetByPostID($post_id);
197
- }
198
- }
 
1
+ <?php
2
+
3
+ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord
4
+ {
5
+ public $id = 0;
6
+ public $site_id = 0;
7
+ public $alert_id = 0;
8
+ public $created_on = 0.0;
9
+ public $is_read = false;
10
+ public $is_migrated = false;
11
+ protected $adapterName = "Occurrence";
12
+
13
+ /**
14
+ * Returns the alert related to this occurrence.
15
+ * @return WSAL_Alert
16
+ */
17
+ public function GetAlert()
18
+ {
19
+ return WpSecurityAuditLog::GetInstance()->alerts->GetAlert($this->alert_id);
20
+ }
21
+
22
+ /**
23
+ * Returns the value of a meta item.
24
+ * @param string $name Name of meta item.
25
+ * @param mixed $default Default value returned when meta does not exist.
26
+ * @return mixed The value, if meta item does not exist $default returned.
27
+ */
28
+ public function GetMetaValue($name, $default = array())
29
+ {
30
+ //get meta adapter
31
+ //call the function ($name, $this->getId())
32
+ $meta = $this->getAdapter()->GetNamedMeta($this, $name);
33
+ return maybe_unserialize($meta['value']);
34
+
35
+ //TO DO: re-introduce add is loaded check before running query
36
+ //return $meta->IsLoaded() ? $meta->value : $default;
37
+ }
38
+
39
+ /**
40
+ * Set the value of a meta item (creates or updates meta item).
41
+ * @param string $name Meta name.
42
+ * @param mixed $value Meta value.
43
+ */
44
+ public function SetMetaValue($name, $value)
45
+ {
46
+ if (!empty($value)) {
47
+ // get meta adapter
48
+ $model = new WSAL_Models_Meta();
49
+ $model->occurrence_id = $this->getId();
50
+ $model->name = $name;
51
+ $model->value = maybe_serialize($value);
52
+ $model->SaveMeta();
53
+ }
54
+ }
55
+
56
+ public function UpdateMetaValue($name, $value)
57
+ {
58
+ $model = new WSAL_Models_Meta();
59
+ $model->UpdateByNameAndOccurenceId($name, $value, $this->getId());
60
+ }
61
+
62
+ /**
63
+ * Returns a key-value pair of meta data.
64
+ * @return array
65
+ */
66
+ public function GetMetaArray()
67
+ {
68
+ $result = array();
69
+ $metas = $this->getAdapter()->GetMultiMeta($this);
70
+ foreach ($metas as $meta) {
71
+ $result[$meta->name] = maybe_unserialize($meta->value);
72
+ }
73
+ return $result;
74
+ }
75
+
76
+ /**
77
+ * Creates or updates all meta data passed as an array of meta-key/meta-value pairs.
78
+ * @param array $data New meta data.
79
+ */
80
+ public function SetMeta($data)
81
+ {
82
+ foreach ((array)$data as $key => $val) {
83
+ $this->SetMetaValue($key, $val);
84
+ }
85
+ }
86
+
87
+ /**
88
+ * @param callable|null $metaFormatter (Optional) Meta formatter callback.
89
+ * @return string Full-formatted message.
90
+ */
91
+ public function GetMessage($metaFormatter = null)
92
+ {
93
+ if (!isset($this->_cachedmessage)) {
94
+ // get correct message entry
95
+ if ($this->is_migrated) {
96
+ $this->_cachedmessage = $this->GetMetaValue('MigratedMesg', false);
97
+ }
98
+ if (!$this->is_migrated || !$this->_cachedmessage) {
99
+ $this->_cachedmessage = $this->GetAlert()->mesg;
100
+ }
101
+ // fill variables in message
102
+ $this->_cachedmessage = $this->GetAlert()->GetMessage($this->GetMetaArray(), $metaFormatter, $this->_cachedmessage);
103
+ }
104
+ return $this->_cachedmessage;
105
+ }
106
+
107
+ /**
108
+ * Delete occurrence as well as associated meta data.
109
+ * @return boolean True on success, false on failure.
110
+ */
111
+ public function Delete()
112
+ {
113
+ foreach ($this->getAdapter()->GetMeta() as $meta) {
114
+ $meta->Delete();
115
+ }
116
+ return parent::Delete();
117
+ }
118
+
119
+ /**
120
+ * @return string User's username.
121
+ */
122
+ public function GetUsername()
123
+ {
124
+ $meta = $this->getAdapter()->GetFirstNamedMeta($this, array('Username', 'CurrentUserID'));
125
+ if ($meta) {
126
+ switch (true) {
127
+ case $meta->name == 'Username':
128
+ return $meta->value;
129
+ case $meta->name == 'CurrentUserID':
130
+ return ($data = get_userdata($meta->value)) ? $data->user_login : null;
131
+ }
132
+ }
133
+ return null;
134
+ }
135
+
136
+ /**
137
+ * @return string IP address of request.
138
+ */
139
+ public function GetSourceIP()
140
+ {
141
+ return $this->GetMetaValue('ClientIP', '');
142
+ }
143
+
144
+ /**
145
+ * @return string IP address of request (from proxies etc).
146
+ */
147
+ public function GetOtherIPs()
148
+ {
149
+ $result = array();
150
+ $data = (array)$this->GetMetaValue('OtherIPs', array());
151
+ foreach ($data as $ips) {
152
+ foreach ($ips as $ip) {
153
+ $result[] = $ip;
154
+ }
155
+ }
156
+ return array_unique($result);
157
+ }
158
+
159
+ /**
160
+ * @return array Array of user roles.
161
+ */
162
+ public function GetUserRoles()
163
+ {
164
+ return $this->GetMetaValue('CurrentUserRoles', array());
165
+ }
166
+
167
+ /**
168
+ * @return float Number of seconds (and microseconds as fraction) since unix Day 0.
169
+ * @todo This needs some caching.
170
+ */
171
+ protected function GetMicrotime()
172
+ {
173
+ return microtime(true);// + get_option('gmt_offset') * HOUR_IN_SECONDS;
174
+ }
175
+
176
+ /**
177
+ * Finds occurences of the same type by IP and Username within specified time frame
178
+ * @param string $ipAddress
179
+ * @param string $username
180
+ * @param int $alertId Alert type we are lookign for
181
+ * @param int $siteId
182
+ * @param $startTime mktime
183
+ * @param $endTime mktime
184
+ */
185
+ public function CheckKnownUsers($args = array())
186
+ {
187
+ return $this->getAdapter()->CheckKnownUsers($args);
188
+ }
189
+
190
+ public function CheckUnKnownUsers($args = array())
191
+ {
192
+ return $this->getAdapter()->CheckUnKnownUsers($args);
193
+ }
194
+
195
+ public function GetByPostID($post_id)
196
+ {
197
+ return $this->getAdapter()->GetByPostID($post_id);
198
+ }
199
+ }
classes/Models/OccurrenceQuery.php CHANGED
@@ -1,29 +1,29 @@
1
- <?php
2
-
3
- class WSAL_Models_OccurrenceQuery extends WSAL_Models_Query
4
- {
5
- protected $arguments = array();
6
-
7
- public function addArgument($field, $value)
8
- {
9
- $this->arguments[$field] = $value;
10
- return $this;
11
- }
12
-
13
- public function clearArguments()
14
- {
15
- $this->arguments = array();
16
- return $this;
17
- }
18
-
19
- public function __construct()
20
- {
21
- parent::__construct();
22
-
23
- //TO DO: Consider if Get Table is the right method to call given that this is mysql specific
24
- $this->addFrom(
25
- $this->getConnector()->getAdapter("Occurrence")->GetTable()
26
- );
27
- }
28
-
29
- }
1
+ <?php
2
+
3
+ class WSAL_Models_OccurrenceQuery extends WSAL_Models_Query
4
+ {
5
+ protected $arguments = array();
6
+
7
+ public function addArgument($field, $value)
8
+ {
9
+ $this->arguments[$field] = $value;
10
+ return $this;
11
+ }
12
+
13
+ public function clearArguments()
14
+ {
15
+ $this->arguments = array();
16
+ return $this;
17
+ }
18
+
19
+ public function __construct()
20
+ {
21
+ parent::__construct();
22
+
23
+ //TO DO: Consider if Get Table is the right method to call given that this is mysql specific
24
+ $this->addFrom(
25
+ $this->getConnector()->getAdapter("Occurrence")->GetTable()
26
+ );
27
+ }
28
+
29
+ }
classes/Models/Option.php CHANGED
@@ -1,80 +1,80 @@
1
- <?php
2
-
3
- /**
4
- * Wordpress options are always loaded from the default wordpress database.
5
- */
6
- class WSAL_Models_Option extends WSAL_Models_ActiveRecord
7
- {
8
-
9
- protected $adapterName = "Option";
10
- public $id = '';
11
- public $option_name = '';
12
- public $option_value = '';
13
- /**
14
- * Options are always stored in WPDB. This setting ensures that
15
- */
16
- protected $useDefaultAdapter = true;
17
-
18
- public function SetOptionValue($name, $value)
19
- {
20
- $option = $this->getAdapter()->GetNamedOption($name);
21
- $this->id = $option['id'];
22
- $this->option_name = $name;
23
- // Serialize if $value is array or object
24
- $value = maybe_serialize($value);
25
- $this->option_value = $value;
26
- return $this->Save();
27
- }
28
-
29
- public function GetOptionValue($name, $default = array())
30
- {
31
- $option = $this->getAdapter()->GetNamedOption($name);
32
- $this->option_value = (!empty($option)) ? $option['option_value'] : null;
33
- if (!empty($this->option_value)) {
34
- $this->_state = self::STATE_LOADED;
35
- }
36
- // Unerialize if $value is array or object
37
- $this->option_value = maybe_unserialize($this->option_value);
38
- return $this->IsLoaded() ? $this->option_value : $default;
39
- }
40
-
41
- public function Save()
42
- {
43
- $this->_state = self::STATE_UNKNOWN;
44
-
45
- $updateId = $this->getId();
46
- $result = $this->getAdapter()->Save($this);
47
-
48
- if ($result !== false) {
49
- $this->_state = (!empty($updateId))?self::STATE_UPDATED:self::STATE_CREATED;
50
- }
51
- return $result;
52
- }
53
-
54
- public function GetNotificationsSetting($opt_prefix)
55
- {
56
- return $this->getAdapter()->GetNotificationsSetting($opt_prefix);
57
- }
58
-
59
- public function GetNotification($id)
60
- {
61
- return $this->LoadData(
62
- $this->getAdapter()->GetNotification($id)
63
- );
64
- }
65
-
66
- public function DeleteByName($name)
67
- {
68
- return $this->getAdapter()->DeleteByName($name);
69
- }
70
-
71
- public function DeleteByPrefix($opt_prefix)
72
- {
73
- return $this->getAdapter()->DeleteByPrefix($opt_prefix);
74
- }
75
-
76
- public function CountNotifications($opt_prefix)
77
- {
78
- return $this->getAdapter()->CountNotifications($opt_prefix);
79
- }
80
- }
1
+ <?php
2
+
3
+ /**
4
+ * Wordpress options are always loaded from the default wordpress database.
5
+ */
6
+ class WSAL_Models_Option extends WSAL_Models_ActiveRecord
7
+ {
8
+
9
+ protected $adapterName = "Option";
10
+ public $id = '';
11
+ public $option_name = '';
12
+ public $option_value = '';
13
+ /**
14
+ * Options are always stored in WPDB. This setting ensures that
15
+ */
16
+ protected $useDefaultAdapter = true;
17
+
18
+ public function SetOptionValue($name, $value)
19
+ {
20
+ $option = $this->getAdapter()->GetNamedOption($name);
21
+ $this->id = $option['id'];
22
+ $this->option_name = $name;
23
+ // Serialize if $value is array or object
24
+ $value = maybe_serialize($value);
25
+ $this->option_value = $value;
26
+ return $this->Save();
27
+ }
28
+
29
+ public function GetOptionValue($name, $default = array())
30
+ {
31
+ $option = $this->getAdapter()->GetNamedOption($name);
32
+ $this->option_value = (!empty($option)) ? $option['option_value'] : null;
33
+ if (!empty($this->option_value)) {
34
+ $this->_state = self::STATE_LOADED;
35
+ }
36
+ // Unerialize if $value is array or object
37
+ $this->option_value = maybe_unserialize($this->option_value);
38
+ return $this->IsLoaded() ? $this->option_value : $default;
39
+ }
40
+
41
+ public function Save()
42
+ {
43
+ $this->_state = self::STATE_UNKNOWN;
44
+
45
+ $updateId = $this->getId();
46
+ $result = $this->getAdapter()->Save($this);
47
+
48
+ if ($result !== false) {
49
+ $this->_state = (!empty($updateId))?self::STATE_UPDATED:self::STATE_CREATED;
50
+ }
51
+ return $result;
52
+ }
53
+
54
+ public function GetNotificationsSetting($opt_prefix)
55
+ {
56
+ return $this->getAdapter()->GetNotificationsSetting($opt_prefix);
57
+ }
58
+
59
+ public function GetNotification($id)
60
+ {
61
+ return $this->LoadData(
62
+ $this->getAdapter()->GetNotification($id)
63
+ );
64
+ }
65
+
66
+ public function DeleteByName($name)
67
+ {
68
+ return $this->getAdapter()->DeleteByName($name);
69
+ }
70
+
71
+ public function DeleteByPrefix($opt_prefix)
72
+ {
73
+ return $this->getAdapter()->DeleteByPrefix($opt_prefix);
74
+ }
75
+
76
+ public function CountNotifications($opt_prefix)
77
+ {
78
+ return $this->getAdapter()->CountNotifications($opt_prefix);
79
+ }
80
+ }
classes/Models/Query.php CHANGED
@@ -1,187 +1,187 @@
1
- <?php
2
-
3
- class WSAL_Models_Query
4
- {
5
- protected $columns = array();
6
- protected $conditions = array();
7
- protected $orderBy = array();
8
- protected $offset = null;
9
- protected $limit = null;
10
- protected $from = array();
11
- protected $meta_join = false;
12
- protected $searchCondition = null;
13
- protected $useDefaultAdapter = false;
14
-
15
- public function __construct()
16
- {
17
-
18
- }
19
-
20
- public function getConnector()
21
- {
22
- if (!empty($this->connector)) {
23
- return $this->connector;
24
- }
25
- if ($this->useDefaultAdapter) {
26
- $this->connector = WSAL_Connector_ConnectorFactory::GetDefaultConnector();
27
- } else {
28
- $this->connector = WSAL_Connector_ConnectorFactory::GetConnector();
29
- }
30
- return $this->connector;
31
- }
32
-
33
- public function getAdapter()
34
- {
35
- return $this->getConnector()->getAdapter('Query');
36
- }
37
-
38
- public function addColumn($column)
39
- {
40
- $this->columns[] = $column;
41
- return $this;
42
- }
43
-
44
- public function clearColumns()
45
- {
46
- $this->columns = array();
47
- return $this;
48
- }
49
-
50
- public function getColumns()
51
- {
52
- return $this->columns;
53
- }
54
-
55
- public function setColumns($columns)
56
- {
57
- $this->columns = $columns;
58
- return $this;
59
- }
60
-
61
- public function addCondition($field, $value)
62
- {
63
- $this->conditions[$field] = $value;
64
- return $this;
65
- }
66
-
67
- public function addORCondition($aConditions)
68
- {
69
- $this->conditions[] = $aConditions;
70
- }
71
-
72
- public function clearConditions()
73
- {
74
- $this->conditions = array();
75
- return $this;
76
- }
77
-
78
- public function getConditions()
79
- {
80
- return $this->conditions;
81
- }
82
-
83
- public function addOrderBy($field, $isDescending = false)
84
- {
85
- $order = ($isDescending) ? 'DESC' : 'ASC';
86
- $this->orderBy[$field] = $order;
87
- return $this;
88
- }
89
-
90
- public function clearOrderBy()
91
- {
92
- $this->orderBy = array();
93
- return $this;
94
- }
95
-
96
- public function getOrderBy()
97
- {
98
- return $this->orderBy;
99
- }
100
-
101
- public function addFrom($fromDataSet)
102
- {
103
- $this->from[] = $fromDataSet;
104
- return $this;
105
- }
106
-
107
- public function clearFrom()
108
- {
109
- $this->from = array();
110
- return $this;
111
- }
112
-
113
- public function getFrom()
114
- {
115
- return $this->from;
116
- }
117
-
118
- /**
119
- * Gets the value of limit.
120
- *
121
- * @return mixed
122
- */
123
- public function getLimit()
124
- {
125
- return $this->limit;
126
- }
127
-
128
- /**
129
- * Sets the value of limit.
130
- *
131
- * @param mixed $limit the limit
132
- *
133
- * @return self
134
- */
135
- public function setLimit($limit)
136
- {
137
- $this->limit = $limit;
138
-
139
- return $this;
140
- }
141
-
142
- /**
143
- * Gets the value of offset.
144
- *
145
- * @return mixed
146
- */
147
- public function getOffset()
148
- {
149
- return $this->offset;
150
- }
151
-
152
- /**
153
- * Sets the value of offset.
154
- *
155
- * @param mixed $offset the offset
156
- *
157
- * @return self
158
- */
159
- public function setOffset($offset)
160
- {
161
- $this->offset = $offset;
162
-
163
- return $this;
164
- }
165
-
166
- public function addSearchCondition($value)
167
- {
168
- $this->searchCondition = $value;
169
- return $this;
170
- }
171
-
172
- public function getSearchCondition()
173
- {
174
- return $this->searchCondition;
175
- }
176
-
177
- public function hasMetaJoin()
178
- {
179
- return $this->meta_join;
180
- }
181
-
182
- public function addMetaJoin()
183
- {
184
- $this->meta_join = true;
185
- return $this;
186
- }
187
- }
1
+ <?php
2
+
3
+ class WSAL_Models_Query
4
+ {
5
+ protected $columns = array();
6
+ protected $conditions = array();
7
+ protected $orderBy = array();
8
+ protected $offset = null;
9
+ protected $limit = null;
10
+ protected $from = array();
11
+ protected $meta_join = false;
12
+ protected $searchCondition = null;
13
+ protected $useDefaultAdapter = false;
14
+
15
+ public function __construct()
16
+ {
17
+
18
+ }
19
+
20
+ public function getConnector()
21
+ {
22
+ if (!empty($this->connector)) {
23
+ return $this->connector;
24
+ }
25
+ if ($this->useDefaultAdapter) {
26
+ $this->connector = WSAL_Connector_ConnectorFactory::GetDefaultConnector();
27
+ } else {
28
+ $this->connector = WSAL_Connector_ConnectorFactory::GetConnector();
29
+ }
30
+ return $this->connector;
31
+ }
32
+
33
+ public function getAdapter()
34
+ {
35
+ return $this->getConnector()->getAdapter('Query');
36
+ }
37
+
38
+ public function addColumn($column)
39
+ {
40
+ $this->columns[] = $column;
41
+ return $this;
42
+ }
43
+
44
+ public function clearColumns()
45
+ {
46
+ $this->columns = array();
47
+ return $this;
48
+ }
49
+
50
+ public function getColumns()
51
+ {
52
+ return $this->columns;
53
+ }
54
+
55
+ public function setColumns($columns)
56
+ {
57
+ $this->columns = $columns;
58
+ return $this;
59
+ }
60
+
61
+ public function addCondition($field, $value)
62
+ {
63
+ $this->conditions[$field] = $value;
64
+ return $this;
65
+ }
66
+
67
+ public function addORCondition($aConditions)
68
+ {
69
+ $this->conditions[] = $aConditions;
70
+ }
71
+
72
+ public function clearConditions()
73
+ {
74
+ $this->conditions = array();
75
+ return $this;
76
+ }
77
+
78
+ public function getConditions()
79
+ {
80
+ return $this->conditions;
81
+ }
82
+
83
+ public function addOrderBy($field, $isDescending = false)
84
+ {
85
+ $order = ($isDescending) ? 'DESC' : 'ASC';
86
+ $this->orderBy[$field] = $order;
87
+ return $this;
88
+ }
89
+
90
+ public function clearOrderBy()
91
+ {
92
+ $this->orderBy = array();
93
+ return $this;
94
+ }
95
+
96
+ public function getOrderBy()
97
+ {
98
+ return $this->orderBy;
99
+ }
100
+
101
+ public function addFrom($fromDataSet)
102
+ {
103
+ $this->from[] = $fromDataSet;
104
+ return $this;
105
+ }
106
+
107
+ public function clearFrom()
108
+ {
109
+ $this->from = array();
110
+ return $this;
111
+ }
112
+
113
+ public function getFrom()
114
+ {
115
+ return $this->from;
116
+ }
117
+
118
+ /**
119
+ * Gets the value of limit.
120
+ *
121
+ * @return mixed
122
+ */
123
+ public function getLimit()
124
+ {
125
+ return $this->limit;
126
+ }
127
+
128
+ /**
129
+ * Sets the value of limit.
130
+ *
131
+ * @param mixed $limit the limit
132
+ *
133
+ * @return self
134
+ */
135
+ public function setLimit($limit)
136
+ {
137
+ $this->limit = $limit;
138
+
139
+ return $this;
140
+ }
141
+
142
+ /**
143
+ * Gets the value of offset.
144
+ *
145
+ * @return mixed
146
+ */
147
+ public function getOffset()
148
+ {
149
+ return $this->offset;
150
+ }
151
+
152
+ /**
153
+ * Sets the value of offset.
154
+ *
155
+ * @param mixed $offset the offset
156
+ *
157
+ * @return self
158
+ */
159
+ public function setOffset($offset)
160
+ {
161
+ $this->offset = $offset;
162
+
163
+ return $this;
164
+ }
165
+
166
+ public function addSearchCondition($value)
167
+ {
168
+ $this->searchCondition = $value;
169
+ return $this;
170
+ }
171
+
172
+ public function getSearchCondition()
173
+ {
174
+ return $this->searchCondition;
175
+ }
176
+
177
+ public function hasMetaJoin()
178
+ {
179
+ return $this->meta_join;
180
+ }
181
+
182
+ public function addMetaJoin()
183
+ {
184
+ $this->meta_join = true;
185
+ return $this;
186
+ }
187
+ }
classes/Sensors/BBPress.php CHANGED
@@ -1,410 +1,412 @@
1
- <?php
2
- /**
3
- * Support for BBPress Forum Plugin
4
- */
5
- class WSAL_Sensors_BBPress extends WSAL_AbstractSensor
6
- {
7
- protected $_OldPost = null;
8
- protected $_OldLink = null;
9
-
10
- public function HookEvents()
11
- {
12
- if (current_user_can("edit_posts")) {
13
- add_action('admin_init', array($this, 'EventAdminInit'));
14
- }
15
- add_action('post_updated', array($this, 'CheckForumChange'), 10, 3);
16
- add_action('delete_post', array($this, 'EventForumDeleted'), 10, 1);
17
- add_action('wp_trash_post', array($this, 'EventForumTrashed'), 10, 1);
18
- add_action('untrash_post', array($this, 'EventForumUntrashed'));
19
- }
20
-
21
- public function EventAdminInit()
22
- {
23
- // load old data, if applicable
24
- $this->RetrieveOldData();
25
- // check for Ajax changes
26
- $this->TriggerAjaxChange();
27
- }
28
-
29
- protected function RetrieveOldData()
30
- {
31
- if (isset($_POST) && isset($_POST['post_ID'])
32
- && !(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
33
- && !(isset($_POST['action']) && $_POST['action'] == 'autosave')
34
- ) {
35
- $postID = intval($_POST['post_ID']);
36
- $this->_OldPost = get_post($postID);
37
- $this->_OldLink = get_permalink($postID);
38
- }
39
- }
40
-
41
- public function CheckForumChange($post_ID, $newpost, $oldpost)
42
- {
43
- if ($this->CheckBBPress($oldpost)) {
44
- $changes = 0 + $this->EventForumCreation($oldpost, $newpost);
45
- // Change Visibility
46
- if (!$changes) {
47
- $changes = $this->EventForumChangedVisibility($oldpost);
48
- }
49
- // Change Type
50
- if (!$changes) {
51
- $changes = $this->EventForumChangedType($oldpost);
52
- }
53
- // Change status
54
- if (!$changes) {
55
- $changes = $this->EventForumChangedStatus($oldpost);
56
- }
57
- // Change Order, Parent or URL
58
- if (!$changes) {
59
- $changes = $this->EventForumChanged($oldpost, $newpost);
60
- }
61
- }
62
- }
63
-
64
- /**
65
- * Permanently deleted
66
- */
67
- public function EventForumDeleted($post_id)
68
- {
69
- $post = get_post($post_id);
70
- if ($this->CheckBBPress($post)) {
71
- switch ($post->post_type) {
72
- case 'forum':
73
- $this->EventForumByCode($post, 8006);
74
- break;
75
- case 'topic':
76
- $this->EventTopicByCode($post, 8020);
77
- break;
78
- }
79
- }
80
- }
81
-
82
- /**
83
- * Moved to Trash
84
- */
85
- public function EventForumTrashed($post_id)
86
- {
87
- $post = get_post($post_id);
88
- if ($this->CheckBBPress($post)) {
89
- switch ($post->post_type) {
90
- case 'forum':
91
- $this->EventForumByCode($post, 8005);
92
- break;
93
- case 'topic':
94
- $this->EventTopicByCode($post, 8019);
95
- break;
96
- }
97
- }
98
- }
99
-
100
- /**
101
- * Restored from Trash
102
- */
103
- public function EventForumUntrashed($post_id)
104
- {
105
- $post = get_post($post_id);
106
- if ($this->CheckBBPress($post)) {
107
- switch ($post->post_type) {
108
- case 'forum':
109
- $this->EventForumByCode($post, 8007);
110
- break;
111
- case 'topic':
112
- $this->EventTopicByCode($post, 8021);
113
- break;
114
- }
115
- }
116
- }
117
-
118
- private function CheckBBPress($post)
119
- {
120
- switch ($post->post_type) {
121
- case 'forum':
122
- case 'topic':
123
- case 'reply':
124
- return true;
125
- default:
126
- return false;
127
- }
128
- }
129
-
130
- private function EventForumCreation($old_post, $new_post)
131
- {
132
- $original = isset($_POST['original_post_status']) ? $_POST['original_post_status'] : '';
133
- if ($old_post->post_status == 'draft' || $original == 'auto-draft') {
134
- if ($new_post->post_status == 'publish') {
135
- switch ($old_post->post_type) {
136
- case 'forum':
137
- $this->plugin->alerts->Trigger(8000, array(
138
- 'ForumName' => $new_post->post_title,
139
- 'ForumURL' => get_permalink($new_post->ID)
140
- ));
141
- break;
142
- case 'topic':
143
- $this->plugin->alerts->Trigger(8014, array(
144
- 'TopicName' => $new_post->post_title,
145
- 'TopicURL' => get_permalink($new_post->ID)
146
- ));
147
- break;
148
- }
149
- return 1;
150
- }
151
- }
152
- return 0;
153
- }
154
-
155
- private function EventForumChangedVisibility($post)
156
- {
157
- $result = 0;
158
- switch ($post->post_type) {
159
- case 'forum':
160
- $oldVisibility = !empty($_REQUEST['visibility']) ? $_REQUEST['visibility'] : '';
161
- $newVisibility = !empty($_REQUEST['bbp_forum_visibility']) ? $_REQUEST['bbp_forum_visibility'] : '';
162
- $newVisibility = ($newVisibility == 'publish') ? 'public' : $newVisibility;
163
-
164
- if (!empty($newVisibility) && $oldVisibility != 'auto-draft' && $oldVisibility != $newVisibility) {
165
- $this->plugin->alerts->Trigger(8002, array(
166
- 'ForumName' => $post->post_title,
167
- 'OldVisibility' => $oldVisibility,
168
- 'NewVisibility' => $newVisibility
169
- ));
170
- $result = 1;
171
- }
172
- break;
173
- case 'topic':
174
- $oldVisibility = !empty($_REQUEST['hidden_post_visibility']) ? $_REQUEST['hidden_post_visibility'] : '';
175
- $newVisibility = !empty($_REQUEST['visibility']) ? $_REQUEST['visibility'] : '';
176
- $newVisibility = ($newVisibility == 'password') ? 'password protected' : $newVisibility;
177
-
178
- if (!empty($newVisibility) && $oldVisibility != 'auto-draft' && $oldVisibility != $newVisibility) {
179
- $this->plugin->alerts->Trigger(8022, array(
180
- 'TopicName' => $post->post_title,
181
- 'OldVisibility' => $oldVisibility,
182
- 'NewVisibility' => $newVisibility
183
- ));
184
- $result = 1;
185
- }
186
- break;
187
- }
188
- return $result;
189
- }
190
-
191
- private function EventForumChangedType($post)
192
- {
193
- $result = 0;
194
- switch ($post->post_type) {
195
- case 'forum':
196
- $bbp_forum_type = get_post_meta($post->ID, '_bbp_forum_type', true);
197
- $oldType = !empty($bbp_forum_type) ? $bbp_forum_type : 'forum';
198
- $newType = !empty($_POST['bbp_forum_type']) ? $_POST['bbp_forum_type'] : '';
199
- if (!empty($newType) && $oldType != $newType) {
200
- $this->plugin->alerts->Trigger(8011, array(
201
- 'ForumName' => $post->post_title,
202
- 'OldType' => $oldType,
203
- 'NewType' => $newType
204
- ));
205
- $result = 1;
206
- }
207
- break;
208
- case 'topic':
209
- if (!empty($_POST['parent_id'])) {
210
- $post_id = $_POST['parent_id'];
211
- } else {
212
- $post_id = $post->ID;
213
- }
214
- $bbp_sticky_topics = maybe_unserialize(get_post_meta($post_id, '_bbp_sticky_topics', true));
215
- $bbp_super_sticky_topics = maybe_unserialize(get_option('_bbp_super_sticky_topics'));
216
- if (!empty($bbp_sticky_topics) && in_array($post->ID, $bbp_sticky_topics)) {
217
- $oldType = 'sticky';
218
- } elseif (!empty($bbp_super_sticky_topics) && in_array($post->ID, $bbp_super_sticky_topics)) {
219
- $oldType = 'super';
220
- } else {
221
- $oldType = 'unstick';
222
- }
223
- $newType = !empty($_POST['bbp_stick_topic']) ? $_POST['bbp_stick_topic'] : '';
224
- if (!empty($newType) && $oldType != $newType) {
225
- $this->plugin->alerts->Trigger(8016, array(
226
- 'TopicName' => $post->post_title,
227
- 'OldType' => ($oldType == 'unstick') ? 'normal' : (($oldType == 'super') ? 'super sticky' : $oldType),
228
- 'NewType' => ($newType == 'unstick') ? 'normal' : (($newType == 'super') ? 'super sticky' : $newType)
229
- ));
230
- $result = 1;
231
- }
232
- break;
233
- }
234
- return $result;
235
- }
236
-
237
- private function EventForumChangedStatus($post)
238
- {
239
- $result = 0;
240
- switch ($post->post_type) {
241
- case 'forum':
242
- $bbp_status = get_post_meta($post->ID, '_bbp_status', true);
243
- $oldStatus = !empty($bbp_status) ? $bbp_status : 'open';
244
- $newStatus = !empty($_REQUEST['bbp_forum_status']) ? $_REQUEST['bbp_forum_status'] : '';
245
- if (!empty($newStatus) && $oldStatus != $newStatus) {
246
- $this->plugin->alerts->Trigger(8001, array(
247
- 'ForumName' => $post->post_title,
248
- 'OldStatus' => $oldStatus,
249
- 'NewStatus' => $newStatus
250
- ));
251
- $result = 1;
252
- }
253
- break;
254
- case 'topic':
255
- $oldStatus = !empty($_REQUEST['original_post_status']) ? $_REQUEST['original_post_status'] : '';
256
- $newStatus = !empty($_REQUEST['post_status']) ? $_REQUEST['post_status'] : '';
257
- // In case of Ajax request Spam/Not spam
258
- if (isset($_GET['action']) && $_GET['action'] == 'bbp_toggle_topic_spam') {
259
- $oldStatus = $post->post_status;
260
- $newStatus = 'spam';
261
- if (isset($_GET['post_status']) && $_GET['post_status'] == 'spam') {
262
- $newStatus = 'publish';
263
- }
264
- }
265
- // In case of Ajax request Close/Open
266
- if (isset($_GET['action']) && $_GET['action'] == 'bbp_toggle_topic_close') {
267
- $oldStatus = $post->post_status;
268
- $newStatus = 'closed';
269
- if (isset($_GET['post_status']) && $_GET['post_status'] == 'closed') {
270
- $newStatus = 'publish';
271
- }
272
- }
273
- if (!empty($newStatus) && $oldStatus != $newStatus) {
274
- $this->plugin->alerts->Trigger(8015, array(
275
- 'TopicName' => $post->post_title,
276
- 'OldStatus' => ($oldStatus == 'publish') ? 'open' : $oldStatus,
277
- 'NewStatus' => ($newStatus == 'publish') ? 'open' : $newStatus
278
- ));
279
- $result = 1;
280
- }
281
- break;
282
- }
283
- return $result;
284
- }
285
-
286
- private function EventForumChanged($old_post, $new_post)
287
- {
288
- // Changed Order
289
- if ($old_post->menu_order != $new_post->menu_order) {
290
- $this->plugin->alerts->Trigger(8004, array(
291
- 'ForumName' => $new_post->post_title,
292
- 'OldOrder' => $old_post->menu_order,
293
- 'NewOrder' => $new_post->menu_order
294
- ));
295
- return 1;
296
- }
297
- // Changed Parent
298
- if ($old_post->post_parent != $new_post->post_parent) {
299
- switch ($old_post->post_type) {
300
- case 'forum':
301
- $this->plugin->alerts->Trigger(8008, array(
302
- 'ForumName' => $new_post->post_title,
303
- 'OldParent' => $old_post->post_parent ? get_the_title($old_post->post_parent) : 'no parent',
304
- 'NewParent' => $new_post->post_parent ? get_the_title($new_post->post_parent) : 'no parent'
305
- ));
306
- break;
307
- case 'topic':
308
- $this->plugin->alerts->Trigger(8018, array(
309
- 'TopicName' => $new_post->post_title,
310
- 'OldForum' => $old_post->post_parent ? get_the_title($old_post->post_parent) : 'no parent',
311
- 'NewForum' => $new_post->post_parent ? get_the_title($new_post->post_parent) : 'no parent'
312
- ));
313
- break;
314
- }
315
- return 1;
316
- }
317
- // Changed URL
318
- $oldLink = $this->_OldLink;
319
- $newLink = get_permalink($new_post->ID);
320
- if (!empty($oldLink) && $oldLink != $newLink) {
321
- switch ($old_post->post_type) {
322
- case 'forum':
323
- $this->plugin->alerts->Trigger(8003, array(
324
- 'ForumName' => $new_post->post_title,
325
- 'OldUrl' => $oldLink,
326
- 'NewUrl' => $newLink
327
- ));
328
- break;
329
- case 'topic':
330
- $this->plugin->alerts->Trigger(8017, array(
331
- 'TopicName' => $new_post->post_title,
332
- 'OldUrl' => $oldLink,
333
- 'NewUrl' => $newLink
334
- ));
335
- break;
336
- }
337
- return 1;
338
- }
339
- return 0;
340
- }
341
-
342
- private function EventForumByCode($post, $event)
343
- {
344
- $this->plugin->alerts->Trigger($event, array(
345
- 'ForumID' => $post->ID,
346
- 'ForumName' => $post->post_title
347
- ));
348
- }
349
-
350
- private function EventTopicByCode($post, $event)
351
- {
352
- $this->plugin->alerts->Trigger($event, array(
353
- 'TopicID' => $post->ID,
354
- 'TopicName' => $post->post_title
355
- ));
356
- }
357
-
358
- /**
359
- * Trigger of ajax events generated in the Topic Grid
360
- */
361
- public function TriggerAjaxChange()
362
- {
363
- if (!empty($_GET['post_type']) && !empty($_GET['topic_id'])) {
364
- if ($_GET['post_type'] == 'topic') {
365
- $post = get_post($_GET['topic_id']);
366
-
367
- // Topic type
368
- if (isset($_GET['action']) && $_GET['action'] == 'bbp_toggle_topic_stick') {
369
- if (!empty($post->post_parent)) {
370
- $post_id = $post->post_parent;
371
- } else {
372
- $post_id = $_GET['topic_id'];
373
- }
374
-
375
- $bbp_sticky_topics = maybe_unserialize(get_post_meta($post_id, '_bbp_sticky_topics', true));
376
- $bbp_super_sticky_topics = maybe_unserialize(get_option('_bbp_super_sticky_topics'));
377
- if (!empty($bbp_sticky_topics) && in_array($_GET['topic_id'], $bbp_sticky_topics)) {
378
- $oldType = 'sticky';
379
- } elseif (!empty($bbp_super_sticky_topics) && in_array($_GET['topic_id'], $bbp_super_sticky_topics)) {
380
- $oldType = 'super sticky';
381
- } else {
382
- $oldType = 'normal';
383
- }
384
-
385
- switch ($oldType) {
386
- case 'sticky':
387
- case 'super sticky':
388
- $newType = 'normal';
389
- break;
390
- case 'normal':
391
- if (isset($_GET['super']) && $_GET['super'] == 1) {
392
- $newType = 'super sticky';
393
- } else {
394
- $newType = 'sticky';
395
- }
396
- break;
397
- }
398
-
399
- if (!empty($newType) && $oldType != $newType) {
400
- $this->plugin->alerts->Trigger(8016, array(
401
- 'TopicName' => $post->post_title,
402
- 'OldType' => $oldType,
403
- 'NewType' => $newType
404
- ));
405
- }
406
- }
407
- }
408
- }
409
- }
410
- }
 
 
1
+ <?php
2
+ /**
3
+ * Support for BBPress Forum Plugin
4
+ */
5
+ class WSAL_Sensors_BBPress extends WSAL_AbstractSensor
6
+ {
7
+ protected $_OldPost = null;
8
+ protected $_OldLink = null;
9
+
10
+ public function HookEvents()
11
+ {
12
+ if (current_user_can("edit_posts")) {
13
+ add_action('admin_init', array($this, 'EventAdminInit'));
14
+ }
15
+ add_action('post_updated', array($this, 'CheckForumChange'), 10, 3);
16
+ add_action('delete_post', array($this, 'EventForumDeleted'), 10, 1);
17
+ add_action('wp_trash_post', array($this, 'EventForumTrashed'), 10, 1);
18
+ add_action('untrash_post', array($this, 'EventForumUntrashed'));
19
+ }
20
+
21
+ public function EventAdminInit()
22
+ {
23
+ // load old data, if applicable
24
+ $this->RetrieveOldData();
25
+ // check for Ajax changes
26
+ $this->TriggerAjaxChange();
27
+ }
28
+
29
+ protected function RetrieveOldData()
30
+ {
31
+ if (isset($_POST) && isset($_POST['post_ID'])
32
+ && !(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
33
+ && !(isset($_POST['action']) && $_POST['action'] == 'autosave')
34
+ ) {
35
+ $postID = intval($_POST['post_ID']);
36
+ $this->_OldPost = get_post($postID);
37
+ $this->_OldLink = get_permalink($postID);
38
+ }
39
+ }
40
+
41
+ public function CheckForumChange($post_ID, $newpost, $oldpost)
42
+ {
43
+ if ($this->CheckBBPress($oldpost)) {
44
+ $changes = 0 + $this->EventForumCreation($oldpost, $newpost);
45
+ // Change Visibility
46
+ if (!$changes) {
47
+ $changes = $this->EventForumChangedVisibility($oldpost);
48
+ }
49
+ // Change Type
50
+ if (!$changes) {
51
+ $changes = $this->EventForumChangedType($oldpost);
52
+ }
53
+ // Change status
54
+ if (!$changes) {
55
+ $changes = $this->EventForumChangedStatus($oldpost);
56
+ }
57
+ // Change Order, Parent or URL
58
+ if (!$changes) {
59
+ $changes = $this->EventForumChanged($oldpost, $newpost);
60
+ }
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Permanently deleted
66
+ */
67
+ public function EventForumDeleted($post_id)
68
+ {
69
+ $post = get_post($post_id);
70
+ if ($this->CheckBBPress($post)) {
71
+ switch ($post->post_type) {
72
+ case 'forum':
73
+ $this->EventForumByCode($post, 8006);
74
+ break;
75
+ case 'topic':
76
+ $this->EventTopicByCode($post, 8020);
77
+ break;
78
+ }
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Moved to Trash
84
+ */
85
+ public function EventForumTrashed($post_id)
86
+ {
87
+ $post = get_post($post_id);
88
+ if ($this->CheckBBPress($post)) {
89
+ switch ($post->post_type) {
90
+ case 'forum':
91
+ $this->EventForumByCode($post, 8005);
92
+ break;
93
+ case 'topic':
94
+ $this->EventTopicByCode($post, 8019);
95
+ break;
96
+ }
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Restored from Trash
102
+ */
103
+ public function EventForumUntrashed($post_id)
104
+ {
105
+ $post = get_post($post_id);
106
+ if ($this->CheckBBPress($post)) {
107
+ switch ($post->post_type) {
108
+ case 'forum':
109
+ $this->EventForumByCode($post, 8007);
110
+ break;
111
+ case 'topic':
112
+ $this->EventTopicByCode($post, 8021);
113
+ break;
114
+ }
115
+ }
116
+ }
117
+
118
+ private function CheckBBPress($post)
119
+ {
120
+ switch ($post->post_type) {
121
+ case 'forum':
122
+ case 'topic':
123
+ case 'reply':
124
+ return true;
125
+ default:
126
+ return false;
127
+ }
128
+ }
129
+
130
+ private function EventForumCreation($old_post, $new_post)
131
+ {
132
+ $original = isset($_POST['original_post_status']) ? $_POST['original_post_status'] : '';
133
+ if ($old_post->post_status == 'draft' || $original == 'auto-draft') {
134
+ if ($new_post->post_status == 'publish') {
135
+ switch ($old_post->post_type) {
136
+ case 'forum':
137
+ $this->plugin->alerts->Trigger(8000, array(
138
+ 'ForumName' => $new_post->post_title,
139
+ 'ForumURL' => get_permalink($new_post->ID)
140
+ ));
141
+ break;
142
+ case 'topic':
143
+ $this->plugin->alerts->Trigger(8014, array(
144
+ 'TopicName' => $new_post->post_title,
145
+ 'TopicURL' => get_permalink($new_post->ID)
146
+ ));
147
+ break;
148
+ }
149
+ return 1;
150
+ }
151
+ }
152
+ return 0;
153
+ }
154
+
155
+ private function EventForumChangedVisibility($post)
156
+ {
157
+ $result = 0;
158
+ switch ($post->post_type) {
159
+ case 'forum':
160
+ $oldVisibility = !empty($_REQUEST['visibility']) ? $_REQUEST['visibility'] : '';
161
+ $newVisibility = !empty($_REQUEST['bbp_forum_visibility']) ? $_REQUEST['bbp_forum_visibility'] : '';
162
+ $newVisibility = ($newVisibility == 'publish') ? 'public' : $newVisibility;
163
+
164
+ if (!empty($newVisibility) && $oldVisibility != 'auto-draft' && $oldVisibility != $newVisibility) {
165
+ $this->plugin->alerts->Trigger(8002, array(
166
+ 'ForumName' => $post->post_title,
167
+ 'OldVisibility' => $oldVisibility,
168
+ 'NewVisibility' => $newVisibility
169
+ ));
170
+ $result = 1;
171
+ }
172
+ break;
173
+ case 'topic':
174
+ $oldVisibility = !empty($_REQUEST['hidden_post_visibility']) ? $_REQUEST['hidden_post_visibility'] : '';
175
+ $newVisibility = !empty($_REQUEST['visibility']) ? $_REQUEST['visibility'] : '';
176
+ $newVisibility = ($newVisibility == 'password') ? 'password protected' : $newVisibility;
177
+
178
+ if (!empty($newVisibility) && $oldVisibility != 'auto-draft' && $oldVisibility != $newVisibility) {
179
+ $this->plugin->alerts->Trigger(8022, array(
180
+ 'TopicName' => $post->post_title,
181
+ 'OldVisibility' => $oldVisibility,
182
+ 'NewVisibility' => $newVisibility
183
+ ));
184
+ $result = 1;
185
+ }
186
+ break;
187
+ }
188
+ return $result;
189
+ }
190
+
191
+ private function EventForumChangedType($post)
192
+ {
193
+ $result = 0;
194
+ switch ($post->post_type) {
195
+ case 'forum':
196
+ $bbp_forum_type = get_post_meta($post->ID, '_bbp_forum_type', true);
197
+ $oldType = !empty($bbp_forum_type) ? $bbp_forum_type : 'forum';
198
+ $newType = !empty($_POST['bbp_forum_type']) ? $_POST['bbp_forum_type'] : '';
199
+ if (!empty($newType) && $oldType != $newType) {
200
+ $this->plugin->alerts->Trigger(8011, array(
201
+ 'ForumName' => $post->post_title,
202
+ 'OldType' => $oldType,
203
+ 'NewType' => $newType
204
+ ));
205
+ $result = 1;
206
+ }
207
+ break;
208
+ case 'topic':
209
+ if (!empty($_POST['parent_id'])) {
210
+ $post_id = $_POST['parent_id'];
211
+ } else {
212
+ $post_id = $post->ID;
213
+ }
214
+ $bbp_sticky_topics = maybe_unserialize(get_post_meta($post_id, '_bbp_sticky_topics', true));
215
+ $fn = $this->IsMultisite() ? 'get_site_option' : 'get_option';
216
+ $bbp_super_sticky_topics = maybe_unserialize($fn('_bbp_super_sticky_topics'));
217
+ if (!empty($bbp_sticky_topics) && in_array($post->ID, $bbp_sticky_topics)) {
218
+ $oldType = 'sticky';
219
+ } elseif (!empty($bbp_super_sticky_topics) && in_array($post->ID, $bbp_super_sticky_topics)) {
220
+ $oldType = 'super';
221
+ } else {
222
+ $oldType = 'unstick';
223
+ }
224
+ $newType = !empty($_POST['bbp_stick_topic']) ? $_POST['bbp_stick_topic'] : '';
225
+ if (!empty($newType) && $oldType != $newType) {
226
+ $this->plugin->alerts->Trigger(8016, array(
227
+ 'TopicName' => $post->post_title,
228
+ 'OldType' => ($oldType == 'unstick') ? 'normal' : (($oldType == 'super') ? 'super sticky' : $oldType),
229
+ 'NewType' => ($newType == 'unstick') ? 'normal' : (($newType == 'super') ? 'super sticky' : $newType)
230
+ ));
231
+ $result = 1;
232
+ }
233
+ break;
234
+ }
235
+ return $result;
236
+ }
237
+
238
+ private function EventForumChangedStatus($post)
239
+ {
240
+ $result = 0;
241
+ switch ($post->post_type) {
242
+ case 'forum':
243
+ $bbp_status = get_post_meta($post->ID, '_bbp_status', true);
244
+ $oldStatus = !empty($bbp_status) ? $bbp_status : 'open';
245
+ $newStatus = !empty($_REQUEST['bbp_forum_status']) ? $_REQUEST['bbp_forum_status'] : '';
246
+ if (!empty($newStatus) && $oldStatus != $newStatus) {
247
+ $this->plugin->alerts->Trigger(8001, array(
248
+ 'ForumName' => $post->post_title,
249
+ 'OldStatus' => $oldStatus,
250
+ 'NewStatus' => $newStatus
251
+ ));
252
+ $result = 1;
253
+ }
254
+ break;
255
+ case 'topic':
256
+ $oldStatus = !empty($_REQUEST['original_post_status']) ? $_REQUEST['original_post_status'] : '';
257
+ $newStatus = !empty($_REQUEST['post_status']) ? $_REQUEST['post_status'] : '';
258
+ // In case of Ajax request Spam/Not spam
259
+ if (isset($_GET['action']) && $_GET['action'] == 'bbp_toggle_topic_spam') {
260
+ $oldStatus = $post->post_status;
261
+ $newStatus = 'spam';
262
+ if (isset($_GET['post_status']) && $_GET['post_status'] == 'spam') {
263
+ $newStatus = 'publish';
264
+ }
265
+ }
266
+ // In case of Ajax request Close/Open
267
+ if (isset($_GET['action']) && $_GET['action'] == 'bbp_toggle_topic_close') {
268
+ $oldStatus = $post->post_status;
269
+ $newStatus = 'closed';
270
+ if (isset($_GET['post_status']) && $_GET['post_status'] == 'closed') {
271
+ $newStatus = 'publish';
272
+ }
273
+ }
274
+ if (!empty($newStatus) && $oldStatus != $newStatus) {
275
+ $this->plugin->alerts->Trigger(8015, array(
276
+ 'TopicName' => $post->post_title,
277
+ 'OldStatus' => ($oldStatus == 'publish') ? 'open' : $oldStatus,
278
+ 'NewStatus' => ($newStatus == 'publish') ? 'open' : $newStatus
279
+ ));
280
+ $result = 1;
281
+ }
282
+ break;
283
+ }
284
+ return $result;
285
+ }
286
+
287
+ private function EventForumChanged($old_post, $new_post)
288
+ {
289
+ // Changed Order
290
+ if ($old_post->menu_order != $new_post->menu_order) {
291
+ $this->plugin->alerts->Trigger(8004, array(
292
+ 'ForumName' => $new_post->post_title,
293
+ 'OldOrder' => $old_post->menu_order,
294
+ 'NewOrder' => $new_post->menu_order
295
+ ));
296
+ return 1;
297
+ }
298
+ // Changed Parent
299
+ if ($old_post->post_parent != $new_post->post_parent) {
300
+ switch ($old_post->post_type) {
301
+ case 'forum':
302
+ $this->plugin->alerts->Trigger(8008, array(
303
+ 'ForumName' => $new_post->post_title,
304
+ 'OldParent' => $old_post->post_parent ? get_the_title($old_post->post_parent) : 'no parent',
305
+ 'NewParent' => $new_post->post_parent ? get_the_title($new_post->post_parent) : 'no parent'
306
+ ));
307
+ break;
308
+ case 'topic':
309
+ $this->plugin->alerts->Trigger(8018, array(
310
+ 'TopicName' => $new_post->post_title,
311
+ 'OldForum' => $old_post->post_parent ? get_the_title($old_post->post_parent) : 'no parent',
312
+ 'NewForum' => $new_post->post_parent ? get_the_title($new_post->post_parent) : 'no parent'
313
+ ));
314
+ break;
315
+ }
316
+ return 1;
317
+ }
318
+ // Changed URL
319
+ $oldLink = $this->_OldLink;
320
+ $newLink = get_permalink($new_post->ID);
321
+ if (!empty($oldLink) && $oldLink != $newLink) {
322
+ switch ($old_post->post_type) {
323
+ case 'forum':
324
+ $this->plugin->alerts->Trigger(8003, array(
325
+ 'ForumName' => $new_post->post_title,
326
+ 'OldUrl' => $oldLink,
327
+ 'NewUrl' => $newLink
328
+ ));
329
+ break;
330
+ case 'topic':
331
+ $this->plugin->alerts->Trigger(8017, array(
332
+ 'TopicName' => $new_post->post_title,
333
+ 'OldUrl' => $oldLink,
334
+ 'NewUrl' => $newLink
335
+ ));
336
+ break;
337
+ }
338
+ return 1;
339
+ }
340
+ return 0;
341
+ }
342
+
343
+ private function EventForumByCode($post, $event)
344
+ {
345
+ $this->plugin->alerts->Trigger($event, array(
346
+ 'ForumID' => $post->ID,
347
+ 'ForumName' => $post->post_title
348
+ ));
349
+ }
350
+
351
+ private function EventTopicByCode($post, $event)
352
+ {
353
+ $this->plugin->alerts->Trigger($event, array(
354
+ 'TopicID' => $post->ID,
355
+ 'TopicName' => $post->post_title
356
+ ));
357
+ }
358
+
359
+ /**
360
+ * Trigger of ajax events generated in the Topic Grid
361
+ */
362
+ public function TriggerAjaxChange()
363
+ {
364
+ if (!empty($_GET['post_type']) && !empty($_GET['topic_id'])) {
365
+ if ($_GET['post_type'] == 'topic') {
366
+ $post = get_post($_GET['topic_id']);
367
+
368
+ // Topic type
369
+ if (isset($_GET['action']) && $_GET['action'] == 'bbp_toggle_topic_stick') {
370
+ if (!empty($post->post_parent)) {
371
+ $post_id = $post->post_parent;
372
+ } else {
373
+ $post_id = $_GET['topic_id'];
374
+ }
375
+
376
+ $bbp_sticky_topics = maybe_unserialize(get_post_meta($post_id, '_bbp_sticky_topics', true));
377
+ $fn = $this->IsMultisite() ? 'get_site_option' : 'get_option';
378
+ $bbp_super_sticky_topics = maybe_unserialize($fn('_bbp_super_sticky_topics'));
379
+ if (!empty($bbp_sticky_topics) && in_array($_GET['topic_id'], $bbp_sticky_topics)) {
380
+ $oldType = 'sticky';
381
+ } elseif (!empty($bbp_super_sticky_topics) && in_array($_GET['topic_id'], $bbp_super_sticky_topics)) {
382
+ $oldType = 'super sticky';
383
+ } else {
384
+ $oldType = 'normal';
385
+ }
386
+
387
+ switch ($oldType) {
388
+ case 'sticky':
389
+ case 'super sticky':
390
+ $newType = 'normal';
391
+ break;
392
+ case 'normal':
393
+ if (isset($_GET['super']) && $_GET['super'] == 1) {
394
+ $newType = 'super sticky';
395
+ } else {
396
+ $newType = 'sticky';
397
+ }
398
+ break;
399
+ }
400
+
401
+ if (!empty($newType) && $oldType != $newType) {
402
+ $this->plugin->alerts->Trigger(8016, array(
403
+ 'TopicName' => $post->post_title,
404
+ 'OldType' => $oldType,
405
+ 'NewType' => $newType
406
+ ));
407
+ }
408
+ }
409
+ }
410
+ }
411
+ }
412
+ }
classes/Sensors/Content.php CHANGED
@@ -14,6 +14,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor
14
  add_action('untrash_post', array($this, 'EventPostUntrashed'));
15
  add_action('edit_category', array($this, 'EventChangedCategoryParent'));
16
  add_action('save_post', array($this, 'SetRevisionLink'), 10, 3);
 
17
  }
18
 
19
  protected function GetEventTypeForPostType($post, $typePost, $typePage, $typeCustom)
@@ -136,6 +137,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor
136
  protected function CheckPostCreation($oldPost, $newPost)
137
  {
138
  $event = 0;
 
139
  switch ($newPost->post_status) {
140
  case 'publish':
141
  $event = $this->GetEventTypeForPostType($oldPost, 2001, 2005, 2030);
@@ -143,16 +145,43 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor
143
  case 'draft':
144
  $event = $this->GetEventTypeForPostType($oldPost, 2000, 2004, 2029);
145
  break;
 
 
 
 
146
  case 'pending':
147
  $event = 2073;
148
  break;
149
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  if ($event) {
151
  $this->plugin->alerts->Trigger($event, array(
152
- 'PostID' => $newPost->ID,
153
- 'PostType' => $newPost->post_type,
154
- 'PostTitle' => $newPost->post_title,
155
- 'PostUrl' => get_permalink($newPost->ID),
156
  ));
157
  }
158
  }
@@ -217,7 +246,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor
217
  if ($this->CheckBBPress($post)) {
218
  return;
219
  }
220
- if (!in_array($post->post_type, array('attachment', 'revision'))) { // ignore attachments and revisions
221
  $event = $this->GetEventTypeForPostType($post, 2008, 2009, 2033);
222
  // check WordPress backend operations
223
  if ($this->CheckAutoDraft($event, $post->post_title)) {
14
  add_action('untrash_post', array($this, 'EventPostUntrashed'));
15
  add_action('edit_category', array($this, 'EventChangedCategoryParent'));
16
  add_action('save_post', array($this, 'SetRevisionLink'), 10, 3);
17
+ add_action('publish_future_post', array($this, 'EventPublishFuture'), 10, 1);
18
  }
19
 
20
  protected function GetEventTypeForPostType($post, $typePost, $typePage, $typeCustom)
137
  protected function CheckPostCreation($oldPost, $newPost)
138
  {
139
  $event = 0;
140
+ $is_scheduled = false;
141
  switch ($newPost->post_status) {
142
  case 'publish':
143
  $event = $this->GetEventTypeForPostType($oldPost, 2001, 2005, 2030);
145
  case 'draft':
146
  $event = $this->GetEventTypeForPostType($oldPost, 2000, 2004, 2029);
147
  break;
148
+ case 'future':
149
+ $event = $this->GetEventTypeForPostType($oldPost, 2074, 2075, 2076);
150
+ $is_scheduled = true;
151
+ break;
152
  case 'pending':
153
  $event = 2073;
154
  break;
155
  }
156
+ if ($event) {
157
+ if ($is_scheduled) {
158
+ $this->plugin->alerts->Trigger($event, array(
159
+ 'PostType' => $newPost->post_type,
160
+ 'PostTitle' => $newPost->post_title,
161
+ 'PublishingDate' => $newPost->post_date
162
+ ));
163
+ } else {
164
+ $this->plugin->alerts->Trigger($event, array(
165
+ 'PostID' => $newPost->ID,
166
+ 'PostType' => $newPost->post_type,
167
+ 'PostTitle' => $newPost->post_title,
168
+ 'PostUrl' => get_permalink($newPost->ID)
169
+ ));
170
+ }
171
+ }
172
+ }
173
+
174
+ public function EventPublishFuture($post_id)
175
+ {
176
+ $post = get_post($post_id);
177
+ $event = $this->GetEventTypeForPostType($post, 2001, 2005, 2030);
178
+
179
  if ($event) {
180
  $this->plugin->alerts->Trigger($event, array(
181
+ 'PostID' => $post->ID,
182
+ 'PostType' => $post->post_type,
183
+ 'PostTitle' => $post->post_title,
184
+ 'PostUrl' => get_permalink($post->ID)
185
  ));
186
  }
187
  }
246
  if ($this->CheckBBPress($post)) {
247
  return;
248
  }
249
+ if (!in_array($post->post_type, array('attachment', 'revision', 'nav_menu_item'))) { // ignore attachments, revisions and menu items
250
  $event = $this->GetEventTypeForPostType($post, 2008, 2009, 2033);
251
  // check WordPress backend operations
252
  if ($this->CheckAutoDraft($event, $post->post_title)) {
classes/Sensors/CustomHooks.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class used for to allow developers to create custom
4
+ * alerts
5
+ */
6
+ class WSAL_Sensors_CustomHooks extends WSAL_AbstractSensor
7
+ {
8
+ public function HookEvents()
9
+ {
10
+ /**
11
+ * For each hook use add_action() and pass:
12
+ * @param string sample_hook_name
13
+ * @param string SampleFunction is the name of the function above
14
+ * @param int 10 priority (Optional)
15
+ * @param int 2 number of parameters passed to the function (Optional)(Check the hook documentation)
16
+ * @see http://adambrown.info/p/wp_hooks
17
+ */
18
+ add_action('sample_hook_name', array($this, 'SampleFunction'), 10, 2);
19
+ }
20
+
21
+ /**
22
+ * Sample function with 0 or more parameters,
23
+ * create one function for each hook
24
+ * @param anyType $paramname (Optional)
25
+ */
26
+ public function SampleFunction($value_1 = null, $value_2 = null)
27
+ {
28
+ /**
29
+ * @var int (4 digit) $alertCode Alert code (3 types of criticality level)
30
+ * @example Critical 2222, Warning 3333, Notice 4444
31
+ */
32
+ $alertCode = 2222;
33
+
34
+ /**
35
+ * @var string alert text
36
+ */
37
+ $alertText = 'Sample alert text';
38
+
39
+ /**
40
+ * @var array $variables used in the alert (With 1 or more elements)
41
+ * { @var string $alertText }
42
+ */
43
+ $variables = array(
44
+ 'CustomAlertText' => $alertText
45
+ );
46
+
47
+ $this->plugin->alerts->Trigger($alertCode, $variables);
48
+ }
49
+ }
classes/Sensors/Database.php CHANGED
@@ -1,130 +1,132 @@
1
- <?php
2
-
3
- class WSAL_Sensors_Database extends WSAL_AbstractSensor {
4
-
5
- public function HookEvents() {
6
- add_action('dbdelta_queries', array($this, 'EventDBDeltaQuery'));
7
- add_action('query', array($this, 'EventDropQuery'));
8
- }
9
-
10
- public function EventDropQuery($query) {
11
- $table_names = array();
12
- $str = explode(" ", $query);
13
-
14
- if (preg_match("|DROP TABLE ([^ ]*)|", $query)) {
15
- if (!empty($str[4])) {
16
- array_push($table_names, $str[4]);
17
- } else {
18
- array_push($table_names, $str[2]);
19
- }
20
- $actype = basename($_SERVER['SCRIPT_NAME'], '.php');
21
- $alertOptions = $this->GetActionType($actype);
22
- }
23
-
24
- if (!empty($table_names)) {
25
- $event_code = $this->GetEventQueryType($actype, "delete");
26
- $alertOptions["TableNames"] = implode(",", $table_names);
27
- $this->plugin->alerts->Trigger($event_code, $alertOptions);
28
- }
29
- return $query;
30
- }
31
-
32
- public function EventDBDeltaQuery($queries) {
33
-
34
- $typeQueries = array(
35
- "create" => array(),
36
- "update" => array(),
37
- "delete" => array()
38
- );
39
- global $wpdb;
40
-
41
- foreach($queries as $qry) {
42
- $str = explode(" ", $qry);
43
- if (preg_match("|CREATE TABLE ([^ ]*)|", $qry)) {
44
- if ($wpdb->get_var("SHOW TABLES LIKE '" . $str[2] . "'") != $str[2]) {
45
- //some plugins keep trying to create tables even when they already exist- would result in too many alerts
46
- array_push($typeQueries['create'], $str[2]);
47
- }
48
- } else if (preg_match("|ALTER TABLE ([^ ]*)|", $qry)) {
49
- array_push($typeQueries['update'], $str[2]);
50
- } else if (preg_match("|DROP TABLE ([^ ]*)|", $qry)) {
51
- if (!empty($str[4])) {
52
- array_push($typeQueries['delete'], $str[4]);
53
- } else {
54
- array_push($typeQueries['delete'], $str[2]);
55
- }
56
- }
57
- }
58
-
59
- if (!empty($typeQueries["create"]) || !empty($typeQueries["update"]) || !empty($typeQueries["delete"])) {
60
- $actype = basename($_SERVER['SCRIPT_NAME'], '.php');
61
- $alertOptions = $this->GetActionType($actype);
62
-
63
-
64
- foreach($typeQueries as $queryType => $tableNames) {
65
- if (!empty($tableNames)) {
66
- $event_code = $this->GetEventQueryType($actype, $queryType);
67
- $alertOptions["TableNames"] = implode(",", $tableNames);
68
- $this->plugin->alerts->Trigger($event_code, $alertOptions);
69
- }
70
- }
71
- }
72
-
73
- return $queries;
74
- }
75
-
76
- protected function GetEventQueryType($type_action, $type_query) {
77
- switch($type_action){
78
- case 'plugins':
79
- if ($type_query == 'create') return 5010;
80
- else if ($type_query == 'update') return 5011;
81
- else if ($type_query == 'delete') return 5012;
82
- case 'themes':
83
- if ($type_query == 'create') return 5013;
84
- else if ($type_query == 'update') return 5014;
85
- else if ($type_query == 'delete') return 5015;
86
- default:
87
- if ($type_query == 'create') return 5016;
88
- else if ($type_query == 'update') return 5017;
89
- else if ($type_query == 'delete') return 5018;
90
- }
91
- }
92
-
93
- protected function GetActionType($actype) {
94
- $is_themes = $actype == 'themes';
95
- $is_plugins = $actype == 'plugins';
96
- //Action Plugin Component
97
- $alertOptions = array();
98
- if ($is_plugins) {
99
- if (isset($_REQUEST['plugin'])) {
100
- $pluginFile = $_REQUEST['plugin'];
101
- } else {
102
- $pluginFile = $_REQUEST['checked'][0];
103
- }
104
- $pluginName = basename($pluginFile, '.php');
105
- $pluginName = str_replace(array('_', '-', ' '), ' ', $pluginName);
106
- $pluginName = ucwords($pluginName);
107
- $alertOptions["Plugin"] = (object)array(
108
- 'Name' => $pluginName,
109
- );
110
- //Action Theme Component
111
- } else if ($is_themes) {
112
- if (isset($_REQUEST['theme'])) {
113
- $themeName = $_REQUEST['theme'];
114
- } else {
115
- $themeName = $_REQUEST['checked'][0];
116
- }
117
- $themeName = str_replace(array('_', '-', ' '), ' ', $themeName);
118
- $themeName = ucwords($themeName);
119
- $alertOptions["Theme"] = (object)array(
120
- 'Name' => $themeName,
121
- );
122
- //Action Unknown Component
123
- } else {
124
- $alertOptions["Component"] = "Unknown";
125
- }
126
-
127
- return $alertOptions;
128
- }
129
-
130
- }
 
 
1
+ <?php
2
+
3
+ class WSAL_Sensors_Database extends WSAL_AbstractSensor
4
+ {
5
+ public function HookEvents()
6
+ {
7
+ add_action('dbdelta_queries', array($this, 'EventDBDeltaQuery'));
8
+ add_action('query', array($this, 'EventDropQuery'));
9
+ }
10
+
11
+ public function EventDropQuery($query)
12
+ {
13
+ $table_names = array();
14
+ $str = explode(" ", $query);
15
+
16
+ if (preg_match("|DROP TABLE ([^ ]*)|", $query)) {
17
+ if (!empty($str[4])) {
18
+ array_push($table_names, $str[4]);
19
+ } else {
20
+ array_push($table_names, $str[2]);
21
+ }
22
+ $actype = basename($_SERVER['SCRIPT_NAME'], '.php');
23
+ $alertOptions = $this->GetActionType($actype);
24
+ }
25
+
26
+ if (!empty($table_names)) {
27
+ $event_code = $this->GetEventQueryType($actype, "delete");
28
+ $alertOptions["TableNames"] = implode(",", $table_names);
29
+ $this->plugin->alerts->Trigger($event_code, $alertOptions);
30
+ }
31
+ return $query;
32
+ }
33
+
34
+ public function EventDBDeltaQuery($queries)
35
+ {
36
+ $typeQueries = array(
37
+ "create" => array(),
38
+ "update" => array(),
39
+ "delete" => array()
40
+ );
41
+ global $wpdb;
42
+
43
+ foreach ($queries as $qry) {
44
+ $str = explode(" ", $qry);
45
+ if (preg_match("|CREATE TABLE ([^ ]*)|", $qry)) {
46
+ if ($wpdb->get_var("SHOW TABLES LIKE '" . $str[2] . "'") != $str[2]) {
47
+ //some plugins keep trying to create tables even when they already exist- would result in too many alerts
48
+ array_push($typeQueries['create'], $str[2]);
49
+ }
50
+ } else if (preg_match("|ALTER TABLE ([^ ]*)|", $qry)) {
51
+ array_push($typeQueries['update'], $str[2]);
52
+ } else if (preg_match("|DROP TABLE ([^ ]*)|", $qry)) {
53
+ if (!empty($str[4])) {
54
+ array_push($typeQueries['delete'], $str[4]);
55
+ } else {
56
+ array_push($typeQueries['delete'], $str[2]);
57
+ }
58
+ }
59
+ }
60
+
61
+ if (!empty($typeQueries["create"]) || !empty($typeQueries["update"]) || !empty($typeQueries["delete"])) {
62
+ $actype = basename($_SERVER['SCRIPT_NAME'], '.php');
63
+ $alertOptions = $this->GetActionType($actype);
64
+
65
+ foreach ($typeQueries as $queryType => $tableNames) {
66
+ if (!empty($tableNames)) {
67
+ $event_code = $this->GetEventQueryType($actype, $queryType);
68
+ $alertOptions["TableNames"] = implode(",", $tableNames);
69
+ $this->plugin->alerts->Trigger($event_code, $alertOptions);
70
+ }
71
+ }
72
+ }
73
+
74
+ return $queries;
75
+ }
76
+
77
+ protected function GetEventQueryType($type_action, $type_query)
78
+ {
79
+ switch ($type_action) {
80
+ case 'plugins':
81
+ if ($type_query == 'create') return 5010;
82
+ else if ($type_query == 'update') return 5011;
83
+ else if ($type_query == 'delete') return 5012;
84
+ case 'themes':
85
+ if ($type_query == 'create') return 5013;
86
+ else if ($type_query == 'update') return 5014;
87
+ else if ($type_query == 'delete') return 5015;
88
+ default:
89
+ if ($type_query == 'create') return 5016;
90
+ else if ($type_query == 'update') return 5017;
91
+ else if ($type_query == 'delete') return 5018;
92
+ }
93
+ }
94
+
95
+ protected function GetActionType($actype)
96
+ {
97
+ $is_themes = $actype == 'themes';
98
+ $is_plugins = $actype == 'plugins';
99
+ //Action Plugin Component
100
+ $alertOptions = array();
101
+ if ($is_plugins) {
102
+ if (isset($_REQUEST['plugin'])) {
103
+ $pluginFile = $_REQUEST['plugin'];
104
+ } else {
105
+ $pluginFile = $_REQUEST['checked'][0];
106
+ }
107
+ $pluginName = basename($pluginFile, '.php');
108
+ $pluginName = str_replace(array('_', '-', ' '), ' ', $pluginName);
109
+ $pluginName = ucwords($pluginName);
110
+ $alertOptions["Plugin"] = (object)array(
111
+ 'Name' => $pluginName,
112
+ );
113
+ //Action Theme Component
114
+ } else if ($is_themes) {
115
+ if (isset($_REQUEST['theme'])) {
116
+ $themeName = $_REQUEST['theme'];
117
+ } else {
118
+ $themeName = $_REQUEST['checked'][0];
119
+ }
120
+ $themeName = str_replace(array('_', '-', ' '), ' ', $themeName);
121
+ $themeName = ucwords($themeName);
122
+ $alertOptions["Theme"] = (object)array(
123
+ 'Name' => $themeName,
124
+ );
125
+ //Action Unknown Component
126
+ } else {
127
+ $alertOptions["Component"] = "Unknown";
128
+ }
129
+
130
+ return $alertOptions;
131
+ }
132
+ }
classes/Sensors/LogInOut.php CHANGED
@@ -39,14 +39,6 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
39
  ), true);
40
  }
41
  }
42
-
43
- /**
44
- * @return boolean Whether we are running on multisite or not.
45
- */
46
- public function IsMultisite()
47
- {
48
- return function_exists('is_multisite') && is_multisite();
49
- }
50
 
51
  const TRANSIENT_FAILEDLOGINS = 'wsal-failedlogins-known';
52
  const TRANSIENT_FAILEDLOGINS_UNKNOWN = 'wsal-failedlogins-unknown';
39
  ), true);
40
  }
41
  }
 
 
 
 
 
 
 
 
42
 
43
  const TRANSIENT_FAILEDLOGINS = 'wsal-failedlogins-known';
44
  const TRANSIENT_FAILEDLOGINS_UNKNOWN = 'wsal-failedlogins-unknown';
classes/Sensors/Menus.php ADDED
@@ -0,0 +1,416 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class WSAL_Sensors_Menus extends WSAL_AbstractSensor
4
+ {
5
+ protected $_OldMenu = null;
6
+ protected $_OldMenuTerms = array();
7
+ protected $_OldMenuItems = array();
8
+ protected $_OldMenuLocations = null;
9
+
10
+ public function HookEvents()
11
+ {
12
+ add_action('wp_create_nav_menu', array($this, 'CreateMenu'), 10, 2);
13
+ add_action('wp_delete_nav_menu', array($this, 'DeleteMenu'), 10, 1);
14
+ add_action('wp_update_nav_menu', array($this, 'UpdateMenu'), 10, 2);
15
+ add_action('admin_menu', array($this, 'ManageMenuLocations'));
16
+
17
+ add_action('admin_init', array($this, 'EventAdminInit'));
18
+ // Customizer trigger
19
+ add_action('customize_register', array($this, 'CustomizeInit'));
20
+ add_action('customize_save_after', array($this, 'CustomizeSave'));
21
+ }
22
+
23
+ public function CreateMenu($term_id, $menu_data)
24
+ {
25
+ $this->plugin->alerts->Trigger(2078, array(
26
+ 'MenuName' => $menu_data['menu-name']
27
+ ));
28
+ }
29
+
30
+ public function ManageMenuLocations()
31
+ {
32
+ // Manage Location tab
33
+ if (isset($_POST['menu-locations'])) {
34
+ $new_locations = $_POST['menu-locations'];
35
+ if (isset($new_locations['primary'])) {
36
+ $this->LocationSetting($new_locations['primary'], 'primary');
37
+ }
38
+ if (isset($new_locations['social'])) {
39
+ $this->LocationSetting($new_locations['social'], 'social');
40
+ }
41
+ }
42
+ }
43
+
44
+ private function LocationSetting($new_location, $type)
45
+ {
46
+ $old_locations = get_nav_menu_locations();
47
+ if ($new_location != 0) {
48
+ $menu = wp_get_nav_menu_object($new_location);
49
+ if (!empty($old_locations[$type]) && $old_locations[$type] != $new_location) {
50
+ $this->EventMenuSetting($menu->name, "Enabled", "Location: ".$type." menu");
51
+ }
52
+ } else {
53
+ if (!empty($old_locations[$type])) {
54
+ $menu = wp_get_nav_menu_object($old_locations[$type]);
55
+ $this->EventMenuSetting($menu->name, "Disabled", "Location: ".$type." menu");
56
+ }
57
+ }
58
+ }
59
+
60
+ public function DeleteMenu($term_id)
61
+ {
62
+ if ($this->_OldMenu) {
63
+ $this->plugin->alerts->Trigger(2081, array(
64
+ 'MenuName' => $this->_OldMenu->name
65
+ ));
66
+ }
67
+ }
68
+
69
+ public function UpdateMenu($menu_id, $menu_data = null)
70
+ {
71
+ if (!empty($menu_data)) {
72
+ $contentNamesOld = array();
73
+ $contentTypesOld = array();
74
+ $contentOrderOld = array();
75
+
76
+ $items = wp_get_nav_menu_items($menu_id);
77
+ if (!empty($items)) {
78
+ foreach ($items as $item) {
79
+ array_push($contentNamesOld, $item->title);
80
+ array_push($contentTypesOld, $item->object);
81
+ $contentOrderOld[$item->ID] = $item->menu_order;
82
+ }
83
+ }
84
+ // Menu changed name
85
+ if (!empty($this->_OldMenuTerms) && isset($_POST['menu']) && isset($_POST['menu-name'])) {
86
+ foreach ($this->_OldMenuTerms as $oldMenuTerm) {
87
+ if ($oldMenuTerm['term_id'] == $_POST['menu']) {
88
+ if ($oldMenuTerm['name'] != $_POST['menu-name']) {
89
+ $this->EventChangeName($oldMenuTerm['name'], $_POST['menu-name']);
90
+ } else {
91
+ // Remove the last menu item
92
+ if (count($contentNamesOld) == 1 && count($contentTypesOld) == 1) {
93
+ $this->EventRemoveItems($contentTypesOld[0], $contentNamesOld[0], $_POST['menu-name']);
94
+ }
95
+ }
96
+ }
97
+ }
98
+ }
99
+
100
+ $is_occurred_event = false;
101
+ if (isset($_POST['menu-item-title']) && isset($_POST['menu-item-object'])) {
102
+ $contentNamesNew = array_values($_POST['menu-item-title']);
103
+ $contentTypesNew = array_values($_POST['menu-item-object']);
104
+ $contentOrderNew = $_POST['menu-item-position'];
105
+
106
+ $order = array_diff_assoc($contentOrderNew, $contentOrderOld);
107
+ // Changed order of the objects in a menu
108
+ if ((count($contentOrderOld) == count($contentOrderNew)) && count($order) > 0) {
109
+ $is_occurred_event = true;
110
+ $this->EventChangeOrder($menu_data['menu-name']);
111
+ }
112
+ $addedNames = array_diff_assoc($contentNamesNew, $contentNamesOld);
113
+ $addedTypes = array_diff_assoc($contentTypesNew, $contentTypesOld);
114
+
115
+ if (!$is_occurred_event) {
116
+ // Add Items to the menu
117
+ if (count($addedNames) > 0 && count($addedTypes) > 0) {
118
+ $is_occurred_event = true;
119
+ foreach ($addedNames as $key => $contentName) {
120
+ $contentType = str_replace("custom", "custom link", $contentTypesNew[$key]);
121
+ if (!empty($contentType)) {
122
+ $this->EventAddItems($contentType, $contentName, $menu_data['menu-name']);
123
+ }
124
+ }
125
+ }
126
+
127
+ $removedNames = array_diff_assoc($contentNamesOld, $contentNamesNew);
128
+ $removedTypes = array_diff_assoc($contentTypesOld, $contentTypesNew);
129
+ // Remove items from the menu
130
+ if (count($removedNames) > 0 && count($removedTypes) > 0) {
131
+ $is_occurred_event = true;
132
+ foreach ($removedNames as $key => $contentName) {
133
+ $contentType = str_replace("custom", "custom link", $contentTypesOld[$key]);
134
+ if (!empty($contentType)) {
135
+ $this->EventRemoveItems($contentType, $contentName, $menu_data['menu-name']);
136
+ }
137
+ }
138
+ }
139
+ }
140
+
141
+ // Modified Items in the menu
142
+ if (!$is_occurred_event && count($addedNames) > 0) {
143
+ foreach ($addedNames as $key => $contentName) {
144
+ $contentType = str_replace("custom", "custom link", $contentTypesOld[$key]);
145
+ if (!empty($contentType)) {
146
+ $this->EventModifiedItems($contentType, $contentName, $menu_data['menu-name']);
147
+ }
148
+ }
149
+ }
150
+ }
151
+ // Enable/Disable menu setting
152
+ $nav_menu_options = maybe_unserialize(get_option('nav_menu_options'));
153
+ $auto_add = null;
154
+ if (isset($nav_menu_options['auto_add'])) {
155
+ if (in_array($menu_id, $nav_menu_options['auto_add'])) {
156
+ if (empty($_POST['auto-add-pages'])) {
157
+ $auto_add = "Disabled";
158
+ }
159
+ } else {
160
+ if (isset($_POST['auto-add-pages'])) {
161
+ $auto_add = "Enabled";
162
+ }
163
+ }
164
+ } else {
165
+ if (isset($_POST['auto-add-pages'])) {
166
+ $auto_add = "Enabled";
167
+ }
168
+ }
169
+ // Alert 2082 Auto add pages
170
+ if (!empty($auto_add)) {
171
+ $this->EventMenuSetting($menu_data['menu-name'], $auto_add, "Auto add pages");
172
+ }
173
+
174
+ $nav_menu_locations = get_nav_menu_locations();
175
+
176
+ $locationPrimary = null;
177
+ if (isset($this->_OldMenuLocations['primary']) && isset($nav_menu_locations['primary'])) {
178
+ if ($nav_menu_locations['primary'] == $menu_id && $this->_OldMenuLocations['primary'] != $nav_menu_locations['primary']) {
179
+ $locationPrimary = "Enabled";
180
+ }
181
+ } elseif (empty($this->_OldMenuLocations['primary']) && isset($nav_menu_locations['primary'])) {
182
+ if ($nav_menu_locations['primary'] == $menu_id) {
183
+ $locationPrimary = "Enabled";
184
+ }
185
+ } elseif (isset($this->_OldMenuLocations['primary']) && empty($nav_menu_locations['primary'])) {
186
+ if ($this->_OldMenuLocations['primary'] == $menu_id) {
187
+ $locationPrimary = "Disabled";
188
+ }
189
+ }
190
+ // Alert 2082 Primary menu
191
+ if (!empty($locationPrimary)) {
192
+ $this->EventMenuSetting($menu_data['menu-name'], $locationPrimary, "Location: primary menu");
193
+ }
194
+
195
+ $locationSocial = null;
196
+ if (isset($this->_OldMenuLocations['social']) && isset($nav_menu_locations['social'])) {
197
+ if ($nav_menu_locations['social'] == $menu_id && $this->_OldMenuLocations['social'] != $nav_menu_locations['social']) {
198
+ $locationSocial = "Enabled";
199
+ }
200
+ } elseif (empty($this->_OldMenuLocations['social']) && isset($nav_menu_locations['social'])) {
201
+ if ($nav_menu_locations['social'] == $menu_id) {
202
+ $locationSocial = "Enabled";
203
+ }
204
+ } elseif (isset($this->_OldMenuLocations['social']) && empty($nav_menu_locations['social'])) {
205
+ if ($this->_OldMenuLocations['social'] == $menu_id) {
206
+ $locationSocial = "Disabled";
207
+ }
208
+ }
209
+ // Alert 2082 Social links menu
210
+ if (!empty($locationSocial)) {
211
+ $this->EventMenuSetting($menu_data['menu-name'], $locationSocial, "Location: social menu");
212
+ }
213
+ }
214
+ }
215
+
216
+ private function BuildOldMenuTermsAndItems()
217
+ {
218
+ $menus = wp_get_nav_menus();
219
+ if (!empty($menus)) {
220
+ foreach ($menus as $menu) {
221
+ array_push($this->_OldMenuTerms, array("term_id" => $menu->term_id, "name" => $menu->name));
222
+ $items = wp_get_nav_menu_items($menu->term_id);
223
+ if (!empty($items)) {
224
+ foreach ($items as $item) {
225
+ array_push($this->_OldMenuItems, array(
226
+ 'item_id' => $item->ID,
227
+ 'title' => $item->title,
228
+ 'object' => $item->object,
229
+ 'menu_name' => $menu->name,
230
+ 'menu_order' => $item->menu_order
231
+ ));
232
+ }
233
+ }
234
+ }
235
+ }
236
+ }
237
+
238
+ public function EventAdminInit()
239
+ {
240
+ $is_nav_menu = basename($_SERVER['SCRIPT_NAME']) == 'nav-menus.php';
241
+ if ($is_nav_menu) {
242
+ if (isset($_GET['action']) && $_GET['action'] == 'delete') {
243
+ if (isset($_GET['menu'])) {
244
+ $this->_OldMenu = wp_get_nav_menu_object($_GET['menu']);
245
+ }
246
+ } else {
247
+ $this->BuildOldMenuTermsAndItems();
248
+ }
249
+ $this->_OldMenuLocations = get_nav_menu_locations();
250
+ }
251
+ }
252
+
253
+ public function CustomizeInit()
254
+ {
255
+ $this->BuildOldMenuTermsAndItems();
256
+ $this->_OldMenuLocations = get_nav_menu_locations();
257
+ }
258
+
259
+ /**
260
+ * Customize Events Function
261
+ */
262
+ public function CustomizeSave()
263
+ {
264
+ $updateMenus = array();
265
+ $menus = wp_get_nav_menus();
266
+ if (!empty($menus)) {
267
+ foreach ($menus as $menu) {
268
+ array_push($updateMenus, array("term_id" => $menu->term_id, "name" => $menu->name));
269
+ }
270
+ }
271
+ // Deleted Menu
272
+ if (isset($updateMenus) && isset($this->_OldMenuTerms)) {
273
+ $terms = array_diff(array_map('serialize', $this->_OldMenuTerms), array_map('serialize', $updateMenus));
274
+ $terms = array_map('unserialize', $terms);
275
+
276
+ if (isset($terms) && count($terms) > 0) {
277
+ foreach ($terms as $term) {
278
+ $this->plugin->alerts->Trigger(2081, array(
279
+ 'MenuName' => $term['name']
280
+ ));
281
+ }
282
+ }
283
+ }
284
+ if (isset($_POST['action']) && $_POST['action'] == 'customize_save') {
285
+ if (isset($_POST['wp_customize'], $_POST['customized'])) {
286
+ $customized = json_decode(wp_unslash($_POST['customized']), true);
287
+ if (is_array($customized)) {
288
+ foreach ($customized as $key => $value) {
289
+ if (!empty($value['nav_menu_term_id'])) {
290
+ $is_occurred_event = false;
291
+ $menu = wp_get_nav_menu_object($value['nav_menu_term_id']);
292
+ $content_name = !empty($value['title']) ? $value['title'] : "no title";
293
+ if (!empty($this->_OldMenuItems)) {
294
+ foreach ($this->_OldMenuItems as $old_item) {
295
+ $item_id = substr(trim($key, ']'), 14);
296
+ // Modified Items in the menu
297
+ if ($old_item['item_id'] == $item_id && $old_item['title'] != $content_name) {
298
+ $is_occurred_event = true;
299
+ $this->EventModifiedItems($value['type_label'], $content_name, $menu->name);
300
+ }
301
+ // Changed order of the objects in a menu
302
+ if ($old_item['item_id'] == $item_id && $old_item['menu_order'] != $value['position']) {
303
+ $is_occurred_event = true;
304
+ $this->EventChangeOrder($menu->name);
305
+ return;
306
+ }
307
+ }
308
+ }
309
+ // Add Items to the menu
310
+ if (!$is_occurred_event) {
311
+ $menu_name = !empty($customized['new_menu_name']) ? $customized['new_menu_name'] : $menu->name;
312
+ $this->EventAddItems($value['type_label'], $content_name, $menu_name);
313
+ }
314
+ } else {
315
+ // Menu changed name
316
+ if (isset($updateMenus) && isset($this->_OldMenuTerms)) {
317
+ foreach ($this->_OldMenuTerms as $old_menu) {
318
+ foreach ($updateMenus as $update_menu) {
319
+ if ($old_menu['term_id'] == $update_menu['term_id'] && $old_menu['name'] != $update_menu['name']) {
320
+ $this->EventChangeName($old_menu['name'], $update_menu['name']);
321
+ }
322
+ }
323
+ }
324
+ }
325
+ // Setting Auto add pages
326
+ if (!empty($value) && isset($value['auto_add'])) {
327
+ if ($value['auto_add']) {
328
+ $this->EventMenuSetting($value['name'], 'Enabled', "Auto add pages");
329
+ } else {
330
+ $this->EventMenuSetting($value['name'], 'Disabled', "Auto add pages");
331
+ }
332
+ }
333
+ // Setting Location
334
+ if (false !== strpos($key, 'nav_menu_locations[')) {
335
+ $loc = substr(trim($key, ']'), 19);
336
+ if (!empty($value)) {
337
+ $menu = wp_get_nav_menu_object($value);
338
+ $menu_name = !empty($customized['new_menu_name']) ? $customized['new_menu_name'] : (!empty($menu) ? $menu->name : '');
339
+ $this->EventMenuSetting($menu_name, "Enabled", "Location: ".$loc." menu");
340
+ } else {
341
+ if (!empty($this->_OldMenuLocations[$loc])) {
342
+ $menu = wp_get_nav_menu_object($this->_OldMenuLocations[$loc]);
343
+ $menu_name = !empty($customized['new_menu_name']) ? $customized['new_menu_name'] : (!empty($menu) ? $menu->name : '');
344
+ $this->EventMenuSetting($menu_name, "Disabled", "Location: ".$loc." menu");
345
+ }
346
+ }
347
+ }
348
+ // Remove items from the menu
349
+ if (false !== strpos($key, 'nav_menu_item[')) {
350
+ $item_id = substr(trim($key, ']'), 14);
351
+ if (!empty($this->_OldMenuItems)) {
352
+ foreach ($this->_OldMenuItems as $old_item) {
353
+ if ($old_item['item_id'] == $item_id) {
354
+ $this->EventRemoveItems($old_item['object'], $old_item['title'], $old_item['menu_name']);
355
+ }
356
+ }
357
+ }
358
+ }
359
+ }
360
+ }
361
+ }
362
+ }
363
+ }
364
+ }
365
+
366
+ private function EventAddItems($content_type, $content_name, $menu_name)
367
+ {
368
+ $this->plugin->alerts->Trigger(2079, array(
369
+ 'ContentType' => $content_type,
370
+ 'ContentName' => $content_name,
371
+ 'MenuName' => $menu_name
372
+ ));
373
+ }
374
+
375
+ private function EventRemoveItems($content_type, $content_name, $menu_name)
376
+ {
377
+ $this->plugin->alerts->Trigger(2080, array(
378
+ 'ContentType' => $content_type,
379
+ 'ContentName' => $content_name,
380
+ 'MenuName' => $menu_name
381
+ ));
382
+ }
383
+
384
+ private function EventMenuSetting($menu_name, $status, $menu_setting)
385
+ {
386
+ $this->plugin->alerts->Trigger(2082, array(
387
+ 'Status' => $status,
388
+ 'MenuSetting' => $menu_setting,
389
+ 'MenuName' => $menu_name
390
+ ));
391
+ }
392
+
393
+ private function EventModifiedItems($content_type, $content_name, $menu_name)
394
+ {
395
+ $this->plugin->alerts->Trigger(2083, array(
396
+ 'ContentType' => $content_type,
397
+ 'ContentName' => $content_name,
398
+ 'MenuName' => $menu_name
399
+ ));
400
+ }
401
+
402
+ private function EventChangeName($old_menu_name, $new_menu_name)
403
+ {
404
+ $this->plugin->alerts->Trigger(2084, array(
405
+ 'OldMenuName' => $old_menu_name,
406
+ 'NewMenuName' => $new_menu_name
407
+ ));
408
+ }
409
+
410
+ private function EventChangeOrder($menu_name)
411
+ {
412
+ $this->plugin->alerts->Trigger(2085, array(
413
+ 'MenuName' => $menu_name
414
+ ));
415
+ }
416
+ }
classes/Sensors/MetaData.php CHANGED
@@ -1,8 +1,10 @@
1
  <?php
2
 
3
- class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
 
4
 
5
- public function HookEvents() {
 
6
  add_action('add_post_meta', array($this, 'EventPostMetaCreated'), 10, 3);
7
  add_action('update_post_meta', array($this, 'EventPostMetaUpdating'), 10, 3);
8
  add_action('updated_post_meta', array($this, 'EventPostMetaUpdated'), 10, 4);
@@ -14,9 +16,9 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
14
  protected function CanLogPostMeta($object_id, $meta_key)
15
  {
16
  //check if excluded meta key or starts with _
17
- if ( substr($meta_key, 0, 1) == '_' ) {
18
  return false;
19
- } else if ( $this->IsExcludedCustomFields($meta_key) ) {
20
  return false;
21
  } else {
22
  return true;
@@ -29,18 +31,19 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
29
  return (in_array($custom, $customFields)) ? true : false;
30
  }
31
 
32
- public function EventPostMetaCreated($object_id, $meta_key, $_meta_value) {
 
33
  $post = get_post($object_id);
34
 
35
- if(!$this->CanLogPostMeta($object_id, $meta_key))return;
36
 
37
- switch($post->post_type){
38
  case 'page':
39
  $this->plugin->alerts->Trigger(2059, array(
40
  'PostID' => $object_id,
41
  'PostTitle' => $post->post_title,
42
  'MetaKey' => $meta_key,
43
- 'MetaValue' => $_meta_value,
44
  'MetaLink' => $meta_key,
45
  ));
46
  break;
@@ -49,7 +52,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
49
  'PostID' => $object_id,
50
  'PostTitle' => $post->post_title,
51
  'MetaKey' => $meta_key,
52
- 'MetaValue' => $_meta_value,
53
  'MetaLink' => $meta_key,
54
  ));
55
  break;
@@ -59,14 +62,15 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
59
  'PostTitle' => $post->post_title,
60
  'PostType' => $post->post_type,
61
  'MetaKey' => $meta_key,
62
- 'MetaValue' => $_meta_value,
63
  'MetaLink' => $meta_key,
64
  ));
65
  break;
66
  }
67
  }
68
 
69
- public function EventPostMetaUpdating($meta_id, $object_id, $meta_key){
 
70
  static $meta_type = 'post';
71
  $this->old_meta[$meta_id] = (object)array(
72
  'key' => ($meta = get_metadata_by_mid($meta_type, $meta_id)) ? $meta->meta_key : $meta_key,
@@ -74,16 +78,16 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
74
  );
75
  }
76
 
77
- public function EventPostMetaUpdated($meta_id, $object_id, $meta_key, $_meta_value){
 
78
  $post = get_post($object_id);
79
 
80
- if(!$this->CanLogPostMeta($object_id, $meta_key))return;
81
 
82
- if(isset($this->old_meta[$meta_id])){
83
-
84
  // check change in meta key
85
- if($this->old_meta[$meta_id]->key != $meta_key){
86
- switch($post->post_type){
87
  case 'page':
88
  $this->plugin->alerts->Trigger(2064, array(
89
  'PostID' => $object_id,
@@ -91,7 +95,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
91
  'MetaID' => $meta_id,
92
  'MetaKeyNew' => $meta_key,
93
  'MetaKeyOld' => $this->old_meta[$meta_id]->key,
94
- 'MetaValue' => $_meta_value,
95
  'MetaLink' => $meta_key,
96
  ));
97
  break;
@@ -102,7 +106,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
102
  'MetaID' => $meta_id,
103
  'MetaKeyNew' => $meta_key,
104
  'MetaKeyOld' => $this->old_meta[$meta_id]->key,
105
- 'MetaValue' => $_meta_value,
106
  'MetaLink' => $meta_key,
107
  ));
108
  break;
@@ -114,23 +118,20 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
114
  'MetaID' => $meta_id,
115
  'MetaKeyNew' => $meta_key,
116
  'MetaKeyOld' => $this->old_meta[$meta_id]->key,
117
- 'MetaValue' => $_meta_value,
118
  'MetaLink' => $smeta_key,
119
  ));
120
  break;
121
  }
122
- }
123
- else
124
- // check change in meta value
125
- if($this->old_meta[$meta_id]->val != $_meta_value){
126
- switch($post->post_type){
127
  case 'page':
128
  $this->plugin->alerts->Trigger(2060, array(
129
  'PostID' => $object_id,
130
  'PostTitle' => $post->post_title,
131
  'MetaID' => $meta_id,
132
  'MetaKey' => $meta_key,
133
- 'MetaValueNew' => $_meta_value,
134
  'MetaValueOld' => $this->old_meta[$meta_id]->val,
135
  'MetaLink' => $meta_key,
136
  ));
@@ -141,7 +142,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
141
  'PostTitle' => $post->post_title,
142
  'MetaID' => $meta_id,
143
  'MetaKey' => $meta_key,
144
- 'MetaValueNew' => $_meta_value,
145
  'MetaValueOld' => $this->old_meta[$meta_id]->val,
146
  'MetaLink' => $meta_key,
147
  ));
@@ -153,34 +154,33 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
153
  'PostType' => $post->post_type,
154
  'MetaID' => $meta_id,
155
  'MetaKey' => $meta_key,
156
- 'MetaValueNew' => $_meta_value,
157
  'MetaValueOld' => $this->old_meta[$meta_id]->val,
158
  'MetaLink' => $meta_key,
159
  ));
160
  break;
161
  }
162
  }
163
-
164
  // remove old meta update data
165
  unset($this->old_meta[$meta_id]);
166
  }
167
  }
168
 
169
- public function EventPostMetaDeleted($meta_ids, $object_id, $meta_key, $_meta_value){
 
170
  $post = get_post($object_id);
171
 
172
- foreach($meta_ids as $meta_id){
 
173
 
174
- if(!$this->CanLogPostMeta($object_id, $meta_key))continue;
175
-
176
- switch($post->post_type){
177
  case 'page':
178
  $this->plugin->alerts->Trigger(2061, array(
179
  'PostID' => $object_id,
180
  'PostTitle' => $post->post_title,
181
  'MetaID' => $meta_id,
182
  'MetaKey' => $meta_key,
183
- 'MetaValue' => $_meta_value,
184
  ));
185
  break;
186
  case 'post':
@@ -189,7 +189,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
189
  'PostTitle' => $post->post_title,
190
  'MetaID' => $meta_id,
191
  'MetaKey' => $meta_key,
192
- 'MetaValue' => $_meta_value,
193
  ));
194
  break;
195
  default:
@@ -199,11 +199,10 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
199
  'PostType' => $post->post_type,
200
  'MetaID' => $meta_id,
201
  'MetaKey' => $meta_key,
202
- 'MetaValue' => $_meta_value,
203
  ));
204
  break;
205
  }
206
  }
207
  }
208
-
209
  }
1
  <?php
2
 
3
+ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor
4
+ {
5
 
6
+ public function HookEvents()
7
+ {
8
  add_action('add_post_meta', array($this, 'EventPostMetaCreated'), 10, 3);
9
  add_action('update_post_meta', array($this, 'EventPostMetaUpdating'), 10, 3);
10
  add_action('updated_post_meta', array($this, 'EventPostMetaUpdated'), 10, 4);
16
  protected function CanLogPostMeta($object_id, $meta_key)
17
  {
18
  //check if excluded meta key or starts with _
19
+ if (substr($meta_key, 0, 1) == '_') {
20
  return false;
21
+ } else if ($this->IsExcludedCustomFields($meta_key)) {
22
  return false;
23
  } else {
24
  return true;
31
  return (in_array($custom, $customFields)) ? true : false;
32
  }
33
 
34
+ public function EventPostMetaCreated($object_id, $meta_key, $meta_value)
35
+ {
36
  $post = get_post($object_id);
37
 
38
+ if (!$this->CanLogPostMeta($object_id, $meta_key)) return;
39
 
40
+ switch ($post->post_type) {
41
  case 'page':
42
  $this->plugin->alerts->Trigger(2059, array(
43
  'PostID' => $object_id,
44
  'PostTitle' => $post->post_title,
45
  'MetaKey' => $meta_key,
46
+ 'MetaValue' => $meta_value,
47
  'MetaLink' => $meta_key,
48
  ));
49
  break;
52
  'PostID' => $object_id,
53
  'PostTitle' => $post->post_title,
54
  'MetaKey' => $meta_key,
55
+ 'MetaValue' => $meta_value,
56
  'MetaLink' => $meta_key,
57
  ));
58
  break;
62
  'PostTitle' => $post->post_title,
63
  'PostType' => $post->post_type,
64
  'MetaKey' => $meta_key,
65
+ 'MetaValue' => $meta_value,
66
  'MetaLink' => $meta_key,
67
  ));
68
  break;
69
  }
70
  }
71
 
72
+ public function EventPostMetaUpdating($meta_id, $object_id, $meta_key)
73
+ {
74
  static $meta_type = 'post';
75
  $this->old_meta[$meta_id] = (object)array(
76
  'key' => ($meta = get_metadata_by_mid($meta_type, $meta_id)) ? $meta->meta_key : $meta_key,
78
  );
79
  }
80
 
81
+ public function EventPostMetaUpdated($meta_id, $object_id, $meta_key, $meta_value)
82
+ {
83
  $post = get_post($object_id);
84
 
85
+ if (!$this->CanLogPostMeta($object_id, $meta_key)) return;
86
 
87
+ if (isset($this->old_meta[$meta_id])) {
 
88
  // check change in meta key
89
+ if ($this->old_meta[$meta_id]->key != $meta_key) {
90
+ switch ($post->post_type) {
91
  case 'page':
92
  $this->plugin->alerts->Trigger(2064, array(
93
  'PostID' => $object_id,
95
  'MetaID' => $meta_id,
96
  'MetaKeyNew' => $meta_key,
97
  'MetaKeyOld' => $this->old_meta[$meta_id]->key,
98
+ 'MetaValue' => $meta_value,
99
  'MetaLink' => $meta_key,
100
  ));
101
  break;
106
  'MetaID' => $meta_id,
107
  'MetaKeyNew' => $meta_key,
108
  'MetaKeyOld' => $this->old_meta[$meta_id]->key,
109
+ 'MetaValue' => $meta_value,
110
  'MetaLink' => $meta_key,
111
  ));
112
  break;
118
  'MetaID' => $meta_id,
119
  'MetaKeyNew' => $meta_key,
120
  'MetaKeyOld' => $this->old_meta[$meta_id]->key,
121
+ 'MetaValue' => $meta_value,
122
  'MetaLink' => $smeta_key,
123
  ));
124
  break;
125
  }
126
+ } else if ($this->old_meta[$meta_id]->val != $meta_value) { // check change in meta value
127
+ switch ($post->post_type) {
 
 
 
128
  case 'page':
129
  $this->plugin->alerts->Trigger(2060, array(
130
  'PostID' => $object_id,
131
  'PostTitle' => $post->post_title,
132
  'MetaID' => $meta_id,
133
  'MetaKey' => $meta_key,
134
+ 'MetaValueNew' => $meta_value,
135
  'MetaValueOld' => $this->old_meta[$meta_id]->val,
136
  'MetaLink' => $meta_key,
137
  ));
142
  'PostTitle' => $post->post_title,
143
  'MetaID' => $meta_id,
144
  'MetaKey' => $meta_key,
145
+ 'MetaValueNew' => $meta_value,
146
  'MetaValueOld' => $this->old_meta[$meta_id]->val,
147
  'MetaLink' => $meta_key,
148
  ));
154
  'PostType' => $post->post_type,
155
  'MetaID' => $meta_id,
156
  'MetaKey' => $meta_key,
157
+ 'MetaValueNew' => $meta_value,
158
  'MetaValueOld' => $this->old_meta[$meta_id]->val,
159
  'MetaLink' => $meta_key,
160
  ));
161
  break;
162
  }
163
  }
 
164
  // remove old meta update data
165
  unset($this->old_meta[$meta_id]);
166
  }
167
  }
168
 
169
+ public function EventPostMetaDeleted($meta_ids, $object_id, $meta_key, $meta_value)
170
+ {
171
  $post = get_post($object_id);
172
 
173
+ foreach ($meta_ids as $meta_id) {
174
+ if (!$this->CanLogPostMeta($object_id, $meta_key)) continue;
175
 
176
+ switch ($post->post_type) {
 
 
177
  case 'page':
178
  $this->plugin->alerts->Trigger(2061, array(
179
  'PostID' => $object_id,
180
  'PostTitle' => $post->post_title,
181
  'MetaID' => $meta_id,
182
  'MetaKey' => $meta_key,
183
+ 'MetaValue' => $meta_value,
184
  ));
185
  break;
186
  case 'post':
189
  'PostTitle' => $post->post_title,
190
  'MetaID' => $meta_id,
191
  'MetaKey' => $meta_key,
192
+ 'MetaValue' => $meta_value,
193
  ));
194
  break;
195
  default:
199
  'PostType' => $post->post_type,
200
  'MetaID' => $meta_id,
201
  'MetaKey' => $meta_key,
202
+ 'MetaValue' => $meta_value,
203
  ));
204
  break;
205
  }
206
  }
207
  }
 
208
  }
classes/Sensors/System.php CHANGED
@@ -7,7 +7,8 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor
7
  {
8
  add_action('wsal_prune', array($this, 'EventPruneEvents'), 10, 2);
9
  add_action('admin_init', array($this, 'EventAdminInit'));
10
- add_action('auto_update_core', array($this, 'WPUpdate'), 10, 2);
 
11
  }
12
 
13
  /**
@@ -152,15 +153,16 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor
152
 
153
  /**
154
  * WordPress auto core update
155
- * @param bool $update Whether to update.
156
- * @param object $item The update offer.
157
  */
158
- public function WPUpdate($update, $item)
159
  {
160
- $oldVersion = get_bloginfo('version');
161
- $this->plugin->alerts->Trigger(6004, array(
162
- 'OldVersion' => $oldVersion,
163
- 'NewVersion' => $item->version.' (auto update)'
164
- ));
 
 
 
165
  }
166
  }
7
  {
8
  add_action('wsal_prune', array($this, 'EventPruneEvents'), 10, 2);
9
  add_action('admin_init', array($this, 'EventAdminInit'));
10
+
11
+ add_action('automatic_updates_complete', array($this, 'WPUpdate'), 10, 3);
12
  }
13
 
14
  /**
153
 
154
  /**
155
  * WordPress auto core update
 
 
156
  */
157
+ public function WPUpdate($automatic, $updates, $complete)
158
  {
159
+ if (isset($automatic['core'][0])) {
160
+ $obj = $automatic['core'][0];
161
+ $oldVersion = get_bloginfo('version');
162
+ $this->plugin->alerts->Trigger(6004, array(
163
+ 'OldVersion' => $oldVersion,
164
+ 'NewVersion' => $obj->item->version.' (auto update)'
165
+ ));
166
+ }
167
  }
168
  }
classes/Sensors/UserProfile.php CHANGED
@@ -16,11 +16,6 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor
16
 
17
  protected $old_superadmins;
18
 
19
- protected function IsMultisite()
20
- {
21
- return function_exists('is_multisite') && is_multisite();
22
- }
23
-
24
  public function EventAdminInit()
25
  {
26
  if ($this->IsMultisite()) {
16
 
17
  protected $old_superadmins;
18
 
 
 
 
 
 
19
  public function EventAdminInit()
20
  {
21
  if ($this->IsMultisite()) {
css/install-error.css CHANGED
@@ -1,41 +1,41 @@
1
- .warn-icon-tri {
2
- top: 5px;
3
- left: 5px;
4
- position: absolute;
5
- border-left: 16px solid #FFF;
6
- border-right: 16px solid #FFF;
7
- border-bottom: 28px solid #C33;
8
- height: 3px;
9
- width: 4px
10
- }
11
-
12
- .warn-icon-chr {
13
- top: 8px;
14
- left: 18px;
15
- position: absolute;
16
- color: #FFF;
17
- font: 26px Georgia;
18
- }
19
-
20
- .warn-icon-cir {
21
- top: 2px;
22
- left: 0px;
23
- position: absolute;
24
- overflow: hidden;
25
- border: 6px solid #FFF;
26
- border-radius: 32px;
27
- width: 34px;
28
- height: 34px;
29
- }
30
-
31
- .warn-wrap {
32
- position: relative;
33
- color: #A00;
34
- font: 14px Arial;
35
- padding: 6px 48px;
36
- }
37
-
38
- .warn-wrap a,
39
- .warn-wrap a:hover {
40
- color: #F56;
41
- }
1
+ .warn-icon-tri {
2
+ top: 5px;
3
+ left: 5px;
4
+ position: absolute;
5
+ border-left: 16px solid #FFF;
6
+ border-right: 16px solid #FFF;
7
+ border-bottom: 28px solid #C33;
8
+ height: 3px;
9
+ width: 4px
10
+ }
11
+
12
+ .warn-icon-chr {
13
+ top: 8px;
14
+ left: 18px;
15
+ position: absolute;
16
+ color: #FFF;
17
+ font: 26px Georgia;
18
+ }
19
+
20
+ .warn-icon-cir {
21
+ top: 2px;
22
+ left: 0px;
23
+ position: absolute;
24
+ overflow: hidden;
25
+ border: 6px solid #FFF;
26
+ border-radius: 32px;
27
+ width: 34px;
28
+ height: 34px;
29
+ }
30
+
31
+ .warn-wrap {
32
+ position: relative;
33
+ color: #A00;
34
+ font: 14px Arial;
35
+ padding: 6px 48px;
36
+ }
37
+
38
+ .warn-wrap a,
39
+ .warn-wrap a:hover {
40
+ color: #F56;
41
+ }
css/settings.css CHANGED
@@ -1,71 +1,71 @@
1
- #audit-log-settings {
2
- padding-right: 256px;
3
- position: relative;
4
- }
5
-
6
- #audit-log-adverts {
7
- position: absolute;
8
- top: 3px;
9
- right: 3px;
10
- overflow: hidden;
11
- }
12
-
13
- #audit-log-adverts a {
14
- display: block;
15
- text-decoration: none;
16
- margin: 4px 0;
17
- }
18
-
19
- .sectoken-user,
20
- .sectoken-role,
21
- .sectoken-other {
22
- display: inline-block;
23
- border-width: 1px;
24
- border-style: solid;
25
- padding: 2px 4px;
26
- margin: 2px 0 0 2px;
27
- border-radius: 3px;
28
- cursor: default;
29
- }
30
- .sectoken-other {
31
- display: table;
32
- border-collapse: separate;
33
- }
34
-
35
- .sectoken-user a,
36
- .sectoken-role a,
37
- .sectoken-other a {
38
- text-decoration: none;
39
- font-size: 12px;
40
- font-weight: bold;
41
- color: #FFF;
42
- margin-left: 2px;
43
- background: #BBB;
44
- border-radius: 25px;
45
- height: 14px;
46
- display: inline-block;
47
- width: 14px;
48
- text-align: center;
49
- line-height: 16px;
50
- }
51
-
52
- .sectoken-user a:hover,
53
- .sectoken-role a:hover,
54
- .sectoken-other a:hover {
55
- background: #FB9;
56
- }
57
-
58
- .sectoken-user { background: #EFF; border-color: #5BE; }
59
- .sectoken-role { background: #EFE; border-color: #5B5; }
60
- .sectoken-other { background: #FFE; border-color: #ED5; }
61
- .sectoken-del { background: #FEE; border-color: #EBB; }
62
-
63
- .wsal-tab {
64
- margin-top: 0px;
65
- }
66
- .wsal-tab th {
67
- padding-left: 20px;
68
- }
69
- .wsal-tab td {
70
- padding-left: 20px;
71
  }
1
+ #audit-log-settings {
2
+ padding-right: 256px;
3
+ position: relative;
4
+ }
5
+
6
+ #audit-log-adverts {
7
+ position: absolute;
8
+ top: 3px;
9
+ right: 3px;
10
+ overflow: hidden;
11
+ }
12
+
13
+ #audit-log-adverts a {
14
+ display: block;
15
+ text-decoration: none;
16
+ margin: 4px 0;
17
+ }
18
+
19
+ .sectoken-user,
20
+ .sectoken-role,
21
+ .sectoken-other {
22
+ display: inline-block;
23
+ border-width: 1px;
24
+ border-style: solid;
25
+ padding: 2px 4px;
26
+ margin: 2px 0 0 2px;
27
+ border-radius: 3px;
28
+ cursor: default;
29
+ }
30
+ .sectoken-other {
31
+ display: table;
32
+ border-collapse: separate;
33
+ }
34
+
35
+ .sectoken-user a,
36
+ .sectoken-role a,
37
+ .sectoken-other a {
38
+ text-decoration: none;
39
+ font-size: 12px;
40
+ font-weight: bold;
41
+ color: #FFF;
42
+ margin-left: 2px;
43
+ background: #BBB;
44
+ border-radius: 25px;
45
+ height: 14px;
46
+ display: inline-block;
47
+ width: 14px;
48
+ text-align: center;
49
+ line-height: 16px;
50
+ }
51
+
52
+ .sectoken-user a:hover,
53
+ .sectoken-role a:hover,
54
+ .sectoken-other a:hover {
55
+ background: #FB9;
56
+ }
57
+
58
+ .sectoken-user { background: #EFF; border-color: #5BE; }
59
+ .sectoken-role { background: #EFE; border-color: #5B5; }
60
+ .sectoken-other { background: #FFE; border-color: #ED5; }
61
+ .sectoken-del { background: #FEE; border-color: #EBB; }
62
+
63
+ .wsal-tab {
64
+ margin-top: 0px;
65
+ }
66
+ .wsal-tab th {
67
+ padding-left: 20px;
68
+ }
69
+ .wsal-tab td {
70
+ padding-left: 20px;
71
  }
defaults.php CHANGED
@@ -10,7 +10,8 @@ defined('E_RECOVERABLE_ERROR') || define('E_RECOVERABLE_ERROR', 'E_RECOVERABLE_E
10
  defined('E_DEPRECATED') || define('E_DEPRECATED', 'E_DEPRECATED');
11
  defined('E_USER_DEPRECATED') || define('E_USER_DEPRECATED', 'E_USER_DEPRECATED');
12
 
13
- function wsaldefaults_wsal_init(WpSecurityAuditLog $wsal){
 
14
  $wsal->constants->UseConstants(array(
15
  // default PHP constants
16
  array('name' => 'E_ERROR', 'description' => __('Fatal run-time error.', 'wp-security-audit-log')),
@@ -32,7 +33,7 @@ function wsaldefaults_wsal_init(WpSecurityAuditLog $wsal){
32
  array('name' => 'E_CRITICAL', 'description' => __('Critical, high-impact messages.', 'wp-security-audit-log')),
33
  array('name' => 'E_DEBUG', 'description' => __('Debug informational messages.', 'wp-security-audit-log')),
34
  ));
35
- // create list of default alerts
36
  $wsal->alerts->RegisterGroup(array(
37
  __('Other User Activity', 'wp-security-audit-log') => array(
38
  array(1000, E_NOTICE, __('User logs in', 'wp-security-audit-log'), __('Successfully logged in', 'wp-security-audit-log')),
@@ -71,6 +72,7 @@ function wsaldefaults_wsal_init(WpSecurityAuditLog $wsal){
71
  array(2068, E_NOTICE, __('User modifies content for a draft post', 'wp-security-audit-log'), __('Modified the content of draft post %PostTitle%.'.'%RevisionLink%', 'wp-security-audit-log')),
72
  array(2072, E_NOTICE, __('User modifies content of a post', 'wp-security-audit-log'), __('Modified the content of post %PostTitle% which is submitted for review.'.'%RevisionLink%', 'wp-security-audit-log')),
73
  array(2073, E_NOTICE, __('User submitted a post for review', 'wp-security-audit-log'), __('Submitted blog post %PostTitle% for review. Blog post ID is %PostID%', 'wp-security-audit-log')),
 
74
  ),
75
  __('Pages', 'wp-security-audit-log') => array(
76
  array(2004, E_NOTICE, __('User created a new WordPress page and saved it as draft', 'wp-security-audit-log'), __('Created a new page called %PostTitle%. Page ID is %PostID%', 'wp-security-audit-log')),
@@ -93,6 +95,7 @@ function wsaldefaults_wsal_init(WpSecurityAuditLog $wsal){
93
  array(2064, E_NOTICE, __('User updates a custom field name for a page', 'wp-security-audit-log'), __('Changed the custom field name from %MetaKeyOld% to %MetaKeyNew% in page %PostTitle%'.'%MetaLink%', 'wp-security-audit-log')),
94
  array(2066, E_WARNING, __('User modifies content for a published page', 'wp-security-audit-log'), __('Modified the content of published page %PostTitle%.'.'%RevisionLink%', 'wp-security-audit-log')),
95
  array(2069, E_NOTICE, __('User modifies content for a draft page', 'wp-security-audit-log'), __('Modified the content of draft page %PostTitle%.'.'%RevisionLink%', 'wp-security-audit-log')),
 
96
  ),
97
  __('Custom Posts', 'wp-security-audit-log') => array(
98
  array(2029, E_NOTICE, __('User created a new post with custom post type and saved it as draft', 'wp-security-audit-log'), __('Created a new custom post called %PostTitle% of type %PostType%. Post ID is %PostID%', 'wp-security-audit-log')),
@@ -114,6 +117,7 @@ function wsaldefaults_wsal_init(WpSecurityAuditLog $wsal){
114
  array(2063, E_NOTICE, __('User updates a custom field name for a custom post', 'wp-security-audit-log'), __('Changed the custom field name from %MetaKeyOld% to %MetaKeyNew% in custom post %PostTitle% of type %PostType%'.'%MetaLink%', 'wp-security-audit-log')),
115
  array(2067, E_WARNING, __('User modifies content for a published custom post', 'wp-security-audit-log'), __('Modified the content of published custom post type %PostTitle%.'.'%RevisionLink%', 'wp-security-audit-log')),
116
  array(2070, E_NOTICE, __('User modifies content for a draft custom post', 'wp-security-audit-log'), __('Modified the content of draft custom post type %PostTitle%.'.'%RevisionLink%', 'wp-security-audit-log')),
 
117
  ),
118
  __('Widgets', 'wp-security-audit-log') => array(
119
  array(2042, E_CRITICAL, __('User added a new widget', 'wp-security-audit-log'), __('Added a new %WidgetName% widget in %Sidebar%', 'wp-security-audit-log')),
@@ -208,8 +212,22 @@ function wsaldefaults_wsal_init(WpSecurityAuditLog $wsal){
208
  array(8020, E_WARNING, __('User permanently deleted topic', 'wp-security-audit-log'), __('Permanently deleted topic %TopicName%', 'wp-security-audit-log')),
209
  array(8021, E_WARNING, __('User restored topic from trash', 'wp-security-audit-log'), __('Restored topic %TopicName% from trash', 'wp-security-audit-log')),
210
  array(8022, E_NOTICE, __('User changed visibility of a topic', 'wp-security-audit-log'), __('Changed the visibility of topic %TopicName% from %OldVisibility% to %NewVisibility%', 'wp-security-audit-log')),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  )
212
  ));
213
  }
214
  add_action('wsal_init', 'wsaldefaults_wsal_init');
215
-
10
  defined('E_DEPRECATED') || define('E_DEPRECATED', 'E_DEPRECATED');
11
  defined('E_USER_DEPRECATED') || define('E_USER_DEPRECATED', 'E_USER_DEPRECATED');
12
 
13
+ function wsaldefaults_wsal_init(WpSecurityAuditLog $wsal)
14
+ {
15
  $wsal->constants->UseConstants(array(
16
  // default PHP constants
17
  array('name' => 'E_ERROR', 'description' => __('Fatal run-time error.', 'wp-security-audit-log')),
33
  array('name' => 'E_CRITICAL', 'description' => __('Critical, high-impact messages.', 'wp-security-audit-log')),
34
  array('name' => 'E_DEBUG', 'description' => __('Debug informational messages.', 'wp-security-audit-log')),
35
  ));
36
+ // create list of default alerts
37
  $wsal->alerts->RegisterGroup(array(
38
  __('Other User Activity', 'wp-security-audit-log') => array(
39
  array(1000, E_NOTICE, __('User logs in', 'wp-security-audit-log'), __('Successfully logged in', 'wp-security-audit-log')),
72
  array(2068, E_NOTICE, __('User modifies content for a draft post', 'wp-security-audit-log'), __('Modified the content of draft post %PostTitle%.'.'%RevisionLink%', 'wp-security-audit-log')),
73
  array(2072, E_NOTICE, __('User modifies content of a post', 'wp-security-audit-log'), __('Modified the content of post %PostTitle% which is submitted for review.'.'%RevisionLink%', 'wp-security-audit-log')),
74
  array(2073, E_NOTICE, __('User submitted a post for review', 'wp-security-audit-log'), __('Submitted blog post %PostTitle% for review. Blog post ID is %PostID%', 'wp-security-audit-log')),
75
+ array(2074, E_NOTICE, __('User scheduled a post', 'wp-security-audit-log'), __('Scheduled the post %PostTitle% to be published %PublishingDate%', 'wp-security-audit-log'))
76
  ),
77
  __('Pages', 'wp-security-audit-log') => array(
78
  array(2004, E_NOTICE, __('User created a new WordPress page and saved it as draft', 'wp-security-audit-log'), __('Created a new page called %PostTitle%. Page ID is %PostID%', 'wp-security-audit-log')),
95
  array(2064, E_NOTICE, __('User updates a custom field name for a page', 'wp-security-audit-log'), __('Changed the custom field name from %MetaKeyOld% to %MetaKeyNew% in page %PostTitle%'.'%MetaLink%', 'wp-security-audit-log')),
96
  array(2066, E_WARNING, __('User modifies content for a published page', 'wp-security-audit-log'), __('Modified the content of published page %PostTitle%.'.'%RevisionLink%', 'wp-security-audit-log')),
97
  array(2069, E_NOTICE, __('User modifies content for a draft page', 'wp-security-audit-log'), __('Modified the content of draft page %PostTitle%.'.'%RevisionLink%', 'wp-security-audit-log')),
98
+ array(2075, E_NOTICE, __('User scheduled a page', 'wp-security-audit-log'), __('Scheduled the page %PostTitle% to be published %PublishingDate%', 'wp-security-audit-log'))
99
  ),
100
  __('Custom Posts', 'wp-security-audit-log') => array(
101
  array(2029, E_NOTICE, __('User created a new post with custom post type and saved it as draft', 'wp-security-audit-log'), __('Created a new custom post called %PostTitle% of type %PostType%. Post ID is %PostID%', 'wp-security-audit-log')),
117
  array(2063, E_NOTICE, __('User updates a custom field name for a custom post', 'wp-security-audit-log'), __('Changed the custom field name from %MetaKeyOld% to %MetaKeyNew% in custom post %PostTitle% of type %PostType%'.'%MetaLink%', 'wp-security-audit-log')),
118
  array(2067, E_WARNING, __('User modifies content for a published custom post', 'wp-security-audit-log'), __('Modified the content of published custom post type %PostTitle%.'.'%RevisionLink%', 'wp-security-audit-log')),
119
  array(2070, E_NOTICE, __('User modifies content for a draft custom post', 'wp-security-audit-log'), __('Modified the content of draft custom post type %PostTitle%.'.'%RevisionLink%', 'wp-security-audit-log')),
120
+ array(2076, E_NOTICE, __('User scheduled a custom post type', 'wp-security-audit-log'), __('Scheduled the custom post type %PostTitle% to be published %PublishingDate%', 'wp-security-audit-log'))
121
  ),
122
  __('Widgets', 'wp-security-audit-log') => array(
123
  array(2042, E_CRITICAL, __('User added a new widget', 'wp-security-audit-log'), __('Added a new %WidgetName% widget in %Sidebar%', 'wp-security-audit-log')),
212
  array(8020, E_WARNING, __('User permanently deleted topic', 'wp-security-audit-log'), __('Permanently deleted topic %TopicName%', 'wp-security-audit-log')),
213
  array(8021, E_WARNING, __('User restored topic from trash', 'wp-security-audit-log'), __('Restored topic %TopicName% from trash', 'wp-security-audit-log')),
214
  array(8022, E_NOTICE, __('User changed visibility of a topic', 'wp-security-audit-log'), __('Changed the visibility of topic %TopicName% from %OldVisibility% to %NewVisibility%', 'wp-security-audit-log')),
215
+ ),
216
+ __('Menus', 'wp-security-audit-log') => array(
217
+ array(2078, E_NOTICE, __('User created new menu', 'wp-security-audit-log'), __('Created a new menu called %MenuName%', 'wp-security-audit-log')),
218
+ array(2079, E_WARNING, __('User added content to a menu', 'wp-security-audit-log'), __('Added the %ContentType% called %ContentName% to menu %MenuName%', 'wp-security-audit-log')),
219
+ array(2080, E_WARNING, __('User removed content from a menu', 'wp-security-audit-log'), __('Removed the %ContentType% called %ContentName% from the menu %MenuName%', 'wp-security-audit-log')),
220
+ array(2081, E_CRITICAL, __('User deleted menu', 'wp-security-audit-log'), __('Deleted the menu %MenuName%', 'wp-security-audit-log')),
221
+ array(2082, E_WARNING, __('User changed menu setting', 'wp-security-audit-log'), __('%Status% the menu setting %MenuSetting% in %MenuName%', 'wp-security-audit-log')),
222
+ array(2083, E_NOTICE, __('User modified content in a menu', 'wp-security-audit-log'), __('Modified the %ContentType% called %ContentName% in menu %MenuName%', 'wp-security-audit-log')),
223
+ array(2084, E_WARNING, __('User changed name of a menu', 'wp-security-audit-log'), __('Changed the name of menu %OldMenuName% to %NewMenuName%', 'wp-security-audit-log')),
224
+ array(2085, E_NOTICE, __('User changed order of the objects in a menu', 'wp-security-audit-log'), __('Changed the order of the objects in menu %MenuName%', 'wp-security-audit-log'))
225
+ ),
226
+ __('Custom Alerts', 'wp-security-audit-log') => array(
227
+ array(2222, E_CRITICAL, __('Custom critical Alert', 'wp-security-audit-log'), __('%CustomAlertText%', 'wp-security-audit-log')),
228
+ array(3333, E_WARNING, __('Custom warning Alert', 'wp-security-audit-log'), __('%CustomAlertText%', 'wp-security-audit-log')),
229
+ array(4444, E_NOTICE, __('Custom notice Alert', 'wp-security-audit-log'), __('%CustomAlertText%', 'wp-security-audit-log'))
230
  )
231
  ));
232
  }
233
  add_action('wsal_init', 'wsaldefaults_wsal_init');
 
js/auditlog.js CHANGED
@@ -1,150 +1,150 @@
1
- var WsalData;
2
-
3
- window['WsalAuditLogRefreshed'] = function(){
4
- // fix pagination links causing form params to get lost
5
- jQuery('span.pagination-links a').click(function(ev){
6
- ev.preventDefault();
7
- var deparam = function(url){
8
- var obj = {};
9
- var pairs = url.split('&');
10
- for(var i in pairs){
11
- var split = pairs[i].split('=');
12
- obj[decodeURIComponent(split[0])] = decodeURIComponent(split[1]);
13
- }
14
- return obj;
15
- };
16
- var paged = deparam(this.href).paged;
17
- if (typeof paged === 'undefined') paged = 1;
18
- jQuery('#audit-log-viewer').append(
19
- jQuery('<input type="hidden" name="paged"/>').val(paged)
20
- ).submit();
21
- });
22
- };
23
-
24
- function WsalAuditLogInit(_WsalData){
25
- WsalData = _WsalData;
26
- var WsalTkn = WsalData.autorefresh.token;
27
-
28
- // list refresher
29
- var WsalAjx = null;
30
- var WsalChk = function(){
31
- if(WsalAjx)WsalAjx.abort();
32
- WsalAjx = jQuery.post(WsalData.ajaxurl, {
33
- action: 'AjaxRefresh',
34
- logcount: WsalTkn
35
- }, function(data){
36
- WsalAjx = null;
37
- if(data && data !== 'false'){
38
- WsalTkn = data;
39
- jQuery('#audit-log-viewer').load(
40
- location.href + ' #audit-log-viewer-content',
41
- window['WsalAuditLogRefreshed']
42
- );
43
- }
44
- WsalChk();
45
- });
46
- };
47
- if(WsalData.autorefresh.enabled){
48
- setInterval(WsalChk, 40000);
49
- WsalChk();
50
- }
51
-
52
- WsalSsasInit();
53
- }
54
-
55
- var WsalIppsPrev;
56
-
57
- function WsalIppsFocus(value){
58
- WsalIppsPrev = value;
59
- }
60
-
61
- function WsalIppsChange(value){
62
- if(value === ''){
63
- value = window.prompt(WsalData.tr8n.numofitems, WsalIppsPrev);
64
- if(value === null || value === WsalIppsPrev)return this.value = WsalIppsPrev; // operation canceled
65
- }
66
- jQuery('select.wsal-ipps').attr('disabled', true);
67
- jQuery.post(WsalData.ajaxurl, {
68
- action: 'AjaxSetIpp',
69
- count: value
70
- }, function(){
71
- location.reload();
72
- });
73
- }
74
-
75
- function WsalSsasInit(){
76
- var SsasAjx = null;
77
- var SsasInps = jQuery("input.wsal-ssas");
78
- SsasInps.after('<div class="wsal-ssas-dd" style="display: none;"/>');
79
- SsasInps.click(function(){
80
- jQuery(this).select();
81
- });
82
- window['WsalAuditLogRefreshed']();
83
- SsasInps.keyup(function(){
84
- var SsasInp = jQuery(this);
85
- var SsasDiv = SsasInp.next();
86
- var SsasVal = SsasInp.val();
87
- if(SsasAjx)SsasAjx.abort();
88
- SsasInp.removeClass('loading');
89
-
90
- // do a new search
91
- if(SsasInp.attr('data-oldvalue') !== SsasVal && SsasVal.length > 2){
92
- SsasInp.addClass('loading');
93
- SsasAjx = jQuery.post(WsalData.ajaxurl, {
94
- action: 'AjaxSearchSite',
95
- search: SsasVal
96
- }, function(data){
97
- if(SsasAjx)SsasAjx = null;
98
- SsasInp.removeClass('loading');
99
- SsasDiv.hide();
100
- SsasDiv.html('');
101
- if(data && data.length){
102
- var SsasReg = new RegExp(SsasVal.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1'), 'gi');
103
- for (var i = 0; i < data.length; i++){
104
- var link = jQuery('<a href="javascript:;" onclick="WsalSsasChange(' + data[i].blog_id + ')"/>')
105
- .text(data[i].blogname + ' (' + data[i].domain + ')');
106
- link.html(link.text().replace(SsasReg, '<u>$&</u>'));
107
- SsasDiv.append(link);
108
- }
109
- }else{
110
- SsasDiv.append(jQuery('<span/>').text(WsalData.tr8n.searchnone));
111
- }
112
- SsasDiv.prepend(jQuery('<a href="javascript:;" onclick="WsalSsasChange(0)" class="allsites"/>').text(WsalData.tr8n.searchback));
113
- SsasDiv.show();
114
- }, 'json');
115
- SsasInp.attr('data-oldvalue', SsasVal);
116
- }
117
-
118
- // handle keys
119
- });
120
- SsasInps.blur(function(){
121
- setTimeout(function(){
122
- var SsasInp = jQuery(this);
123
- var SsasDiv = SsasInp.next();
124
- SsasInp.attr('data-oldvalue', '');
125
- SsasDiv.hide();
126
- }, 200);
127
- });
128
- }
129
-
130
- function WsalSsasChange(value){
131
- jQuery('div.wsal-ssas-dd').hide();
132
- jQuery('input.wsal-ssas').attr('disabled', true);
133
- jQuery('#wsal-cbid').val(value);
134
- jQuery('#audit-log-viewer').submit();
135
- }
136
-
137
- function WsalDisableCustom(link, meta_key){
138
- var nfe = jQuery(this).parents('div:first');
139
- jQuery(link).hide();
140
- jQuery.ajax({
141
- type: 'POST',
142
- url: ajaxurl,
143
- async: false,
144
- data: { action: 'AjaxDisableCustomField', notice: meta_key },
145
- success: function(data) {
146
- var notice = jQuery('<div class="updated" data-notice-name="notifications-extension"></div>').html(data);
147
- jQuery("h2:first").after(notice);
148
- }
149
- });
150
  }
1
+ var WsalData;
2
+
3
+ window['WsalAuditLogRefreshed'] = function(){
4
+ // fix pagination links causing form params to get lost
5
+ jQuery('span.pagination-links a').click(function(ev){
6
+ ev.preventDefault();
7
+ var deparam = function(url){
8
+ var obj = {};
9
+ var pairs = url.split('&');
10
+ for(var i in pairs){
11
+ var split = pairs[i].split('=');
12
+ obj[decodeURIComponent(split[0])] = decodeURIComponent(split[1]);
13
+ }
14
+ return obj;
15
+ };
16
+ var paged = deparam(this.href).paged;
17
+ if (typeof paged === 'undefined') paged = 1;
18
+ jQuery('#audit-log-viewer').append(
19
+ jQuery('<input type="hidden" name="paged"/>').val(paged)
20
+ ).submit();
21
+ });
22
+ };
23
+
24
+ function WsalAuditLogInit(_WsalData){
25
+ WsalData = _WsalData;
26
+ var WsalTkn = WsalData.autorefresh.token;
27
+
28
+ // list refresher
29
+ var WsalAjx = null;
30
+ var WsalChk = function(){
31
+ if(WsalAjx)WsalAjx.abort();
32
+ WsalAjx = jQuery.post(WsalData.ajaxurl, {
33
+ action: 'AjaxRefresh',
34
+ logcount: WsalTkn
35
+ }, function(data){
36
+ WsalAjx = null;
37
+ if(data && data !== 'false'){
38
+ WsalTkn = data;
39
+ jQuery('#audit-log-viewer').load(
40
+ location.href + ' #audit-log-viewer-content',
41
+ window['WsalAuditLogRefreshed']
42
+ );
43
+ }
44
+ WsalChk();
45
+ });
46
+ };
47
+ if(WsalData.autorefresh.enabled){
48
+ setInterval(WsalChk, 40000);
49
+ WsalChk();
50
+ }
51
+
52
+ WsalSsasInit();
53
+ }
54
+
55
+ var WsalIppsPrev;
56
+
57
+ function WsalIppsFocus(value){
58
+ WsalIppsPrev = value;
59
+ }
60
+
61
+ function WsalIppsChange(value){
62
+ if(value === ''){
63
+ value = window.prompt(WsalData.tr8n.numofitems, WsalIppsPrev);
64
+ if(value === null || value === WsalIppsPrev)return this.value = WsalIppsPrev; // operation canceled
65
+ }
66
+ jQuery('select.wsal-ipps').attr('disabled', true);
67
+ jQuery.post(WsalData.ajaxurl, {
68
+ action: 'AjaxSetIpp',
69
+ count: value
70
+ }, function(){
71
+ location.reload();
72
+ });
73
+ }
74
+
75
+ function WsalSsasInit(){
76
+ var SsasAjx = null;
77
+ var SsasInps = jQuery("input.wsal-ssas");
78
+ SsasInps.after('<div class="wsal-ssas-dd" style="display: none;"/>');
79
+ SsasInps.click(function(){
80
+ jQuery(this).select();
81
+ });
82
+ window['WsalAuditLogRefreshed']();
83
+ SsasInps.keyup(function(){
84
+ var SsasInp = jQuery(this);
85
+ var SsasDiv = SsasInp.next();
86
+ var SsasVal = SsasInp.val();
87
+ if(SsasAjx)SsasAjx.abort();
88
+ SsasInp.removeClass('loading');
89
+
90
+ // do a new search
91
+ if(SsasInp.attr('data-oldvalue') !== SsasVal && SsasVal.length > 2){
92
+ SsasInp.addClass('loading');
93
+ SsasAjx = jQuery.post(WsalData.ajaxurl, {
94
+ action: 'AjaxSearchSite',
95
+ search: SsasVal
96
+ }, function(data){
97
+ if(SsasAjx)SsasAjx = null;
98
+ SsasInp.removeClass('loading');
99
+ SsasDiv.hide();
100
+ SsasDiv.html('');
101
+ if(data && data.length){
102
+ var SsasReg = new RegExp(SsasVal.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1'), 'gi');
103
+ for (var i = 0; i < data.length; i++){
104
+ var link = jQuery('<a href="javascript:;" onclick="WsalSsasChange(' + data[i].blog_id + ')"/>')
105
+ .text(data[i].blogname + ' (' + data[i].domain + ')');
106
+ link.html(link.text().replace(SsasReg, '<u>$&</u>'));
107
+ SsasDiv.append(link);
108
+ }
109
+ }else{
110
+ SsasDiv.append(jQuery('<span/>').text(WsalData.tr8n.searchnone));
111
+ }
112
+ SsasDiv.prepend(jQuery('<a href="javascript:;" onclick="WsalSsasChange(0)" class="allsites"/>').text(WsalData.tr8n.searchback));
113
+ SsasDiv.show();
114
+ }, 'json');
115
+ SsasInp.attr('data-oldvalue', SsasVal);
116
+ }
117
+
118
+ // handle keys
119
+ });
120
+ SsasInps.blur(function(){
121
+ setTimeout(function(){
122
+ var SsasInp = jQuery(this);
123
+ var SsasDiv = SsasInp.next();
124
+ SsasInp.attr('data-oldvalue', '');
125
+ SsasDiv.hide();
126
+ }, 200);
127
+ });
128
+ }
129
+
130
+ function WsalSsasChange(value){
131
+ jQuery('div.wsal-ssas-dd').hide();
132
+ jQuery('input.wsal-ssas').attr('disabled', true);
133
+ jQuery('#wsal-cbid').val(value);
134
+ jQuery('#audit-log-viewer').submit();
135
+ }
136
+
137
+ function WsalDisableCustom(link, meta_key){
138
+ var nfe = jQuery(this).parents('div:first');
139
+ jQuery(link).hide();
140
+ jQuery.ajax({
141
+ type: 'POST',
142
+ url: ajaxurl,
143
+ async: false,
144
+ data: { action: 'AjaxDisableCustomField', notice: meta_key },
145
+ success: function(data) {
146
+ var notice = jQuery('<div class="updated" data-notice-name="notifications-extension"></div>').html(data);
147
+ jQuery("h2:first").after(notice);
148
+ }
149
+ });
150
  }
js/common.js CHANGED
@@ -1,17 +1,17 @@
1
-
2
- jQuery(document).ready(function(){
3
- jQuery('a.wsal-dismiss-notification').click(function(){
4
- var nfe = jQuery(this).parents('div:first');
5
- var nfn = nfe.attr('data-notice-name');
6
- jQuery.ajax({
7
- type: 'POST',
8
- url: ajaxurl,
9
- async: false,
10
- data: { action: 'AjaxDismissNotice', notice: nfn }
11
- });
12
- nfe.fadeOut();
13
- });
14
-
15
- jQuery('head').append('<style>.wp-submenu .dashicons-external:before{vertical-align: bottom;}</style>');
16
- jQuery("a[href*='page=wsal-extensions']").addClass('dashicons-before dashicons-external').css('color', '#CC4444');
17
- });
1
+
2
+ jQuery(document).ready(function(){
3
+ jQuery('a.wsal-dismiss-notification').click(function(){
4
+ var nfe = jQuery(this).parents('div:first');
5
+ var nfn = nfe.attr('data-notice-name');
6
+ jQuery.ajax({
7
+ type: 'POST',
8
+ url: ajaxurl,
9
+ async: false,
10
+ data: { action: 'AjaxDismissNotice', notice: nfn }
11
+ });
12
+ nfe.fadeOut();
13
+ });
14
+
15
+ jQuery('head').append('<style>.wp-submenu .dashicons-external:before{vertical-align: bottom;}</style>');
16
+ jQuery("a[href*='page=wsal-extensions']").addClass('dashicons-before dashicons-external').css('color', '#CC4444');
17
+ });
js/nice_r.js CHANGED
@@ -1,12 +1,12 @@
1
- function nice_r_toggle(pfx, id){
2
- var el = document.getElementById(pfx+'_v'+id);
3
- if(el){
4
- if(el.style.display==='block'){
5
- el.style.display = 'none';
6
- document.getElementById(pfx+'_a'+id).innerHTML = '&#9658;';
7
- }else{
8
- el.style.display = 'block';
9
- document.getElementById(pfx+'_a'+id).innerHTML = '&#9660;';
10
- }
11
- }
12
  }
1
+ function nice_r_toggle(pfx, id){
2
+ var el = document.getElementById(pfx+'_v'+id);
3
+ if(el){
4
+ if(el.style.display==='block'){
5
+ el.style.display = 'none';
6
+ document.getElementById(pfx+'_a'+id).innerHTML = '&#9658;';
7
+ }else{
8
+ el.style.display = 'block';
9
+ document.getElementById(pfx+'_a'+id).innerHTML = '&#9660;';
10
+ }
11
+ }
12
  }
js/settings.js CHANGED
@@ -1,73 +1,73 @@
1
- jQuery(document).ready(function(){
2
- var RemoveSecToken = function(){
3
- var $this = jQuery(this).parents('span:first');
4
- $this.addClass('sectoken-del').fadeOut('fast', function(){
5
- $this.remove();
6
- });
7
- };
8
-
9
- jQuery('#ViewerQueryBox, #EditorQueryBox, #ExRoleQueryBox, #ExUserQueryBox, #CustomQueryBox, #IpAddrQueryBox').keydown(function(event){
10
- if(event.keyCode === 13) {
11
- var type = jQuery(this).attr('id').substr(0, 6);
12
- jQuery('#'+type+'QueryAdd').click();
13
- return false;
14
- }
15
- });
16
-
17
- jQuery('#ViewerQueryAdd, #EditorQueryAdd, #ExRoleQueryAdd, #ExUserQueryAdd, #CustomQueryAdd, #IpAddrQueryAdd').click(function(){
18
- var type = jQuery(this).attr('id').substr(0, 6);
19
- var value = jQuery.trim(jQuery('#'+type+'QueryBox').val());
20
- var existing = jQuery('#'+type+'List input').filter(function() { return this.value === value; });
21
-
22
- if(!value || existing.length)return; // if value is empty or already used, stop here
23
-
24
- jQuery('#'+type+'QueryBox, #'+type+'QueryAdd').attr('disabled', true);
25
- jQuery.post(jQuery('#ajaxurl').val(), {action: 'AjaxCheckSecurityToken', token: value}, function(data){
26
- jQuery('#'+type+'QueryBox, #'+type+'QueryAdd').attr('disabled', false);
27
- if (type != 'Custom' && type != 'IpAddr') {
28
- if(data === 'other') {
29
- alert('The specified token is not a user nor a role!');
30
- jQuery('#'+type+'QueryBox').val('');
31
- return;
32
- }
33
- }
34
- jQuery('#'+type+'QueryBox').val('');
35
- jQuery('#'+type+'List').append(jQuery('<span class="sectoken-'+data+'"/>').text(value).append(
36
- jQuery('<input type="hidden" name="'+type+'s[]"/>').val(value),
37
- jQuery('<a href="javascript:;" title="Remove">&times;</a>').click(RemoveSecToken)
38
- ));
39
- });
40
- });
41
-
42
- jQuery('#ViewerList>span>a, #EditorList>span>a, #ExRoleList>span>a, #ExUserList>span>a, #CustomList>span>a, #IpAddrList>span>a').click(RemoveSecToken);
43
-
44
- jQuery('#RestrictAdmins').change(function(){
45
- var user = jQuery('#RestrictAdminsDefaultUser').val();
46
- var fltr = function() { return this.value === user; };
47
- if (this.checked && jQuery('#EditorList input').filter(fltr).length === 0) {
48
- jQuery('#EditorList').append(
49
- jQuery('<span class="sectoken-user"/>').text(user)
50
- .prepend(jQuery('<input type="hidden" name="Editors[]"/>').val(user))
51
- .append(jQuery('<a href="javascript:;" title="Remove">&times;</a>').click(RemoveSecToken))
52
- );
53
- } else {
54
- jQuery('#EditorList').children().remove();
55
- }
56
- });
57
-
58
-
59
- var usersUrl = ajaxurl + "?action=AjaxGetAllUsers";
60
- jQuery("#ExUserQueryBox").autocomplete({
61
- source: usersUrl,
62
- minLength:1
63
- });
64
-
65
- var rolesUrl = ajaxurl + "?action=AjaxGetAllRoles";
66
- jQuery("#ExRoleQueryBox").autocomplete({
67
- source: rolesUrl,
68
- minLength:1
69
- });
70
-
71
- });
72
-
73
-
1
+ jQuery(document).ready(function(){
2
+ var RemoveSecToken = function(){
3
+ var $this = jQuery(this).parents('span:first');
4
+ $this.addClass('sectoken-del').fadeOut('fast', function(){
5
+ $this.remove();
6
+ });
7
+ };
8
+
9
+ jQuery('#ViewerQueryBox, #EditorQueryBox, #ExRoleQueryBox, #ExUserQueryBox, #CustomQueryBox, #IpAddrQueryBox').keydown(function(event){
10
+ if(event.keyCode === 13) {
11
+ var type = jQuery(this).attr('id').substr(0, 6);
12
+ jQuery('#'+type+'QueryAdd').click();
13
+ return false;
14
+ }
15
+ });
16
+
17
+ jQuery('#ViewerQueryAdd, #EditorQueryAdd, #ExRoleQueryAdd, #ExUserQueryAdd, #CustomQueryAdd, #IpAddrQueryAdd').click(function(){
18
+ var type = jQuery(this).attr('id').substr(0, 6);
19
+ var value = jQuery.trim(jQuery('#'+type+'QueryBox').val());
20
+ var existing = jQuery('#'+type+'List input').filter(function() { return this.value === value; });
21
+
22
+ if(!value || existing.length)return; // if value is empty or already used, stop here
23
+
24
+ jQuery('#'+type+'QueryBox, #'+type+'QueryAdd').attr('disabled', true);
25
+ jQuery.post(jQuery('#ajaxurl').val(), {action: 'AjaxCheckSecurityToken', token: value}, function(data){
26
+ jQuery('#'+type+'QueryBox, #'+type+'QueryAdd').attr('disabled', false);
27
+ if (type != 'Custom' && type != 'IpAddr') {
28
+ if(data === 'other') {
29
+ alert('The specified token is not a user nor a role!');
30
+ jQuery('#'+type+'QueryBox').val('');
31
+ return;
32
+ }
33
+ }
34
+ jQuery('#'+type+'QueryBox').val('');
35
+ jQuery('#'+type+'List').append(jQuery('<span class="sectoken-'+data+'"/>').text(value).append(
36
+ jQuery('<input type="hidden" name="'+type+'s[]"/>').val(value),
37
+ jQuery('<a href="javascript:;" title="Remove">&times;</a>').click(RemoveSecToken)
38
+ ));
39
+ });
40
+ });
41
+
42
+ jQuery('#ViewerList>span>a, #EditorList>span>a, #ExRoleList>span>a, #ExUserList>span>a, #CustomList>span>a, #IpAddrList>span>a').click(RemoveSecToken);
43
+
44
+ jQuery('#RestrictAdmins').change(function(){
45
+ var user = jQuery('#RestrictAdminsDefaultUser').val();
46
+ var fltr = function() { return this.value === user; };
47
+ if (this.checked && jQuery('#EditorList input').filter(fltr).length === 0) {
48
+ jQuery('#EditorList').append(
49
+ jQuery('<span class="sectoken-user"/>').text(user)
50
+ .prepend(jQuery('<input type="hidden" name="Editors[]"/>').val(user))
51
+ .append(jQuery('<a href="javascript:;" title="Remove">&times;</a>').click(RemoveSecToken))
52
+ );
53
+ } else {
54
+ jQuery('#EditorList').children().remove();
55
+ }
56
+ });
57
+
58
+
59
+ var usersUrl = ajaxurl + "?action=AjaxGetAllUsers";
60
+ jQuery("#ExUserQueryBox").autocomplete({
61
+ source: usersUrl,
62
+ minLength:1
63
+ });
64
+
65
+ var rolesUrl = ajaxurl + "?action=AjaxGetAllRoles";
66
+ jQuery("#ExRoleQueryBox").autocomplete({
67
+ source: rolesUrl,
68
+ minLength:1
69
+ });
70
+
71
+ });
72
+
73
+
readme.txt CHANGED
@@ -6,8 +6,8 @@ License: GPLv3
6
  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
8
  Requires at least: 3.6
9
- Tested up to: 4.4.2
10
- Stable tag: 2.3.3
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
 
@@ -83,6 +83,9 @@ WP Security Audit Log is the first tracking and audit WordPress security monitor
83
 
84
  For more information about the features for WordPress Multisite network installation refer to [WP Security Audit Log Features for WordPress Multisite](http://www.wpsecurityauditlog.com/documentation/wordpress-multisite-plugin-features-support/)
85
 
 
 
 
86
  = WordPress Security Audit Log in your Language! =
87
  We need help translating the plugin and the WordPress Security Alerts. If you would like to translate this plugin visit the [WordPress translate Project](https://translate.wordpress.org/) for more information on how to translate the plugin. If you already know how translations work, [start translating WP Security Audit Log now](https://translate.wordpress.org/projects/wp-plugins/wp-security-audit-log) and contact us on plugins@wpwhitesecurity.com for a free license of all add-ons.
88
 
@@ -205,6 +208,35 @@ Yes. To exclude an IP address you can specify it in the Excluded Objects section
205
 
206
  == Changelog ==
207
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  = 2.3.3 (2016-02-16) =
209
  * **Bug Fixes**
210
  * Fixed an issue where automated WordPress updates were not being reported.
6
  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
8
  Requires at least: 3.6
9
+ Tested up to: 4.5
10
+ Stable tag: 2.4
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
 
83
 
84
  For more information about the features for WordPress Multisite network installation refer to [WP Security Audit Log Features for WordPress Multisite](http://www.wpsecurityauditlog.com/documentation/wordpress-multisite-plugin-features-support/)
85
 
86
+ = Easiy Create Your Own Custom Alerts =
87
+ Is there something on your WordPress that the plugin does not monitor, but you would like to keep a record of it? Refer to the [Hooks for custom alerts documentation](https://www.wpsecurityauditlog.com/documentation/create-custom-alerts-wordpress-audit-trail/) to easily create your own custom alerts and keep record of any change on your WordPress, be it a change in a WordPress customization, a third party plugin and more.
88
+
89
  = WordPress Security Audit Log in your Language! =
90
  We need help translating the plugin and the WordPress Security Alerts. If you would like to translate this plugin visit the [WordPress translate Project](https://translate.wordpress.org/) for more information on how to translate the plugin. If you already know how translations work, [start translating WP Security Audit Log now](https://translate.wordpress.org/projects/wp-plugins/wp-security-audit-log) and contact us on plugins@wpwhitesecurity.com for a free license of all add-ons.
91
 
208
 
209
  == Changelog ==
210
 
211
+ = 2.4 (2016-03-28) =
212
+
213
+ Read the [WP Security Audit Log 2.4 release notes](https://www.wpsecurityauditlog.com/wordpress-user-monitoring-plugin-releases/integration-hooks-custom-alerts-monitoring-wordpress-menus-2-4) for a detailed overview of what is new.
214
+
215
+ * **New Features**
216
+ * Monitoring of WordPress menus changes from both admin pages and theme customizer.
217
+ * New hook that allows users to create their own custom alerts. Read the [WP Security Audit Log Custom Alerts documentation](https://www.wpsecurityauditlog.com/documentation/create-custom-alerts-wordpress-audit-trail/) for more information.
218
+ * New alerts for when a either a post, a post or a custom post type is scheduled.
219
+
220
+ * **New WordPress Security Alerts for Menus**
221
+ * 2078: User created a new menu
222
+ * 2079: User added objects to menu
223
+ * 2080: User removed object from menu
224
+ * 2081: User deleted a menu
225
+ * 2082: User changed menu settings
226
+ * 2083: USer modified an object in menu
227
+ * 2084: User renamed a menu
228
+ * 2085: User changed the order of the objects in menu
229
+
230
+ * **New WordPress Security Alerts for Scheduled Items**
231
+ * 2074: User scheduled a post for publishing
232
+ * 2075: User scheduled a page for publishing
233
+ * 2076: User scheduled a custom post type for publishing
234
+
235
+ * **Bug Fixes**
236
+ * Fixed an issue where WordPress updated alerts were begin generated repeatedly upon accessing the updates page. [Support Ticket](https://wordpress.org/support/topic/weird-update-message-in-logs)
237
+ * Fixed an issue where WordPress pruning was not working in an out of the box installation. [Support Ticket](https://wordpress.org/support/topic/huge-wsal-metadata-table-not-being-cleanedfixed)
238
+ * Fixed a conflict with Migrate DB. [Support Ticket](https://wordpress.org/support/topic/wp-migrate-db-pro)
239
+
240
  = 2.3.3 (2016-02-16) =
241
  * **Bug Fixes**
242
  * Fixed an issue where automated WordPress updates were not being reported.
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.3.3
8
  Text Domain: wp-security-audit-log
9
  Author URI: http://www.wpsecurityauditlog.com/
10
  License: GPL2
@@ -277,8 +277,8 @@ class WpSecurityAuditLog {
277
  $pruningDate = $this->settings->GetPruningDate();
278
  $this->settings->SetPruningDate($pruningDate);
279
 
280
- $pruningEnabled = $this->settings->IsPruningLimitEnabled();
281
- $this->settings->SetPruningLimitEnabled($pruningEnabled);
282
  //setting the prunig limit with the old value or the default value
283
  $pruningLimit = $this->settings->GetPruningLimit();
284
  $this->settings->SetPruningLimit($pruningLimit);
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.4
8
  Text Domain: wp-security-audit-log
9
  Author URI: http://www.wpsecurityauditlog.com/
10
  License: GPL2
277
  $pruningDate = $this->settings->GetPruningDate();
278
  $this->settings->SetPruningDate($pruningDate);
279
 
280
+ //$pruningEnabled = $this->settings->IsPruningLimitEnabled();
281
+ $this->settings->SetPruningLimitEnabled(true);
282
  //setting the prunig limit with the old value or the default value
283
  $pruningLimit = $this->settings->GetPruningLimit();
284
  $this->settings->SetPruningLimit($pruningLimit);