_plugin = $plugin;
$this->query_args = $query_args;
parent::__construct(
array(
'singular' => 'log',
'plural' => 'logs',
'ajax' => true,
'screen' => 'interval-grid',
)
);
}
/**
* Empty View.
*/
public function no_items() {
esc_html_e( 'No events so far.', 'wp-security-audit-log' );
}
protected function get_table_classes() {
return array( 'widefat', 'fixed', 'striped', $this->_args['plural'], 'wsal-table', 'wsal-table-grid' );
}
/**
* Generate the table navigation above or below the table
*
* @since 3.2.3
* @param string $which – Position of the nav.
*/
protected function display_tablenav( $which ) {
if ( 'top' === $which ) {
wp_nonce_field( 'bulk-' . $this->_args['plural'] );
}
?>
extra_tablenav( $which );
/**
* Action: `wsal_search_filters_list`
*
* Display list of search filters of WSAL.
*
* @param string $which – Navigation position; value is either top or bottom.
* @since 3.2.3
*/
do_action( 'wsal_search_filters_list', $which );
?>
pagination( $which );
?>
_plugin->settings()->is_infinite_scroll() ) :
// Items-per-page widget.
$p = $this->_plugin->settings()->GetViewPerPage();
$items = array( 5, 10, 15, 30, 50 );
if ( ! in_array( $p, $items, true ) ) {
$items[] = $p;
}
?>
>
_plugin->settings()->is_infinite_scroll() ) :
?>
is_multisite() && $this->is_main_blog() && ! apply_filters( 'search_extensition_active', false ) ) {
if (
( 'top' === $which && $this->_plugin->settings()->is_infinite_scroll() )
|| ! $this->_plugin->settings()->is_infinite_scroll()
) {
$curr = $this->_plugin->settings()->get_view_site_id();
?>
get_site_count() > 15 ) : ?>
blogname . ' (' . $curr->domain . ')' ) : 'All Sites'; ?>
get_sites() as $info ) : ?>
blog_id == $curr ) ? 'selected="selected"' : false; ?>>
blogname ) . ' (' . esc_html( $info->domain ) . ')'; ?>
_plugin->settings()->IsArchivingEnabled() ) {
if (
( 'top' === $which && $this->_plugin->settings()->is_infinite_scroll() )
|| ! $this->_plugin->settings()->is_infinite_scroll()
) {
$selected = 'live';
$selected_db = get_transient( 'wsal_wp_selected_db' );
if ( $selected_db && 'archive' === $selected_db ) {
$selected = 'archive';
}
?>
>
>
blogs;
if ( ! is_null( $limit ) ) {
$sql .= ' LIMIT ' . $limit;
}
// Execute query.
$res = $wpdb->get_results( $sql );
// Modify result.
foreach ( $res as $row ) {
$row->blogname = get_blog_option( $row->blog_id, 'blogname' );
}
// Return result.
return $res;
}
/**
* Method: The number of sites on the network.
*
* @return int
*/
public function get_site_count() {
global $wpdb;
$sql = 'SELECT COUNT(*) FROM ' . $wpdb->blogs;
return (int) $wpdb->get_var( $sql );
}
/**
* Method: Get View Columns.
*
* @return array
*/
public function get_columns() {
$cols = array(
'type' => __( 'ID', 'wp-security-audit-log' ),
'code' => __( 'Severity', 'wp-security-audit-log' ),
'info' => __( 'Info', 'wp-security-audit-log' ),
);
// If multisite then add "Site" column to the view.
if ( $this->is_multisite() && $this->is_main_blog() && ! $this->is_specific_view() ) {
$cols['site'] = __( 'Site', 'wp-security-audit-log' );
}
$cols['mesg'] = __( 'Message', 'wp-security-audit-log' );
// Get selected columns from settings.
if ( empty( $this->selected_columns ) && ! is_array( $this->selected_columns ) ) {
$this->selected_columns = $this->_plugin->settings()->GetColumnsSelected();
}
// If selected columns are not empty, then unset default columns.
if ( ! empty( $this->selected_columns ) ) {
unset( $cols );
$this->selected_columns = is_string( $this->selected_columns ) ? (array) json_decode( $this->selected_columns ) : $this->selected_columns;
foreach ( $this->selected_columns as $key => $value ) {
switch ( $key ) {
case 'alert_code':
$cols['type'] = __( 'ID', 'wp-security-audit-log' );
break;
case 'type':
$cols['code'] = __( 'Severity', 'wp-security-audit-log' );
break;
case 'info':
$cols['info'] = __( 'Grid', 'wp-security-audit-log' );
break;
case 'message':
$cols['mesg'] = __( 'Message', 'wp-security-audit-log' );
break;
default:
// fallback for any new columns would go here
break;
}
}
}
$cols['data'] = '';
return $cols;
}
/**
* Method: Get checkbox column.
*
* @param object $item - Item.
* @return string
*/
public function column_cb( $item ) {
return ' ';
}
/**
* Method: Get Sortable Columns.
*
* @return array
*/
public function get_sortable_columns() {
return array(
'type' => array( 'alert_id', false ),
'info' => array( 'info', false ),
);
}
/**
* Method: Get default column values.
*
* @param WSAL_Models_Occurrence $item - Column item.
* @param string $column_name - Name of the column.
*/
public function column_default( $item, $column_name ) {
// Store meta if not set.
if ( ! isset( $this->item_meta[ $item->getId() ] ) ) {
$this->item_meta[ $item->getId() ] = $item->GetMetaArray();
}
// Store current alert id.
$this->current_alert_id = $item->id;
switch ( $column_name ) {
case 'type':
$code = $this->_plugin->alerts->GetAlert( $item->alert_id );
$extra_msg = '';
$data_link = '';
$modification_alerts = array( 1002, 1003 );
if ( in_array( $item->alert_id, $modification_alerts, true ) ) {
$extra_msg = '. Modify this alert.';
$data_link = add_query_arg( 'page', 'wsal-togglealerts#tab-users-profiles---activity', admin_url( 'admin.php' ) );
}
if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
return '' . str_pad( $item->alert_id, 4, '0', STR_PAD_LEFT ) . ' ';
}
// add description to $extra_msg only if one is available.
$extra_msg = ( isset( $code->desc ) ) ? ' - ' . esc_html( $code->desc ) . $extra_msg : $extra_msg;
return ''
. str_pad( $item->alert_id, 4, '0', STR_PAD_LEFT ) . ' ';
case 'code':
$code = $this->_plugin->alerts->GetAlert( $item->alert_id );
$code = $code ? $code->code : 0;
$const = $this->_plugin->constants->get_constant_to_display( $code );
return ' ';
case 'site':
$info = get_blog_details( $item->site_id, true );
return ! $info ? ( 'Unknown Site ' . $item->site_id )
: ( '' . esc_html( $info->blogname ) . ' ' );
case 'mesg':
ob_start();
// login, logout and failed login has no message attached.
if ( ! in_array( $item->alert_id, array( 1000, 1001, 1002 ), true ) ) {
?>
GetMessage( array( $this->_plugin->settings, 'meta_formatter' ), false, $this->item_meta[ $item->getId() ] ); ?>
created_on
? WSAL_Utilities_DateTimeFormatter::instance()->getFormattedDateTime($item->created_on, 'date' )
: '' . __( 'Unknown', 'wp-security-audit-log' ) . ' ';
$eventtime = $item->created_on
? WSAL_Utilities_DateTimeFormatter::instance()->getFormattedDateTime($item->created_on, 'time' )
: '' . __( 'Unknown', 'wp-security-audit-log' ) . ' ';
$username = $item->GetUsername( $this->item_meta[ $item->getId() ] ); // Get username.
$user = get_user_by( 'login', $username ); // Get user.
if ( empty( $this->name_type ) ) {
$this->name_type = $this->_plugin->settings()->get_type_username();
}
// Check if the username and user exists.
if ( $username && $user ) {
// Checks for display name.
if ( 'display_name' === $this->name_type && ! empty( $user->display_name ) ) {
$display_name = $user->display_name;
} elseif (
'first_last_name' === $this->name_type
&& ( ! empty( $user->first_name ) || ! empty( $user->last_name ) )
) {
$display_name = $user->first_name . ' ' . $user->last_name;
} else {
$display_name = $user->user_login;
}
if ( class_exists( 'WSAL_SearchExtension' ) ) {
$tooltip = esc_attr__( 'Show me all activity by this User', 'wp-security-audit-log' );
$uhtml = '' . esc_html( $display_name ) . ' ';
} else {
$uhtml = '' . esc_html( $display_name ) . ' ';
}
$roles = $item->GetUserRoles( $this->item_meta[ $item->getId() ] );
if ( is_array( $roles ) && count( $roles ) ) {
$roles = esc_html( ucwords( implode( ', ', $roles ) ) );
} elseif ( is_string( $roles ) && '' != $roles ) {
$roles = esc_html( ucwords( str_replace( array( '"', '[', ']' ), ' ', $roles ) ) );
} else {
$roles = '' . __( 'Unknown', 'wp-security-audit-log' ) . ' ';
}
} elseif ( 'Plugin' == $username ) {
$uhtml = '' . __( 'Plugin', 'wp-security-audit-log' ) . ' ';
$roles = '';
} elseif ( 'Plugins' == $username ) {
$uhtml = '' . __( 'Plugins', 'wp-security-audit-log' ) . ' ';
$roles = '';
} elseif ( 'Website Visitor' == $username || 'Unregistered user' == $username ) {
$uhtml = '' . __( 'Unregistered user', 'wp-security-audit-log' ) . ' ';
$roles = '';
} else {
$uhtml = '' . __( 'System', 'wp-security-audit-log' ) . ' ';
$roles = '';
}
$row_user_data = $uhtml . ' ' . $roles;
/**
* WSAL Filter: `wsal_auditlog_row_user_data`
*
* Filters user data before displaying on the audit log.
*
* @since 3.3.1
*
* @param string $row_user_data - User data to display in audit log row.
* @param integer $this->current_alert_id - Event database ID.
*/
$eventuser = apply_filters( 'wsal_auditlog_row_user_data', $row_user_data, $this->current_alert_id );
$scip = $item->GetSourceIP( $this->item_meta[ $item->getId() ] );
if ( is_string( $scip ) ) {
$scip = str_replace( array( '"', '[', ']' ), '', $scip );
}
$oips = array();
// If there's no IP...
if ( is_null( $scip ) || '' == $scip ) {
return 'unknown ';
}
// If there's only one IP...
$link = 'https://whatismyipaddress.com/ip/' . $scip . '?utm_source=plugin&utm_medium=referral&utm_campaign=WPSAL';
if ( class_exists( 'WSAL_SearchExtension' ) ) {
$tooltip = esc_attr__( 'Show me all activity originating from this IP Address', 'wp-security-audit-log' );
if ( count( $oips ) < 2 ) {
$oips_html = "" . esc_html( $scip ) . ' ';
}
} else {
if ( count( $oips ) < 2 ) {
$oips_html = "" . esc_html( $scip ) . ' ';
}
}
// If there are many IPs...
if ( class_exists( 'WSAL_SearchExtension' ) ) {
$tooltip = esc_attr__( 'Show me all activity originating from this IP Address', 'wp-security-audit-log' );
$ip_html = "" . esc_html( $scip ) . ' (more…) ';
foreach ( $oips as $ip ) {
if ( $scip != $ip ) {
$ip_html .= '
' . $ip . '
';
}
}
$ip_html .= '
';
} else {
$ip_html = "" . esc_html( $scip ) . ' (more…) ';
foreach ( $oips as $ip ) {
if ( $scip != $ip ) {
$ip_html .= '
' . $ip . '
';
}
}
$ip_html .= '
';
}
$eventobj = isset( $this->item_meta[ $item->getId() ]['Object'] ) ? $this->_plugin->alerts->get_event_objects_data( $this->item_meta[ $item->getId() ]['Object'] ) : '';
$eventtypeobj = isset( $this->item_meta[ $item->getId() ]['EventType'] ) ? $this->_plugin->alerts->get_event_type_data( $this->item_meta[ $item->getId() ]['EventType'] ) : '';
ob_start();
?>
id;
$tooltip = esc_attr__( 'View all details of this change', 'wp-security-audit-log' );
return '… ';
default:
return isset( $item->$column_name )
? esc_html( $item->$column_name )
: 'Column "' . esc_html( $column_name ) . '" not found';
}
}
/**
* Method: Reorder string items.
*
* @param object $a - Item to compare.
* @param object $b - Item to compare.
* @return int
*/
public function reorder_items_str( $a, $b ) {
$result = strcmp( $a->{$this->_orderby}, $b->{$this->_orderby} );
return ( 'asc' === $this->_order ) ? $result : -$result;
}
/**
* Method: Reorder items.
*
* @param object $a - Item to compare.
* @param object $b - Item to compare.
* @return int
*/
public function reorder_items_int( $a, $b ) {
$result = $a->{$this->_orderby} - $b->{$this->_orderby};
return ( 'asc' === $this->_order ) ? $result : -$result;
}
/**
* Method: Check if multisite.
*
* @return bool
*/
protected function is_multisite() {
return $this->_plugin->IsMultisite();
}
/**
* Method: Check if the blog is main blog.
*
* @return bool
*/
protected function is_main_blog() {
return get_current_blog_id() == 1;
}
/**
* Method: Check if it is a specific view.
*
* @return bool
*/
protected function is_specific_view() {
return isset( $this->query_args->site_id ) && '0' != $this->query_args->site_id;
}
/**
* Method: Get a specific view.
*
* @return int
*/
protected function get_specific_view() {
return isset( $this->query_args->site_id ) ? (int) $this->query_args->site_id : 0;
}
/**
* Method: Get view site id.
*
* @return int
*/
protected function get_view_site_id() {
switch ( true ) {
// Non-multisite.
case ! $this->is_multisite():
return 0;
// Multisite + main site view.
case $this->is_main_blog() && ! $this->is_specific_view():
return 0;
// Multisite + switched site view.
case $this->is_main_blog() && $this->is_specific_view():
return $this->get_specific_view();
// Multisite + local site view.
default:
return get_current_blog_id();
}
}
/**
* Set Events for Audit Log Viewer.
*/
public function prepare_items() {
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array( $columns, $hidden, $sortable );
$query_events = $this->query_events();
$this->items = isset( $query_events['items'] ) ? $query_events['items'] : false;
$total_items = isset( $query_events['total_items'] ) ? $query_events['total_items'] : false;
$per_page = isset( $query_events['per_page'] ) ? $query_events['per_page'] : false;
if ( ! $this->_plugin->settings()->is_infinite_scroll() ) {
$this->set_pagination_args(
array(
'total_items' => $total_items,
'per_page' => $per_page,
'total_pages' => ceil( $total_items / $per_page ),
)
);
}
}
/**
* Method: Output Single row.
*
* @param object $item - Item.
*/
public function single_row( $item ) {
if ( 9999 === $item->alert_id ) {
echo '';
$this->single_row_columns( $item );
echo ' ';
} else {
parent::single_row( $item );
}
}
/**
* Print column headers, accounting for hidden and sortable columns.
*
* @static var int $cb_counter
*
* @param bool $with_id – Whether to set the id attribute or not.
* @since 3.2.3
*/
public function print_column_headers( $with_id = true ) {
list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
$current_url = set_url_scheme( esc_url_raw( wp_unslash( $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ) ) );
$current_url = remove_query_arg( 'paged', $current_url );
// Set order by query arg.
if ( isset( $this->query_args->order_by ) ) {
$current_orderby = $this->query_args->order_by;
} else {
$current_orderby = '';
}
if ( isset( $this->query_args->order ) && 'desc' === $this->query_args->order ) {
$current_order = 'desc';
} else {
$current_order = 'asc';
}
if ( ! empty( $columns['cb'] ) ) {
static $cb_counter = 1;
$columns['cb'] = '' . __( 'Select All' ) . ' '
. ' ';
$cb_counter++;
}
foreach ( $columns as $column_key => $column_display_name ) {
$class = array( 'manage-column', "column-$column_key" );
if ( in_array( $column_key, $hidden ) ) {
$class[] = 'hidden';
}
if ( 'cb' === $column_key ) {
$class[] = 'check-column';
} elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) ) {
$class[] = 'num';
}
if ( $column_key === $primary ) {
$class[] = 'column-primary';
}
if ( isset( $sortable[ $column_key ] ) ) {
list( $orderby, $desc_first ) = $sortable[ $column_key ];
if ( $current_orderby === $orderby ) {
$order = 'asc' === $current_order ? 'desc' : 'asc';
$class[] = 'sorted';
$class[] = $current_order;
} else {
$order = $desc_first ? 'desc' : 'asc';
$class[] = 'sortable';
$class[] = $desc_first ? 'asc' : 'desc';
}
$column_display_name = '' . $column_display_name . ' ';
}
$tag = ( 'cb' === $column_key ) ? 'td' : 'th';
$scope = ( 'th' === $tag ) ? 'scope="col"' : '';
$id = $with_id ? "id='$column_key'" : '';
if ( ! empty( $class ) ) {
$class = "class='" . implode( ' ', $class ) . "'";
}
echo "<$tag $scope $id $class>";
echo ! in_array( $column_key, array( 'code', 'data', 'site' ), true ) ? '' : '';
if ( $with_id ) {
/**
* Action: `wsal_audit_log_column_header`
*
* Action hook to add search filters in the audit log
* column headers.
*
* @param string $column_key – Column key.
*/
do_action( 'wsal_audit_log_column_header', $column_key );
}
echo $column_display_name;
echo ! in_array( $column_key, array( 'code', 'data', 'site' ), true ) ? '
' : '';
echo "$tag>";
}
}
/**
* Returns total events in the Audit Log.
*
* @return int
*/
public function get_total_items() {
return isset( $this->_pagination_args['total_items'] ) ? $this->_pagination_args['total_items'] : false;
}
/**
* Query Events from WSAL DB.
*
* @since 3.3.1.1
*
* @param integer $paged - Page number.
* @return array
*/
public function query_events( $paged = 0 ) {
if ( $this->_plugin->settings()->IsArchivingEnabled() ) {
// Switch to Archive DB.
$selected_db = get_transient( 'wsal_wp_selected_db' );
if ( $selected_db && 'archive' === $selected_db ) {
$this->_plugin->settings()->SwitchToArchiveDB();
}
}
// TO DO: Get rid of OccurrenceQuery and use the Occurence Model.
$query = new WSAL_Models_OccurrenceQuery();
$bid = (int) $this->query_args->site_id;
if ( $bid ) {
$query->addCondition( 'site_id = %s ', $bid );
}
/**
* Hook: `wsal_auditlog_query`
*
* This hook is used to filter events query object.
* It is used to support search by filters.
*
* @see WSAL_SearchExtension()->__construct()
* @param WSAL_Models_OccurrenceQuery $query - Audit log events query object.
*/
$query = apply_filters( 'wsal_auditlog_query', $query );
if ( ! $this->_plugin->settings()->is_infinite_scroll() ) {
$total_items = $query->getAdapter()->Count( $query );
$per_page = $this->_plugin->settings()->GetViewPerPage();
$offset = ( $this->get_pagenum() - 1 ) * $per_page;
} else {
$total_items = false;
$per_page = apply_filters( 'wsal_infinite_scroll_events', 25 ); // Manually set per page events for infinite scroll.
$offset = ( max( 1, $paged ) - 1 ) * $per_page;
}
// Set query order arguments.
$order_by = isset( $this->query_args->order_by ) ? $this->query_args->order_by : false;
$order = isset( $this->query_args->order ) ? $this->query_args->order : false;
if ( ! $order_by ) {
$query->addOrderBy( 'created_on', true );
} else {
$is_descending = true;
if ( $order && 'asc' === $order ) {
$is_descending = false;
}
if ( 'code' === $order_by ) {
/*
* Handle the 'code' (Severity) column sorting.
*/
$query->addMetaJoin(); // Since LEFT JOIN clause causes the result values to duplicate.
$query->addCondition( 'meta.name = %s', 'Severity' ); // A where condition is added to make sure that we're only requesting the relevant meta data rows from metadata table.
$query->addOrderBy( 'CASE WHEN meta.name = "Severity" THEN meta.value END', $is_descending );
} elseif ( 'info' === $order_by ) {
// for the info col we are ordering just by dates.
$query->addOrderBy( 'created_on', $is_descending );
} else {
$tmp = new WSAL_Models_Occurrence();
// Making sure the field exists to order by.
if ( isset( $tmp->{$order_by} ) ) {
$query->addOrderBy( $order_by, $is_descending );
} else {
$query->addOrderBy( 'created_on', true );
}
}
}
$query->setOffset( $offset ); // Set query offset.
$query->setLimit( $per_page ); // Set number of events per page.
return array(
'total_items' => $total_items,
'per_page' => $per_page,
'items' => $query->getAdapter()->Execute( $query ),
);
}
}