WP Security Audit Log - Version 0.6

Version Description

(2014-01-15) = * New Plugin Feature * WordPress Multisite Support Read More

  • New WordPress Security Alerts for monitoring specific multisite activity on a WordPress multisite network installation

    • Alert 4008: User is granted super admin privileges (network)
    • Alert 4009: Super admin privileges (network) are revoked from a user
    • Alert 4010: Added an existing user to a site and assigned a specific role
    • Alert 4011: Removed user with a specific role from a site
    • Alert 4012: New user created on the network
    • Alert 7000: Added a new site to network
    • Alert 7001: A site was archived
    • Alert 7002: A site was unarchived
    • Alert 7003: A site was activated
    • Alert 7004: A site was deactivated
    • Alert 7005: A site was deleted
  • Plugin Improvements

    • Plugin settings page to have the same look and feel of the new WordPress dashboard (3.8)
Download this release

Release Info

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

Code changes from version 0.5.1 to 0.6

inc/WPPH.php CHANGED
@@ -16,6 +16,11 @@ class WPPH
16
  */
17
  static $baseMenuSlug = WPPH_PLUGIN_PREFIX;
18
 
 
 
 
 
 
19
  /**
20
  * @since v0.5
21
  * Retrieve the list of all events to display in the enable/disable alerts page
@@ -93,6 +98,9 @@ class WPPH
93
  2044 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('User deleted a widget',WPPH_PLUGIN_TEXT_DOMAIN)),
94
  2045 => array('type' => WPPH_E_NOTICE_TEXT, 'text' => __('User moved a widget',WPPH_PLUGIN_TEXT_DOMAIN)),
95
  ),
 
 
 
96
  'Plugins' => array(
97
  5000 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('User installed a plugin',WPPH_PLUGIN_TEXT_DOMAIN)),
98
  5001 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('User activated a WordPress plugin',WPPH_PLUGIN_TEXT_DOMAIN)),
@@ -106,6 +114,19 @@ class WPPH
106
  6002 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('New User Default Role changed',WPPH_PLUGIN_TEXT_DOMAIN)),
107
  6003 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('WordPress Administrator Notification email changed',WPPH_PLUGIN_TEXT_DOMAIN))
108
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  );
110
  }
111
 
@@ -121,17 +142,15 @@ class WPPH
121
  if(self::canLoad())
122
  {
123
  wp_enqueue_style('wpph_styles_base', WPPH_PLUGIN_URL . 'res/css/styles.base.css');
124
- wp_enqueue_script('wpph-ko-js', WPPH_PLUGIN_URL . 'res/js/knockout.js' );
125
- wp_enqueue_script('wpph-alvm-js', WPPH_PLUGIN_URL . 'res/js/audit-view-model.js' );
126
- wp_enqueue_script('wpph-jcookie-js', WPPH_PLUGIN_URL . 'res/js/jquery-ck.js' );
127
  }
128
  }
129
 
130
  public static function createPluginWpSidebar()
131
  {
132
  $reqCap = self::$requiredCapMenu;
133
- $user = wp_get_current_user();
134
- $userId = $user->ID;
135
 
136
  if (!function_exists('add_menu_page'))
137
  {
@@ -139,7 +158,7 @@ class WPPH
139
  return;
140
  }
141
 
142
- if(WPPHUtil::isAdministrator($userId)){
143
  self::_createMenu($reqCap, true, true, true);
144
  }
145
  elseif (WPPHUtil::isAllowedChange()){
@@ -155,14 +174,26 @@ class WPPH
155
  if($isAdministrator || $allowedChange){
156
  add_menu_page('WP Security Audit Log', 'WP Security Audit Log', $reqCap, self::$baseMenuSlug, 'WPPH::pageMain', WPPH_PLUGIN_URL.'res/img/logo-main-menu.png');
157
  add_submenu_page(self::$baseMenuSlug, 'Audit Log Viewer', 'Audit Log Viewer', $reqCap, self::$baseMenuSlug, 'WPPH::pageMain');
158
- add_submenu_page(self::$baseMenuSlug, __('Settings',WPPH_PLUGIN_TEXT_DOMAIN), __('Settings',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'settings', 'WPPH::pageSettings');
159
- add_submenu_page(self::$baseMenuSlug, __('Enable/Disable Alerts',WPPH_PLUGIN_TEXT_DOMAIN), __('Enable/Disable Alerts',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'alerts', 'WPPH::pageAlerts');
 
 
 
 
 
 
 
 
160
  add_submenu_page(self::$baseMenuSlug, __('About',WPPH_PLUGIN_TEXT_DOMAIN), __('About',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'about', 'WPPH::pageAbout');
161
  add_submenu_page(self::$baseMenuSlug, __('Support',WPPH_PLUGIN_TEXT_DOMAIN), __('Support',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'support', 'WPPH::pageSupport');
162
  }
163
  elseif($allowedAccess){
164
  add_menu_page('WP Security Audit Log', 'WP Security Audit Log', $reqCap, self::$baseMenuSlug, 'WPPH::pageMain', WPPH_PLUGIN_URL.'res/img/logo-main-menu.png');
165
  add_submenu_page(self::$baseMenuSlug, 'Audit Log Viewer', 'Audit Log Viewer', $reqCap, self::$baseMenuSlug, 'WPPH::pageMain');
 
 
 
 
166
  add_submenu_page(self::$baseMenuSlug, __('About',WPPH_PLUGIN_TEXT_DOMAIN), __('About',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'about', 'WPPH::pageAbout');
167
  add_submenu_page(self::$baseMenuSlug, __('Support',WPPH_PLUGIN_TEXT_DOMAIN), __('Support',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'support', 'WPPH::pageSupport');
168
  }
@@ -199,7 +230,7 @@ class WPPH
199
  }
200
  }
201
  }
202
- update_option(WPPH_PLUGIN_EVENTS_LIST_OPTION_NAME, $alerts);
203
  return $alerts;
204
  }
205
 
@@ -209,7 +240,7 @@ class WPPH
209
  * @return array
210
  */
211
  static function getEvents(){
212
- $events = get_option(WPPH_PLUGIN_EVENTS_LIST_OPTION_NAME);
213
  if(false === $events){
214
  $events = self::createDefaultEventsList();
215
  }
@@ -225,6 +256,7 @@ class WPPH
225
  $settings->lastCleanup = time();
226
  $settings->cleanupRan = 0;
227
  $settings->showDW = 1; // whether or not to show the dashboard widget. @since v0.4
 
228
  update_option(WPPH_PLUGIN_SETTING_NAME, $settings);
229
  self::createDefaultEventsList();
230
  wpphLog('Settings added.');
@@ -233,14 +265,14 @@ class WPPH
233
  public static function getPluginSettings()
234
  {
235
  $settings = get_option(WPPH_PLUGIN_SETTING_NAME);
236
- if(false === $settings){
237
  $settings = self::createPluginDefaultSettings();
238
  }
239
  return $settings;
240
  }
241
 
242
  /**
243
- * @param object $settings If this param is null, $settingName & $settingValue must be set
244
  * @param string $settingName Optional. Required if $settings is null
245
  * @param string $settingValue Optional. Required if $settings is null
246
  * @param bool $overrideCleanupRan Whether or not to override the cleanupRan option. Defaults to false
@@ -271,8 +303,12 @@ class WPPH
271
  wpphLog('Settings saved.', $settings);
272
  }
273
 
274
- public static function onPluginActivate()
275
  {
 
 
 
 
276
  wpphLog(__METHOD__.'() triggered.');
277
 
278
  $canContinue = true;
@@ -323,7 +359,6 @@ class WPPH
323
  self::__addPluginError(__("Plugin could not be properly installed because we have encountered errors during the database update.",WPPH_PLUGIN_TEXT_DOMAIN));
324
  return false;
325
  }
326
-
327
  }
328
  // plugin already installed
329
  else
@@ -378,16 +413,21 @@ class WPPH
378
  }
379
 
380
  /**
381
- * triggered when the plugin is deactivated
 
 
382
  */
383
- public static function onPluginDeactivate()
384
  {
 
385
  wp_clear_scheduled_hook(WPPH_PLUGIN_DEL_EVENTS_CRON_TASK_NAME);
386
  delete_option(WPPH_PLUGIN_ERROR_OPTION_NAME);
387
- wpphLog('__FUNCTION__.() triggered.');
 
388
  }
389
 
390
- public static function __addPluginError($error){
 
391
  $data = get_option(WPPH_PLUGIN_ERROR_OPTION_NAME);
392
  if(empty($data)){
393
  $data = array();
@@ -408,13 +448,26 @@ class WPPH
408
  WPPHUtil::saveInitialAccessChangeList();
409
  if($triggerInstallEvent)
410
  {
411
- define('WPPH_PLUGIN_INSTALLED_OK',true); //@see: WPPHEventWatcher::watchPluginInstall()
 
 
 
412
  // log plugin installation
413
- WPPHEvent::_addLogEvent(5000,wp_get_current_user()->ID, WPPHUtil::getIP(), array(WPPH_PLUGIN_NAME));
414
- wpphLog('Plugin installed.', array('plugin'=>WPPH_PLUGIN_NAME));
415
  }
416
  // log plugin activation
417
  WPPHEvent::hookWatchPluginActivity();
 
 
 
 
 
 
 
 
 
 
 
418
  }
419
  /**
420
  * @internal
@@ -446,6 +499,15 @@ class WPPH
446
  return true;
447
  }
448
  public static function checkPHP(){ return (version_compare(phpversion(), '5.0.0', '>=')); }
 
 
 
 
 
 
 
 
 
449
  }
450
 
451
 
16
  */
17
  static $baseMenuSlug = WPPH_PLUGIN_PREFIX;
18
 
19
+ static function loadTextDomain()
20
+ {
21
+ load_plugin_textdomain(WPPH_PLUGIN_TEXT_DOMAIN, false, WPPH_PLUGIN_DIR.'languages/');
22
+ }
23
+
24
  /**
25
  * @since v0.5
26
  * Retrieve the list of all events to display in the enable/disable alerts page
98
  2044 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('User deleted a widget',WPPH_PLUGIN_TEXT_DOMAIN)),
99
  2045 => array('type' => WPPH_E_NOTICE_TEXT, 'text' => __('User moved a widget',WPPH_PLUGIN_TEXT_DOMAIN)),
100
  ),
101
+ 'Themes' => array(
102
+ 3000 => array('type' => WPPH_E_NOTICE_TEXT, 'text' => __('User activated a theme.',WPPH_PLUGIN_TEXT_DOMAIN)),
103
+ ),
104
  'Plugins' => array(
105
  5000 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('User installed a plugin',WPPH_PLUGIN_TEXT_DOMAIN)),
106
  5001 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('User activated a WordPress plugin',WPPH_PLUGIN_TEXT_DOMAIN)),
114
  6002 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('New User Default Role changed',WPPH_PLUGIN_TEXT_DOMAIN)),
115
  6003 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('WordPress Administrator Notification email changed',WPPH_PLUGIN_TEXT_DOMAIN))
116
  ),
117
+ 'MultiSite' => array(
118
+ 4008 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('Granted Super Admin privileges to user',WPPH_PLUGIN_TEXT_DOMAIN)),
119
+ 4009 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('Revoked Super Admin privileges from user',WPPH_PLUGIN_TEXT_DOMAIN)),
120
+ 4010 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('Existent user added to site',WPPH_PLUGIN_TEXT_DOMAIN)),
121
+ 4011 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('User removed from site',WPPH_PLUGIN_TEXT_DOMAIN)),
122
+ 4012 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('New network user created',WPPH_PLUGIN_TEXT_DOMAIN)),
123
+ 7000 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('Site added to network',WPPH_PLUGIN_TEXT_DOMAIN)),
124
+ 7001 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('Site archived',WPPH_PLUGIN_TEXT_DOMAIN)),
125
+ 7002 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('Site unarchived',WPPH_PLUGIN_TEXT_DOMAIN)),
126
+ 7003 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('Site activated',WPPH_PLUGIN_TEXT_DOMAIN)),
127
+ 7004 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('Site deactivated',WPPH_PLUGIN_TEXT_DOMAIN)),
128
+ 7005 => array('type' => WPPH_E_HIGH_TEXT, 'text' => __('Site deleted',WPPH_PLUGIN_TEXT_DOMAIN)),
129
+ ),
130
  );
131
  }
132
 
142
  if(self::canLoad())
143
  {
144
  wp_enqueue_style('wpph_styles_base', WPPH_PLUGIN_URL . 'res/css/styles.base.css');
145
+ wp_enqueue_script('wpph-alvm-js', WPPH_PLUGIN_URL . 'res/js/audit-view-model.js', array('wpph-jcookie-js', 'wpph-ko-js'));
146
+ wp_enqueue_script('wpph-ko-js', WPPH_PLUGIN_URL . 'res/js/knockout.js', array('jquery'));
147
+ wp_enqueue_script('wpph-jcookie-js', WPPH_PLUGIN_URL . 'res/js/jquery-ck.js', array('jquery'));
148
  }
149
  }
150
 
151
  public static function createPluginWpSidebar()
152
  {
153
  $reqCap = self::$requiredCapMenu;
 
 
154
 
155
  if (!function_exists('add_menu_page'))
156
  {
158
  return;
159
  }
160
 
161
+ if(WPPHUtil::isAdministrator(wp_get_current_user()->ID)){
162
  self::_createMenu($reqCap, true, true, true);
163
  }
164
  elseif (WPPHUtil::isAllowedChange()){
174
  if($isAdministrator || $allowedChange){
175
  add_menu_page('WP Security Audit Log', 'WP Security Audit Log', $reqCap, self::$baseMenuSlug, 'WPPH::pageMain', WPPH_PLUGIN_URL.'res/img/logo-main-menu.png');
176
  add_submenu_page(self::$baseMenuSlug, 'Audit Log Viewer', 'Audit Log Viewer', $reqCap, self::$baseMenuSlug, 'WPPH::pageMain');
177
+ if(WPPHUtil::isMainSite()){
178
+ add_submenu_page(self::$baseMenuSlug, __('Settings',WPPH_PLUGIN_TEXT_DOMAIN), __('Settings',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'settings', 'WPPH::pageSettings');
179
+ add_submenu_page(self::$baseMenuSlug, __('Enable/Disable Alerts',WPPH_PLUGIN_TEXT_DOMAIN), __('Enable/Disable Alerts',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'alerts', 'WPPH::pageAlerts');
180
+ }
181
+ else {
182
+ if(WPPHUtil::isAllowedChange()){
183
+ add_submenu_page(self::$baseMenuSlug, __('Settings',WPPH_PLUGIN_TEXT_DOMAIN), __('Settings',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'settings', 'WPPH::pageSettings');
184
+ add_submenu_page(self::$baseMenuSlug, __('Enable/Disable Alerts',WPPH_PLUGIN_TEXT_DOMAIN), __('Enable/Disable Alerts',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'alerts', 'WPPH::pageAlerts');
185
+ }
186
+ }
187
  add_submenu_page(self::$baseMenuSlug, __('About',WPPH_PLUGIN_TEXT_DOMAIN), __('About',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'about', 'WPPH::pageAbout');
188
  add_submenu_page(self::$baseMenuSlug, __('Support',WPPH_PLUGIN_TEXT_DOMAIN), __('Support',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'support', 'WPPH::pageSupport');
189
  }
190
  elseif($allowedAccess){
191
  add_menu_page('WP Security Audit Log', 'WP Security Audit Log', $reqCap, self::$baseMenuSlug, 'WPPH::pageMain', WPPH_PLUGIN_URL.'res/img/logo-main-menu.png');
192
  add_submenu_page(self::$baseMenuSlug, 'Audit Log Viewer', 'Audit Log Viewer', $reqCap, self::$baseMenuSlug, 'WPPH::pageMain');
193
+ if(WPPHUtil::isAllowedChange()){
194
+ add_submenu_page(self::$baseMenuSlug, __('Settings',WPPH_PLUGIN_TEXT_DOMAIN), __('Settings',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'settings', 'WPPH::pageSettings');
195
+ add_submenu_page(self::$baseMenuSlug, __('Enable/Disable Alerts',WPPH_PLUGIN_TEXT_DOMAIN), __('Enable/Disable Alerts',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'alerts', 'WPPH::pageAlerts');
196
+ }
197
  add_submenu_page(self::$baseMenuSlug, __('About',WPPH_PLUGIN_TEXT_DOMAIN), __('About',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'about', 'WPPH::pageAbout');
198
  add_submenu_page(self::$baseMenuSlug, __('Support',WPPH_PLUGIN_TEXT_DOMAIN), __('Support',WPPH_PLUGIN_TEXT_DOMAIN), $reqCap, self::$baseMenuSlug.'support', 'WPPH::pageSupport');
199
  }
230
  }
231
  }
232
  }
233
+ wpph_updatePluginEventsList($alerts);
234
  return $alerts;
235
  }
236
 
240
  * @return array
241
  */
242
  static function getEvents(){
243
+ $events = wpph_getPluginEventsList();
244
  if(false === $events){
245
  $events = self::createDefaultEventsList();
246
  }
256
  $settings->lastCleanup = time();
257
  $settings->cleanupRan = 0;
258
  $settings->showDW = 1; // whether or not to show the dashboard widget. @since v0.4
259
+
260
  update_option(WPPH_PLUGIN_SETTING_NAME, $settings);
261
  self::createDefaultEventsList();
262
  wpphLog('Settings added.');
265
  public static function getPluginSettings()
266
  {
267
  $settings = get_option(WPPH_PLUGIN_SETTING_NAME);
268
+ if(false == $settings){
269
  $settings = self::createPluginDefaultSettings();
270
  }
271
  return $settings;
272
  }
273
 
274
  /**
275
+ * @param object $settings If this param is null, $settingName & $settingValue(this cannot be null) must be set
276
  * @param string $settingName Optional. Required if $settings is null
277
  * @param string $settingValue Optional. Required if $settings is null
278
  * @param bool $overrideCleanupRan Whether or not to override the cleanupRan option. Defaults to false
303
  wpphLog('Settings saved.', $settings);
304
  }
305
 
306
+ public static function onPluginActivate($blogId=1)
307
  {
308
+ if($blogId > 1){
309
+ return true;
310
+ }
311
+
312
  wpphLog(__METHOD__.'() triggered.');
313
 
314
  $canContinue = true;
359
  self::__addPluginError(__("Plugin could not be properly installed because we have encountered errors during the database update.",WPPH_PLUGIN_TEXT_DOMAIN));
360
  return false;
361
  }
 
362
  }
363
  // plugin already installed
364
  else
413
  }
414
 
415
  /**
416
+ * Triggered when the plugin is deactivated
417
+ * @param int $blogId
418
+ * @return bool true
419
  */
420
+ public static function onPluginDeactivate($blogId=1)
421
  {
422
+ wpphLog(__FUNCTION__.'() triggered.');
423
  wp_clear_scheduled_hook(WPPH_PLUGIN_DEL_EVENTS_CRON_TASK_NAME);
424
  delete_option(WPPH_PLUGIN_ERROR_OPTION_NAME);
425
+ update_option('WPPH_PLUGIN_ACTIVATED',0);
426
+ return true;
427
  }
428
 
429
+ public static function __addPluginError($error)
430
+ {
431
  $data = get_option(WPPH_PLUGIN_ERROR_OPTION_NAME);
432
  if(empty($data)){
433
  $data = array();
448
  WPPHUtil::saveInitialAccessChangeList();
449
  if($triggerInstallEvent)
450
  {
451
+ if(! defined('WPPH_PLUGIN_INSTALLED_OK')) {
452
+ //@see: WPPHEventWatcher::watchPluginInstall()
453
+ define('WPPH_PLUGIN_INSTALLED_OK',true);
454
+ }
455
  // log plugin installation
456
+ wpph_installPlugin(WPPH_PLUGIN_NAME, wp_get_current_user()->ID, WPPHUtil::getIP());
 
457
  }
458
  // log plugin activation
459
  WPPHEvent::hookWatchPluginActivity();
460
+
461
+ // register cron job for events deletion
462
+ if(defined('DISABLE_WP_CRON') && DISABLE_WP_CRON){ return true; }
463
+ else
464
+ {
465
+ if ( ! wp_next_scheduled(WPPH_PLUGIN_DEL_EVENTS_CRON_TASK_NAME)) {
466
+ $interval = (defined('WPPH_CLEANUP_INTERVAL') ? WPPH_CLEANUP_INTERVAL : 'hourly');
467
+ wp_schedule_event( time(), $interval, WPPH_PLUGIN_DEL_EVENTS_CRON_TASK_NAME );
468
+ wpphLog(__METHOD__.'() '.WPPH_PLUGIN_DEL_EVENTS_CRON_TASK_NAME.' task scheduled by wp-cron. Time Interval set to: '.$interval);
469
+ }
470
+ }
471
  }
472
  /**
473
  * @internal
499
  return true;
500
  }
501
  public static function checkPHP(){ return (version_compare(phpversion(), '5.0.0', '>=')); }
502
+
503
+
504
+ /**
505
+ * Check to see whether or not this is a multisite instance
506
+ * @since v0.6
507
+ * @return bool
508
+ */
509
+ static function isMultisite(){ return ((function_exists('is_multisite') && is_multisite()) ? true : false); }
510
+
511
  }
512
 
513
 
inc/WPPHDatabase.php CHANGED
@@ -16,16 +16,16 @@ class WPPHDatabase
16
  /**
17
  * @var string
18
  * @private
19
- * Holds the name of the event logs table WITHOUT the db prefix!
20
  */
21
- private static $_eventsLogTableBaseName = '_wordpress_eventlog';
22
 
23
  /**
24
  * @var string
25
  * @private
26
- * Holds the name of the events details table WITHOUT the db prefix!
27
  */
28
- private static $_eventsDetailsTableBaseName = '_wordpress_eventlog_details';
29
 
30
 
31
  private static $_tablesCreated = false;
@@ -35,6 +35,41 @@ class WPPHDatabase
35
 
36
  //================================================================================================================
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  static function handleDatabase()
39
  {
40
  // Check database
@@ -106,10 +141,10 @@ class WPPHDatabase
106
  {
107
  global $wpdb;
108
  if(strcasecmp($what, 'MAIN') == 0){
109
- return $wpdb->prefix.self::$_eventsLogTableBaseName;
110
  }
111
  elseif(strcasecmp($what, 'EVENTS') == 0){
112
- return $wpdb->prefix.self::$_eventsDetailsTableBaseName;
113
  }
114
  return '';
115
  }
@@ -151,7 +186,6 @@ class WPPHDatabase
151
  return self::$_canUpgrade;
152
  }
153
 
154
-
155
  private static function _createEventLogsTable($wpdb, $tableFullName)
156
  {
157
  $query = "CREATE TABLE IF NOT EXISTS `$tableFullName` (
@@ -202,6 +236,19 @@ class WPPHDatabase
202
  return false;
203
  }
204
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  return true;
206
  }
207
  private static function _upgradeEventDetailsTable($wpdb, $tableFullName)
@@ -265,6 +312,17 @@ class WPPHDatabase
265
  {
266
  return true;
267
  }
 
 
 
 
 
 
 
 
 
 
 
268
  }
269
 
270
  /**
@@ -287,6 +345,12 @@ class WPPHDB extends WPPHDatabase
287
  // returns array(userName, userRole)
288
  static function getUserInfo($userID)
289
  {
 
 
 
 
 
 
290
  global $wpdb;
291
 
292
  $t = $wpdb->users;
@@ -295,6 +359,8 @@ class WPPHDB extends WPPHDatabase
295
  $user = new WP_User( $userID );
296
  $userRole = (empty($user->roles[0]) ? '' : $user->roles[0]);
297
 
 
 
298
  return array(
299
  'userName' => $username,
300
  'userRole' => $userRole
@@ -303,11 +369,17 @@ class WPPHDB extends WPPHDatabase
303
 
304
  /**
305
  * Retrieve the total number of events from db
 
306
  * @return int
307
  */
308
- static function getEventsCount()
309
  {
310
  global $wpdb;
 
 
 
 
 
311
  return $wpdb->get_var("SELECT COUNT(EventNumber) FROM ".self::getFullTableName('main'));
312
  }
313
  }
16
  /**
17
  * @var string
18
  * @private
19
+ * Holds the name of the event logs table WITHOUT the db prefix. As of version 0.6 it has been changed to: wordpress_auditlog
20
  */
21
+ private static $_eventsLogTableBaseName = 'wordpress_auditlog'; //old: {prefix}_wordpress_eventlog
22
 
23
  /**
24
  * @var string
25
  * @private
26
+ * Holds the name of the events details table WITHOUT the db prefix. As of version 0.6 it has been changed to: wordpress_auditlog_events
27
  */
28
+ private static $_eventsDetailsTableBaseName = 'wordpress_auditlog_events'; //old: {prefix}_wordpress_eventlog_details
29
 
30
 
31
  private static $_tablesCreated = false;
35
 
36
  //================================================================================================================
37
 
38
+ // since v0.6
39
+ static function dropTables()
40
+ {
41
+ $version = WPPHNetwork::getGlobalOption(WPPH_PLUGIN_VERSION_OPTION_NAME, false, true, null);
42
+ if(is_null($version)){
43
+ return;
44
+ }
45
+ if(version_compare($version,'0.6','>=')){
46
+ return;
47
+ }
48
+
49
+ global $wpdb;
50
+ if(self::tableExists($wpdb, self::getFullTableName('MAIN')) && self::tableExists($wpdb, self::getFullTableName('EVENTS'))){
51
+ return;
52
+ }
53
+
54
+ WPPHNetwork::updateGlobalOption(WPPH_PLUGIN_DB_UPDATED, 0, false, true);
55
+ $prefix = (WPPH::isMultisite() ? self::getDefaultPrefix() : $wpdb->prefix);
56
+
57
+ $tMainOld = $prefix.'_wordpress_eventlog';
58
+ $tEventsOld = $prefix.'_wordpress_eventlog_details';
59
+
60
+ if(self::tableExists($wpdb, $tMainOld)){
61
+ $q = "DROP TABLE IF EXISTS {$tMainOld}";
62
+ $r = $wpdb->query($q);
63
+ wpphLog("Old table {$tMainOld} found. Deleting table.", array('query'=>$q, 'result'=> $r===true?'success':'failed'));
64
+ }
65
+ if(self::tableExists($wpdb, $tEventsOld)){
66
+ $q = "DROP TABLE IF EXISTS {$tEventsOld}";
67
+ $r = $wpdb->query($q);
68
+ wpphLog("Old table {$tEventsOld} found. Deleting table.", array('query'=>$q, 'result'=> $r===true?'success':'failed'));
69
+ }
70
+ }
71
+
72
+
73
  static function handleDatabase()
74
  {
75
  // Check database
141
  {
142
  global $wpdb;
143
  if(strcasecmp($what, 'MAIN') == 0){
144
+ return (WPPH::isMultisite() ? self::getDefaultPrefix() : $wpdb->prefix) . self::$_eventsLogTableBaseName;
145
  }
146
  elseif(strcasecmp($what, 'EVENTS') == 0){
147
+ return (WPPH::isMultisite() ? self::getDefaultPrefix() : $wpdb->prefix) . self::$_eventsDetailsTableBaseName;
148
  }
149
  return '';
150
  }
186
  return self::$_canUpgrade;
187
  }
188
 
 
189
  private static function _createEventLogsTable($wpdb, $tableFullName)
190
  {
191
  $query = "CREATE TABLE IF NOT EXISTS `$tableFullName` (
236
  return false;
237
  }
238
  }
239
+ $q = "SHOW COLUMNS FROM $tableFullName LIKE 'BlogId';";
240
+ $rowData = $wpdb->get_row($q, ARRAY_A);
241
+ if(empty($rowData['Field']))
242
+ {
243
+ $q = "ALTER TABLE $tableFullName ADD COLUMN `BlogId` INT NOT NULL DEFAULT 1 AFTER `UserName`;";
244
+ $result = @$wpdb->query($q);
245
+ if($result === false){
246
+ WPPH::__addPluginError(
247
+ sprintf(__("Plugin could not be properly installed. The db user used to connect to the WordPress database is missing the <strong>ALTER</strong> right for query: <strong>%s</strong>",WPPH_PLUGIN_TEXT_DOMAIN),$q)
248
+ );
249
+ return false;
250
+ }
251
+ }
252
  return true;
253
  }
254
  private static function _upgradeEventDetailsTable($wpdb, $tableFullName)
312
  {
313
  return true;
314
  }
315
+
316
+ /**
317
+ * Retrieve the default database prefix
318
+ * @since v0.6
319
+ * @uses global var $wpdb
320
+ * @return string
321
+ */
322
+ static function getDefaultPrefix(){
323
+ global $wpdb;
324
+ return $wpdb->base_prefix;
325
+ }
326
  }
327
 
328
  /**
345
  // returns array(userName, userRole)
346
  static function getUserInfo($userID)
347
  {
348
+ if(empty($userID)){
349
+ wpphLog(__METHOD__.'() called with an invalid argument $userID. Ignoring request.', array('$userID'=>$userID));
350
+ return array('userName'=>'', 'userRole'=>'');
351
+ }
352
+ wpphLog(__METHOD__.'() called.', array('$userID'=>$userID));
353
+
354
  global $wpdb;
355
 
356
  $t = $wpdb->users;
359
  $user = new WP_User( $userID );
360
  $userRole = (empty($user->roles[0]) ? '' : $user->roles[0]);
361
 
362
+ wpphLog("Function: ".__METHOD__." User info", array('id'=>$userID, 'roles'=>$user->roles));
363
+
364
  return array(
365
  'userName' => $username,
366
  'userRole' => $userRole
369
 
370
  /**
371
  * Retrieve the total number of events from db
372
+ * @param integer $blogId
373
  * @return int
374
  */
375
+ static function getEventsCount($blogId = 1)
376
  {
377
  global $wpdb;
378
+ $where = '';
379
+ if(!empty($blogId)){
380
+ $where = " WHERE BlogId = ".intval($blogId);
381
+ return $wpdb->get_var("SELECT COUNT(EventNumber) FROM ".self::getFullTableName('main').$where);
382
+ }
383
  return $wpdb->get_var("SELECT COUNT(EventNumber) FROM ".self::getFullTableName('main'));
384
  }
385
  }
inc/WPPHEvent.php CHANGED
@@ -147,13 +147,39 @@ class WPPHEvent
147
 
148
  // 6xxx - System events
149
  // #6000 Events automatically deleted by system.
150
- array( 'id' => 6000, 'category' => WPPH_E_NOTICE_TEXT, 'text' => __('Events automatically deleted by system.',WPPH_PLUGIN_TEXT_DOMAIN)),
151
  // #6001 - <strong>%s</strong> the option Anyone can register
152
  array( 'id' => 6001, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('<strong>%s</strong> the option Anyone can register',WPPH_PLUGIN_TEXT_DOMAIN)),
153
  // #6002 - Changed the New User Default Role from <strong>%s</strong> to <strong>%s</strong>
154
  array( 'id' => 6002, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Changed the New User Default Role from <strong>%s</strong> to <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
155
  // #6003 - Changed the WordPress administrator notifications email address from %old_email% to %new_mail%
156
  array( 'id' => 6003, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Changed the WordPress administrator notifications email address from <strong>%s</strong> to <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  );
158
  }
159
 
@@ -217,10 +243,10 @@ class WPPHEvent
217
  }
218
 
219
  $_postType = $postType;
220
- if(! in_array($postType, array('post','page'))){
221
  $_postType = 'custom';
222
  }
223
- do_action('wpph_set_post_type',$postType);
224
 
225
  /*
226
  * CHECK IF POST/PAGE AUTHOR UPDATED; 2019
@@ -232,7 +258,7 @@ class WPPHEvent
232
  $GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID'] = intval($_POST['post_author']);
233
  if(isset($GLOBALS['WPPH_SCREEN_EDITOR_ENABLED'])){
234
  // trigger hook manually
235
- add_filter('wp_insert_post_data', array('WPPHPost','managePostAuthorUpdateQuickEditForm'), '1', 2);
236
  }
237
  }
238
 
@@ -248,6 +274,7 @@ class WPPHEvent
248
  {
249
  // before further checks, we have to make sure this post isn't new
250
  if(! $postExists){
 
251
  return;
252
  }
253
 
@@ -287,6 +314,20 @@ class WPPHEvent
287
  */
288
  $GLOBALS['WPPH_POST_NEW_URL'] = get_permalink($pid);
289
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
  }
291
  }
292
 
@@ -303,8 +344,16 @@ class WPPHEvent
303
 
304
  // 4xxx - User profile events
305
 
306
- // 4000, 4001
307
- static function hookUserRegisterEvent() { add_action('user_register', array('WPPHEventWatcher', 'watchEventUserRegister')); }
 
 
 
 
 
 
 
 
308
  // 4002
309
  static function hookUserRoleUpdated() {
310
  add_action('edit_user_profile_update', array('WPPHEventWatcher', 'watchUserInfoUpdated'));
@@ -320,6 +369,12 @@ class WPPHEvent
320
  add_action('edit_user_profile_update', array('WPPHEventWatcher', 'watchUserInfoUpdated'));
321
  add_action('personal_options_update', array('WPPHEventWatcher', 'watchUserInfoUpdated'));
322
  }
 
 
 
 
 
 
323
  // 4007
324
  static function hookUserDeletion() { add_action( 'delete_user', array('WPPHEventWatcher', 'watchUserDeletion') ); }
325
 
@@ -339,11 +394,35 @@ class WPPHEvent
339
 
340
  // 6xxx - System events
341
 
342
- // 6000
343
- static function hookEventsDeletion() { add_action('init', array('WPPHEventWatcher', 'watchDeleteEvents')); }
344
 
345
- // 6001, 6002
 
346
  static function hookCheckWpGeneralSettings(){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  if(isset($_POST))
348
  {
349
  $wpphOptData = get_option(WPPH_USERS_CAN_REGISTER_OPT_NAME);
@@ -398,7 +477,7 @@ class WPPHEvent
398
 
399
 
400
  /**
401
- * Add log event. Internal function. Don not use outside class scope.
402
  * @internal
403
  * @static
404
  * @param int $eventID
@@ -406,10 +485,24 @@ class WPPHEvent
406
  * @param string $userIP
407
  * @param array $eventData Optional. If provided should be as an array.
408
  * @param string $failedLoginUserName The name of the user used for the failed login
 
409
  * @return bool
410
  */
411
- static function _addLogEvent($eventID = 1000, $userID = 0, $userIP = '', $eventData = array(), $failedLoginUserName='')
412
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
413
  if(! wpph_isEventEnabled($eventID)){
414
  wpphLog('Event '.$eventID.' is not enabled. Ignoring request.');
415
  return true;
@@ -418,7 +511,7 @@ class WPPHEvent
418
  if(empty($userIP)){ $userIP = WPPHUtil::getIP(); }
419
  $tableName = WPPHDB::getFullTableName('MAIN');
420
  $eventData = base64_encode(serialize($eventData));
421
- $query = sprintf("INSERT INTO $tableName (EventID, UserID, UserIP, EventData,UserName) VALUES(%d, %d, '%s', '%s', '%s')",$eventID, $userID, $userIP, $eventData, $failedLoginUserName);
422
 
423
  global $wpdb;
424
  if($eventID == 1002){ // 1002 == failed login
@@ -453,12 +546,13 @@ class WPPHEvent
453
 
454
  /**
455
  * Retrieve the events from db.
456
- * @param array $limit
457
  * @param string $orderBy. Must be a valid column name. Defaults to EventNumber
458
  * @param string $sort ASC or DESC
 
 
459
  * @return mixed
460
  */
461
- static function getEvents($orderBy='EventNumber', $sort = 'DESC', $limit = array(0,0))
462
  {
463
  $validArgsSort = array('ASC', 'DESC');
464
  $validCnTableLogDetails = array('EventID', 'EventType');
@@ -486,14 +580,15 @@ class WPPHEvent
486
  $t1 = WPPHDatabase::getFullTableName('main');
487
  $t2 = WPPHDatabase::getFullTableName('events');
488
  global $wpdb;
489
- $query = "SELECT le.EventNumber, le.EventID, le.EventDate, le.UserID, le.UserIP, le.EventData, le.EventCount, le.UserName,
490
- led.EventType, led.EventDescription
491
- FROM `$t1` as le
492
- INNER JOIN `$t2` as led
493
- ON le.EventID = led.EventID
494
- ORDER BY $orderBy
495
- $sort
496
- LIMIT $limit;";
 
497
  return $wpdb->get_results($query, ARRAY_A);
498
  }
499
 
@@ -530,6 +625,7 @@ class WPPHEventWatcher extends WPPHEvent
530
  self::_addLogEvent(1001, wp_get_current_user()->ID);
531
  }
532
 
 
533
  /**
534
  * @internal
535
  * Hooks to the user register event
@@ -546,6 +642,8 @@ class WPPHEventWatcher extends WPPHEvent
546
  $nu = $uInfo['userName'];
547
  $nur = ucfirst($uInfo['userRole']);
548
 
 
 
549
  if($un == 'System')
550
  {
551
  // A new user with the username %username% has registered with the role of %user_role%
@@ -564,37 +662,17 @@ class WPPHEventWatcher extends WPPHEvent
564
  * @internal
565
  * Hooks to the events deletion event
566
  */
567
- static function watchDeleteEvents()
568
- {
569
- wpphLog(__METHOD__.'() triggered by hook.');
570
-
571
- if((defined('DISABLE_WP_CRON') && 'DISABLE_WP_CRON'))
572
- {
573
- wpphLog('wp-cron is disabled.');
574
- self::__deleteEvents();
575
- }
576
- else{
577
- add_action(WPPH_PLUGIN_DEL_EVENTS_CRON_TASK_NAME, array('WPPHEventWatcher','__deleteEvents'));
578
- if ( ! wp_next_scheduled(WPPH_PLUGIN_DEL_EVENTS_CRON_TASK_NAME)) {
579
- wp_schedule_event( time(), 'daily', WPPH_PLUGIN_DEL_EVENTS_CRON_TASK_NAME );
580
- wpphLog(__METHOD__.'() scheduled by wp-cron.');
581
- }
582
- }
583
- }
584
-
585
- //@internal
586
  static function __deleteEvents()
587
  {
 
 
588
  // check settings and delete the events (if any)
589
  $settings = WPPH::getPluginSettings();
590
 
591
- //if wp-cron disabled
592
- if((defined('DISABLE_WP_CRON') && 'DISABLE_WP_CRON'))
593
- {
594
- if($settings->cleanupRan == 1){
595
- wpphLog(__METHOD__.'() Ignored. Cleanup already ran today.');
596
- return;
597
- }
598
  }
599
 
600
  // check to see how we should do the cleanup (by days or by number)
@@ -631,40 +709,96 @@ class WPPHEventWatcher extends WPPHEvent
631
  // delete by days
632
  private static function _deleteEventsOlderThan($days = 1)
633
  {
634
- $query = "DELETE FROM ".WPPHDatabase::getFullTableName('main')." WHERE EventDate < (NOW() - INTERVAL ".$days." DAY)";
635
  global $wpdb;
636
- $result = $wpdb->query($query);
637
- if($result === false){ $status = 'Error executing query'; }
638
- else { $status = 'Query executed'; }
639
- wpphLog(__METHOD__.'('.$days.') called.', array('query'=>$query, 'status'=>$status, 'rowsDeleted'=> (int)$result));
640
- return ($result !== false);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
641
  }
642
  //@internal
643
  // delete by number
644
  private static function _deleteEventsGreaterThan($number = WPPH_KEEP_MAX_EVENTS)
645
  {
646
- if($number > WPPH_KEEP_MAX_EVENTS){ $number = WPPH_KEEP_MAX_EVENTS; }
647
  global $wpdb;
 
648
  $tableName = WPPHDatabase::getFullTableName('main');
649
- $count = $wpdb->get_var("SELECT COUNT(0) FROM $tableName");
650
- if(empty($count)){
651
- wpphLog(__METHOD__.'('.$number.') called. Ignored, there are no events in the database');
652
- return true;
653
- }
654
- $keep = $number;
655
- if($count > $keep)
656
  {
657
- $limit = $count - $keep;
658
- $query = "DELETE FROM $tableName ORDER BY EventDate LIMIT $limit";
659
- $result = $wpdb->query($query);
660
- if($result === false){ $status = 'Error executing query'; }
661
- else { $status = 'Query executed'; }
662
- wpphLog(__METHOD__.'('.$number.') called.', array('query'=>$query, 'status'=>$status, 'rowsAffected'=> (int)$result));
663
- return ($result !== false);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
664
  }
665
  else {
666
- wpphLog(__METHOD__.'('.$number.') called. Ignored, there are not enough events to trigger this action.');
667
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
668
  }
669
  }
670
 
@@ -680,7 +814,7 @@ class WPPHEventWatcher extends WPPHEvent
680
 
681
  static function watchUserInfoUpdated($userID)
682
  {
683
- wpphLog(__METHOD__.'() triggered by hook.');
684
 
685
  // get info for the currently logged in user
686
  $current_user = wp_get_current_user();
@@ -698,14 +832,14 @@ class WPPHEventWatcher extends WPPHEvent
698
  if(!empty($_POST['role'])){
699
  $updatedRole = trim($_POST['role']);
700
  if(self::_userRoleUpdated($cid, $initialUserRole, $updatedRole, $editedUserName, $cName)){
701
- return;
702
  }
703
  }
704
 
705
  // If a user's password has been updated
706
  if(!empty($_POST['pass1'])){
707
  if(self::_userPasswordUpdated($userID, $cid, $cName, $editedUserName, $initialUserRole)){
708
- return;
709
  }
710
  }
711
 
@@ -841,40 +975,70 @@ class WPPHEventWatcher extends WPPHEvent
841
  {
842
  wpphLog(__METHOD__.'() triggered by hook.');
843
 
844
- // get info for the currently logged in user
845
- $current_user = wp_get_current_user();
846
 
847
  // activate one by link
848
- if(!empty($_GET['action']) && ($_GET['action']=='activate') || !empty($_GET['action2']) && ($_GET['action2']=='activate'))
849
  {
850
- $pluginFile = $_GET['plugin'];
851
- $pluginData = get_plugin_data(WP_PLUGIN_DIR.'/'.$pluginFile,false,false);
852
- $pluginName = $pluginData['Name'];
853
- self::_addLogEvent(5001,$current_user->ID, WPPHUtil::getIP(), array($pluginName,$pluginFile));
 
 
 
 
 
 
 
 
 
854
  wpphLog('Plugin activated.', array('plugin file'=>$pluginFile));
 
855
  }
856
  // one by bulk
857
- elseif(isset($_POST['action']) && ($_POST['action'] == 'activate-selected') || isset($_POST['action2']) && ($_POST['action2'] == 'activate-selected'))
858
  {
 
859
  if(! empty($_POST['checked']))
860
  {
861
- foreach($_POST['checked'] as $k=>$pluginFile){
862
- $pluginData = get_plugin_data(WP_PLUGIN_DIR.'/'.$pluginFile,false,false);
863
- $pluginName = $pluginData['Name'];
864
- self::_addLogEvent(5001,$current_user->ID, WPPHUtil::getIP(), array($pluginName,$pluginFile));
 
 
 
 
 
 
 
 
 
865
  wpphLog('Plugin activated.', array('plugin file'=>$pluginFile));
866
  }
867
  }
868
  }
869
  // more by bulk
870
- elseif(isset($_POST['activate-multi']) && ($_POST['action']=='activate-selected' || $_POST['action2']=='activate-selected'))
871
  {
 
872
  if(! empty($_POST['checked']))
873
  {
874
- foreach($_POST['checked'] as $k=>$pluginFile){
875
- $pluginData = get_plugin_data(WP_PLUGIN_DIR.'/'.$pluginFile,false,false);
876
- $pluginName = $pluginData['Name'];
877
- self::_addLogEvent(5001,$current_user->ID, WPPHUtil::getIP(), array($pluginName,$pluginFile));
 
 
 
 
 
 
 
 
 
878
  wpphLog('Plugin activated.', array('plugin file'=>$pluginFile));
879
  }
880
  }
@@ -886,72 +1050,62 @@ class WPPHEventWatcher extends WPPHEvent
886
  wpphLog(__METHOD__.'() triggered by hook.');
887
 
888
  // get info for the currently logged in user
889
- $current_user = wp_get_current_user();
 
890
 
891
  // activate one by link
892
- if(isset($_GET['action']) && ($_GET['action']=='deactivate') || isset($_GET['action2']) && ($_GET['action2']=='deactivate'))
893
  {
 
894
  $pluginFile = $_GET['plugin'];
895
  $pluginData = get_plugin_data(WP_PLUGIN_DIR.'/'.$pluginFile,false,false);
896
  $pluginName = $pluginData['Name'];
897
- self::_addLogEvent(5002,$current_user->ID, WPPHUtil::getIP(), array($pluginName,$pluginFile));
898
  wpphLog('Plugin deactivated.', array('plugin file'=>$pluginFile));
899
  }
900
  // one by bulk
901
- elseif(isset($_POST['action']) && ($_POST['action'] == 'deactivate-selected') || isset($_POST['action2']) && ($_POST['action2'] == 'deactivate-selected'))
902
  {
903
  if(! empty($_POST['checked']))
904
  {
 
905
  foreach($_POST['checked'] as $k=>$pluginFile){
906
  $pluginData = get_plugin_data(WP_PLUGIN_DIR.'/'.$pluginFile,false,false);
907
  $pluginName = $pluginData['Name'];
908
- self::_addLogEvent(5002,$current_user->ID, WPPHUtil::getIP(), array($pluginName,$pluginFile));
909
  wpphLog('Plugin deactivated.', array('plugin file'=>$pluginFile));
910
  }
911
  }
912
  }
913
  // more by bulk
914
- elseif(isset($_GET['activate-multi']) && ($_POST['action']=='deactivate-selected' || $_POST['action2']=='deactivate-selected'))
915
  {
916
  if(! empty($_POST['checked']))
917
  {
 
918
  foreach($_POST['checked'] as $k=>$pluginFile){
919
  $pluginData = get_plugin_data(WP_PLUGIN_DIR.'/'.$pluginFile,false,false);
920
  $pluginName = $pluginData['Name'];
921
- self::_addLogEvent(5002,$current_user->ID, WPPHUtil::getIP(), array($pluginName,$pluginFile));
922
  wpphLog('Plugin deactivated.', array('plugin file'=>$pluginFile));
923
  }
924
  }
925
  }
926
  }
 
927
  // # 5000
928
  static function watchPluginInstall()
929
  {
930
  if(defined('WPPH_PLUGIN_INSTALLED_OK')){ return; }
931
  if(empty($_GET)) { return; }
932
 
933
- /**
934
- * @internal
935
- * @param $pluginName
936
- */
937
- function wpph_installPlugin($pluginName)
938
- {
939
- if(! empty($_GET['plugin']))
940
- {
941
- // get info for the currently logged in user
942
- $current_user = wp_get_current_user();
943
- WPPHEvent::_addLogEvent(5000,$current_user->ID, WPPHUtil::getIP(), array($pluginName));
944
- wpphLog('Plugin installed.', array('plugin'=>$pluginName));
945
- }
946
- }
947
-
948
  if(isset($_GET['action']) && $_GET['action']=='install-plugin'){
949
  wpphLog(__METHOD__.'() triggered by hook.');
950
- wpph_installPlugin($_GET['plugin']);
951
  }
952
  elseif(isset($_GET['action2']) && $_GET['action2']=='install-plugin'){
953
  wpphLog(__METHOD__.'() triggered by hook.');
954
- wpph_installPlugin($_GET['plugin']);
955
  }
956
  }
957
  // # 5003
@@ -981,6 +1135,8 @@ class WPPHEventWatcher extends WPPHEvent
981
  // # 5004
982
  static function watchPluginUpgrade()
983
  {
 
 
984
  $current_user = wp_get_current_user();
985
  $userID = $current_user->ID;
986
  $ip = WPPHUtil::getIP();
@@ -1043,6 +1199,7 @@ class WPPHEventWatcher extends WPPHEvent
1043
  wpphLog(__METHOD__.'. POST STATUS DATA', array(
1044
  '$oldStatus' => $oldStatus,
1045
  '$newStatus' => $newStatus,
 
1046
  '$post' => $post
1047
  ));
1048
 
@@ -1064,7 +1221,7 @@ class WPPHEventWatcher extends WPPHEvent
1064
  $postUrl = get_permalink($postID);
1065
  $postStatus = $post->post_status;
1066
  $currentUserID = wp_get_current_user()->ID;
1067
- $userID = $postAuthorID = $post->post_author;
1068
  if($currentUserID != $postAuthorID){
1069
  // someone else is doing this
1070
  $userID = $currentUserID;
@@ -1099,7 +1256,6 @@ class WPPHEventWatcher extends WPPHEvent
1099
 
1100
  WPPHPost::$currentPostType = $post->post_type;
1101
 
1102
-
1103
  global $wpdb;
1104
 
1105
  //## 2025 & 2026 & 2040
@@ -1120,20 +1276,20 @@ class WPPHEventWatcher extends WPPHEvent
1120
  $authorChanged = false;
1121
  if(isset($GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID']))
1122
  {
 
1123
  if($customPostType){
1124
- if(WPPHPost::postAuthorChanged((int)$GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID'], $postID, $userID, $postTitle, 2038)){
1125
- unset($GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID']);
1126
  $GLOBALS['WPPH_POST_AUTHOR_UPDATED'] = true;
1127
  $authorChanged = true;
1128
  }
1129
  }
1130
  else {
1131
- if(WPPHPost::postAuthorChanged((int)$GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID'], $postID, $userID, $postTitle, ($postTypePost) ? 2019 : 2020)){
1132
- unset($GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID']);
1133
  $GLOBALS['WPPH_POST_AUTHOR_UPDATED'] = true;
1134
  $authorChanged = true;
1135
  }
1136
  }
 
1137
  }
1138
 
1139
  // 2000 & 2004 & 2029
@@ -1230,8 +1386,8 @@ class WPPHEventWatcher extends WPPHEvent
1230
  {
1231
  $event = 0;
1232
  if($customPostType) { $event = 2039;}
1233
- elseif($postTypePost) { $event = 2001; }
1234
- elseif($postTypePage) { $event = 2005; }
1235
  if(! empty($event)){
1236
  WPPHPost::postStatusChanged($postTitle, __('Published'), __('Draft'), $userID, $event);
1237
  }
@@ -1587,17 +1743,14 @@ class WPPHEventWatcher extends WPPHEvent
1587
  wpphLog(__METHOD__.'() triggered.');
1588
  $data = (isset($GLOBALS['WPPH_WIDGET_MOVE']) ? $GLOBALS['WPPH_WIDGET_MOVE'] : null);
1589
  if(empty($data)){
1590
- wpphLog('variable not found: WPPH_WIDGET_MOVE');
1591
  return;
1592
  }
1593
  $from = $data['from'];
1594
  $to = $data['to'];
1595
-
1596
  global $wp_registered_sidebars;
1597
-
1598
  if(preg_match("/^sidebar-/", $from)){ $from = (isset($wp_registered_sidebars[$from]) ? $wp_registered_sidebars[$from]['name'] : $from); }
1599
  if(preg_match("/^sidebar-/", $to)){ $to = (isset($wp_registered_sidebars[$to]) ? $wp_registered_sidebars[$to]['name'] : $to); }
1600
-
1601
  self::_addLogEvent(2045, $data['user'], $data['ip'], array($data['widget'], $from, $to));
1602
  }
1603
 
@@ -1686,7 +1839,7 @@ class WPPHEventWatcher extends WPPHEvent
1686
  // 2025, 2026
1687
  static function watchPostVisibilityChange($oldStatus, $newStatus, $userID, $postTitle, $post, $event)
1688
  {
1689
- wpphLog(__METHOD__.'() triggered.');
1690
 
1691
  global $wpdb;
1692
 
@@ -1699,12 +1852,15 @@ class WPPHEventWatcher extends WPPHEvent
1699
  // pwd protected -> public
1700
  if($oldStatus == 'publish' && $newStatus == 'publish')
1701
  {
1702
- // if post is already pwd protected and there is no change, it will still be issued an event: public to pwd protected
1703
- if(isset($GLOBALS['WPPH_POST_PWD_PROTECTED']) && $GLOBALS['WPPH_POST_PWD_PROTECTED']){
1704
- $GLOBALS['WPPH_PREVENT_BUBBLE'] = true;
1705
- wpphLog(__METHOD__.'() No change.');
1706
- return;
 
 
1707
  }
 
1708
  // pwd protected -> public
1709
  if(empty($crtPostPassword) && !empty($oldPostPassword)){
1710
  $from = __('Password Protected');
@@ -1752,7 +1908,7 @@ class WPPHEventWatcher extends WPPHEvent
1752
  }
1753
  }
1754
  }
1755
-
1756
  if(empty($from) || empty($to)){
1757
  return;
1758
  }
@@ -1802,9 +1958,14 @@ class WPPHEventWatcher extends WPPHEvent
1802
  }
1803
 
1804
  static function watchPostCategoriesChange($post, $wpdb, $postTitle, $event)
1805
- { return true;
1806
  wpphLog(__METHOD__.'() triggered.');
1807
 
 
 
 
 
 
1808
  if(isset($GLOBALS['WPPH_POST_OLD_CATEGORIES']))
1809
  {
1810
  $originalCats = $GLOBALS['WPPH_POST_OLD_CATEGORIES'];
@@ -1815,10 +1976,16 @@ class WPPHEventWatcher extends WPPHEvent
1815
  }
1816
  $categories_2 = array();
1817
  $newCats = $post->post_category;
1818
- if(empty($newCats[0])){
1819
- unset($newCats[0]);
 
1820
  }
 
1821
  foreach($newCats as $catID){
 
 
 
 
1822
  $cat = get_category($catID);
1823
  array_push($categories_2, $cat->name);
1824
  }
@@ -1877,4 +2044,169 @@ class WPPHEventWatcher extends WPPHEvent
1877
  }
1878
  return false;
1879
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1880
  }
147
 
148
  // 6xxx - System events
149
  // #6000 Events automatically deleted by system.
150
+ array( 'id' => 6000, 'category' => WPPH_E_NOTICE_TEXT, 'text' => __('Alerts automatically deleted by system.',WPPH_PLUGIN_TEXT_DOMAIN)),
151
  // #6001 - <strong>%s</strong> the option Anyone can register
152
  array( 'id' => 6001, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('<strong>%s</strong> the option Anyone can register',WPPH_PLUGIN_TEXT_DOMAIN)),
153
  // #6002 - Changed the New User Default Role from <strong>%s</strong> to <strong>%s</strong>
154
  array( 'id' => 6002, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Changed the New User Default Role from <strong>%s</strong> to <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
155
  // #6003 - Changed the WordPress administrator notifications email address from %old_email% to %new_mail%
156
  array( 'id' => 6003, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Changed the WordPress administrator notifications email address from <strong>%s</strong> to <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
157
+
158
+
159
+ // xxxx - MultiSite Events
160
+
161
+ // #4008 - Granted Super Admin privileges from <strong>%user%</strong>
162
+ array( 'id' => 4008, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Granted Super Admin privileges to <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
163
+ // #4009 - Revoked Super Admin privileges from <strong>%user%</strong>
164
+ array( 'id' => 4009, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Revoked Super Admin privileges from <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
165
+ // #4010 - Added existing user %user% with %role% role to site %site%
166
+ array( 'id' => 4010, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Added existing user <strong>%s</strong> with role <strong>%s</strong> to site <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
167
+ // #4011 - Removed user %user% with role %role% from %site% site
168
+ array( 'id' => 4011, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Removed user <strong>%s</strong> with role <strong>%s</strong> from site <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
169
+ // #4012 - Created a new network user %user%
170
+ array( 'id' => 4012, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Created a new network user <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
171
+ // #7000 - Added <strong>%site%</strong> to the network
172
+ array( 'id' => 7000, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Added site <strong>%s</strong> to the network',WPPH_PLUGIN_TEXT_DOMAIN)),
173
+ // #7001 - Archived site <strong>%site%</strong>
174
+ array( 'id' => 7001, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Archived site <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
175
+ // #7002 - Unarchived site <strong>%site%</strong>
176
+ array( 'id' => 7002, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Unarchived site <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
177
+ // #7003 - Activated site <strong>%site%</strong>
178
+ array( 'id' => 7003, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Activated site <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
179
+ // #7004 - Deactivated site <strong>%site%</strong>
180
+ array( 'id' => 7004, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Deactivated site <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
181
+ // #7005 - Deleted site <strong>%site%</strong>
182
+ array( 'id' => 7005, 'category' => WPPH_E_HIGH_TEXT, 'text' => __('Deleted site <strong>%s</strong>',WPPH_PLUGIN_TEXT_DOMAIN)),
183
  );
184
  }
185
 
243
  }
244
 
245
  $_postType = $postType;
246
+ if($_postType != 'post' && $_postType != 'page'){
247
  $_postType = 'custom';
248
  }
249
+ do_action('wpph_set_post_type',$_postType);
250
 
251
  /*
252
  * CHECK IF POST/PAGE AUTHOR UPDATED; 2019
258
  $GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID'] = intval($_POST['post_author']);
259
  if(isset($GLOBALS['WPPH_SCREEN_EDITOR_ENABLED'])){
260
  // trigger hook manually
261
+ add_filter('wp_insert_post_data', array('WPPHPost','managePostAuthorUpdateQuickEditForm'), 1, 2);
262
  }
263
  }
264
 
274
  {
275
  // before further checks, we have to make sure this post isn't new
276
  if(! $postExists){
277
+ wpphLog("POST DOES NOT EXISTS.");
278
  return;
279
  }
280
 
314
  */
315
  $GLOBALS['WPPH_POST_NEW_URL'] = get_permalink($pid);
316
  }
317
+ wpphLog('GLOBAL VARIABLES', array(
318
+ 'WPPH_POST_AUTHOR_UPDATED_ID' => $GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID'],
319
+ 'WPPH_POST_EXISTS' => $GLOBALS['WPPH_POST_EXISTS'],
320
+ 'WPPH_POST_PWD_PROTECTED' => $GLOBALS['WPPH_POST_PWD_PROTECTED'],
321
+ 'WPPH_OLD_POST_PASSWORD' => $GLOBALS['WPPH_OLD_POST_PASSWORD'],
322
+ 'WPPH_POST_OLD_DATE' => $GLOBALS['WPPH_POST_OLD_DATE'],
323
+ 'WPPH_POST_OLD_NAME' => $GLOBALS['WPPH_POST_OLD_NAME'],
324
+ 'WPPH_POST_OLD_CATEGORIES' => isset($GLOBALS['WPPH_POST_OLD_CATEGORIES']) ? $GLOBALS['WPPH_POST_OLD_CATEGORIES'] : '',
325
+ 'WPPH_POST_NEW_URL' => $GLOBALS['WPPH_POST_NEW_URL'],
326
+ 'post_type' => $postType,
327
+ 'WPPH_DEFAULT_EDITOR_ENABLED' => isset($GLOBALS['WPPH_DEFAULT_EDITOR_ENABLED']) ? 'true' : 'false',
328
+ 'WPPH_SCREEN_EDITOR_ENABLED' => isset($GLOBALS['WPPH_SCREEN_EDITOR_ENABLED']) ? 'true' : 'false',
329
+ )
330
+ );
331
  }
332
  }
333
 
344
 
345
  // 4xxx - User profile events
346
 
347
+ // 4000, 4001, 4012
348
+ static function hookUserRegisterEvent()
349
+ {
350
+ if(WPPH::isMultisite()){
351
+ // 4012
352
+ add_action('user_register', array('WPPHEventWatcher', 'watchWpmuUserRegister'));
353
+ }
354
+ // 4000 & 4001
355
+ else { add_action('user_register', array('WPPHEventWatcher', 'watchEventUserRegister')); }
356
+ }
357
  // 4002
358
  static function hookUserRoleUpdated() {
359
  add_action('edit_user_profile_update', array('WPPHEventWatcher', 'watchUserInfoUpdated'));
369
  add_action('edit_user_profile_update', array('WPPHEventWatcher', 'watchUserInfoUpdated'));
370
  add_action('personal_options_update', array('WPPHEventWatcher', 'watchUserInfoUpdated'));
371
  }
372
+ // 4008
373
+ static function hookUserAdminPriv() {
374
+ add_action('edit_user_profile_update', array('WPPHEventWatcher', 'watchUserAdminPrivUpdated'));
375
+ add_action('personal_options_update', array('WPPHEventWatcher', 'watchUserAdminPrivUpdated'));
376
+ }
377
+
378
  // 4007
379
  static function hookUserDeletion() { add_action( 'delete_user', array('WPPHEventWatcher', 'watchUserDeletion') ); }
380
 
394
 
395
  // 6xxx - System events
396
 
 
 
397
 
398
+ // Events: 6001, 6002 are not available in MultiSite.
399
+ // 6001, 6002, 6003
400
  static function hookCheckWpGeneralSettings(){
401
+ if(WPPH::isMultisite())
402
+ {
403
+ if(isset($_POST))
404
+ {
405
+ if(isset($_POST['_wp_http_referer']) && !empty($_POST['_wp_http_referer'])){
406
+ $wp_referrer = $_POST['_wp_http_referer'];
407
+ if(false === ($pos = stripos($wp_referrer,'settings.php'))){
408
+ return;
409
+ }
410
+ // 6003
411
+ if(! empty($_POST['admin_email'])){
412
+ $from = get_option('admin_email');
413
+ $to = trim($_POST['admin_email']);
414
+ if(strcasecmp($from,$to)!=0){
415
+ wpphLog('Admin email changed',array(
416
+ 'from' => $from,
417
+ 'to' => $to
418
+ ));
419
+ self::_addLogEvent(6003, wp_get_current_user()->ID, WPPHUtil::getIP(), array($from, $to));
420
+ }
421
+ }
422
+ }
423
+ }
424
+ return;
425
+ }
426
  if(isset($_POST))
427
  {
428
  $wpphOptData = get_option(WPPH_USERS_CAN_REGISTER_OPT_NAME);
477
 
478
 
479
  /**
480
+ * Add log event. Internal function. Do not use outside class scope.
481
  * @internal
482
  * @static
483
  * @param int $eventID
485
  * @param string $userIP
486
  * @param array $eventData Optional. If provided should be as an array.
487
  * @param string $failedLoginUserName The name of the user used for the failed login
488
+ * @param int $blogID The blog id for which the event is triggered. If omitted, the global $blog_id variable will be used.
489
  * @return bool
490
  */
491
+ static function _addLogEvent($eventID = 1000, $userID = 0, $userIP = '', $eventData = array(), $failedLoginUserName='', $blogID = null)
492
  {
493
+ $params = func_get_args();
494
+ wpphLog(__METHOD__.'() called with params:', $params);
495
+ wpphLog(__METHOD__.'() triggered.');
496
+ if(empty($blogID)){
497
+ wpphLog('The blog ID was not provided. Trying to use the global $blog_id');
498
+ global $blog_id; // try to get the current blog id if none provided
499
+ if(empty($blog_id)){
500
+ wpphLog('The blog ID could not be determined. Ignoring request for adding the log event.');
501
+ return true;
502
+ }
503
+ }
504
+ else { $blog_id = $blogID; }
505
+
506
  if(! wpph_isEventEnabled($eventID)){
507
  wpphLog('Event '.$eventID.' is not enabled. Ignoring request.');
508
  return true;
511
  if(empty($userIP)){ $userIP = WPPHUtil::getIP(); }
512
  $tableName = WPPHDB::getFullTableName('MAIN');
513
  $eventData = base64_encode(serialize($eventData));
514
+ $query = sprintf("INSERT INTO $tableName (EventID, UserID, UserIP, EventData, UserName, BlogId) VALUES(%d, %d, '%s', '%s', '%s', %d)",$eventID, $userID, $userIP, $eventData, $failedLoginUserName,$blog_id);
515
 
516
  global $wpdb;
517
  if($eventID == 1002){ // 1002 == failed login
546
 
547
  /**
548
  * Retrieve the events from db.
 
549
  * @param string $orderBy. Must be a valid column name. Defaults to EventNumber
550
  * @param string $sort ASC or DESC
551
+ * @param array $limit
552
+ * @param integer $blogId
553
  * @return mixed
554
  */
555
+ static function getEvents($orderBy='EventNumber', $sort = 'DESC', $limit = array(0,0), $blogId = 1)
556
  {
557
  $validArgsSort = array('ASC', 'DESC');
558
  $validCnTableLogDetails = array('EventID', 'EventType');
580
  $t1 = WPPHDatabase::getFullTableName('main');
581
  $t2 = WPPHDatabase::getFullTableName('events');
582
  global $wpdb;
583
+ $query = "SELECT le.EventNumber, le.EventID, le.EventDate, le.UserID, le.UserIP, le.EventData, le.EventCount, le.UserName, le.BlogId,
584
+ led.EventType, led.EventDescription
585
+ FROM `$t1` as le
586
+ INNER JOIN `$t2` as led
587
+ ON le.EventID = led.EventID
588
+ WHERE ($blogId = 0) OR (le.BlogId = $blogId)
589
+ ORDER BY $orderBy
590
+ $sort
591
+ LIMIT $limit;";
592
  return $wpdb->get_results($query, ARRAY_A);
593
  }
594
 
625
  self::_addLogEvent(1001, wp_get_current_user()->ID);
626
  }
627
 
628
+
629
  /**
630
  * @internal
631
  * Hooks to the user register event
642
  $nu = $uInfo['userName'];
643
  $nur = ucfirst($uInfo['userRole']);
644
 
645
+ wpphLog(__METHOD__.'() -> USER INFO', array('user_id'=>$user_id, 'current_user'=>$current_user, 'user_info'=>$uInfo));
646
+
647
  if($un == 'System')
648
  {
649
  // A new user with the username %username% has registered with the role of %user_role%
662
  * @internal
663
  * Hooks to the events deletion event
664
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
665
  static function __deleteEvents()
666
  {
667
+ wpphLog(__METHOD__.'() triggered.');
668
+
669
  // check settings and delete the events (if any)
670
  $settings = WPPH::getPluginSettings();
671
 
672
+ $runCleanup = ((time() - $settings->lastCleanup) < WPPH_CLEANUP_WAIT_TIME);
673
+ if(! $runCleanup){
674
+ wpphLog(__METHOD__.'() Ignored. Not enough time elapsed between deletion requests.');
675
+ return;
 
 
 
676
  }
677
 
678
  // check to see how we should do the cleanup (by days or by number)
709
  // delete by days
710
  private static function _deleteEventsOlderThan($days = 1)
711
  {
 
712
  global $wpdb;
713
+
714
+ // run for each blog
715
+ if(WPPH::isMultisite())
716
+ {
717
+ $old_blog = $wpdb->blogid;
718
+ $blogIds = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
719
+ foreach ($blogIds as $blog_id)
720
+ {
721
+ switch_to_blog($blog_id);
722
+ $query = sprintf("DELETE FROM ".WPPHDatabase::getFullTableName('main')." WHERE BlogID=%d EventDate < (NOW() - INTERVAL %d DAY)",$blog_id, $days);
723
+ $result = $wpdb->query($query);
724
+ if($result === false){ $status = 'Error executing query'; }
725
+ else { $status = 'Query executed'; }
726
+ wpphLog(__METHOD__.'('.$days.') called for blog: '.$blog_id.'.', array('query'=>$query, 'status'=>$status, 'rowsDeleted'=> (int)$result));
727
+ }
728
+ switch_to_blog($old_blog);
729
+ return true;
730
+ }
731
+ else {
732
+ $query = sprintf("DELETE FROM ".WPPHDatabase::getFullTableName('main')." WHERE EventDate < (NOW() - INTERVAL %d DAY)", $days);
733
+ $result = $wpdb->query($query);
734
+ if($result === false){ $status = 'Error executing query'; }
735
+ else { $status = 'Query executed'; }
736
+ wpphLog(__METHOD__.'('.$days.') called.', array('query'=>$query, 'status'=>$status, 'rowsDeleted'=> (int)$result));
737
+ return ($result !== false);
738
+ }
739
+
740
  }
741
  //@internal
742
  // delete by number
743
  private static function _deleteEventsGreaterThan($number = WPPH_KEEP_MAX_EVENTS)
744
  {
 
745
  global $wpdb;
746
+ if($number > WPPH_KEEP_MAX_EVENTS){ $number = WPPH_KEEP_MAX_EVENTS; }
747
  $tableName = WPPHDatabase::getFullTableName('main');
748
+
749
+ // run for each blog
750
+ if(WPPH::isMultisite())
 
 
 
 
751
  {
752
+ $old_blog = $wpdb->blogid;
753
+ $blogIds = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
754
+ foreach ($blogIds as $blog_id)
755
+ {
756
+ switch_to_blog($blog_id);
757
+ $count = $wpdb->get_var(sprintf("SELECT COUNT(0) FROM $tableName WHERE BlogID=%d",$blog_id));
758
+ if(empty($count)){
759
+ wpphLog(__METHOD__.'('.$number.') called for blog id: '.$blog_id.'. Ignored, there are no events for this blog id in the database.');
760
+ continue;
761
+ }
762
+ $keep = $number;
763
+ if($count > $keep)
764
+ {
765
+ $limit = $count - $keep;
766
+ $query = sprintf("DELETE FROM $tableName WHERE BlogID=%d ORDER BY EventDate LIMIT %d", $blog_id, $limit);
767
+ $result = $wpdb->query($query);
768
+ if($result === false){ $status = 'Error executing query'; }
769
+ else { $status = 'Query executed'; }
770
+ wpphLog(__METHOD__.'('.$number.') called for blog id: '.$blog_id.'.', array('query'=>$query, 'status'=>$status, 'rowsAffected'=> (int)$result));
771
+ return ($result !== false);
772
+ }
773
+ else {
774
+ wpphLog(__METHOD__.'('.$number.') called for blog id: '.$blog_id.'. Ignored, there are not enough events to perform this action.');
775
+ continue;
776
+ }
777
+ }
778
+ switch_to_blog($old_blog);
779
+ return true;
780
  }
781
  else {
782
+ $count = $wpdb->get_var("SELECT COUNT(0) FROM $tableName");
783
+ if(empty($count)){
784
+ wpphLog(__METHOD__.'('.$number.') called. Ignored, there are no events in the database');
785
+ return true;
786
+ }
787
+ $keep = $number;
788
+ if($count > $keep)
789
+ {
790
+ $limit = $count - $keep;
791
+ $query = "DELETE FROM $tableName ORDER BY EventDate LIMIT $limit";
792
+ $result = $wpdb->query($query);
793
+ if($result === false){ $status = 'Error executing query'; }
794
+ else { $status = 'Query executed'; }
795
+ wpphLog(__METHOD__.'('.$number.') called.', array('query'=>$query, 'status'=>$status, 'rowsAffected'=> (int)$result));
796
+ return ($result !== false);
797
+ }
798
+ else {
799
+ wpphLog(__METHOD__.'('.$number.') called. Ignored, there are not enough events to trigger this action.');
800
+ return true;
801
+ }
802
  }
803
  }
804
 
814
 
815
  static function watchUserInfoUpdated($userID)
816
  {
817
+ wpphLog(__METHOD__.'() triggered by hook.', array('POST DATA'=>$_POST));
818
 
819
  // get info for the currently logged in user
820
  $current_user = wp_get_current_user();
832
  if(!empty($_POST['role'])){
833
  $updatedRole = trim($_POST['role']);
834
  if(self::_userRoleUpdated($cid, $initialUserRole, $updatedRole, $editedUserName, $cName)){
835
+ //return;
836
  }
837
  }
838
 
839
  // If a user's password has been updated
840
  if(!empty($_POST['pass1'])){
841
  if(self::_userPasswordUpdated($userID, $cid, $cName, $editedUserName, $initialUserRole)){
842
+ // return;
843
  }
844
  }
845
 
975
  {
976
  wpphLog(__METHOD__.'() triggered by hook.');
977
 
978
+ $userID = wp_get_current_user()->ID;
979
+ $userIP = WPPHUtil::getIP();
980
 
981
  // activate one by link
982
+ if(isset($_GET['action']) && ($_GET['action']=='activate') || isset($_GET['action2']) && ($_GET['action2']=='activate'))
983
  {
984
+ wpphLog('------------------------------- 1 ------------------------------');
985
+ $pluginFile = isset($_GET['plugin']) ? $_GET['plugin'] : null;
986
+ if(empty($pluginFile)){
987
+ wpphLog("EMPTY plugin param in GET");
988
+ return;
989
+ }
990
+ $fp = WP_PLUGIN_DIR.'/'.$pluginFile;
991
+ if(! is_file($fp)){
992
+ wpphLog("Plugin not found", array('filePath'=>$fp));
993
+ return;
994
+ }
995
+ $pluginData = get_plugin_data($fp,false,false);
996
+ self::_addLogEvent(5001, $userID, $userIP, array($pluginData['Name'],$pluginFile));
997
  wpphLog('Plugin activated.', array('plugin file'=>$pluginFile));
998
+ return;
999
  }
1000
  // one by bulk
1001
+ elseif(isset($_POST['action']) && ($_POST['action'] == 'activate-selected') || (isset($_POST['action2']) && ($_POST['action2'] == 'activate-selected')))
1002
  {
1003
+ wpphLog('------------------------------- 2 ------------------------------');
1004
  if(! empty($_POST['checked']))
1005
  {
1006
+ foreach($_POST['checked'] as $k=>$pluginFile)
1007
+ {
1008
+ if(empty($pluginFile)){
1009
+ wpphLog("EMPTY plugin param in POST");
1010
+ return;
1011
+ }
1012
+ $fp = WP_PLUGIN_DIR.'/'.$pluginFile;
1013
+ if(! is_file($fp)){
1014
+ wpphLog("Plugin not found", array('filePath'=>$fp));
1015
+ return;
1016
+ }
1017
+ $pluginData = get_plugin_data($fp,false,false);
1018
+ self::_addLogEvent(5001, $userID, $userIP, array($pluginData['Name'],$pluginFile));
1019
  wpphLog('Plugin activated.', array('plugin file'=>$pluginFile));
1020
  }
1021
  }
1022
  }
1023
  // more by bulk
1024
+ elseif(isset($_POST['activate-multi']) && ($_POST['action']=='activate-selected' || (isset($_POST['action2']) && $_POST['action2']=='activate-selected')))
1025
  {
1026
+ wpphLog('------------------------------- 3 ------------------------------');
1027
  if(! empty($_POST['checked']))
1028
  {
1029
+ foreach($_POST['checked'] as $k=>$pluginFile)
1030
+ {
1031
+ if(empty($pluginFile)){
1032
+ wpphLog("EMPTY plugin param in POST");
1033
+ return;
1034
+ }
1035
+ $fp = WP_PLUGIN_DIR.'/'.$pluginFile;
1036
+ if(! is_file($fp)){
1037
+ wpphLog("Plugin not found", array('filePath'=>$fp));
1038
+ return;
1039
+ }
1040
+ $pluginData = get_plugin_data($fp,false,false);
1041
+ self::_addLogEvent(5001, $userID, $userIP, array($pluginData['Name'],$pluginFile));
1042
  wpphLog('Plugin activated.', array('plugin file'=>$pluginFile));
1043
  }
1044
  }
1050
  wpphLog(__METHOD__.'() triggered by hook.');
1051
 
1052
  // get info for the currently logged in user
1053
+ $userID = wp_get_current_user()->ID;
1054
+ $userIP = WPPHUtil::getIP();
1055
 
1056
  // activate one by link
1057
+ if((isset($_GET['action']) && $_GET['action']=='deactivate') || isset($_GET['action2']) && ($_GET['action2']=='deactivate'))
1058
  {
1059
+ wpphLog('------------------------------- 1 ------------------------------');
1060
  $pluginFile = $_GET['plugin'];
1061
  $pluginData = get_plugin_data(WP_PLUGIN_DIR.'/'.$pluginFile,false,false);
1062
  $pluginName = $pluginData['Name'];
1063
+ self::_addLogEvent(5002, $userID, $userIP, array($pluginName,$pluginFile));
1064
  wpphLog('Plugin deactivated.', array('plugin file'=>$pluginFile));
1065
  }
1066
  // one by bulk
1067
+ elseif((isset($_POST['action']) && $_POST['action'] == 'deactivate-selected') || isset($_POST['action2']) && ($_POST['action2'] == 'deactivate-selected'))
1068
  {
1069
  if(! empty($_POST['checked']))
1070
  {
1071
+ wpphLog('------------------------------- 2 ------------------------------');
1072
  foreach($_POST['checked'] as $k=>$pluginFile){
1073
  $pluginData = get_plugin_data(WP_PLUGIN_DIR.'/'.$pluginFile,false,false);
1074
  $pluginName = $pluginData['Name'];
1075
+ self::_addLogEvent(5002, $userID, $userIP, array($pluginName,$pluginFile));
1076
  wpphLog('Plugin deactivated.', array('plugin file'=>$pluginFile));
1077
  }
1078
  }
1079
  }
1080
  // more by bulk
1081
+ elseif(isset($_GET['deactivate-multi']) && (isset($_POST['action']) && $_POST['action']=='deactivate-selected' || (isset($_POST['action2']) && $_POST['action2']=='deactivate-selected')))
1082
  {
1083
  if(! empty($_POST['checked']))
1084
  {
1085
+ wpphLog('------------------------------- 3 ------------------------------');
1086
  foreach($_POST['checked'] as $k=>$pluginFile){
1087
  $pluginData = get_plugin_data(WP_PLUGIN_DIR.'/'.$pluginFile,false,false);
1088
  $pluginName = $pluginData['Name'];
1089
+ self::_addLogEvent(5002, $userID, $userIP, array($pluginName,$pluginFile));
1090
  wpphLog('Plugin deactivated.', array('plugin file'=>$pluginFile));
1091
  }
1092
  }
1093
  }
1094
  }
1095
+
1096
  // # 5000
1097
  static function watchPluginInstall()
1098
  {
1099
  if(defined('WPPH_PLUGIN_INSTALLED_OK')){ return; }
1100
  if(empty($_GET)) { return; }
1101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1102
  if(isset($_GET['action']) && $_GET['action']=='install-plugin'){
1103
  wpphLog(__METHOD__.'() triggered by hook.');
1104
+ wpph_installPlugin($_GET['plugin'], wp_get_current_user()->ID, WPPHUtil::getIP());
1105
  }
1106
  elseif(isset($_GET['action2']) && $_GET['action2']=='install-plugin'){
1107
  wpphLog(__METHOD__.'() triggered by hook.');
1108
+ wpph_installPlugin($_GET['plugin'], wp_get_current_user()->ID, WPPHUtil::getIP());
1109
  }
1110
  }
1111
  // # 5003
1135
  // # 5004
1136
  static function watchPluginUpgrade()
1137
  {
1138
+ wpphLog(__METHOD__.'() triggered.');
1139
+
1140
  $current_user = wp_get_current_user();
1141
  $userID = $current_user->ID;
1142
  $ip = WPPHUtil::getIP();
1199
  wpphLog(__METHOD__.'. POST STATUS DATA', array(
1200
  '$oldStatus' => $oldStatus,
1201
  '$newStatus' => $newStatus,
1202
+ '$postStatus' => $post->post_status,
1203
  '$post' => $post
1204
  ));
1205
 
1221
  $postUrl = get_permalink($postID);
1222
  $postStatus = $post->post_status;
1223
  $currentUserID = wp_get_current_user()->ID;
1224
+ $userID = $postAuthorID = (int)$post->post_author;
1225
  if($currentUserID != $postAuthorID){
1226
  // someone else is doing this
1227
  $userID = $currentUserID;
1256
 
1257
  WPPHPost::$currentPostType = $post->post_type;
1258
 
 
1259
  global $wpdb;
1260
 
1261
  //## 2025 & 2026 & 2040
1276
  $authorChanged = false;
1277
  if(isset($GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID']))
1278
  {
1279
+ $quickFormEnabled = isset($GLOBALS['WPPH_SCREEN_EDITOR_ENABLED']) ? true : false;
1280
  if($customPostType){
1281
+ if(WPPHPost::postAuthorChanged((int)$GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID'], $postID, $userID, $postTitle, 2038, $quickFormEnabled)){
 
1282
  $GLOBALS['WPPH_POST_AUTHOR_UPDATED'] = true;
1283
  $authorChanged = true;
1284
  }
1285
  }
1286
  else {
1287
+ if(WPPHPost::postAuthorChanged((int)$GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID'], $postID, $userID, $postTitle, ($postTypePost) ? 2019 : 2020, $quickFormEnabled)){
 
1288
  $GLOBALS['WPPH_POST_AUTHOR_UPDATED'] = true;
1289
  $authorChanged = true;
1290
  }
1291
  }
1292
+ unset($GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID']);
1293
  }
1294
 
1295
  // 2000 & 2004 & 2029
1386
  {
1387
  $event = 0;
1388
  if($customPostType) { $event = 2039;}
1389
+ elseif($postTypePost) { $event = 2021; }
1390
+ elseif($postTypePage) { $event = 2022; }
1391
  if(! empty($event)){
1392
  WPPHPost::postStatusChanged($postTitle, __('Published'), __('Draft'), $userID, $event);
1393
  }
1743
  wpphLog(__METHOD__.'() triggered.');
1744
  $data = (isset($GLOBALS['WPPH_WIDGET_MOVE']) ? $GLOBALS['WPPH_WIDGET_MOVE'] : null);
1745
  if(empty($data)){
1746
+ wpphLog("Global var: WPPH_WIDGET_MOVE not available yet. Nothing to do here.");
1747
  return;
1748
  }
1749
  $from = $data['from'];
1750
  $to = $data['to'];
 
1751
  global $wp_registered_sidebars;
 
1752
  if(preg_match("/^sidebar-/", $from)){ $from = (isset($wp_registered_sidebars[$from]) ? $wp_registered_sidebars[$from]['name'] : $from); }
1753
  if(preg_match("/^sidebar-/", $to)){ $to = (isset($wp_registered_sidebars[$to]) ? $wp_registered_sidebars[$to]['name'] : $to); }
 
1754
  self::_addLogEvent(2045, $data['user'], $data['ip'], array($data['widget'], $from, $to));
1755
  }
1756
 
1839
  // 2025, 2026
1840
  static function watchPostVisibilityChange($oldStatus, $newStatus, $userID, $postTitle, $post, $event)
1841
  {
1842
+ wpphLog(__METHOD__.'() triggered.', array('params'=>func_get_args()));
1843
 
1844
  global $wpdb;
1845
 
1852
  // pwd protected -> public
1853
  if($oldStatus == 'publish' && $newStatus == 'publish')
1854
  {
1855
+ if(! WPPH::isMultisite()){
1856
+ // if post is already pwd protected and there is no change, it will still be issued an event: public to pwd protected
1857
+ if(isset($GLOBALS['WPPH_POST_PWD_PROTECTED']) && $GLOBALS['WPPH_POST_PWD_PROTECTED']){
1858
+ $GLOBALS['WPPH_PREVENT_BUBBLE'] = true;
1859
+ wpphLog(__METHOD__.'() No change.');
1860
+ return;
1861
+ }
1862
  }
1863
+
1864
  // pwd protected -> public
1865
  if(empty($crtPostPassword) && !empty($oldPostPassword)){
1866
  $from = __('Password Protected');
1908
  }
1909
  }
1910
  }
1911
+ wpphLog("Changing post visibility:",array('from'=>$from, 'to'=>$to));
1912
  if(empty($from) || empty($to)){
1913
  return;
1914
  }
1958
  }
1959
 
1960
  static function watchPostCategoriesChange($post, $wpdb, $postTitle, $event)
1961
+ {
1962
  wpphLog(__METHOD__.'() triggered.');
1963
 
1964
+ if(! wpph_isEventEnabled($event)){
1965
+ wpphLog('Event '.$event.' is not enabled. Ignoring request.');
1966
+ return true;
1967
+ }
1968
+
1969
  if(isset($GLOBALS['WPPH_POST_OLD_CATEGORIES']))
1970
  {
1971
  $originalCats = $GLOBALS['WPPH_POST_OLD_CATEGORIES'];
1976
  }
1977
  $categories_2 = array();
1978
  $newCats = $post->post_category;
1979
+ if(empty($newCats)){
1980
+ wpphLog('No categories found for this post.');
1981
+ return true;
1982
  }
1983
+ wpphLog('$newCats', $newCats);
1984
  foreach($newCats as $catID){
1985
+ if(empty($catID)){
1986
+ wpphLog('Category is empty: '.$catID);
1987
+ continue;
1988
+ }
1989
  $cat = get_category($catID);
1990
  array_push($categories_2, $cat->name);
1991
  }
2044
  }
2045
  return false;
2046
  }
2047
+
2048
+
2049
+ // 7000 new site added to network
2050
+ static function watchBlogAdded($blog_id, $user_id)
2051
+ {
2052
+ if(empty($blog_id)) { return; }
2053
+ $blogName = WPPHNetwork::getBlogName($blog_id);
2054
+ if(empty($blogName)) { return; }
2055
+ $currentBlogID = WPPHNetwork::getGlobalOption(WPPH_MAIN_SITE_ID_OPTION_NAME, false, true);
2056
+ WPPHEvent::_addLogEvent(7000, wp_get_current_user()->ID, WPPHUtil::getIP(), array($blogName), null, $currentBlogID);
2057
+ wpphLog(__METHOD__.'() triggered by hook. Blog added: '.$blogName.'; user ID = '.$user_id);
2058
+ }
2059
+
2060
+ // 7001 - blog archived
2061
+ static function watchBlogArchived($blog_id)
2062
+ {
2063
+ if(empty($blog_id)) { return; }
2064
+ $blogName = WPPHNetwork::getBlogName($blog_id);
2065
+ if(empty($blogName)) { return; }
2066
+ $currentBlogID = WPPHNetwork::getGlobalOption(WPPH_MAIN_SITE_ID_OPTION_NAME, false, true);
2067
+ WPPHEvent::_addLogEvent(7001, wp_get_current_user()->ID, WPPHUtil::getIP(), array($blogName), null, $currentBlogID);
2068
+ wpphLog(__METHOD__.'() triggered by hook. Blog archived: '.$blogName);
2069
+ }
2070
+
2071
+ // 7002 - blog unarchived
2072
+ static function watchBlogUnarchived($blog_id)
2073
+ {
2074
+ if(empty($blog_id)) { return; }
2075
+ $blogName = WPPHNetwork::getBlogName($blog_id);
2076
+ if(empty($blogName)) { return; }
2077
+ $currentBlogID = WPPHNetwork::getGlobalOption(WPPH_MAIN_SITE_ID_OPTION_NAME, false, true);
2078
+ WPPHEvent::_addLogEvent(7002, wp_get_current_user()->ID, WPPHUtil::getIP(), array($blogName), null, $currentBlogID);
2079
+ wpphLog(__METHOD__.'() triggered by hook. Blog unarchived: '.$blogName);
2080
+ }
2081
+
2082
+ // 7003 - blog activated
2083
+ static function watchBlogActivated($blog_id)
2084
+ {
2085
+ if(empty($blog_id)) { return; }
2086
+ $blogName = WPPHNetwork::getBlogName($blog_id);
2087
+ if(empty($blogName)) { return; }
2088
+ $currentBlogID = WPPHNetwork::getGlobalOption(WPPH_MAIN_SITE_ID_OPTION_NAME, false, true);
2089
+ WPPHEvent::_addLogEvent(7003, wp_get_current_user()->ID, WPPHUtil::getIP(), array($blogName), null, $currentBlogID);
2090
+ wpphLog(__METHOD__.'() triggered by hook. Blog activated: '.$blogName);
2091
+ }
2092
+
2093
+ // 7004 - blog deactivated
2094
+ static function watchBlogDeactivated($blog_id)
2095
+ {
2096
+ if(empty($blog_id)) { return; }
2097
+ $blogName = WPPHNetwork::getBlogName($blog_id);
2098
+ if(empty($blogName)) { return; }
2099
+ $currentBlogID = WPPHNetwork::getGlobalOption(WPPH_MAIN_SITE_ID_OPTION_NAME, false, true);
2100
+ WPPHEvent::_addLogEvent(7004, wp_get_current_user()->ID, WPPHUtil::getIP(), array($blogName), null, $currentBlogID);
2101
+ wpphLog(__METHOD__.'() triggered by hook. Blog deactivated: '.$blogName);
2102
+ }
2103
+
2104
+ // 7005 - blog deleted
2105
+ static function watchBlogDeleted($blog_id)
2106
+ {
2107
+ if(empty($blog_id)) { return; }
2108
+ $blogName = WPPHNetwork::getBlogName($blog_id);
2109
+ if(empty($blogName)) { return; }
2110
+ $currentBlogID = WPPHNetwork::getGlobalOption(WPPH_MAIN_SITE_ID_OPTION_NAME, false, true);
2111
+ WPPHEvent::_addLogEvent(7005, wp_get_current_user()->ID, WPPHUtil::getIP(), array($blogName), null, $currentBlogID);
2112
+ wpphLog(__METHOD__.'() triggered by hook. Blog deleted: ', array('id'=>$blog_id, 'name'=>$blogName));
2113
+ }
2114
+
2115
+ // 4008 && 4009
2116
+ static function watchUserAdminPrivUpdated($userID)
2117
+ {
2118
+ wpphLog(__METHOD__.'() triggered by hook.');
2119
+ wpphLog('POST DATA', $_POST);
2120
+
2121
+ // 4008
2122
+ if(isset($_POST['super_admin']) && !empty($_POST['super_admin']))
2123
+ {
2124
+ $bid = WPPHNetwork::getGlobalOption(WPPH_MAIN_SITE_ID_OPTION_NAME, false, true);
2125
+ $userName = trim($_POST['display_name']);
2126
+ WPPHEvent::_addLogEvent(4008, wp_get_current_user()->ID, WPPHUtil::getIP(), array($userName), null, $bid);
2127
+ }
2128
+ // 4009
2129
+ else {
2130
+ $bid = WPPHNetwork::getGlobalOption(WPPH_MAIN_SITE_ID_OPTION_NAME, false, true);
2131
+ $superAdmins = get_super_admins();
2132
+ $u = new WP_User($userID);
2133
+ $userName = $u->get('user_login');
2134
+ if(! empty($superAdmins)){
2135
+ foreach($superAdmins as $admin){
2136
+ if($admin == $userName){
2137
+ WPPHEvent::_addLogEvent(4009, wp_get_current_user()->ID, WPPHUtil::getIP(), array($userName), null, $bid);
2138
+ return;
2139
+ }
2140
+ }
2141
+ }
2142
+ }
2143
+ }
2144
+
2145
+ // 4010
2146
+ static function watchUserAddedToBlog($user_id, $role, $blog_id)
2147
+ {
2148
+ wpphLog(__METHOD__.'() triggered with params: ', array(
2149
+ '$user_id' => $user_id,
2150
+ '$role' => $role,
2151
+ '$blog_id' => $blog_id
2152
+ ));
2153
+
2154
+ // current blog id
2155
+ $currentBlogID = WPPHNetwork::getGlobalOption(WPPH_MAIN_SITE_ID_OPTION_NAME, false, true);
2156
+
2157
+ // get current user info
2158
+ $userInfo = WPPHDB::getUserInfo($user_id);
2159
+ $userName = $userInfo['userName'];
2160
+ $siteName = WPPHNetwork::getBlogName($blog_id);
2161
+
2162
+ WPPHEvent::_addLogEvent(4010, wp_get_current_user()->ID, WPPHUtil::getIP(), array($userName, $role, $siteName), null, $currentBlogID);
2163
+ wpphLog('User added to site.');
2164
+ }
2165
+
2166
+ // 4011
2167
+ static function watchUserRemovedFromBlog($user_id)
2168
+ {
2169
+ $blog_id = (isset($_REQUEST['id']) ? $_REQUEST['id'] : 0);
2170
+ wpphLog(__METHOD__.'() triggered with params: ', array(
2171
+ '$user_id' => $user_id,
2172
+ '$blog_id' => $blog_id
2173
+ ));
2174
+
2175
+ $currentBlogID = WPPHNetwork::getGlobalOption(WPPH_MAIN_SITE_ID_OPTION_NAME, false, true);
2176
+
2177
+ // get current user info
2178
+ $userInfo = WPPHDB::getUserInfo($user_id);
2179
+ $userName = $userInfo['userName'];
2180
+ $userRole = $userInfo['userRole'];
2181
+ $siteName = WPPHNetwork::getBlogName($blog_id);
2182
+
2183
+ if(empty($currentBlogID) || empty($userName) || empty($userRole) || empty($siteName)){
2184
+ wpphLog('Cannot trigger the event 4011. One or more required variables are empty.', array(
2185
+ '$currentBlogID' => $currentBlogID,
2186
+ '$userName' => $userName,
2187
+ '$userRole' => $userRole,
2188
+ '$siteName' => $siteName,
2189
+ ));
2190
+ return;
2191
+ }
2192
+
2193
+ WPPHEvent::_addLogEvent(4011, wp_get_current_user()->ID, WPPHUtil::getIP(), array($userName, $userRole, $siteName), null, $currentBlogID);
2194
+ wpphLog('User removed from site.');
2195
+ }
2196
+
2197
+ // 4012
2198
+ static function watchWpmuUserRegister($user_id)
2199
+ {
2200
+ wpphLog(__METHOD__.'() triggered with params: ', array('$user_id' => $user_id));
2201
+
2202
+ $currentBlogID = WPPHNetwork::getGlobalOption(WPPH_MAIN_SITE_ID_OPTION_NAME, false, true);
2203
+ $userInfo = WPPHDB::getUserInfo($user_id);
2204
+ $userName = $userInfo['userName'];
2205
+
2206
+ WPPHEvent::_addLogEvent(4012, wp_get_current_user()->ID, WPPHUtil::getIP(), array($userName), null, $currentBlogID);
2207
+ wpphLog('Created new network user.');
2208
+ }
2209
+
2210
+
2211
+
2212
  }
inc/WPPHNetwork.php ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class wpphNetwork
4
+ */
5
+ class WPPHNetwork
6
+ {
7
+ // runs per site
8
+ static function _activate($blogId=1)
9
+ {
10
+ wpphLog("Activating plugin for blog: $blogId");
11
+
12
+ // Network ID
13
+ update_option(WPPH_NETWORK_ID_OPTION_NAME, (defined('SITE_ID_CURRENT_SITE') ? SITE_ID_CURRENT_SITE : 1));
14
+ // Main Site ID
15
+ update_option(WPPH_MAIN_SITE_ID_OPTION_NAME, (defined('BLOG_ID_CURRENT_SITE') ? BLOG_ID_CURRENT_SITE : 1));
16
+
17
+ if(WPPH::isMultisite())
18
+ {
19
+ // if main site
20
+ if(WPPHUtil::isMainSite()){
21
+ WPPH::createPluginDefaultSettings();
22
+ }
23
+ // nothing to do here
24
+ else {
25
+ update_option('WPPH_PLUGIN_ACTIVATED',1);
26
+ wpphLog("Plugin activated successfully for blog: $blogId");
27
+ return true;
28
+ }
29
+ }
30
+
31
+ $ok = WPPH::onPluginActivate($blogId);
32
+ if($ok)
33
+ {
34
+ update_option('WPPH_PLUGIN_ACTIVATED',1);
35
+ wpphLog("Plugin activated successfully for blog: $blogId");
36
+ }
37
+ else { wpphLog("Plugin could not be activated for blog: $blogId"); }
38
+ }
39
+ // runs per site
40
+ static function _deactivate($blogId=1){
41
+ wpphLog("Deactivating plugin for blog: $blogId");
42
+ $ok = WPPH::onPluginDeactivate($blogId);
43
+ if($ok){
44
+ wpphLog("Plugin deactivated successfully for blog: $blogId");
45
+ }
46
+ else { wpphLog("Plugin could not be deactivated for blog: $blogId"); }
47
+ }
48
+ // runs per site
49
+ static function _uninstall($blogId=1){
50
+ wpphLog("Uninstalling plugin from blog: $blogId");
51
+
52
+ //check first for the wpph_plugin_activated for each site and if active first deactivate and then uninstall
53
+ $active = (int)get_option('WPPH_PLUGIN_ACTIVATED');
54
+ if(!empty($active)){
55
+ self::_deactivate($blogId);
56
+ }
57
+
58
+ global $wpdb;
59
+
60
+ // check if any tables created for a particular blog inside the network exist
61
+ $prefix = $wpdb->prefix;
62
+
63
+ if(empty($blogId) || $blogId == 1){}
64
+ else { $prefix .= $blogId.'_'; }
65
+
66
+ $wpdb->query("DROP TABLE IF EXISTS ".$prefix.'_wordpress_eventlog');
67
+ $wpdb->query("DROP TABLE IF EXISTS ".$prefix.'_wordpress_eventlog_details');
68
+ $wpdb->query("DROP TABLE IF EXISTS ".$prefix.'wordpress_auditlog');
69
+ $wpdb->query("DROP TABLE IF EXISTS ".$prefix.'wordpress_auditlog_events');
70
+
71
+ delete_option('WPPH_CRON_TASK_NAME');
72
+ delete_option('WPPH_NETWORK_INSTALL');
73
+ delete_option('WPPH_PLUGIN_ACTIVATED');
74
+ delete_option(WPPH_MAIN_SITE_ID_OPTION_NAME);
75
+ delete_option(WPPH_NETWORK_ID_OPTION_NAME);
76
+ delete_option(WPPH_PLUGIN_ALLOW_ACCESS_OPTION_NAME);
77
+ delete_option(WPPH_PLUGIN_ALLOW_CHANGE_OPTION_NAME);
78
+ delete_option(WPPH_PLUGIN_DB_UPDATED);
79
+ delete_option(WPPH_PLUGIN_SETTING_NAME);
80
+ delete_option(WPPH_PLUGIN_EVENTS_LIST_OPTION_NAME);
81
+ delete_option(WPPH_PLUGIN_VERSION_OPTION_NAME);
82
+ delete_option(WPPH_USERS_CAN_REGISTER_OPT_NAME);
83
+ delete_option(WPPH_PLUGIN_ERROR_OPTION_NAME);
84
+ wpphLog("Plugin successfully uninstalled.");
85
+ }
86
+
87
+ static function networkActivate($networkwide=false)
88
+ {
89
+ global $wpdb;
90
+ if (WPPH::isMultisite()) {
91
+ // check if it is a network activation - if so, run the activation function for each blog id
92
+ if ($networkwide)
93
+ {
94
+ $old_blog = $wpdb->blogid;
95
+ $blogids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");
96
+ foreach ($blogids as $blog_id) {
97
+ switch_to_blog($blog_id);
98
+ self::_activate($blog_id);
99
+ }
100
+ switch_to_blog($old_blog);
101
+ update_option('WPPH_NETWORK_INSTALL',1);
102
+ return;
103
+ }
104
+ }
105
+ update_option('WPPH_NETWORK_INSTALL',0);
106
+ self::_activate($wpdb->blogid);
107
+ }
108
+
109
+ static function networkDeactivate($networkwide=false){
110
+ global $wpdb;
111
+ if (WPPH::isMultisite()) {
112
+ // check if it is a network activation - if so, run the activation function
113
+ // for each blog id
114
+ if ($networkwide) {
115
+ $old_blog = $wpdb->blogid;
116
+ // Get all blog ids
117
+ $blogids = $wpdb->get_col("SELECT blog_id FROM {$wpdb->blogs}");
118
+ foreach ($blogids as $blog_id) {
119
+ switch_to_blog($blog_id);
120
+ self::_deactivate($blog_id);
121
+ }
122
+ switch_to_blog($old_blog);
123
+ return;
124
+ }
125
+ }
126
+ self::_deactivate($wpdb->blogid);
127
+ }
128
+
129
+ static function networkUninstall(){
130
+ global $wpdb;
131
+ if (WPPH::isMultisite()) {
132
+ $old_blog = $wpdb->blogid;
133
+ // Get all blog ids
134
+ $blogids = $wpdb->get_col("SELECT blog_id FROM {$wpdb->blogs}");
135
+ foreach ($blogids as $blog_id) {
136
+ switch_to_blog($blog_id);
137
+ self::_uninstall($blog_id);
138
+ }
139
+ switch_to_blog($old_blog);
140
+ return;
141
+ }
142
+ self::_uninstall();
143
+ }
144
+
145
+ /**
146
+ * Retrieve the list of all blogs in the network
147
+ * @return array( blogID => blogName )
148
+ */
149
+ static function getBlogsList()
150
+ {
151
+ global $wpdb;
152
+ $out = array();
153
+ $results = $wpdb->get_results("SELECT blog_id FROM $wpdb->blogs WHERE public = 1 ORDER BY blog_id", ARRAY_A);
154
+ if(empty($results)){
155
+ return $out;
156
+ }
157
+ $basePrefix = WPPHDatabase::getDefaultPrefix();
158
+ foreach($results as $entry){
159
+ $blogID = $entry['blog_id'];
160
+ if($blogID == 1){
161
+ $blogName = $wpdb->get_var("SELECT option_value FROM ".$basePrefix."options WHERE option_name = 'blogname';");
162
+ }
163
+ else { $blogName = $wpdb->get_var("SELECT option_value FROM ".$basePrefix.$blogID."_options WHERE option_name = 'blogname';"); }
164
+ $out[$blogID] = $blogName;
165
+ }
166
+ return $out;
167
+ }
168
+
169
+ static function getBlogName($blogID)
170
+ {
171
+ global $wpdb;
172
+ $basePrefix = WPPHDatabase::getDefaultPrefix();
173
+ if(empty($blogID) || (int)$blogID == 1){
174
+ $table = $wpdb->prefix . 'options';
175
+ }
176
+ else { $table = $basePrefix.$blogID.'_options'; }
177
+ return $wpdb->get_var("SELECT option_value FROM {$table} WHERE option_name = 'blogname';");
178
+ }
179
+
180
+ /**
181
+ * Retrive the value of a global option
182
+ * @param $optionName
183
+ * @param bool $unserialize
184
+ * @param bool $isConstant
185
+ * @param null $default The default value to return if option not found
186
+ * @return mixed string if $unserialize = false, otherwise array
187
+ */
188
+ static function getGlobalOption($optionName, $unserialize = false, $isConstant = false, $default = null)
189
+ {
190
+ global $wpdb;
191
+ $table = WPPHDatabase::getDefaultPrefix();
192
+ if($isConstant){
193
+ $optionName = "'{$optionName}'";
194
+ }
195
+ $query = "SELECT option_value FROM {$table}options WHERE option_name = {$optionName}";
196
+ wpphLog(__METHOD__.'() -> Query executed: '.$query);
197
+ $result = $wpdb->get_var($query);
198
+ if(is_null($result)){
199
+ return $default;
200
+ }
201
+ if($unserialize)
202
+ {
203
+ if(! is_array($result)){
204
+ $result = unserialize($result);
205
+ }
206
+ }
207
+ return $result;
208
+ }
209
+
210
+ /**
211
+ * Update a global option
212
+ * @param string $optionName
213
+ * @param mixed $optionValue
214
+ * @param bool $serialize
215
+ * @param bool $isConstant
216
+ * @return bool
217
+ */
218
+ static function updateGlobalOption($optionName, $optionValue, $serialize = false, $isConstant = false)
219
+ {
220
+ global $wpdb;
221
+ $table = WPPHDatabase::getDefaultPrefix().'options';
222
+ if($isConstant){ $optionName = "'{$optionName}'"; }
223
+ if($serialize){ $optionValue = serialize($optionValue); }
224
+ $query = "UPDATE $table SET option_value = '$optionValue' WHERE option_name = $optionName";
225
+ wpphLog(__METHOD__.'() -> Executing query: '.$query);
226
+ $result = $wpdb->query($query);
227
+ return (is_null($result) ? false : true);
228
+ }
229
+
230
+ static function addGlobalOption($optionName, $optionValue, $serialize = false, $isConstant = false)
231
+ {
232
+ $r = self::getGlobalOption($optionName, $serialize, $isConstant, null);
233
+ if(! is_null($r)){
234
+ return true;
235
+ }
236
+ global $wpdb;
237
+ $table = WPPHDatabase::getDefaultPrefix().'options';
238
+ if($isConstant || is_string($optionName)){ $optionName = "'{$optionName}'"; }
239
+ if($serialize || is_array($optionValue) || is_object($optionValue)){ $optionValue = "'".serialize($optionValue)."'"; }
240
+ else {
241
+ if(is_string($optionValue)){ $optionValue = "'".$optionValue."'"; }
242
+ }
243
+ $query = "INSERT INTO $table (option_name, option_value) VALUES ($optionName, $optionValue)";
244
+ wpphLog(__METHOD__.'() -> Executing query: '.$query);
245
+ $result = $wpdb->query($query);
246
+ return (is_null($result) ? false : true);
247
+ }
248
+ }
inc/WPPHPost.php CHANGED
@@ -42,7 +42,7 @@ class WPPHPost
42
  // custom post type
43
  else {
44
  self::$currentPostType = $data['post_type'];
45
- wpphLog('================================== CURRENT POST TYPE: '.self::$currentPostType);
46
  if(self::postAuthorChanged($GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID'], $postArray['ID'], wp_get_current_user()->ID, $data['post_title'], 2038, true)){
47
  $GLOBALS['WPPH_POST_AUTHOR_UPDATED'] = true;
48
  }
@@ -53,6 +53,16 @@ class WPPHPost
53
  // 2019 & 2020 & 2038
54
  static function postAuthorChanged($newAuthorID, $postID, $userID, $postTitle, $event, $quickFormEnabled = false)
55
  {
 
 
 
 
 
 
 
 
 
 
56
  global $wpdb;
57
  $oldAuthorID = $wpdb->get_var("SELECT post_author FROM ".$wpdb->posts." WHERE ID = ".$postID);
58
 
@@ -72,6 +82,7 @@ class WPPHPost
72
  $n = $o;
73
  $o = $t;
74
  }
 
75
  if(self::isCustomPost()){
76
  WPPHEvent::_addLogEvent($event, $userID, WPPHUtil::getIP(), array($postTitle,ucfirst(self::$currentPostType),$n,$o));
77
  }
42
  // custom post type
43
  else {
44
  self::$currentPostType = $data['post_type'];
45
+ wpphLog('CURRENT POST TYPE: '.self::$currentPostType);
46
  if(self::postAuthorChanged($GLOBALS['WPPH_POST_AUTHOR_UPDATED_ID'], $postArray['ID'], wp_get_current_user()->ID, $data['post_title'], 2038, true)){
47
  $GLOBALS['WPPH_POST_AUTHOR_UPDATED'] = true;
48
  }
53
  // 2019 & 2020 & 2038
54
  static function postAuthorChanged($newAuthorID, $postID, $userID, $postTitle, $event, $quickFormEnabled = false)
55
  {
56
+ wpphLog(__METHOD__.'() triggered.',array('params'=> func_get_args()));
57
+ if(empty($postID)){
58
+ wpphLog('Error: $postID is empty. Invalid function call.');
59
+ return false;
60
+ }
61
+ if(empty($newAuthorID)){
62
+ wpphLog('Error: $newAuthorID is empty. Invalid function call.');
63
+ return false;
64
+ }
65
+
66
  global $wpdb;
67
  $oldAuthorID = $wpdb->get_var("SELECT post_author FROM ".$wpdb->posts." WHERE ID = ".$postID);
68
 
82
  $n = $o;
83
  $o = $t;
84
  }
85
+ $userID = (int)$userID;
86
  if(self::isCustomPost()){
87
  WPPHEvent::_addLogEvent($event, $userID, WPPHUtil::getIP(), array($postTitle,ucfirst(self::$currentPostType),$n,$o));
88
  }
inc/WPPHUtil.php CHANGED
@@ -33,26 +33,76 @@ class WPPHUtil
33
  if(isset($_POST['offset'])) { $limit[0] = intval($_POST['offset']); }
34
  if(isset($_POST['count'])) { $limit[1] = intval($_POST['count']); }
35
 
36
- function __formatJsonOutput(array $sourceData=array(), $error=''){
37
- return json_encode(array(
38
- 'dataSource' => $sourceData,
39
- 'error' => $error
40
- ));
41
- };
42
 
43
- // get events
44
- $eventsCount = WPPHDB::getEventsCount();
45
- $events = WPPHEvent::getEvents($orderBy, $sort, $limit);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
 
 
 
 
 
 
 
 
 
 
 
47
  $eventsNum = count($events);
48
 
 
 
49
  if($eventsNum == 0){
50
- exit( __formatJsonOutput(array(),__('There are no security alerts to display.',WPPH_PLUGIN_TEXT_DOMAIN)) );
 
 
 
 
51
  }
52
 
53
- $out = array();
54
- $out['events'] = array();
55
-
56
  // prepare output
57
  foreach($events as $entry)
58
  {
@@ -62,6 +112,7 @@ class WPPHUtil
62
  $EventDate = $entry->EventDate;
63
  $userIP = $entry->UserIP;
64
  $UserID = $entry->UserID;
 
65
  $eventData = ((!empty($entry->EventData)) ? unserialize(base64_decode($entry->EventData)) : ''); //<< values to use for event description
66
 
67
  $eventCount = intval($entry->EventCount);
@@ -95,13 +146,34 @@ class WPPHUtil
95
  'eventDate' => $EventDate,
96
  'ip' => $userIP,
97
  'user' => $username,
 
98
  'description' => stripslashes($evm)
99
  );
100
  array_push($out['events'], $e);
101
  }
102
  $out['eventsCount'] = $eventsCount;
 
 
 
 
103
 
104
- exit(__formatJsonOutput($out));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  }
106
 
107
  static function addDashboardWidget()
@@ -110,7 +182,7 @@ class WPPHUtil
110
  {
111
  $currentUser = wp_get_current_user();
112
  if(WPPHUtil::isAdministrator($currentUser->ID)|| WPPHUtil::isAllowedAccess($currentUser->ID) || WPPHUtil::isAllowedChange($currentUser->ID)){
113
- wp_add_dashboard_widget('wpphPluginDashboardWidget', __('Latest WordPress Security Alerts').' | WP Security Audit Log', array(get_class(),'createDashboardWidget'));
114
  }
115
  }
116
  }
@@ -188,7 +260,7 @@ class WPPHUtil
188
  */
189
  static function isAllowedAccess()
190
  {
191
- $data = get_option(WPPH_PLUGIN_ALLOW_ACCESS_OPTION_NAME, array());
192
  if(empty($data)){return false;}
193
  $userID = wp_get_current_user()->ID;
194
  $userInfo = WPPHDB::getUserInfo($userID);
@@ -201,7 +273,7 @@ class WPPHUtil
201
  */
202
  static function isAllowedChange()
203
  {
204
- $data = get_option(WPPH_PLUGIN_ALLOW_CHANGE_OPTION_NAME, array());
205
  if(empty($data)){return false;}
206
  $userID = wp_get_current_user()->ID;
207
  $userInfo = WPPHDB::getUserInfo($userID);
@@ -212,14 +284,23 @@ class WPPHUtil
212
  * @since v0.5
213
  * @return bool False if value was not updated and true if value was updated.
214
  */
215
- static function saveAllowAccessUserList(array $data) {return update_option(WPPH_PLUGIN_ALLOW_ACCESS_OPTION_NAME, $data);}
 
 
 
 
 
216
  /**
217
  * @param array $data
218
  * @since v0.5
219
  * @return bool False if value was not updated and true if value was updated.
220
  */
221
- static function saveAllowedChangeUserList(array $data){return update_option(WPPH_PLUGIN_ALLOW_CHANGE_OPTION_NAME, $data);}
222
-
 
 
 
 
223
 
224
 
225
  /**
@@ -227,9 +308,12 @@ class WPPHUtil
227
  * @since v0.5
228
  * @return bool
229
  */
230
- static function saveInitialAccessChangeList(){
231
- self::saveAllowAccessUserList(array());
232
- self::saveAllowedChangeUserList(array());
 
 
 
233
  }
234
 
235
  // ajax
@@ -276,4 +360,12 @@ class WPPHUtil
276
  global $wp_roles;
277
  return (isset($wp_roles->roles[$role]) ? true : false);
278
  }
 
 
 
 
 
 
 
 
279
  }
33
  if(isset($_POST['offset'])) { $limit[0] = intval($_POST['offset']); }
34
  if(isset($_POST['count'])) { $limit[1] = intval($_POST['count']); }
35
 
36
+ global $current_user, $blog_id;
 
 
 
 
 
37
 
38
+ $out = array();
39
+ $out['events'] = array();
40
+ $globalBlogID = $blog_id;
41
+ $is_wpmu = WPPH::isMultisite();
42
+ $isMainSite = WPPHUtil::isMainSite();
43
+ $isSA = false;
44
+ $allSites = false;
45
+
46
+ $blogList = ($isMainSite && $is_wpmu) ? self::get_blogs() : array();
47
+ function _getBlogName($id, $blogList) {
48
+ for ($i = 0; $i < count($blogList); $i++) {
49
+ if ($blogList[$i]['blog_id'] == $id) {
50
+ return $blogList[$i]['blogname'];
51
+ }
52
+ }
53
+ }
54
+
55
+ if(!isset($_POST['blogID']) || empty($_POST['blogID'])){
56
+ if($isMainSite){
57
+ $postedBlogID = 0; // get the events for all sites by default
58
+ $allSites = true;
59
+ }
60
+ else {
61
+ $postedBlogID = $globalBlogID;
62
+ $allSites = false;
63
+ }
64
+ }
65
+ else { $postedBlogID = intval($_POST['blogID']); }
66
+
67
+ if($is_wpmu){ $isSA = is_super_admin($current_user->ID); }
68
+ else {
69
+ if(empty($postedBlogID)){
70
+ $postedBlogID = 1;
71
+ }
72
+ }
73
+
74
+ if($is_wpmu && !$isSA)
75
+ {
76
+ // Only Super Admin can view other blogs' alerts
77
+ if($globalBlogID <> $postedBlogID){
78
+ $out['blogs'] = $blogList;
79
+ exit( wpph_formatJsonOutput($out,__('There are no security alerts to display.',WPPH_PLUGIN_TEXT_DOMAIN)) );
80
+ }
81
+ }
82
 
83
+ if(! $isMainSite){ $postedBlogID = $globalBlogID; }
84
+
85
+ // get events
86
+ if($allSites){
87
+ $eventsCount = WPPHDB::getEventsCount(0);
88
+ $events = WPPHEvent::getEvents($orderBy, $sort, $limit, 0);
89
+ }
90
+ else {
91
+ $eventsCount = WPPHDB::getEventsCount($postedBlogID);
92
+ $events = WPPHEvent::getEvents($orderBy, $sort, $limit, $postedBlogID);
93
+ }
94
  $eventsNum = count($events);
95
 
96
+ wpphLog("GETTING EVENTS FOR ".(empty($postedBlogID) ? 'ALL BLOGS' : 'BLOG: '.$postedBlogID).". Num events: $eventsNum");
97
+
98
  if($eventsNum == 0){
99
+ if($is_wpmu){
100
+ $out['blogs'] = $blogList;
101
+ exit( wpph_formatJsonOutput($out,__('There are no security alerts to display.',WPPH_PLUGIN_TEXT_DOMAIN)) );
102
+ }
103
+ exit( wpph_formatJsonOutput(array(),__('There are no security alerts to display.',WPPH_PLUGIN_TEXT_DOMAIN)) );
104
  }
105
 
 
 
 
106
  // prepare output
107
  foreach($events as $entry)
108
  {
112
  $EventDate = $entry->EventDate;
113
  $userIP = $entry->UserIP;
114
  $UserID = $entry->UserID;
115
+ $blogId = $entry->BlogId;
116
  $eventData = ((!empty($entry->EventData)) ? unserialize(base64_decode($entry->EventData)) : ''); //<< values to use for event description
117
 
118
  $eventCount = intval($entry->EventCount);
146
  'eventDate' => $EventDate,
147
  'ip' => $userIP,
148
  'user' => $username,
149
+ 'siteName' => $allSites ? _getBlogName($blogId, $blogList) : '',
150
  'description' => stripslashes($evm)
151
  );
152
  array_push($out['events'], $e);
153
  }
154
  $out['eventsCount'] = $eventsCount;
155
+ $out['blogID'] = $postedBlogID;
156
+ $out['blogs'] = $blogList;
157
+ exit(wpph_formatJsonOutput($out));
158
+ }
159
 
160
+ // @since v0.6
161
+ static function get_blogs()
162
+ {
163
+ if(wp_is_large_network()){
164
+ return get_blog_details(get_option(WPPH_MAIN_SITE_ID_OPTION_NAME),true);
165
+ }
166
+ $blogs = wp_get_sites();
167
+ $out = array();
168
+ foreach($blogs as $blog){
169
+ $entry = get_blog_details($blog['blog_id']);
170
+ array_push($out, array(
171
+ 'blog_id' => $entry->blog_id,
172
+ 'blogname' => $entry->blogname
173
+ ));
174
+ }
175
+ array_unshift($out, array('blog_id' => 0, 'blogname' => 'All sites'));
176
+ return $out;
177
  }
178
 
179
  static function addDashboardWidget()
182
  {
183
  $currentUser = wp_get_current_user();
184
  if(WPPHUtil::isAdministrator($currentUser->ID)|| WPPHUtil::isAllowedAccess($currentUser->ID) || WPPHUtil::isAllowedChange($currentUser->ID)){
185
+ wp_add_dashboard_widget('wpphPluginDashboardWidget', __('Latest WordPress Security Alerts').' | WP Security Audit Log', array(get_class(),'createDashboardWidget'));
186
  }
187
  }
188
  }
260
  */
261
  static function isAllowedAccess()
262
  {
263
+ $data = WPPHNetwork::getGlobalOption(WPPH_PLUGIN_ALLOW_ACCESS_OPTION_NAME, true, true, array());
264
  if(empty($data)){return false;}
265
  $userID = wp_get_current_user()->ID;
266
  $userInfo = WPPHDB::getUserInfo($userID);
273
  */
274
  static function isAllowedChange()
275
  {
276
+ $data = WPPHNetwork::getGlobalOption(WPPH_PLUGIN_ALLOW_CHANGE_OPTION_NAME, true, true, array());
277
  if(empty($data)){return false;}
278
  $userID = wp_get_current_user()->ID;
279
  $userInfo = WPPHDB::getUserInfo($userID);
284
  * @since v0.5
285
  * @return bool False if value was not updated and true if value was updated.
286
  */
287
+ static function saveAllowAccessUserList(array $data)
288
+ {
289
+ $result = WPPHNetwork::updateGlobalOption(WPPH_PLUGIN_ALLOW_ACCESS_OPTION_NAME, $data, true, true);
290
+ wpphLog(__METHOD__.'() result:', array('data'=> $data, 'result'=>$result));
291
+ return $result;
292
+ }
293
  /**
294
  * @param array $data
295
  * @since v0.5
296
  * @return bool False if value was not updated and true if value was updated.
297
  */
298
+ static function saveAllowedChangeUserList(array $data)
299
+ {
300
+ $result = WPPHNetwork::updateGlobalOption(WPPH_PLUGIN_ALLOW_CHANGE_OPTION_NAME, $data, true, true);
301
+ wpphLog(__METHOD__.'() result:', array('data'=> $data, 'result'=>$result));
302
+ return $result;
303
+ }
304
 
305
 
306
  /**
308
  * @since v0.5
309
  * @return bool
310
  */
311
+ static function saveInitialAccessChangeList()
312
+ {
313
+ if(self::isMainSite()){
314
+ WPPHNetwork::addGlobalOption(WPPH_PLUGIN_ALLOW_ACCESS_OPTION_NAME, array(), true, true);
315
+ WPPHNetwork::addGlobalOption(WPPH_PLUGIN_ALLOW_CHANGE_OPTION_NAME, array(), true, true);
316
+ }
317
  }
318
 
319
  // ajax
360
  global $wp_roles;
361
  return (isset($wp_roles->roles[$role]) ? true : false);
362
  }
363
+
364
+ static function isMainSite(){
365
+ if (WPPH::isMultisite()) {
366
+ global $current_site, $blog_id;
367
+ return ($current_site->id == $blog_id);
368
+ }
369
+ return true;
370
+ }
371
  }
inc/wpphFunctions.php CHANGED
@@ -33,15 +33,16 @@ function wpph_isEventEnabled($event, array $events = array())
33
  {
34
  if(empty($event)){ return false; }
35
  if(empty($events)){
36
- $events = get_option(WPPH_PLUGIN_EVENTS_LIST_OPTION_NAME, array());
37
  if(empty($events)){
38
- wpphLog("Error retrieving the list of events from database. option: WPPH_PLUGIN_EVENTS_LIST_OPTION_NAME was either not found or empty.");
39
  return false;
40
  }
41
  }
42
- foreach($events as $k=>$entries){
43
- foreach($entries as $_event => $enabled){
44
- if(($event == $_event) && $enabled){
 
45
  return true;
46
  }
47
  }
@@ -55,3 +56,37 @@ function wpphCustomLinks($links) { return array_merge(array('<a href="admin.php?
55
  function wpphLoadTextDomain() { load_plugin_textdomain(WPPH_PLUGIN_TEXT_DOMAIN, false, 'wp-security-audit-log/languages/'); }
56
 
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  {
34
  if(empty($event)){ return false; }
35
  if(empty($events)){
36
+ $events = wpph_getPluginEventsList();
37
  if(empty($events)){
38
+ wpphLog("Error retrieving the list of events from database. option: ".WPPH_PLUGIN_EVENTS_LIST_OPTION_NAME." was either not found or empty.");
39
  return false;
40
  }
41
  }
42
+ $event = (int)$event;
43
+ foreach($events as $sections){
44
+ foreach($sections as $_event => $enabled){
45
+ if(($event == (int)$_event) && (bool)$enabled){
46
  return true;
47
  }
48
  }
56
  function wpphLoadTextDomain() { load_plugin_textdomain(WPPH_PLUGIN_TEXT_DOMAIN, false, 'wp-security-audit-log/languages/'); }
57
 
58
 
59
+ /**
60
+ * @internal
61
+ * @param string $pluginName
62
+ * @param int $userID
63
+ * @param string $userIP
64
+ */
65
+ function wpph_installPlugin($pluginName, $userID, $userIP)
66
+ {
67
+ if(! empty($_GET['plugin']))
68
+ {
69
+ WPPHEvent::_addLogEvent(5000,$userID, $userIP, array($pluginName));
70
+ wpphLog('Plugin installed.', array('plugin'=>$pluginName));
71
+ }
72
+ }
73
+
74
+ function wpph_updatePluginEventsList($data)
75
+ {
76
+ if(WPPH::isMultisite()){
77
+ update_blog_option((int)get_option(WPPH_MAIN_SITE_ID_OPTION_NAME), WPPH_PLUGIN_EVENTS_LIST_OPTION_NAME, $data);
78
+ }
79
+ else { update_option(WPPH_PLUGIN_EVENTS_LIST_OPTION_NAME, $data); }
80
+ }
81
+
82
+ function wpph_getPluginEventsList()
83
+ {
84
+ return WPPHNetwork::getGlobalOption(WPPH_PLUGIN_EVENTS_LIST_OPTION_NAME, true, true);
85
+ }
86
+
87
+ function wpph_formatJsonOutput(array $sourceData=array(), $error=''){
88
+ return json_encode(array(
89
+ 'dataSource' => $sourceData,
90
+ 'error' => $error
91
+ ));
92
+ };
inc/wpphSettings.php CHANGED
@@ -27,4 +27,8 @@ define('WPPH_KEEP_MAX_EVENTS', 5000);
27
  //since v0.5
28
  define('WPPH_PLUGIN_ALLOW_ACCESS_OPTION_NAME','WPPH_PLUGIN_ALLOW_ACCESS');
29
  define('WPPH_PLUGIN_ALLOW_CHANGE_OPTION_NAME','WPPH_PLUGIN_ALLOW_CHANGE');
30
- define('WPPH_PLUGIN_EVENTS_LIST_OPTION_NAME', 'WPPH_PLUGIN_EVENTS_LIST');
 
 
 
 
27
  //since v0.5
28
  define('WPPH_PLUGIN_ALLOW_ACCESS_OPTION_NAME','WPPH_PLUGIN_ALLOW_ACCESS');
29
  define('WPPH_PLUGIN_ALLOW_CHANGE_OPTION_NAME','WPPH_PLUGIN_ALLOW_CHANGE');
30
+ define('WPPH_PLUGIN_EVENTS_LIST_OPTION_NAME', 'WPPH_PLUGIN_EVENTS_LIST');
31
+
32
+ //since v0.6
33
+ define('WPPH_NETWORK_ID_OPTION_NAME','WPPH_NETWORK_ID');
34
+ define('WPPH_MAIN_SITE_ID_OPTION_NAME','WPPH_MAIN_SITE_ID');
pages/about.php CHANGED
@@ -4,7 +4,7 @@
4
  {
5
  $errors = WPPH::getPluginErrors();
6
  foreach($errors as $error) {
7
- wpph_adminNotice($error);
8
  }
9
  echo '<div id="wpph-pageWrapper" class="wrap">';
10
  echo '<p>'.__('We have encountered some errors during the installation of the plugin which you can find above.',WPPH_PLUGIN_TEXT_DOMAIN).'</p>';
4
  {
5
  $errors = WPPH::getPluginErrors();
6
  foreach($errors as $error) {
7
+ wpph_adminNotice(base64_decode($error));
8
  }
9
  echo '<div id="wpph-pageWrapper" class="wrap">';
10
  echo '<p>'.__('We have encountered some errors during the installation of the plugin which you can find above.',WPPH_PLUGIN_TEXT_DOMAIN).'</p>';
pages/alerts.php CHANGED
@@ -61,7 +61,7 @@ if('POST' == $rm)
61
  }
62
  }
63
  }
64
- update_option(WPPH_PLUGIN_EVENTS_LIST_OPTION_NAME, $logEvents);
65
  $validationMessage['success'] = __('Your settings have been saved.',WPPH_PLUGIN_TEXT_DOMAIN);
66
  }
67
  }
@@ -101,19 +101,32 @@ if('POST' == $rm)
101
  echo '<div id="'.$sectionName.'">';
102
  echo '<table class="wp-list-table widefat" cellspacing="0" cellpadding="0">';
103
  echo '<thead>';
104
- echo '<th class="manage-column column-cb check-column item-cb" scope="col"><input type="checkbox" class="js-select-all"/></th>';
105
- echo '<th class="manage-column column-cb check-column item-event" scope="col">'.__('Event',WPPH_PLUGIN_TEXT_DOMAIN).'</th>';
106
- echo '<th class="manage-column column-cb check-column item-type" scope="col">'.__('Type',WPPH_PLUGIN_TEXT_DOMAIN).'</th>';
107
- echo '<th class="manage-column column-cb check-column item-description" scope="col">'.__('Description',WPPH_PLUGIN_TEXT_DOMAIN).'</th>';
108
  echo '</thead>';
109
  echo '<tbody>';
 
110
  foreach($items as $item => $enabled){
111
- echo '<tr class="row">';
112
- echo '<th class="manage-column column-cb check-column" scope="row"><input class="item_cb" type="checkbox" '.($enabled ? 'checked="checked"' : '').' value="'.$item.'"/></th>';
 
 
 
 
 
 
 
 
 
 
113
  echo '<td>'.$item.'</td>';
114
  echo '<td>'.(isset($defaultEvents[$sectionName][$item]['type']) ? $defaultEvents[$sectionName][$item]['type'] : '').'</td>';
115
  echo '<td>'.(isset($defaultEvents[$sectionName][$item]['text']) ? $defaultEvents[$sectionName][$item]['text'] : '').'</td>';
116
- echo '</tr>';
 
 
117
  }
118
  echo '</tbody>';
119
  echo '</table>';
61
  }
62
  }
63
  }
64
+ wpph_updatePluginEventsList($logEvents);
65
  $validationMessage['success'] = __('Your settings have been saved.',WPPH_PLUGIN_TEXT_DOMAIN);
66
  }
67
  }
101
  echo '<div id="'.$sectionName.'">';
102
  echo '<table class="wp-list-table widefat" cellspacing="0" cellpadding="0">';
103
  echo '<thead>';
104
+ echo '<th class="manage-column column-cb check-column item-cb item-cb_h" scope="col"><input type="checkbox" class="js-select-all"/></th>';
105
+ echo '<th class="manage-column item-event" scope="col">'.__('Event',WPPH_PLUGIN_TEXT_DOMAIN).'</th>';
106
+ echo '<th class="manage-column item-type" scope="col">'.__('Type',WPPH_PLUGIN_TEXT_DOMAIN).'</th>';
107
+ echo '<th class="manage-column item-description" scope="col">'.__('Description',WPPH_PLUGIN_TEXT_DOMAIN).'</th>';
108
  echo '</thead>';
109
  echo '<tbody>';
110
+ $disabledEvents = array(6001,6002);
111
  foreach($items as $item => $enabled){
112
+ if(in_array((int)$item, $disabledEvents)){
113
+ $t = sprintf(__('Event %s is not available in MultiSite.',WPPH_PLUGIN_TEXT_DOMAIN), $item);
114
+ echo '<tr class="row" title="'.$t.'">';
115
+ echo '<th class="manage-column column-cb check-column item-cb_h" scope="row"><input class="item_cb" type="checkbox" disabled="disabled"/></th>';
116
+ echo '<td class="wpph-text-disabled">'.$item.'</td>';
117
+ echo '<td class="wpph-text-disabled">'.(isset($defaultEvents[$sectionName][$item]['type']) ? $defaultEvents[$sectionName][$item]['type'] : '').'</td>';
118
+ echo '<td class="wpph-text-disabled">'.(isset($defaultEvents[$sectionName][$item]['text']) ? $defaultEvents[$sectionName][$item]['text'] : '').'</td>';
119
+ echo '</tr>';
120
+ }
121
+ else {
122
+ echo '<tr class="row">';
123
+ echo '<th class="manage-column column-cb check-column item-cb_h" scope="row"><input class="item_cb" type="checkbox" '.($enabled ? 'checked="checked"' : '').' value="'.$item.'"/></th>';
124
  echo '<td>'.$item.'</td>';
125
  echo '<td>'.(isset($defaultEvents[$sectionName][$item]['type']) ? $defaultEvents[$sectionName][$item]['type'] : '').'</td>';
126
  echo '<td>'.(isset($defaultEvents[$sectionName][$item]['text']) ? $defaultEvents[$sectionName][$item]['text'] : '').'</td>';
127
+ echo '</tr>';
128
+
129
+ }
130
  }
131
  echo '</tbody>';
132
  echo '</table>';
pages/dashboard.php CHANGED
@@ -13,7 +13,6 @@ if(! WPPH::ready())
13
  return;
14
  }
15
  ?>
16
-
17
  <div id="wpph-pageWrapper" class="wrap">
18
  <h2 class="pageTitle pageTitle-eventViewer">Audit Log Viewer</h2>
19
  <div id="EventViewerWrapper">
@@ -22,15 +21,23 @@ if(! WPPH::ready())
22
  <div class="alignleft">
23
  <div style="overflow: hidden;">
24
  <input type="button" class="buttonRefreshEventsList button" value="<?php echo __('Refresh Security Alerts List',WPPH_PLUGIN_TEXT_DOMAIN);?>"
25
- style="float: left; display: block;" data-bind="disable: loading, click: cleanRefresh"/>
26
  <span class="ajaxLoaderWrapper" style="float: left; display: block; width: 20px; height: 20px; padding: 7px 7px;"><img/></span>
27
  </div>
28
  </div>
29
  <div class="alignleft actions" style="overflow: hidden;">
30
  <label class="alignleft" style="margin: 5px 5px 0 0;"><?php echo __('Number of security alerts per page:',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
31
- <select name="actionLimit1" class="actionLimit" data-bind="options: availablePageSize, value: selectedPageSize"></select>
32
- <input type="button" value="Apply" class="button action" data-bind="disable: loading, click: applyPageSize">
 
 
 
 
 
 
33
  </div>
 
 
34
 
35
  <div class="tablenav-pages">
36
  <span class="displaying-num" data-bind="text: totalEventsCount()+' security alerts'"></span>
@@ -48,29 +55,46 @@ if(! WPPH::ready())
48
  </div>
49
  <table class="wp-list-table widefat fixed" cellspacing="0" cellpadding="0">
50
  <thead>
51
- <tr data-bind="foreach: columns">
 
52
  <th class="manage-column column-left-align" scope="col"
53
- data-bind="style: {width: columnWidth}, css: { sortable: sortable, sorted: sorted, desc: sortable && sortedDescending(), asc: sortable && !sortedDescending()}">
54
- <a href="#" data-bind="disable: $root.loading, click: $data.sortable ? $root.applySorting.bind($data.columnName, $root) : function() { return false; }">
55
- <span data-bind="text: columnHeader"></span>
56
  <span class="sorting-indicator"></span>
57
  </a>
58
  </th>
 
59
  </tr>
60
  </thead>
61
  <tfoot>
62
- <tr data-bind="foreach: columns">
 
63
  <th class="manage-column column-left-align" scope="col"
64
- data-bind="style: {width: columnWidth}, css: { sortable: sortable, sorted: sorted, desc: sortable && sortedDescending(), asc: sortable && !sortedDescending()}">
65
- <a href="#" data-bind="disable: $root.loading, click: $data.sortable ? $root.applySorting.bind($data.columnName, $root) : function() { return false; }">
66
- <span data-bind="text: columnHeader"></span>
67
  <span class="sorting-indicator"></span>
68
  </a>
69
  </th>
 
70
  </tr>
71
  </tfoot>
72
  <tbody id="the-list">
73
- <tr data-bind="if: events().length == 0"><td style="padding: 4px !important;" colspan="7"><?php echo __('No security alerts',WPPH_PLUGIN_TEXT_DOMAIN);?></td></tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  <!-- ko foreach: events -->
75
  <tr data-bind="css: {'row-0': ($index() % 2) == 0, 'row-1': ($index() % 2) != 0}">
76
  <td class="column-event_number"><span data-bind="text: eventNumber"></span></td>
@@ -79,6 +103,9 @@ if(! WPPH::ready())
79
  <td class="column-event_category"><span data-bind="text: EventType"></span></td>
80
  <td class="column-ip"><span data-bind="text: ip"></span></td>
81
  <td class="column-user"><span data-bind="text: user"></span></td>
 
 
 
82
  <td class="column-description"><span data-bind="html: description"></span></td>
83
  </tr>
84
  <!-- /ko -->
@@ -89,14 +116,14 @@ if(! WPPH::ready())
89
  <div class="alignleft">
90
  <div style="overflow: hidden;">
91
  <input type="button" class="buttonRefreshEventsList button" value="<?php echo __('Refresh security alerts List',WPPH_PLUGIN_TEXT_DOMAIN);?>"
92
- style="float: left; display: block;" data-bind="disable: loading, click: cleanRefresh"/>
93
  <span class="ajaxLoaderWrapper" style="float: left; display: block; width: 20px; height: 20px; padding: 7px 7px;"><img/></span>
94
  </div>
95
  </div>
96
  <div class="alignleft actions" style="overflow: hidden;">
97
  <label class="alignleft" style="margin: 5px 5px 0 0;"><?php echo __('Number of security alerts per page:',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
98
- <select name="actionLimit1" class="actionLimit" data-bind="options: availablePageSize, value: selectedPageSize"></select>
99
- <input type="button" value="Apply" class="button action" data-bind="disable: loading, click: applyPageSize">
100
  </div>
101
  <div class="tablenav-pages">
102
  <span class="displaying-num" data-bind="text: totalEventsCount()+' security alerts'"></span>
@@ -114,8 +141,9 @@ if(! WPPH::ready())
114
 
115
  </div>
116
  </div>
117
-
118
  <script type="text/javascript">
 
119
  // configure ajax loader
120
  var __ajaxLoaderTargetElement__ = jQuery('.ajaxLoaderWrapper img');
121
  var AjaxLoaderCreate = function(e){
@@ -124,12 +152,14 @@ if(! WPPH::ready())
124
  }(__ajaxLoaderTargetElement__);
125
  var AjaxLoaderShow = function(e){ e.show(); };
126
  var AjaxLoaderHide = function(e){ e.hide(); };
127
-
128
  jQuery(document).ready(function($) {
129
- var myViewModel = new AuditLogViewModel();
130
- ko.applyBindings(myViewModel, $('#wpph-pageWrapper').get(0));
131
  myViewModel.orderBy('EventNumber');
132
  myViewModel.orderByDescending(true);
133
- myViewModel.cleanRefresh(myViewModel);
 
 
 
134
  });
135
  </script>
13
  return;
14
  }
15
  ?>
 
16
  <div id="wpph-pageWrapper" class="wrap">
17
  <h2 class="pageTitle pageTitle-eventViewer">Audit Log Viewer</h2>
18
  <div id="EventViewerWrapper">
21
  <div class="alignleft">
22
  <div style="overflow: hidden;">
23
  <input type="button" class="buttonRefreshEventsList button" value="<?php echo __('Refresh Security Alerts List',WPPH_PLUGIN_TEXT_DOMAIN);?>"
24
+ style="float: left; display: block;" data-bind="disable: loading, click: $root.onRefreshEvents"/>
25
  <span class="ajaxLoaderWrapper" style="float: left; display: block; width: 20px; height: 20px; padding: 7px 7px;"><img/></span>
26
  </div>
27
  </div>
28
  <div class="alignleft actions" style="overflow: hidden;">
29
  <label class="alignleft" style="margin: 5px 5px 0 0;"><?php echo __('Number of security alerts per page:',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
30
+ <select name="actionLimit1" class="actionLimit" data-bind="options: availablePageSize, value: selectedPageSize, disable: loading"></select>
31
+ <input type="button" value="Apply" class="button action" data-bind="disable: loading, click: $root.onApplyPageSize">
32
+ </div>
33
+
34
+ <?php if(WPPH::isMultisite()): ?>
35
+ <!-- ko if: isMainSite -->
36
+ <div class="alignleft" style="padding: 2px 0;">
37
+ <select id="ntwkBlogs" data-bind="disable: loading, options: blogList, optionsText: 'blogname', optionsValue: 'blog_id', value: blogId"></select>
38
  </div>
39
+ <!-- /ko -->
40
+ <?php endif;?>
41
 
42
  <div class="tablenav-pages">
43
  <span class="displaying-num" data-bind="text: totalEventsCount()+' security alerts'"></span>
55
  </div>
56
  <table class="wp-list-table widefat fixed" cellspacing="0" cellpadding="0">
57
  <thead>
58
+ <tr data-bind="foreach: { data: columns, as: 'columnItem' }">
59
+ <!-- ko if: columnItem.visible -->
60
  <th class="manage-column column-left-align" scope="col"
61
+ data-bind="style: {width: columnItem.columnWidth}, css: { sortable: columnItem.sortable, sorted: columnItem.sorted, desc: columnItem.sortable && columnItem.sortedDescending(), asc: columnItem.sortable && !columnItem.sortedDescending()}">
62
+ <a href="#" data-bind="disable: $root.loading, click: columnItem.sortable ? $root.onApplySorting : function() { return false; }">
63
+ <span data-bind="text: columnItem.columnHeader"></span>
64
  <span class="sorting-indicator"></span>
65
  </a>
66
  </th>
67
+ <!-- /ko -->
68
  </tr>
69
  </thead>
70
  <tfoot>
71
+ <tr data-bind="foreach: { data: columns, as: 'columnItem' }">
72
+ <!-- ko if: columnItem.visible -->
73
  <th class="manage-column column-left-align" scope="col"
74
+ data-bind="style: {width: columnItem.columnWidth}, css: { sortable: columnItem.sortable, sorted: columnItem.sorted, desc: columnItem.sortable && columnItem.sortedDescending(), asc: columnItem.sortable && !columnItem.sortedDescending()}">
75
+ <a href="#" data-bind="disable: $root.loading, click: columnItem.sortable ? $root.onApplySorting : function() { return false; }">
76
+ <span data-bind="text: columnItem.columnHeader"></span>
77
  <span class="sorting-indicator"></span>
78
  </a>
79
  </th>
80
+ <!-- /ko -->
81
  </tr>
82
  </tfoot>
83
  <tbody id="the-list">
84
+ <!-- ko if: events().length == 0 -->
85
+ <tr>
86
+ <!-- ko ifnot: error -->
87
+ <td id="wpph_ew" style="padding: 4px !important;" colspan="8"><?php echo __('No security alerts',WPPH_PLUGIN_TEXT_DOMAIN);?></td>
88
+ <!-- /ko -->
89
+
90
+ <!-- ko if: error -->
91
+ <td id="wpph_ew" style="padding: 4px !important;" colspan="8">
92
+ <strong data-bind="text: error"></strong>
93
+ </td>
94
+ <!-- /ko -->
95
+ </tr>
96
+ <!-- /ko -->
97
+
98
  <!-- ko foreach: events -->
99
  <tr data-bind="css: {'row-0': ($index() % 2) == 0, 'row-1': ($index() % 2) != 0}">
100
  <td class="column-event_number"><span data-bind="text: eventNumber"></span></td>
103
  <td class="column-event_category"><span data-bind="text: EventType"></span></td>
104
  <td class="column-ip"><span data-bind="text: ip"></span></td>
105
  <td class="column-user"><span data-bind="text: user"></span></td>
106
+ <!-- ko if: $root.blogId() === 0 -->
107
+ <td class="column-site"><span data-bind="text: $data.siteName"></span></td>
108
+ <!-- /ko -->
109
  <td class="column-description"><span data-bind="html: description"></span></td>
110
  </tr>
111
  <!-- /ko -->
116
  <div class="alignleft">
117
  <div style="overflow: hidden;">
118
  <input type="button" class="buttonRefreshEventsList button" value="<?php echo __('Refresh security alerts List',WPPH_PLUGIN_TEXT_DOMAIN);?>"
119
+ style="float: left; display: block;" data-bind="disable: loading, click: $root.onRefreshEvents"/>
120
  <span class="ajaxLoaderWrapper" style="float: left; display: block; width: 20px; height: 20px; padding: 7px 7px;"><img/></span>
121
  </div>
122
  </div>
123
  <div class="alignleft actions" style="overflow: hidden;">
124
  <label class="alignleft" style="margin: 5px 5px 0 0;"><?php echo __('Number of security alerts per page:',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
125
+ <select name="actionLimit1" class="actionLimit" data-bind="options: availablePageSize, value: selectedPageSize, disable: loading"></select>
126
+ <input type="button" value="Apply" class="button action" data-bind="disable: loading, click: $root.onApplyPageSize">
127
  </div>
128
  <div class="tablenav-pages">
129
  <span class="displaying-num" data-bind="text: totalEventsCount()+' security alerts'"></span>
141
 
142
  </div>
143
  </div>
144
+ <?php global $blog_id; ?>
145
  <script type="text/javascript">
146
+ jQuery.WPPH_CRT_BLOG_ID = <?php echo WPPHUtil::isMainSite() ? 0 : $blog_id;?>;
147
  // configure ajax loader
148
  var __ajaxLoaderTargetElement__ = jQuery('.ajaxLoaderWrapper img');
149
  var AjaxLoaderCreate = function(e){
152
  }(__ajaxLoaderTargetElement__);
153
  var AjaxLoaderShow = function(e){ e.show(); };
154
  var AjaxLoaderHide = function(e){ e.hide(); };
 
155
  jQuery(document).ready(function($) {
156
+ var myViewModel = AuditLogViewModel;
157
+ myViewModel.isMainSite(!!<?php echo WPPHUtil::isMainSite() ? '1': '0';?>);
158
  myViewModel.orderBy('EventNumber');
159
  myViewModel.orderByDescending(true);
160
+ ko.applyBindings(myViewModel, $('#wpph-pageWrapper').get(0));
161
+ setTimeout(function() {
162
+ myViewModel.refreshEvents(0, jQuery.WPPH_CRT_BLOG_ID);
163
+ });
164
  });
165
  </script>
pages/settings.php CHANGED
@@ -24,8 +24,8 @@ $showDW = (empty($opt->showDW) ? false : true);
24
  // active delete option for events
25
  if(!empty($opt->daysToKeep)){ $daysInput = $opt->daysToKeep; $activeOption = 1; }
26
  if(! empty($opt->eventsToKeep)){ $eventsNumber = $opt->eventsToKeep; $activeOption = 2; }
27
- $allowedAccess = get_option(WPPH_PLUGIN_ALLOW_ACCESS_OPTION_NAME, array());
28
- $allowedChange = get_option(WPPH_PLUGIN_ALLOW_CHANGE_OPTION_NAME, array());
29
  if(! isset($activeOption)){ $activeOption = 2; }
30
  // end defaults
31
 
@@ -47,23 +47,45 @@ if('POST' == $rm)
47
  $deleteEventsBy = intval($_POST['deleteEventsBy']);
48
  $deleteEventsValue = intval($_POST['deleteEventsValue']);
49
 
 
 
 
50
  // pre-validate access rules if any
51
- if(! empty($_POST['accessListInput'])){
52
- $set = $_POST['accessListInput'];
53
- $set = str_replace('\\','', $set);
54
- $set = json_decode($set);
55
- $allowedAccess = $set;
56
- // Allowed Access
57
- WPPHUtil::saveAllowAccessUserList($allowedAccess);
 
 
 
 
 
 
 
 
 
58
  }
 
59
  // pre-validate change rules if any
60
- if(! empty($_POST['changeListInput'])){
61
- $set = $_POST['changeListInput'];
62
- $set = str_replace('\\','', $set);
63
- $set = json_decode($set);
64
- $allowedChange = $set;
65
- // Allowed Change
66
- WPPHUtil::saveAllowedChangeUserList($allowedChange);
 
 
 
 
 
 
 
 
 
67
  }
68
 
69
  // if Delete events older than ... days
@@ -148,7 +170,8 @@ if('POST' == $rm)
148
  .the-list td.column-username p,
149
  .the-list td.column-name p,
150
  .the-list td.column-role p { padding-left: 7px !important;}
151
-
 
152
  </style>
153
  <div id="wpph-pageWrapper" class="wrap">
154
  <h2 class="pageTitle pageTitle-settings"><?php echo __('WP Security Audit Log Settings',WPPH_PLUGIN_TEXT_DOMAIN);?></h2>
@@ -170,8 +193,8 @@ if('POST' == $rm)
170
  <table cellspacing="0" cellpadding="0" class="form-table">
171
  <tbody>
172
  <tr valign="top">
173
- <td rowspan="4" class="section-left">
174
- <label style="display:block;margin: 30px 0 0 0;" for="eventsNumberInput"><?php echo __('Security Alerts Pruning',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
175
  </td>
176
  </tr>
177
  <tr>
@@ -195,21 +218,21 @@ if('POST' == $rm)
195
  <input type="text" id="eventsNumberInput" maxlength="6"
196
  placeholder="<?php echo $wpph_t1;?>"
197
  value="<?php if(! empty($eventsNumber)) { echo $eventsNumber; } ;?>"/>
198
- <span> <?php echo $wpph_t1;?></span>
199
  </p>
 
200
  </td>
201
  </tr>
202
  <tr>
203
- <td class="section-right"><p class="description"><?php echo sprintf(__('By default %s will keep up to %d WordPress Security Events.',WPPH_PLUGIN_TEXT_DOMAIN),WPPH_PLUGIN_NAME, WPPH_KEEP_MAX_EVENTS);?></p></td>
204
- </tr>
205
- <tr><td style="height: 10px;"></td></tr>
206
- <tr>
207
- <td rowspan="2" class="section-left" style=""><label style="display:block;margin: 0 0 0;" for="optionDW_on"><?php echo __('Security Alerts Dashboard Widget',WPPH_PLUGIN_TEXT_DOMAIN);?></label></td>
208
  </tr>
209
  <tr>
210
  <td class="section-right">
211
  <input type="radio" id="optionDW_on" class="radioInput" style="margin-top: 2px;"/><label for="optionDW_on" style="padding-top: 5px; padding-left: 3px;"><?php echo __('On',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
 
212
  <input type="radio" id="optionDW_off" class="radioInput" style="margin-top: 2px;"/><label for="optionDW_off" style="padding-top: 5px; padding-left: 3px;"><?php echo __('Off',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
 
 
213
  </td>
214
  </tr>
215
  </tbody>
@@ -222,11 +245,11 @@ if('POST' == $rm)
222
  .tagElement .tagDelete:hover { color: #d00000; }
223
  #section-holder #c-list p.description { margin-top: 0 !important; margin-bottom: 0 !important; }
224
  </style>
225
- <table cellspacing="0" cellpadding="0" class="form-table" style="margin-top: 30px;">
226
  <tbody>
227
  <tr valign="top">
228
  <td valign="top" class="section-left">
229
- <label style="display:block;margin: 12px 0 0 0;" for="inputUser1"><?php echo __('Can view Security Alerts',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
230
  </td>
231
  <td class="section-right">
232
  <div id="a-list">
@@ -237,11 +260,9 @@ if('POST' == $rm)
237
  </div>
238
  </td>
239
  </tr>
240
- <tr><td></td><td></td></tr>
241
- <tr><td></td><td></td></tr>
242
- <tr valign="top">
243
  <td valign="top" class="section-left">
244
- <label style="display:block;margin: 12px 0 0 0;" for="inputUser2"><?php echo __('Can Manage Plugin ',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
245
  </td>
246
  <td class="section-right">
247
  <div id="c-list">
@@ -262,7 +283,6 @@ if('POST' == $rm)
262
  inputAdd1 = $('#inputAdd1'),
263
  divTarget1 = $('#accessListTarget'),
264
  tagElement1 = $('.tagElement', mainContainer1),
265
-
266
  mainContainer2 = $('#c-list'),
267
  inputUser2 = $('#inputUser2'),
268
  inputAdd2 = $('#inputAdd2'),
@@ -393,10 +413,7 @@ if('POST' == $rm)
393
  });
394
  });
395
  </script>
396
-
397
  </div>
398
-
399
-
400
  </div>
401
  <p style="margin-top: 40px;">
402
  <input type="submit" id="submitButton" class="button button-primary" value="<?php echo __('Save settings',WPPH_PLUGIN_TEXT_DOMAIN);?>"/>
24
  // active delete option for events
25
  if(!empty($opt->daysToKeep)){ $daysInput = $opt->daysToKeep; $activeOption = 1; }
26
  if(! empty($opt->eventsToKeep)){ $eventsNumber = $opt->eventsToKeep; $activeOption = 2; }
27
+ $allowedAccess = WPPHNetwork::getGlobalOption(WPPH_PLUGIN_ALLOW_ACCESS_OPTION_NAME, true, true, array());
28
+ $allowedChange = WPPHNetwork::getGlobalOption(WPPH_PLUGIN_ALLOW_CHANGE_OPTION_NAME, true, true, array());
29
  if(! isset($activeOption)){ $activeOption = 2; }
30
  // end defaults
31
 
47
  $deleteEventsBy = intval($_POST['deleteEventsBy']);
48
  $deleteEventsValue = intval($_POST['deleteEventsValue']);
49
 
50
+ $pac = (isset($_POST['accessListInput']) ? trim($_POST['accessListInput']) : null);
51
+ $pcc = (isset($_POST['changeListInput']) ? trim($_POST['changeListInput']) : null);
52
+
53
  // pre-validate access rules if any
54
+ if(! empty($pac) && strlen($pac)>4){
55
+ $pac = str_replace('\\','', $pac);
56
+ $allowedAccess = json_decode($pac);
57
+ if(is_null($allowedAccess)){
58
+ wpphLog('Error decoding json input $pac.', array('pac'=>$pac));
59
+ $validationMessage['error'] = __('UAL: Error decoding json input', WPPH_PLUGIN_TEXT_DOMAIN);
60
+ $hasErrors = true;
61
+ }
62
+ else {
63
+ wpphLog('accessListInput is not empty.', array('pac'=>$pac,'data'=>$allowedAccess));
64
+ WPPHUtil::saveAllowAccessUserList($allowedAccess);
65
+ }
66
+ }
67
+ else {
68
+ wpphLog('accessListInput is empty. Resetting the user access list.');
69
+ WPPHUtil::saveAllowAccessUserList(array());
70
  }
71
+
72
  // pre-validate change rules if any
73
+ if(! empty($pcc) && strlen($pcc)>4){
74
+ $pcc = str_replace('\\','', $pcc);
75
+ $allowedChange = json_decode($pcc);
76
+ if(is_null($allowedChange)){
77
+ wpphLog('Error decoding json input $pcc.', array('pcc'=>$pcc));
78
+ $validationMessage['error'] = __('UCL: Error decoding json input: '.$pcc.' '.var_export($allowedChange,true), WPPH_PLUGIN_TEXT_DOMAIN);
79
+ $hasErrors = true;
80
+ }
81
+ else {
82
+ wpphLog('changeListInput is not empty.', array('pcc'=>$pcc,'data'=>$allowedChange));
83
+ WPPHUtil::saveAllowedChangeUserList($allowedChange);
84
+ }
85
+ }
86
+ else {
87
+ wpphLog('changeListInput is empty. Resetting the user access list.');
88
+ WPPHUtil::saveAllowedChangeUserList(array());
89
  }
90
 
91
  // if Delete events older than ... days
170
  .the-list td.column-username p,
171
  .the-list td.column-name p,
172
  .the-list td.column-role p { padding-left: 7px !important;}
173
+ .form-table td { vertical-align: top !important; }
174
+ .section-left label { margin-top: 3px !important; display: block;}
175
  </style>
176
  <div id="wpph-pageWrapper" class="wrap">
177
  <h2 class="pageTitle pageTitle-settings"><?php echo __('WP Security Audit Log Settings',WPPH_PLUGIN_TEXT_DOMAIN);?></h2>
193
  <table cellspacing="0" cellpadding="0" class="form-table">
194
  <tbody>
195
  <tr valign="top">
196
+ <td rowspan="3" class="section-left">
197
+ <label style="display:block;margin: 0 0;" for="eventsNumberInput"><?php echo __('Security Alerts Pruning',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
198
  </td>
199
  </tr>
200
  <tr>
218
  <input type="text" id="eventsNumberInput" maxlength="6"
219
  placeholder="<?php echo $wpph_t1;?>"
220
  value="<?php if(! empty($eventsNumber)) { echo $eventsNumber; } ;?>"/>
221
+ <span><?php echo $wpph_t1;?></span>
222
  </p>
223
+ <p class="description" style="margin-top: 5px !important;"><?php echo sprintf(__('By default %s will keep up to %d WordPress Security Events.',WPPH_PLUGIN_TEXT_DOMAIN),WPPH_PLUGIN_NAME, WPPH_KEEP_MAX_EVENTS);?></p>
224
  </td>
225
  </tr>
226
  <tr>
227
+ <td rowspan="2" class="section-left" style=""><label style="display:block;margin: 0 0;" for="optionDW_on"><?php echo __('Alerts Dashboard Widget',WPPH_PLUGIN_TEXT_DOMAIN);?></label></td>
 
 
 
 
228
  </tr>
229
  <tr>
230
  <td class="section-right">
231
  <input type="radio" id="optionDW_on" class="radioInput" style="margin-top: 2px;"/><label for="optionDW_on" style="padding-top: 5px; padding-left: 3px;"><?php echo __('On',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
232
+ <br/>
233
  <input type="radio" id="optionDW_off" class="radioInput" style="margin-top: 2px;"/><label for="optionDW_off" style="padding-top: 5px; padding-left: 3px;"><?php echo __('Off',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
234
+ <br/>
235
+ <p class="description" style="margin-top: 5px !important;"><?php echo sprintf(__('Display a dashboard widget with the latest 5 security alerts',WPPH_PLUGIN_TEXT_DOMAIN),WPPH_PLUGIN_NAME, WPPH_KEEP_MAX_EVENTS);?></p>
236
  </td>
237
  </tr>
238
  </tbody>
245
  .tagElement .tagDelete:hover { color: #d00000; }
246
  #section-holder #c-list p.description { margin-top: 0 !important; margin-bottom: 0 !important; }
247
  </style>
248
+ <table cellspacing="0" cellpadding="0" class="form-table">
249
  <tbody>
250
  <tr valign="top">
251
  <td valign="top" class="section-left">
252
+ <label style="display:block;margin: 0 0;" for="inputUser1"><?php echo __('Can view Security Alerts',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
253
  </td>
254
  <td class="section-right">
255
  <div id="a-list">
260
  </div>
261
  </td>
262
  </tr>
263
+ <tr valign="top" style="margin-top: 30px;">
 
 
264
  <td valign="top" class="section-left">
265
+ <label style="display:block;margin: 0 0;" for="inputUser2"><?php echo __('Can Manage Plugin ',WPPH_PLUGIN_TEXT_DOMAIN);?></label>
266
  </td>
267
  <td class="section-right">
268
  <div id="c-list">
283
  inputAdd1 = $('#inputAdd1'),
284
  divTarget1 = $('#accessListTarget'),
285
  tagElement1 = $('.tagElement', mainContainer1),
 
286
  mainContainer2 = $('#c-list'),
287
  inputUser2 = $('#inputUser2'),
288
  inputAdd2 = $('#inputAdd2'),
413
  });
414
  });
415
  </script>
 
416
  </div>
 
 
417
  </div>
418
  <p style="margin-top: 40px;">
419
  <input type="submit" id="submitButton" class="button button-primary" value="<?php echo __('Save settings',WPPH_PLUGIN_TEXT_DOMAIN);?>"/>
readme.txt CHANGED
@@ -2,32 +2,35 @@
2
  Contributors: WPWhiteSecurity
3
  License: GPLv3
4
  License URI: http://www.gnu.org/licenses/gpl.html
5
- Tags: wordpress security plugin, wordpress security audit log, audit 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, wordpress security monitor, analytics, activity, admin
6
  Requires at least: 3.0
7
  Tested up to: 3.8
8
- Stable tag: 0.5.1
9
 
10
- Identify WordPress security issues before they become a problem. Keep an audit log of everything that happens on WordPress including WordPress user activity.
11
 
12
  == Description ==
13
- Identify WordPress security issues before they become a problem by keeping an audit log of what is happening under the hood of your WordPress blog or website. WP Security Audit Log plugin is developed by WordPress Security Consultants and Professionals [WP White Security](http://www.wpwhitesecurity.com/wordpress-security-services/).
14
 
15
  = Keep A WordPress Security Audit Log & Identify WordPress Security Issues =
16
- WP Security Audit Log keeps a log of everything happening on your WordPress blog or website. By using WP Security Audit Log security plugin it is very easy to track suspicious user activity before it becomes a problem or a security issue. A security alert is generated by the plugin when:
17
 
18
  * New user is created via registration or created by another user
19
  * Existing user changes the role or password of another user
20
- * User uploads a file, changes a password or email address
 
21
  * User installs, activates, deactivates, upgrades or uninstalls a plugin
 
 
22
  * User adds, modifies or deletes a widget
23
  * WordPress settings are changed
24
- * Failed login attempt
25
  * and much more...
26
 
27
  Refer to the complete list of [WordPress Security Audit Alerts](http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-log/security-audit-alerts-logs/) for more information.
28
 
29
  = Monitor WordPress Users Activity & Productivity =
30
- If you own a multi user WordPress blog or website you can use the WP Security Audit Log plugin to monitor your users' activity and productivity. With this WordPress security plugin you can monitor:
31
 
32
  * When WordPress users logged in or out
33
  * From where WordPress users are logging in
@@ -36,17 +39,22 @@ If you own a multi user WordPress blog or website you can use the WP Security Au
36
  * Users who published a blog post or a page
37
  * Users who modified published WordPress content such as a page or a blog post
38
  * Users who modify WordPress widgets
 
39
  * and much more...
40
 
41
  Refer to the complete list of [WordPress Security Audit Alerts](http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-log/security-audit-alerts-logs/) for more information.
42
 
43
- = WordPress Audit Log in your Language! =
 
 
 
 
 
44
  We need help translating the plugin and the WordPress Security Events. If you're good at translating, please drop us an email on plugins@wpwhitesecurity.com.
45
 
46
  = WordPress Security Tips & Tricks =
47
  Even if WordPress security is not your cup of tea, the security of your WordPress is your responsibility. Keep yourself up to date with the latest WordPress Security Tips & Tricks. WP White Security frequently publishes WordPress security tips & tricks on the [WordPress Security section](http://www.wpwhitesecurity.com/wordpress-security/) of their blog.
48
 
49
-
50
  = Further Reading =
51
  For more information and to get started with WordPress Security, check out the following:
52
 
@@ -59,7 +67,7 @@ To keep yourself updated with what is new and updated in our WordPress security
59
 
60
  == Installation ==
61
 
62
- 1. Upload the `wordress-security-audit-log` folder to the `/wp-content/plugins/` directory
63
  2. Activate the WP Security Audit Log plugin from the 'Plugins' menu in the WordPress Administration Screens
64
  3. Access the Security audit logs and the plugin settings from the "Security Audit Log" menu that appears in your admin menu
65
 
@@ -76,14 +84,38 @@ Yes. A complete list can be found [here](http://www.wpwhitesecurity.com/wordpres
76
 
77
  Yes it is possible to disable (and re-enable later) specific WordPress security alerts. To do so navigate to the "Enable/Disable Alerts" node in the plugin, select the category tab and untick the WordPress security alert. Tick back the alert to re-enable it.
78
 
 
 
 
79
  == Screenshots ==
80
 
81
  1. The Audit Log Viewer from where the WordPress administrator can see all the security events generated by WP Security Audit Log WordPress plugin.
82
  2. The WP Security Audit Log plugin options from where WordPress administrator can configure the auto pruning of security alerts and specific user access.
83
  3. The Enable/Disable Alerts settings node from where Administrators can disable or enable WordPress security alerts.
 
84
 
85
  == Changelog ==
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  = 0.5.1 (2013-12-11) =
88
  * Bug Fix
89
  * Fixed an issue with Edit Post function (in very specific cases) (http://wordpress.org/support/topic/was-working-great-no-post-edit-function-now)
@@ -94,7 +126,7 @@ Yes it is possible to disable (and re-enable later) specific WordPress security
94
  * Alert 2043: A widget was modified
95
  * Alert 2044: A widget was deleted
96
  * Alert 2045: A widget was moved
97
-
98
  * New Plugin Features
99
  * New setting to allow specific user(s) and role(s) to view the Audit Log Viewer (read only)
100
  * New setting to allow specific user(s) and role(s) to manage the WP Security Audit Log plugin (can change plugin settings, enable disable WordPress security alerts etc)
@@ -105,7 +137,7 @@ Yes it is possible to disable (and re-enable later) specific WordPress security
105
 
106
  * Bug Fixes
107
  * Fixed issue where all users were able to see the Dashboard widgets with security alerts - now restricted only to users who have access to the plugin
108
- * Fixed user reported issue (http://wordpress.org/support/topic/errors-on-enabledisable-alerts-page)
109
 
110
  = 0.4 (2013-10-09) =
111
  * New WordPress Security Alerts for Custom Post Types
2
  Contributors: WPWhiteSecurity
3
  License: GPLv3
4
  License URI: http://www.gnu.org/licenses/gpl.html
5
+ Tags: wordpress security plugin, wordpress security audit log, audit 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, wordpress security monitor, analytics, activity, admin, multisite, wordpress multisite
6
  Requires at least: 3.0
7
  Tested up to: 3.8
8
+ Stable tag: 0.6
9
 
10
+ Identify WordPress issues before they become a security problem by keeping an audit log of users and all of the under the hood WordPress activity.
11
 
12
  == Description ==
13
+ Identify WordPress security issues before they become a security problem by keeping a security audit log of what is happening under the hood of your WordPress blog or website or your WordPress Multisite installation. WP Security Audit Log plugin is developed by WordPress Security Consultants and Professionals [WP White Security](http://www.wpwhitesecurity.com/wordpress-security-services/) and works on both WordPress and [WordPress Multisite](http://www.wpwhitesecurity.com/wordpress-plugins/wp-security-audit-log-plugin-features-wordpress-multisite/).
14
 
15
  = Keep A WordPress Security Audit Log & Identify WordPress Security Issues =
16
+ WP Security Audit Log keeps a log of everything happening on your WordPress blog or website and WordPress multisite network. By using WP Security Audit Log security plugin it is very easy to track suspicious user activity before it becomes a problem or a security issue. A security alert is generated by the plugin when:
17
 
18
  * New user is created via registration or created by another user
19
  * Existing user changes the role or password of another user
20
+ * Existing user on a WordPress multisite network is added to a site
21
+ * User uploads or deletes a file, changes a password or email address
22
  * User installs, activates, deactivates, upgrades or uninstalls a plugin
23
+ * User creates a new post, page, category or a custom post type
24
+ * User modifies an existing post, page, category or a custom post type
25
  * User adds, modifies or deletes a widget
26
  * WordPress settings are changed
27
+ * Failed login attempts
28
  * and much more...
29
 
30
  Refer to the complete list of [WordPress Security Audit Alerts](http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-log/security-audit-alerts-logs/) for more information.
31
 
32
  = Monitor WordPress Users Activity & Productivity =
33
+ If you own a multi user WordPress blog or website, or a WordPress multisite network installation you can use the WP Security Audit Log plugin to monitor your users' activity and productivity. With WP Security Audit Log WordPress plugin you can monitor:
34
 
35
  * When WordPress users logged in or out
36
  * From where WordPress users are logging in
39
  * Users who published a blog post or a page
40
  * Users who modified published WordPress content such as a page or a blog post
41
  * Users who modify WordPress widgets
42
+ * Uses who upload or delete files
43
  * and much more...
44
 
45
  Refer to the complete list of [WordPress Security Audit Alerts](http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-log/security-audit-alerts-logs/) for more information.
46
 
47
+ = WP Security Audit Log for WordPress Multisite =
48
+ WP Security Audit Log is the first and only tracking and audit security plugin that supports WordPress multisite network installations.
49
+
50
+ For more information about WP Security Audit log plugin features for WordPress Multisite network installation refer to [WP Security Audit Log Features for WordPress Multisite](http://www.wpwhitesecurity.com/wordpress-plugins/wp-security-audit-log-plugin-features-wordpress-multisite/)
51
+
52
+ = WordPress Security Audit Log in your Language! =
53
  We need help translating the plugin and the WordPress Security Events. If you're good at translating, please drop us an email on plugins@wpwhitesecurity.com.
54
 
55
  = WordPress Security Tips & Tricks =
56
  Even if WordPress security is not your cup of tea, the security of your WordPress is your responsibility. Keep yourself up to date with the latest WordPress Security Tips & Tricks. WP White Security frequently publishes WordPress security tips & tricks on the [WordPress Security section](http://www.wpwhitesecurity.com/wordpress-security/) of their blog.
57
 
 
58
  = Further Reading =
59
  For more information and to get started with WordPress Security, check out the following:
60
 
67
 
68
  == Installation ==
69
 
70
+ 1. Upload the `wp-security-audit-log` folder to the `/wp-content/plugins/` directory
71
  2. Activate the WP Security Audit Log plugin from the 'Plugins' menu in the WordPress Administration Screens
72
  3. Access the Security audit logs and the plugin settings from the "Security Audit Log" menu that appears in your admin menu
73
 
84
 
85
  Yes it is possible to disable (and re-enable later) specific WordPress security alerts. To do so navigate to the "Enable/Disable Alerts" node in the plugin, select the category tab and untick the WordPress security alert. Tick back the alert to re-enable it.
86
 
87
+ = Can WP Security Audit Log plugin work and monitor activity on WodPress Multisite? =
88
+ Yes, WP Security Audit Log works on WordPress Multisite networkds. For more information refer to the post [WP Security Audit Log Features for WordPress Multisite installation](http://www.wpwhitesecurity.com/wordpress-plugins/wp-security-audit-log-plugin-features-wordpress-multisite/).
89
+
90
  == Screenshots ==
91
 
92
  1. The Audit Log Viewer from where the WordPress administrator can see all the security events generated by WP Security Audit Log WordPress plugin.
93
  2. The WP Security Audit Log plugin options from where WordPress administrator can configure the auto pruning of security alerts and specific user access.
94
  3. The Enable/Disable Alerts settings node from where Administrators can disable or enable WordPress security alerts.
95
+ 4. The Audit Log Viewer of a Super Admin in a WordPress multisite network installation with the Site selection drop down menu.
96
 
97
  == Changelog ==
98
 
99
+ = 0.6 (2014-01-15) =
100
+ * New Plugin Feature
101
+ * WordPress Multisite Support [Read More](http://www.wpwhitesecurity.com/wordpress-plugins/wp-security-audit-log-plugin-features-wordpress-multisite/)
102
+
103
+ * New WordPress Security Alerts for monitoring specific multisite activity on a WordPress multisite network installation
104
+ * Alert 4008: User is granted super admin privileges (network)
105
+ * Alert 4009: Super admin privileges (network) are revoked from a user
106
+ * Alert 4010: Added an existing user to a site and assigned a specific role
107
+ * Alert 4011: Removed user with a specific role from a site
108
+ * Alert 4012: New user created on the network
109
+ * Alert 7000: Added a new site to network
110
+ * Alert 7001: A site was archived
111
+ * Alert 7002: A site was unarchived
112
+ * Alert 7003: A site was activated
113
+ * Alert 7004: A site was deactivated
114
+ * Alert 7005: A site was deleted
115
+
116
+ * Plugin Improvements
117
+ * Plugin settings page to have the same look and feel of the new WordPress dashboard (3.8)
118
+
119
  = 0.5.1 (2013-12-11) =
120
  * Bug Fix
121
  * Fixed an issue with Edit Post function (in very specific cases) (http://wordpress.org/support/topic/was-working-great-no-post-edit-function-now)
126
  * Alert 2043: A widget was modified
127
  * Alert 2044: A widget was deleted
128
  * Alert 2045: A widget was moved
129
+
130
  * New Plugin Features
131
  * New setting to allow specific user(s) and role(s) to view the Audit Log Viewer (read only)
132
  * New setting to allow specific user(s) and role(s) to manage the WP Security Audit Log plugin (can change plugin settings, enable disable WordPress security alerts etc)
137
 
138
  * Bug Fixes
139
  * Fixed issue where all users were able to see the Dashboard widgets with security alerts - now restricted only to users who have access to the plugin
140
+ * Fixed user reported issue (http://wordpress.org/support/topic/errors-on-enabledisable-alerts-page)
141
 
142
  = 0.4 (2013-10-09) =
143
  * New WordPress Security Alerts for Custom Post Types
res/css/styles.base.css CHANGED
@@ -9,6 +9,8 @@ h2.pageTitle-about { background: url("../img/page-about-logo.png") no-repeat lef
9
  #wpph-pageWrapper .button { margin-top: 1px;}
10
  #wpph-pageWrapper .buttonRefreshEventsList { margin-top: 3px;}
11
 
 
 
12
 
13
  /*
14
  * Page: Event Viewer
@@ -46,10 +48,11 @@ h2.pageTitle-about { background: url("../img/page-about-logo.png") no-repeat lef
46
  #section-holder p input[type="text"] { float: left; margin-left: 10px !important; }
47
 
48
  .form-table, .form-table td { border: none 0;}
49
- .form-table td { line-height: normal !important;; }
50
- .form-table td.section-left { width: 190px; padding: 0 30px 0 0; }
 
51
  .form-table td.section-right p { padding: 0 0 !important; margin: 0 0 !important; }
52
- .form-table td #optionDW_off { margin-left: 10px; }
53
 
54
  #errMessage { margin: 20px 0; }
55
  #eventsDeletion #description,
@@ -60,11 +63,11 @@ h2.pageTitle-about { background: url("../img/page-about-logo.png") no-repeat lef
60
  }
61
  #optionsDescription #description { margin: 20px 0; }
62
 
63
- .widefat .item-cb { width: 50px !important; }
64
  .widefat .item-event { width: 100px !important; text-align: left; padding: 8px 7px 2px 7px !important; }
65
- .widefat .item-type { width: 100px !important; text-align: left; padding: 8px 7px 2px 7px !important; }
66
  .widefat .item-description { width: auto !important; text-align: left; padding: 8px 7px 2px 7px !important; }
67
-
68
  /*
69
  * Page: Events :: pagination
70
  */
9
  #wpph-pageWrapper .button { margin-top: 1px;}
10
  #wpph-pageWrapper .buttonRefreshEventsList { margin-top: 3px;}
11
 
12
+ .wpph-text-disabled { color: #c0c0c0 !important; }
13
+
14
 
15
  /*
16
  * Page: Event Viewer
48
  #section-holder p input[type="text"] { float: left; margin-left: 10px !important; }
49
 
50
  .form-table, .form-table td { border: none 0;}
51
+ .form-table td { line-height: normal !important; }
52
+ .form-table td.section-left { width: 190px; padding: 0 0; }
53
+ .form-table td.section-right { padding: 0 0 20px 0 !important; margin: 0 0 !important; }
54
  .form-table td.section-right p { padding: 0 0 !important; margin: 0 0 !important; }
55
+ .form-table td.section-left label { font-weight: bold; }
56
 
57
  #errMessage { margin: 20px 0; }
58
  #eventsDeletion #description,
63
  }
64
  #optionsDescription #description { margin: 20px 0; }
65
 
66
+ .widefat .item-cb_h { width: 50px !important; }
67
  .widefat .item-event { width: 100px !important; text-align: left; padding: 8px 7px 2px 7px !important; }
68
+ .widefat .item-type { min-width: 100px !important; text-align: left; padding: 8px 7px 2px 7px !important; }
69
  .widefat .item-description { width: auto !important; text-align: left; padding: 8px 7px 2px 7px !important; }
70
+ .widefat tbody th.check-column { padding: 11px 0 0 3px !important; }
71
  /*
72
  * Page: Events :: pagination
73
  */
res/js/audit-view-model.js CHANGED
@@ -1,216 +1,314 @@
1
- var AuditLogViewModel = (function($) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- function loadRemoteData(viewModel, offset) {
4
- var data = {
5
- 'action': 'wpph_get_events',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
- 'orderBy': viewModel.orderBy(),
8
- 'sort': viewModel.orderByDescending() ? 'desc' : 'asc',
9
 
10
- 'offset': offset,
11
- 'count': viewModel.pageSize()
12
- };
13
 
14
- AjaxLoaderShow(__ajaxLoaderTargetElement__);
15
 
16
- $.ajax({
17
- url: ajaxurl,
18
- cache: false,
19
- type: 'POST',
20
- data: data,
21
- beforeSend: function() {
22
- viewModel.loading(true)
23
- },
24
- success: function(response) {
25
- viewModel.loading(false);
26
- var json = $.parseJSON(response);
27
-
28
- if (json.error.length > 0) {
29
- AjaxLoaderHide(__ajaxLoaderTargetElement__);
30
- return;
31
- }
32
 
33
- AjaxLoaderHide(__ajaxLoaderTargetElement__);
 
 
 
 
 
 
 
34
 
35
- viewModel.events(json.dataSource.events);
36
- viewModel.totalEventsCount(json.dataSource.eventsCount);
37
- viewModel.offset(offset);
38
 
39
- if (viewModel.totalEventsCount() < viewModel.offset()) {
40
- viewModel.offset(0);
 
 
 
41
  }
42
 
43
- if (viewModel.offset() == 0)
44
- viewModel.currentPage(1);
45
- else
46
- viewModel.currentPage(1 + viewModel.offset() / viewModel.pageSize());
47
-
48
- },
49
- error: function() {
50
- viewModel.loading(false);
51
- }
52
- });
53
- }
54
 
55
- function AuditLogViewModel()
56
- {
57
- this.columns = ko.observableArray([
58
- {columnHeader: 'Event', columnName: 'EventNumber', sortable: true, columnWidth: '5%', sorted: ko.observable(false), sortedDescending: ko.observable(false)},
59
- {columnHeader: 'ID', columnName: 'EventID', sortable: true, columnWidth: '5%', sorted: ko.observable(false), sortedDescending: ko.observable(false)},
60
- {columnHeader: 'Date', columnName: 'EventDate', sortable: true, columnWidth: '11%', sorted: ko.observable(false), sortedDescending: ko.observable(false)},
61
- {columnHeader: 'Type', columnName: 'EventType', sortable: true, columnWidth: '6%', sorted: ko.observable(false), sortedDescending: ko.observable(false)},
62
- {columnHeader: 'IP Address', columnName: 'UserIP', sortable: true, columnWidth: '9%', sorted: ko.observable(false), sortedDescending: ko.observable(false)},
63
- {columnHeader: 'User', columnName: 'UserID', sortable: true, columnWidth: '10%', sorted: ko.observable(false), sortedDescending: ko.observable(false)},
64
- {columnHeader: 'Description', columnName: 'EventDescription', sortable: false, columnWidth: 'auto', sorted: ko.observable(false), sortedDescending: ko.observable(false)}]);
65
-
66
- this.loading = ko.observable(false);
67
- this.events = ko.observableArray([]);
68
- this.totalEventsCount = ko.observable(0);
69
- this.offset = ko.observable(0);
70
- this.availablePageSize = ko.observableArray([25, 50, 100]);
71
-
72
- var _initialPageSize = parseInt($.cookie('wpph_ck_page_size'));
73
- if (this.availablePageSize.indexOf(_initialPageSize) < 0) {
74
- _initialPageSize = this.availablePageSize()[1];
75
- }
76
 
77
- this.pageSize = ko.observable(_initialPageSize);
78
- this.selectedPageSize = ko.observable(_initialPageSize);
79
- this.pageCount = ko.computed(function() {
80
- return Math.ceil(this.totalEventsCount() / this.pageSize());
81
- }, this);
82
-
83
- this. _currentPageIndex = 1;
84
- var vm = this;
85
- this.currentPage = ko.computed({
86
- read: function() {
87
- return this._currentPageIndex;
88
- },
89
- write: function(value) {
90
- value = parseInt(value);
91
- if (isNaN(value) || value < 1 || value > this.pageCount()) {
92
- return;
93
  }
94
- this._currentPageIndex = value;
95
- this.currentPage.notifySubscribers();
96
- $('#fdr').val(this._currentPageIndex);
97
- },
98
- owner: vm
99
- });
100
-
101
- this.orderBy = ko.computed({
102
- read: function() {
103
- var columnInfo = ko.utils.arrayFirst(this.columns(), function(item) { return item.sorted(); })
104
- return columnInfo && columnInfo.columnName || '';
105
- },
106
- write: function(value) {
107
- var columnInfo = ko.utils.arrayFirst(this.columns(), function(item) {
108
- return item.columnName === value;
109
- });
110
- if (columnInfo) {
111
- ko.utils.arrayForEach(this.columns(), function(item) {
112
- item.sorted(false);
113
- item.sortedDescending(false);
114
- });
115
- columnInfo.sorted(value)
116
  }
117
- }
118
- }, this);
119
- this.orderByDescending = ko.computed({
120
- read: function() {
121
- var columnInfo = ko.utils.arrayFirst(this.columns(), function(item) { return item.sorted(); })
122
- return columnInfo && columnInfo.sortedDescending();
123
- },
124
- write: function(value) {
125
- var columnInfo = ko.utils.arrayFirst(this.columns(), function(item) { return item.sorted(); })
126
- columnInfo && columnInfo.sortedDescending(value);
127
- }
128
- }, this);
 
129
  }
130
 
131
- AuditLogViewModel.prototype.onCurrentPageInputKeyDown = function(viewModel, event) {
132
  if (event.keyCode === 13) {
133
- var value = parseInt(event.currentTarget.value);
134
- if (isNaN(value) || value < 1 || value > viewModel.pageCount()) {
135
- viewModel.currentPage(viewModel._currentPageIndex);
136
- viewModel.currentPage.notifySubscribers();
137
  return;
138
  }
139
- viewModel.currentPage(value);
140
- viewModel.refreshEvents(viewModel, ( viewModel._currentPageIndex - 1) * viewModel.pageSize());
141
  return false;
142
  }
143
  return true;
144
- };
145
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
 
148
- AuditLogViewModel.prototype.applyPageSize = function(viewModel){
149
- var newPageSize = parseInt(viewModel.selectedPageSize());
150
- viewModel.pageSize(newPageSize);
151
  var secureCookie = false;
152
  if (window.location.href.indexOf('https://') > -1) {
153
  secureCookie = true;
154
  }
155
  $.cookie('wpph_ck_page_size', newPageSize, {secure: secureCookie});
156
- viewModel.refreshEvents(viewModel, 0);
157
- };
158
 
159
- AuditLogViewModel.prototype.applySorting = function(viewModel, columnInfo) {
160
- if (viewModel.orderBy() == columnInfo.columnName) {
161
- viewModel.orderByDescending(! viewModel.orderByDescending());
162
  }
163
  else {
164
- viewModel.orderBy(columnInfo.columnName);
165
- viewModel.orderByDescending(false);
166
  }
167
- viewModel.refreshEvents(viewModel, 0);
168
- };
 
169
 
170
- AuditLogViewModel.prototype.nextPage = function(viewModel) {
171
- var currentOffset = viewModel.offset();
172
- var newOffset = currentOffset + viewModel.pageSize();
173
 
174
- if (newOffset < viewModel.totalEventsCount()) {
175
- viewModel.refreshEvents(viewModel, newOffset);
176
  }
177
- };
178
 
179
- AuditLogViewModel.prototype.prevPage = function(viewModel) {
180
- var currentOffset = viewModel.offset();
181
- var newOffset = currentOffset - viewModel.pageSize();
182
 
183
  if (newOffset >= 0) {
184
- viewModel.refreshEvents(viewModel, newOffset);
185
  }
186
- };
187
 
188
- //TODO
189
- AuditLogViewModel.prototype.firstPage = function(viewModel) {
190
- if (viewModel.offset() > 0)
191
- viewModel.refreshEvents(viewModel, 0);
192
- };
193
 
194
- //TODO
195
- AuditLogViewModel.prototype.lastPage = function(viewModel) {
196
  var offset = Math.min(
197
- viewModel.totalEventsCount(),
198
- viewModel.pageSize() * (viewModel.pageCount() - 1)
199
  );
200
- if (viewModel.offset() != offset)
201
- viewModel.refreshEvents(viewModel, offset);
202
- };
203
 
204
 
205
- AuditLogViewModel.prototype.refreshEvents = function(viewModel, offset) {
206
- loadRemoteData(viewModel, offset);
207
- };
 
 
 
 
 
 
 
 
208
 
209
- AuditLogViewModel.prototype.cleanRefresh = function(viewModel) {
210
- loadRemoteData(viewModel, 0);
211
- };
212
 
213
- return AuditLogViewModel;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
- })(jQuery);
216
 
1
+ var AuditLogViewModel = (function($, ko) {
2
+ "use strict";
3
+ /*global AjaxLoaderShow, AjaxLoaderHide, ajaxurl, __ajaxLoaderTargetElement__*/
4
+ /*jshint curly:false,devel:true*/
5
+
6
+ var error = ko.observable('');
7
+ var loading = ko.observable(false);
8
+ var events = ko.observableArray([]);
9
+ var totalEventsCount = ko.observable(0);
10
+ var offset = ko.observable(0);
11
+ var availablePageSize = ko.observableArray([25, 50, 100]);
12
+ var isMainSite = ko.observable(false);
13
+ var _blogId = ko.observable();
14
+ var blogId = ko.computed({
15
+ read: function() {
16
+ var parsedValue = parseInt(_blogId(), 10);
17
+ return isNaN(parsedValue) ? undefined : parsedValue;
18
+ },
19
+ write: function(newValue) {
20
+ newValue = parseInt(newValue, 10);
21
+ if (isNaN(newValue)) newValue = undefined;
22
+ if (_blogId() !== newValue) {
23
+ // console.warn('blogId changed from %o to %o', _blogId(), newValue);
24
+ var refresh = false;
25
+ if (_blogId() !== undefined) {
26
+ refresh = true;
27
+ }
28
+ _blogId(newValue);
29
+ if (refresh) {
30
+ refreshEvents(0, newValue);
31
+ }
32
+ }
33
+ }
34
+ });
35
+ var blogList = ko.observableArray();
36
+
37
+ var columns = ko.observableArray([
38
+ {columnHeader: 'Event', columnName: 'EventNumber', sortable: true, columnWidth: '5%', sorted: ko.observable(false), sortedDescending: ko.observable(false), visible: true },
39
+ {columnHeader: 'ID', columnName: 'EventID', sortable: true, columnWidth: '5%', sorted: ko.observable(false), sortedDescending: ko.observable(false), visible: true},
40
+ {columnHeader: 'Date', columnName: 'EventDate', sortable: true, columnWidth: '11%', sorted: ko.observable(false), sortedDescending: ko.observable(false), visible: true},
41
+ {columnHeader: 'Type', columnName: 'EventType', sortable: true, columnWidth: '6%', sorted: ko.observable(false), sortedDescending: ko.observable(false), visible: true},
42
+ {columnHeader: 'IP Address', columnName: 'UserIP', sortable: true, columnWidth: '9%', sorted: ko.observable(false), sortedDescending: ko.observable(false), visible: true},
43
+ {columnHeader: 'User', columnName: 'UserID', sortable: true, columnWidth: '10%', sorted: ko.observable(false), sortedDescending: ko.observable(false), visible: true},
44
+ {columnHeader: 'Site', columnName: 'SiteName', sortable: true, columnWidth: '10%', sorted: ko.observable(true), sortedDescending: ko.observable(false), visible: ko.computed(function() {
45
+ return blogId() === 0;
46
+ })},
47
+ {columnHeader: 'Description', columnName: 'EventDescription', sortable: false, columnWidth: 'auto', sorted: ko.observable(false), sortedDescending: ko.observable(false), visible: true}
48
+ ]);
49
+
50
+
51
+ var _initialPageSize = parseInt($.cookie('wpph_ck_page_size'), 10);
52
+ if (availablePageSize.indexOf(_initialPageSize) < 0) {
53
+ _initialPageSize = availablePageSize()[1];
54
+ }
55
 
56
+ var pageSize = ko.observable(_initialPageSize);
57
+ var selectedPageSize = ko.observable(_initialPageSize);
58
+ var pageCount = ko.computed(function() {
59
+ return Math.ceil(totalEventsCount() / pageSize());
60
+ });
61
+
62
+ var _currentPageIndex = 1;
63
+ var currentPage = ko.computed({
64
+ read: function() {
65
+ return _currentPageIndex;
66
+ },
67
+ write: function(value) {
68
+ value = parseInt(value, 10);
69
+ if (isNaN(value) || value < 1 || value > pageCount()) {
70
+ return;
71
+ }
72
+ _currentPageIndex = value;
73
+ currentPage.notifySubscribers();
74
+ $('#fdr').val(_currentPageIndex);
75
+ }
76
+ });
77
+
78
+ var orderBy = ko.computed({
79
+ read: function() {
80
+ var columnInfo = ko.utils.arrayFirst(columns(), function(item) { return item.sorted(); });
81
+ return columnInfo && columnInfo.columnName || '';
82
+ },
83
+ write: function(value) {
84
+ var columnInfo = ko.utils.arrayFirst(columns(), function(item) {
85
+ return item.columnName === value;
86
+ });
87
+ if (columnInfo) {
88
+ ko.utils.arrayForEach(columns(), function(item) {
89
+ item.sorted(false);
90
+ item.sortedDescending(false);
91
+ });
92
+ columnInfo.sorted(value);
93
+ }
94
+ }
95
+ });
96
+ var orderByDescending = ko.computed({
97
+ read: function() {
98
+ var columnInfo = ko.utils.arrayFirst(columns(), function(item) { return item.sorted(); });
99
+ return !!(columnInfo && columnInfo.sortedDescending());
100
+ },
101
+ write: function(value) {
102
+ var columnInfo = ko.utils.arrayFirst(columns(), function(item) { return item.sorted(); });
103
+ if (columnInfo) columnInfo.sortedDescending(value);
104
+ }
105
+ });
106
 
 
 
107
 
108
+ function loadRemoteData(newOffset, bid) {
109
+ newOffset = newOffset || 0;
 
110
 
111
+ var _blogId = null;
112
 
113
+ if(bid !== null){
114
+ _blogId = bid;
115
+ }
116
+ else {
117
+ _blogId = parseInt(blogId(), 10);
118
+ if (isNaN(_blogId)) _blogId = undefined;
119
+ }
 
 
 
 
 
 
 
 
 
120
 
121
+ var data = {
122
+ action: 'wpph_get_events',
123
+ orderBy: orderBy(),
124
+ sort: orderByDescending() ? 'desc' : 'asc',
125
+ offset: newOffset,
126
+ count: pageSize(),
127
+ blogID: _blogId
128
+ };
129
 
130
+ // busy property possible?
131
+ AjaxLoaderShow(__ajaxLoaderTargetElement__);
132
+ loading(true);
133
 
134
+ $.ajax({ url: ajaxurl, cache: false, type: 'POST', data: data, dataType: 'json' })
135
+ .then(function (response) {
136
+ if (response.dataSource.blogs) {
137
+ blogList.removeAll();
138
+ ko.utils.arrayPushAll(blogList(), response.dataSource.blogs);
139
  }
140
 
141
+ if (response.error.length > 0) {
142
+ error(response.error);
143
+ events.removeAll();
144
+ totalEventsCount(0);
145
+ offset(0);
146
+ $('#wpph_ew').attr('colspan', _blogId===undefined ? 8 : 7);
147
+ return;
148
+ }
149
+ events(response.dataSource.events);
150
+ totalEventsCount(response.dataSource.eventsCount);
151
+ offset(newOffset);
152
 
153
+ if (response.dataSource.blogID) {
154
+ blogId(response.dataSource.blogID);
155
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
+ if (totalEventsCount() < offset()) {
158
+ offset(0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  }
160
+
161
+ if (offset() === 0) {
162
+ currentPage(1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  }
164
+ else { currentPage(1 + offset() / pageSize()); }
165
+ })
166
+ .fail(function () {
167
+ //Report data loading error
168
+ error("An error occurred while loading data. Please try again in a few moments.");
169
+ events.removeAll();
170
+ totalEventsCount(0);
171
+ offset(0);
172
+ })
173
+ .always(function () {
174
+ loading(false);
175
+ AjaxLoaderHide(__ajaxLoaderTargetElement__);
176
+ });
177
  }
178
 
179
+ function onCurrentPageInputKeyDown(viewModel, event) {
180
  if (event.keyCode === 13) {
181
+ var value = parseInt(event.currentTarget.value, 10);
182
+ if (isNaN(value) || value < 1 || value > pageCount()) {
183
+ currentPage(_currentPageIndex);
184
+ currentPage.notifySubscribers();
185
  return;
186
  }
187
+ currentPage(value);
188
+ refreshEvents((_currentPageIndex - 1) * pageSize());
189
  return false;
190
  }
191
  return true;
192
+ }
193
 
194
+ function onRefreshEvents() {
195
+ refreshEvents(0, blogId());
196
+ }
197
+
198
+ function onApplyPageSize() {
199
+ applyPageSize();
200
+ }
201
+
202
+ function onApplySorting(columnItem) {
203
+ applySorting(columnItem);
204
+ }
205
 
206
 
207
+ function applyPageSize(){
208
+ var newPageSize = parseInt(selectedPageSize(), 10);
209
+ pageSize(newPageSize);
210
  var secureCookie = false;
211
  if (window.location.href.indexOf('https://') > -1) {
212
  secureCookie = true;
213
  }
214
  $.cookie('wpph_ck_page_size', newPageSize, {secure: secureCookie});
215
+ refreshEvents(0);
216
+ }
217
 
218
+ function applySorting(columnInfo) {
219
+ if (orderBy() === columnInfo.columnName) {
220
+ orderByDescending(! orderByDescending());
221
  }
222
  else {
223
+ orderBy(columnInfo.columnName);
224
+ orderByDescending(false);
225
  }
226
+ refreshEvents(0);
227
+ }
228
+
229
 
230
+ function nextPage() {
231
+ var currentOffset = offset();
232
+ var newOffset = currentOffset + pageSize();
233
 
234
+ if (newOffset < totalEventsCount()) {
235
+ refreshEvents(newOffset);
236
  }
237
+ }
238
 
239
+ function prevPage() {
240
+ var currentOffset = offset();
241
+ var newOffset = currentOffset - pageSize();
242
 
243
  if (newOffset >= 0) {
244
+ refreshEvents(newOffset);
245
  }
246
+ }
247
 
248
+ function firstPage() {
249
+ if (offset() > 0)
250
+ refreshEvents(0);
251
+ }
 
252
 
253
+ function lastPage() {
 
254
  var offset = Math.min(
255
+ totalEventsCount(),
256
+ pageSize() * (pageCount() - 1)
257
  );
258
+ if (offset() !== offset)
259
+ refreshEvents(offset);
260
+ }
261
 
262
 
263
+ function refreshEvents(offset, bid) {
264
+ if (loading()) {
265
+ console.warn('Cannot refresh events. Still busy!!!');
266
+ return;
267
+ }
268
+ // console.warn('refreshEvents: %d', offset);
269
+ if(bid !== null){
270
+ loadRemoteData(offset, bid);
271
+ }
272
+ else { loadRemoteData(offset); }
273
+ }
274
 
 
 
 
275
 
276
+ return {
277
+ columns: columns,
278
+ error: error,
279
+ loading: loading,
280
+ events: events,
281
+ totalEventsCount: totalEventsCount,
282
+ offset: offset,
283
+ availablePageSize: availablePageSize,
284
+
285
+ isMainSite: isMainSite,
286
+ blogId: blogId,
287
+ blogList: blogList,
288
+
289
+ pageSize: pageSize,
290
+ selectedPageSize: selectedPageSize,
291
+ pageCount: pageCount,
292
+
293
+
294
+ currentPage: currentPage,
295
+ orderBy: orderBy,
296
+ orderByDescending: orderByDescending,
297
+
298
+ onCurrentPageInputKeyDown: onCurrentPageInputKeyDown,
299
+ onRefreshEvents: onRefreshEvents,
300
+ onApplyPageSize: onApplyPageSize,
301
+ onApplySorting: onApplySorting,
302
+
303
+ nextPage: nextPage,
304
+ prevPage: prevPage,
305
+ firstPage: firstPage,
306
+ lastPage: lastPage,
307
+
308
+ applyPageSize: applyPageSize,
309
+ applySorting: applySorting,
310
+ refreshEvents: refreshEvents
311
+ };
312
 
313
+ })(window.jQuery, window.ko);
314
 
wp-security-audit-log.php CHANGED
@@ -4,11 +4,11 @@ Plugin Name: WP Security Audit Log
4
  Plugin URI: http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-log/
5
  Description: Identify WordPress security issues before they become a problem and keep track of everything happening on your WordPress, including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Security Audit Log will generate a security alert for everything that happens on your WordPress blog or website. Use the Audit Log Viewer included in the plugin to see all the security alerts.
6
  Author: WP White Security
7
- Version: 0.5.1
8
  Author URI: http://www.wpwhitesecurity.com/
9
  License: GPL2
10
  Text Domain: wp-security-audit-log
11
- Domain Path: languages/
12
 
13
  WP Security Audit Log
14
  Copyright(c) 2013 Robert Abela (email : robert@wpwhitesecurity.com)
@@ -26,7 +26,7 @@ Domain Path: languages/
26
  along with this program; if not, write to the Free Software
27
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28
  */
29
- define('WPPH_PLUGIN_VERSION','0.5.1');
30
  define('WPPH_PLUGIN_PREFIX', 'wpph_');
31
  define('WPPH_PLUGIN_NAME', 'WP Security Audit Log');
32
  define('WPPH_PLUGIN_URL', trailingslashit(plugins_url('', __FILE__)));
@@ -36,14 +36,38 @@ else { define('WPPH_PLUGIN_BASE_NAME', basename(dirname(__FILE__))); }
36
 
37
  // Load required files
38
  require('inc/wpphSettings.php');
 
39
  require('inc/WPPHLogger.php');
40
  require('inc/WPPHUtil.php');
 
41
  require('inc/WPPHDatabase.php');
42
  require('inc/WPPHEvent.php');
43
  require('inc/WPPHPost.php');
44
- require('inc/WPPH.php');
45
  require('inc/wpphFunctions.php');
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  // 2000
48
  $GLOBALS['WPPH_POST_IS_NEW'] = false;
49
  add_action('wp_insert_post', 'wpphPostDetectNew', 1, 2);
@@ -55,25 +79,13 @@ function wpphPostDetectNew($post, $wp_error = false){
55
  }
56
  }
57
 
58
- /**
59
- * triggered when the plugin is uninstalled (with option files delete: true)
60
- */
61
- function onPluginUninstall()
62
- {
63
- global $wpdb;
64
- delete_option(WPPH_PLUGIN_DB_UPDATED);
65
- delete_option(WPPH_PLUGIN_VERSION_OPTION_NAME);
66
- delete_option(WPPH_USERS_CAN_REGISTER_OPT_NAME);
67
- delete_option(WPPH_PLUGIN_ALLOW_ACCESS_OPTION_NAME);
68
- delete_option(WPPH_PLUGIN_ALLOW_CHANGE_OPTION_NAME);
69
- delete_option(WPPH_PLUGIN_SETTING_NAME);
70
- $wpdb->query("DROP TABLE IF EXISTS ".WPPHDatabase::getFullTableName('main'));
71
- $wpdb->query("DROP TABLE IF EXISTS ".WPPHDatabase::getFullTableName('events'));
72
- }
73
  // register callbacks
74
- register_activation_hook( __FILE__, array('WPPH', 'onPluginActivate') );
75
- register_deactivation_hook( __FILE__, array('WPPH', 'onPluginDeactivate') );
76
- register_uninstall_hook( __FILE__, 'onPluginUninstall' );
 
 
 
77
 
78
  // Add custom links on plugins page
79
  add_filter("plugin_action_links_".plugin_basename(__FILE__), 'wpphCustomLinks' );
@@ -81,23 +93,67 @@ add_filter("plugin_action_links_".plugin_basename(__FILE__), 'wpphCustomLinks' )
81
  add_action('plugins_loaded', 'wpphLoadTextDomain');
82
  // create dashboard widget
83
  add_action('wp_dashboard_setup', array('WPPHUtil','addDashboardWidget'));
 
 
84
 
85
  // $GLOBALS['WPPH_CAN_RUN']
86
  // @since v0.3
87
  // @see WPPH::onPluginActivate()
88
  if($GLOBALS['WPPH_CAN_RUN'])
89
  {
90
- //Create default settings
91
- WPPH::getPluginSettings();
92
  // Watch widget activity
93
  add_action('widgets_init',array('WPPHEventWatcher','watchWidgetMove'));
94
  add_action('sidebar_admin_setup', array('WPPHEventWatcher','watchWidgetActivity'));
95
  // Load the pluggable.php file if needed
96
  add_action('admin_init', array('WPPHUtil','loadPluggable'));
97
  // Load resources
98
- add_action('admin_init', array('WPPH', 'loadBaseResources'));
99
  // Add the sidebar menu
100
- add_action('admin_menu', array('WPPH', 'createPluginWpSidebar'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  // Plugin init
102
  add_action('init', 'wpphPluginInit');
103
  function wpphPluginInit()
@@ -140,20 +196,13 @@ if($GLOBALS['WPPH_CAN_RUN'])
140
  WPPHEvent::hookUntrashedPosts();
141
  WPPHEvent::hookUntrashedPages();
142
  WPPHEvent::hookThemeChange();
143
- WPPHEvent::hookUserRoleUpdated();
144
- WPPHEvent::hookUserPasswordUpdated();
145
- WPPHEvent::hookUserEmailUpdated();
146
  WPPHEvent::hookUserDeletion();
147
- WPPHEvent::hookEventsDeletion();
148
  WPPHEvent::hookWatchPluginActivity();
149
  /* Enable ajax functionality in the dashboard page */
150
  add_action('wp_ajax_wpph_get_events', array('WPPHUtil','get_events_html'));
 
151
  add_action('wp_ajax_wpph_check_user_role', array('WPPHUtil','check_user_role'));
152
  }
153
- WPPHEvent::hookLoginEvent();
154
- WPPHEvent::hookLogoutEvent();
155
- WPPHEvent::hookLoginFailure();
156
- WPPHEvent::hookUserRegisterEvent();
157
  }
158
  }
159
  // End wp-security-audit-log
4
  Plugin URI: http://www.wpwhitesecurity.com/wordpress-security-plugins/wp-security-audit-log/
5
  Description: Identify WordPress security issues before they become a problem and keep track of everything happening on your WordPress, including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Security Audit Log will generate a security alert for everything that happens on your WordPress blog or website. Use the Audit Log Viewer included in the plugin to see all the security alerts.
6
  Author: WP White Security
7
+ Version: 0.6
8
  Author URI: http://www.wpwhitesecurity.com/
9
  License: GPL2
10
  Text Domain: wp-security-audit-log
11
+ Domain Path: /languages
12
 
13
  WP Security Audit Log
14
  Copyright(c) 2013 Robert Abela (email : robert@wpwhitesecurity.com)
26
  along with this program; if not, write to the Free Software
27
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28
  */
29
+ define('WPPH_PLUGIN_VERSION','0.6');
30
  define('WPPH_PLUGIN_PREFIX', 'wpph_');
31
  define('WPPH_PLUGIN_NAME', 'WP Security Audit Log');
32
  define('WPPH_PLUGIN_URL', trailingslashit(plugins_url('', __FILE__)));
36
 
37
  // Load required files
38
  require('inc/wpphSettings.php');
39
+ require('inc/WPPH.php');
40
  require('inc/WPPHLogger.php');
41
  require('inc/WPPHUtil.php');
42
+ require('inc/WPPHNetwork.php');
43
  require('inc/WPPHDatabase.php');
44
  require('inc/WPPHEvent.php');
45
  require('inc/WPPHPost.php');
 
46
  require('inc/wpphFunctions.php');
47
 
48
+
49
+ //#[ENABLE LOGGING]#
50
+ //===============================================
51
+ // WPPHLogger::enableDebugLogging();
52
+ // WPPHLogger::enableErrorLogging();
53
+ //===============================================
54
+
55
+ //# 6000
56
+ function wpph_addCronIntervals( $schedules )
57
+ {
58
+ $schedules['8h'] = array('interval' => 28800,'display' => __('Every 8 hours',WPPH_PLUGIN_TEXT_DOMAIN));
59
+ return $schedules;
60
+ }
61
+ define('WPPH_CLEANUP_INTERVAL','8h');
62
+ // must be in seconds, the time interval when the wp cron runs
63
+ define('WPPH_CLEANUP_WAIT_TIME', strtotime(28800));
64
+ add_filter('cron_schedules', 'wpph_addCronIntervals');
65
+
66
+
67
+ // load the text domain
68
+ add_action('plugins_loaded', array('WPPH','loadTextDomain'));
69
+
70
+
71
  // 2000
72
  $GLOBALS['WPPH_POST_IS_NEW'] = false;
73
  add_action('wp_insert_post', 'wpphPostDetectNew', 1, 2);
79
  }
80
  }
81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  // register callbacks
83
+ if (WPPH::isMultisite()) { add_action('network_admin_menu', array('WPPH','createPluginWpSidebar')); }
84
+ else add_action('admin_menu', array('WPPH','createPluginWpSidebar'));
85
+ register_activation_hook( __FILE__, array('WPPHDatabase','dropTables')); // since v0.6
86
+ register_activation_hook( __FILE__, array('wpphNetwork','networkActivate'));
87
+ register_deactivation_hook( __FILE__, array('wpphNetwork','networkDeactivate'));
88
+ register_uninstall_hook( __FILE__, array('wpphNetwork','networkUninstall'));
89
 
90
  // Add custom links on plugins page
91
  add_filter("plugin_action_links_".plugin_basename(__FILE__), 'wpphCustomLinks' );
93
  add_action('plugins_loaded', 'wpphLoadTextDomain');
94
  // create dashboard widget
95
  add_action('wp_dashboard_setup', array('WPPHUtil','addDashboardWidget'));
96
+ // activate plugin for new created websites
97
+ add_action('wpmu_new_blog', array('WPPH','onPluginActivate'));
98
 
99
  // $GLOBALS['WPPH_CAN_RUN']
100
  // @since v0.3
101
  // @see WPPH::onPluginActivate()
102
  if($GLOBALS['WPPH_CAN_RUN'])
103
  {
 
 
104
  // Watch widget activity
105
  add_action('widgets_init',array('WPPHEventWatcher','watchWidgetMove'));
106
  add_action('sidebar_admin_setup', array('WPPHEventWatcher','watchWidgetActivity'));
107
  // Load the pluggable.php file if needed
108
  add_action('admin_init', array('WPPHUtil','loadPluggable'));
109
  // Load resources
110
+ add_action('admin_init', array('WPPH','loadBaseResources'));
111
  // Add the sidebar menu
112
+ add_action('admin_menu', array('WPPH','createPluginWpSidebar'));
113
+
114
+ if(WPPH::isMultisite())
115
+ {
116
+ // 4001 && 4002 - wpmu user activated/registered
117
+ add_action('wpmu_activate_user', array('WPPHEventWatcher', 'watchEventUserRegister'));
118
+ // 4008 && 4009
119
+ WPPHEvent::hookUserAdminPriv();
120
+ // 4010 - user added to blog
121
+ add_action('add_user_to_blog', array('WPPHEventWatcher','watchUserAddedToBlog'), 10, 3);
122
+ // 4011 - user removed from blog
123
+ add_action('remove_user_from_blog', array('WPPHEventWatcher','watchUserRemovedFromBlog'));
124
+ // 7000 - new blog added
125
+ add_action('wpmu_new_blog', array('WPPHEventWatcher','watchBlogAdded'), 10, 6);
126
+ // 7001 - blog archived
127
+ add_action('archive_blog', array('WPPHEventWatcher','watchBlogArchived'));
128
+ // 7002 - blog unarchived
129
+ add_action('unarchive_blog', array('WPPHEventWatcher','watchBlogUnarchived'));
130
+ // 7003 - blog activated
131
+ add_action('activate_blog', array('WPPHEventWatcher','watchBlogActivated'));
132
+ // 7004 - blog deactivated
133
+ add_action('deactivate_blog', array('WPPHEventWatcher','watchBlogDeactivated'));
134
+ // 7005 - blog deleted
135
+ add_action('delete_blog', array('WPPHEventWatcher','watchBlogDeleted'));
136
+ }
137
+ // end wpmu events
138
+
139
+ WPPHEvent::hookLoginEvent();
140
+ WPPHEvent::hookLogoutEvent();
141
+ WPPHEvent::hookLoginFailure();
142
+ // 4000 && 4001 && 4012
143
+ WPPHEvent::hookUserRegisterEvent();
144
+ // 4003 && 4004
145
+ WPPHEvent::hookUserPasswordUpdated();
146
+ // 4005 && 4006
147
+ WPPHEvent::hookUserEmailUpdated();
148
+
149
+ // 6000
150
+ if(defined('DISABLE_WP_CRON') && DISABLE_WP_CRON)
151
+ {
152
+ wpphLog('wp-cron is disabled.');
153
+ WPPHEventWatcher::__deleteEvents();
154
+ }
155
+ else { add_action(WPPH_PLUGIN_DEL_EVENTS_CRON_TASK_NAME, array('WPPHEventWatcher','__deleteEvents')); }
156
+
157
  // Plugin init
158
  add_action('init', 'wpphPluginInit');
159
  function wpphPluginInit()
196
  WPPHEvent::hookUntrashedPosts();
197
  WPPHEvent::hookUntrashedPages();
198
  WPPHEvent::hookThemeChange();
 
 
 
199
  WPPHEvent::hookUserDeletion();
 
200
  WPPHEvent::hookWatchPluginActivity();
201
  /* Enable ajax functionality in the dashboard page */
202
  add_action('wp_ajax_wpph_get_events', array('WPPHUtil','get_events_html'));
203
+ add_action('wp_ajax_wpph_get_blogs', array('WPPHUtil','ajax_get_blogs'));
204
  add_action('wp_ajax_wpph_check_user_role', array('WPPHUtil','check_user_role'));
205
  }
 
 
 
 
206
  }
207
  }
208
  // End wp-security-audit-log