From 57c8533c0372d19c1f99ef330cb4b8296908a496 Mon Sep 17 00:00:00 2001 From: Amin Date: Tue, 7 May 2019 13:39:19 +0600 Subject: [PATCH] v4.3.9 released --- .../admin/general/wp-security-list-table.php | 1137 ++++++++++++----- .../admin/wp-security-admin-menu.php | 11 + .../admin/wp-security-dashboard-menu.php | 21 +- .../admin/wp-security-database-menu.php | 3 +- .../admin/wp-security-list-acct-activity.php | 30 +- .../admin/wp-security-list-login-fails.php | 26 +- .../wp-security-list-permanent-blocked-ip.php | 28 +- .../wp-security-list-registered-users.php | 14 +- .../admin/wp-security-user-accounts-menu.php | 4 +- .../admin/wp-security-user-login-menu.php | 26 +- .../wp-security-user-registration-menu.php | 9 +- .../classes/wp-security-captcha.php | 38 +- .../wp-security-general-init-tasks.php | 13 +- .../classes/wp-security-user-login.php | 4 +- .../classes/wp-security-utility-file.php | 2 +- .../wp-security-utility-ip-address.php | 4 +- .../css/wp-security-admin-styles.css | 16 + all-in-one-wp-security/readme.txt | 20 +- all-in-one-wp-security/wp-security-core.php | 2 +- all-in-one-wp-security/wp-security.php | 2 +- 20 files changed, 1014 insertions(+), 396 deletions(-) diff --git a/all-in-one-wp-security/admin/general/wp-security-list-table.php b/all-in-one-wp-security/admin/general/wp-security-list-table.php index 66287b7..e35b51c 100644 --- a/all-in-one-wp-security/admin/general/wp-security-list-table.php +++ b/all-in-one-wp-security/admin/general/wp-security-list-table.php @@ -1,141 +1,298 @@ '', - 'singular' => '', - 'ajax' => false, - 'screen' => null, - ) ); + protected $modes = array(); + + /** + * Stores the value returned by ->get_column_info(). + * + * @since 4.1.0 + * @var array + */ + protected $_column_headers; + + /** + * {@internal Missing Summary} + * + * @var array + */ + protected $compat_fields = array( '_args', '_pagination_args', 'screen', '_actions', '_pagination' ); + + /** + * {@internal Missing Summary} + * + * @var array + */ + protected $compat_methods = array( + 'set_pagination_args', + 'get_views', + 'get_bulk_actions', + 'bulk_actions', + 'row_actions', + 'months_dropdown', + 'view_switcher', + 'comments_bubble', + 'get_items_per_page', + 'pagination', + 'get_sortable_columns', + 'get_column_info', + 'get_table_classes', + 'display_tablenav', + 'extra_tablenav', + 'single_row_columns', + ); + + /** + * Constructor. + * + * The child class should call this constructor from its own constructor to override + * the default $args. + * + * @since 3.1.0 + * + * @param array|string $args { + * Array or string of arguments. + * + * @type string $plural Plural value used for labels and the objects being listed. + * This affects things such as CSS class-names and nonces used + * in the list table, e.g. 'posts'. Default empty. + * @type string $singular Singular label for an object being listed, e.g. 'post'. + * Default empty + * @type bool $ajax Whether the list table supports Ajax. This includes loading + * and sorting data, for example. If true, the class will call + * the _js_vars() method in the footer to provide variables + * to any scripts handling Ajax events. Default false. + * @type string $screen String containing the hook name used to determine the current + * screen. If left null, the current screen will be automatically set. + * Default null. + * } + */ + public function __construct( $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'plural' => '', + 'singular' => '', + 'ajax' => false, + 'screen' => null, + ) + ); $this->screen = convert_to_screen( $args['screen'] ); - add_filter( "manage_{$this->screen->id}_columns", array( &$this, 'get_columns' ), 0 ); + add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 ); - if ( !$args['plural'] ) + if ( ! $args['plural'] ) { $args['plural'] = $this->screen->base; + } - $args['plural'] = sanitize_key( $args['plural'] ); + $args['plural'] = sanitize_key( $args['plural'] ); $args['singular'] = sanitize_key( $args['singular'] ); $this->_args = $args; if ( $args['ajax'] ) { // wp_enqueue_script( 'list-table' ); - add_action( 'admin_footer', array( &$this, '_js_vars' ) ); + add_action( 'admin_footer', array( $this, '_js_vars' ) ); + } + + if ( empty( $this->modes ) ) { + $this->modes = array( + 'list' => __( 'List View' ), + 'excerpt' => __( 'Excerpt View' ), + ); + } + } + + /** + * Make private properties readable for backward compatibility. + * + * @since 4.0.0 + * + * @param string $name Property to get. + * @return mixed Property. + */ + public function __get( $name ) { + if ( in_array( $name, $this->compat_fields ) ) { + return $this->$name; + } + } + + /** + * Make private properties settable for backward compatibility. + * + * @since 4.0.0 + * + * @param string $name Property to check if set. + * @param mixed $value Property value. + * @return mixed Newly-set property. + */ + public function __set( $name, $value ) { + if ( in_array( $name, $this->compat_fields ) ) { + return $this->$name = $value; + } + } + + /** + * Make private properties checkable for backward compatibility. + * + * @since 4.0.0 + * + * @param string $name Property to check if set. + * @return bool Whether the property is set. + */ + public function __isset( $name ) { + if ( in_array( $name, $this->compat_fields ) ) { + return isset( $this->$name ); + } + } + + /** + * Make private properties un-settable for backward compatibility. + * + * @since 4.0.0 + * + * @param string $name Property to unset. + */ + public function __unset( $name ) { + if ( in_array( $name, $this->compat_fields ) ) { + unset( $this->$name ); + } + } + + /** + * Make private/protected methods readable for backward compatibility. + * + * @since 4.0.0 + * + * @param string $name Method to call. + * @param array $arguments Arguments to pass when calling. + * @return mixed|bool Return value of the callback, false otherwise. + */ + public function __call( $name, $arguments ) { + if ( in_array( $name, $this->compat_methods ) ) { + return call_user_func_array( array( $this, $name ), $arguments ); } + return false; } /** * Checks the current user's permissions - * @uses wp_die() * * @since 3.1.0 - * @access public * @abstract */ - function ajax_user_can() { + public function ajax_user_can() { die( 'function AIOWPSecurity_List_Table::ajax_user_can() must be over-ridden in a sub-class.' ); } /** * Prepares the list of items for displaying. + * * @uses AIOWPSecurity_List_Table::set_pagination_args() * * @since 3.1.0 - * @access public * @abstract */ - function prepare_items() { + public function prepare_items() { die( 'function AIOWPSecurity_List_Table::prepare_items() must be over-ridden in a sub-class.' ); } /** * An internal method that sets all the necessary pagination arguments * - * @param array $args An associative array with information about the pagination - * @access protected + * @since 3.1.0 + * + * @param array|string $args Array or string of arguments with information about the pagination. */ - function set_pagination_args( $args ) { - $args = wp_parse_args( $args, array( - 'total_items' => 0, - 'total_pages' => 0, - 'per_page' => 0, - ) ); + protected function set_pagination_args( $args ) { + $args = wp_parse_args( + $args, + array( + 'total_items' => 0, + 'total_pages' => 0, + 'per_page' => 0, + ) + ); - if ( !$args['total_pages'] && $args['per_page'] > 0 ) + if ( ! $args['total_pages'] && $args['per_page'] > 0 ) { $args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] ); + } - // redirect if page number is invalid and headers are not already sent - if ( ! headers_sent() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) { + // Redirect if page number is invalid and headers are not already sent. + if ( ! headers_sent() && ! wp_doing_ajax() && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) { wp_redirect( add_query_arg( 'paged', $args['total_pages'] ) ); exit; } @@ -144,74 +301,78 @@ function set_pagination_args( $args ) { } /** - * Access the pagination args + * Access the pagination args. * * @since 3.1.0 - * @access public * - * @param string $key - * @return array + * @param string $key Pagination argument to retrieve. Common values include 'total_items', + * 'total_pages', 'per_page', or 'infinite_scroll'. + * @return int Number of items that correspond to the given pagination argument. */ - function get_pagination_arg( $key ) { - if ( 'page' == $key ) + public function get_pagination_arg( $key ) { + if ( 'page' === $key ) { return $this->get_pagenum(); + } - if ( isset( $this->_pagination_args[$key] ) ) - return $this->_pagination_args[$key]; + if ( isset( $this->_pagination_args[ $key ] ) ) { + return $this->_pagination_args[ $key ]; + } } /** * Whether the table has items to display or not * * @since 3.1.0 - * @access public * * @return bool */ - function has_items() { - return !empty( $this->items ); + public function has_items() { + return ! empty( $this->items ); } /** * Message to be displayed when there are no items * * @since 3.1.0 - * @access public */ - function no_items() { + public function no_items() { _e( 'No items found.' ); } /** - * Display the search box. + * Displays the search box. * * @since 3.1.0 - * @access public * - * @param string $text The search button text - * @param string $input_id The search input id + * @param string $text The 'submit' button label. + * @param string $input_id ID attribute value for the search input field. */ - function search_box( $text, $input_id ) { - if ( empty( $_REQUEST['s'] ) && !$this->has_items() ) + public function search_box( $text, $input_id ) { + if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) { return; + } $input_id = $input_id . '-search-input'; - if ( ! empty( $_REQUEST['orderby'] ) ) + if ( ! empty( $_REQUEST['orderby'] ) ) { echo ''; - if ( ! empty( $_REQUEST['order'] ) ) + } + if ( ! empty( $_REQUEST['order'] ) ) { echo ''; - if ( ! empty( $_REQUEST['post_mime_type'] ) ) + } + if ( ! empty( $_REQUEST['post_mime_type'] ) ) { echo ''; - if ( ! empty( $_REQUEST['detached'] ) ) + } + if ( ! empty( $_REQUEST['detached'] ) ) { echo ''; -?> + } + ?> -get_views(); - $views = apply_filters( 'views_' . $this->screen->id, $views ); - - if ( empty( $views ) ) + /** + * Filters the list of available list table views. + * + * The dynamic portion of the hook name, `$this->screen->id`, refers + * to the ID of the current screen, usually a string. + * + * @since 3.5.0 + * + * @param string[] $views An array of available list table views. + */ + $views = apply_filters( "views_{$this->screen->id}", $views ); + + if ( empty( $views ) ) { return; + } + + $this->screen->render_screen_reader_content( 'heading_views' ); echo ""; + echo ''; } /** @@ -253,11 +425,10 @@ function views() { * of bulk actions available on this table. * * @since 3.1.0 - * @access protected * * @return array */ - function get_bulk_actions() { + protected function get_bulk_actions() { return array(); } @@ -265,34 +436,48 @@ function get_bulk_actions() { * Display the bulk actions dropdown. * * @since 3.1.0 - * @access public + * + * @param string $which The location of the bulk actions: 'top' or 'bottom'. + * This is designated as optional for backward compatibility. */ - function bulk_actions() { + protected function bulk_actions( $which = '' ) { if ( is_null( $this->_actions ) ) { - $no_new_actions = $this->_actions = $this->get_bulk_actions(); - // This filter can currently only be used to remove actions. - $this->_actions = apply_filters( 'bulk_actions-' . $this->screen->id, $this->_actions ); - $this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions ); - $two = ''; + $this->_actions = $this->get_bulk_actions(); + /** + * Filters the list table Bulk Actions drop-down. + * + * The dynamic portion of the hook name, `$this->screen->id`, refers + * to the ID of the current screen, usually a string. + * + * This filter can currently only be used to remove bulk actions. + * + * @since 3.5.0 + * + * @param string[] $actions An array of the available bulk actions. + */ + $this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions ); + $two = ''; } else { $two = '2'; } - if ( empty( $this->_actions ) ) + if ( empty( $this->_actions ) ) { return; + } - echo "\n"; + echo '\n"; foreach ( $this->_actions as $name => $title ) { - $class = 'edit' == $name ? ' class="hide-if-no-js"' : ''; + $class = 'edit' === $name ? ' class="hide-if-no-js"' : ''; - echo "\t\n"; + echo "\t" . '\n"; } echo "\n"; - submit_button( __( 'Apply' ), 'action', false, false, array( 'id' => "doaction$two", 'onClick' => 'return confirm("Are you sure you want to perform this bulk operation on the selected entries?")' ) ); + submit_button( __( 'Apply' ), 'action', '', false, array( 'id' => "doaction$two", 'onclick' => "return confirm('Are you sure you want to perform this bulk action?')" ) ); echo "\n"; } @@ -300,16 +485,21 @@ function bulk_actions() { * Get the current action selected from the bulk actions dropdown. * * @since 3.1.0 - * @access public * - * @return string|bool The action name or False if no action was selected + * @return string|false The action name or False if no action was selected */ - function current_action() { - if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] ) + public function current_action() { + if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) ) { + return false; + } + + if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] ) { return $_REQUEST['action']; + } - if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] ) + if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] ) { return $_REQUEST['action2']; + } return false; } @@ -318,27 +508,29 @@ function current_action() { * Generate row actions div * * @since 3.1.0 - * @access protected * - * @param array $actions The list of actions - * @param bool $always_visible Whether the actions should be always visible + * @param string[] $actions An array of action links. + * @param bool $always_visible Whether the actions should be always visible. * @return string */ - function row_actions( $actions, $always_visible = false ) { + protected function row_actions( $actions, $always_visible = false ) { $action_count = count( $actions ); - $i = 0; + $i = 0; - if ( !$action_count ) + if ( ! $action_count ) { return ''; + } - $out = '
'; + $out = '
'; foreach ( $actions as $action => $link ) { ++$i; ( $i == $action_count ) ? $sep = '' : $sep = ' | '; - $out .= "$link$sep"; + $out .= "$link$sep"; } $out .= '
'; + $out .= ''; + return $out; } @@ -346,106 +538,204 @@ function row_actions( $actions, $always_visible = false ) { * Display a monthly dropdown for filtering items * * @since 3.1.0 - * @access protected + * + * @global wpdb $wpdb + * @global WP_Locale $wp_locale + * + * @param string $post_type */ - function months_dropdown( $post_type ) { + protected function months_dropdown( $post_type ) { global $wpdb, $wp_locale; - $months = $wpdb->get_results( $wpdb->prepare( " + /** + * Filters whether to remove the 'Months' drop-down from the post list table. + * + * @since 4.2.0 + * + * @param bool $disable Whether to disable the drop-down. Default false. + * @param string $post_type The post type. + */ + if ( apply_filters( 'disable_months_dropdown', false, $post_type ) ) { + return; + } + + $extra_checks = "AND post_status != 'auto-draft'"; + if ( ! isset( $_GET['post_status'] ) || 'trash' !== $_GET['post_status'] ) { + $extra_checks .= " AND post_status != 'trash'"; + } elseif ( isset( $_GET['post_status'] ) ) { + $extra_checks = $wpdb->prepare( ' AND post_status = %s', $_GET['post_status'] ); + } + + $months = $wpdb->get_results( + $wpdb->prepare( + " SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month FROM $wpdb->posts WHERE post_type = %s + $extra_checks ORDER BY post_date DESC - ", $post_type ) ); + ", + $post_type + ) + ); + + /** + * Filters the 'Months' drop-down results. + * + * @since 3.7.0 + * + * @param object $months The months drop-down query results. + * @param string $post_type The post type. + */ + $months = apply_filters( 'months_dropdown_results', $months, $post_type ); $month_count = count( $months ); - if ( !$month_count || ( 1 == $month_count && 0 == $months[0]->month ) ) + if ( ! $month_count || ( 1 == $month_count && 0 == $months[0]->month ) ) { return; + } $m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0; -?> - + value="0"> + year ) + if ( 0 == $arc_row->year ) { continue; + } $month = zeroise( $arc_row->month, 2 ); - $year = $arc_row->year; + $year = $arc_row->year; - printf( "\n", + printf( + "\n", selected( $m, $year . $month, false ), esc_attr( $arc_row->year . $month ), /* translators: 1: month name, 2: 4-digit year */ sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year ) ); } -?> + ?> - __( 'List View' ), - 'excerpt' => __( 'Excerpt View' ) - ); - -?> + protected function view_switcher( $current_mode ) { + ?>
- $title ) { - $class = ( $current_mode == $mode ) ? 'class="current"' : ''; - echo "$title\n"; + modes as $mode => $title ) { + $classes = array( 'view-' . $mode ); + if ( $current_mode === $mode ) { + $classes[] = 'current'; } + printf( + "%s\n", + esc_url( add_query_arg( 'mode', $mode ) ), + implode( ' ', $classes ), + $title + ); + } ?>
-'; + $approved_only_phrase = sprintf( _n( '%s comment', '%s comments', $approved_comments ), $approved_comments_number ); + $approved_phrase = sprintf( _n( '%s approved comment', '%s approved comments', $approved_comments ), $approved_comments_number ); + $pending_phrase = sprintf( _n( '%s pending comment', '%s pending comments', $pending_comments ), $pending_comments_number ); - echo "" . number_format_i18n( get_comments_number() ) . ""; + // No comments at all. + if ( ! $approved_comments && ! $pending_comments ) { + printf( + '%s', + __( 'No comments' ) + ); + // Approved comments have different display depending on some conditions. + } elseif ( $approved_comments ) { + printf( + '%s', + esc_url( + add_query_arg( + array( + 'p' => $post_id, + 'comment_status' => 'approved', + ), + admin_url( 'edit-comments.php' ) + ) + ), + $approved_comments_number, + $pending_comments ? $approved_phrase : $approved_only_phrase + ); + } else { + printf( + '%s', + $approved_comments_number, + $pending_comments ? __( 'No approved comments' ) : __( 'No comments' ) + ); + } - if ( $pending_comments ) - echo ''; + if ( $pending_comments ) { + printf( + '%s', + esc_url( + add_query_arg( + array( + 'p' => $post_id, + 'comment_status' => 'moderated', + ), + admin_url( 'edit-comments.php' ) + ) + ), + $pending_comments_number, + $pending_phrase + ); + } else { + printf( + '%s', + $pending_comments_number, + $approved_comments ? __( 'No pending comments' ) : __( 'No comments' ) + ); + } } /** * Get the current page number * * @since 3.1.0 - * @access protected * * @return int */ - function get_pagenum() { + public function get_pagenum() { $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0; - if( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] ) + if ( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] ) { $pagenum = $this->_pagination_args['total_pages']; + } return max( 1, $pagenum ); } @@ -454,96 +744,156 @@ function get_pagenum() { * Get number of items to display on a single page * * @since 3.1.0 - * @access protected * + * @param string $option + * @param int $default * @return int */ - function get_items_per_page( $option, $default = 20 ) { + protected function get_items_per_page( $option, $default = 20 ) { $per_page = (int) get_user_option( $option ); - if ( empty( $per_page ) || $per_page < 1 ) + if ( empty( $per_page ) || $per_page < 1 ) { $per_page = $default; + } - return (int) apply_filters( $option, $per_page ); + /** + * Filters the number of items to be displayed on each page of the list table. + * + * The dynamic hook name, $option, refers to the `per_page` option depending + * on the type of list table in use. Possible values include: 'edit_comments_per_page', + * 'sites_network_per_page', 'site_themes_network_per_page', 'themes_network_per_page', + * 'users_network_per_page', 'edit_post_per_page', 'edit_page_per_page', + * 'edit_{$post_type}_per_page', etc. + * + * @since 2.9.0 + * + * @param int $per_page Number of items to be displayed. Default 20. + */ + return (int) apply_filters( "{$option}", $per_page ); } /** * Display the pagination. * * @since 3.1.0 - * @access protected + * + * @param string $which */ - function pagination( $which ) { - if ( empty( $this->_pagination_args ) ) + protected function pagination( $which ) { + if ( empty( $this->_pagination_args ) ) { return; + } - extract( $this->_pagination_args, EXTR_SKIP ); + $total_items = $this->_pagination_args['total_items']; + $total_pages = $this->_pagination_args['total_pages']; + $infinite_scroll = false; + if ( isset( $this->_pagination_args['infinite_scroll'] ) ) { + $infinite_scroll = $this->_pagination_args['infinite_scroll']; + } + + if ( 'top' === $which && $total_pages > 1 ) { + $this->screen->render_screen_reader_content( 'heading_pagination' ); + } - $output = '' . sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . ''; + $output = '' . sprintf( _n( '%s item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . ''; - $current = $this->get_pagenum(); + $current = $this->get_pagenum(); + $removable_query_args = wp_removable_query_args(); $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); - $current_url = remove_query_arg( array( 'hotkeys_highlight_last', 'hotkeys_highlight_first' ), $current_url ); + $current_url = remove_query_arg( $removable_query_args, $current_url ); $page_links = array(); - $disable_first = $disable_last = ''; - if ( $current == 1 ) - $disable_first = ' disabled'; - if ( $current == $total_pages ) - $disable_last = ' disabled'; - - $page_links[] = sprintf( "%s", - 'first-page' . $disable_first, - esc_attr__( 'Go to the first page' ), - esc_url( remove_query_arg( 'paged', $current_url ) ), - '«' - ); + $total_pages_before = ''; + $total_pages_after = ''; - $page_links[] = sprintf( "%s", - 'prev-page' . $disable_first, - esc_attr__( 'Go to the previous page' ), - esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ), - '‹' - ); + $disable_first = $disable_last = $disable_prev = $disable_next = false; + + if ( $current == 1 ) { + $disable_first = true; + $disable_prev = true; + } + if ( $current == 2 ) { + $disable_first = true; + } + if ( $current == $total_pages ) { + $disable_last = true; + $disable_next = true; + } + if ( $current == $total_pages - 1 ) { + $disable_last = true; + } - if ( 'bottom' == $which ) - $html_current_page = $current; - else - $html_current_page = sprintf( "", - esc_attr__( 'Current page' ), + if ( $disable_first ) { + $page_links[] = ''; + } else { + $page_links[] = sprintf( + "%s", + esc_url( remove_query_arg( 'paged', $current_url ) ), + __( 'First page' ), + '«' + ); + } + + if ( $disable_prev ) { + $page_links[] = ''; + } else { + $page_links[] = sprintf( + "%s", + esc_url( add_query_arg( 'paged', max( 1, $current - 1 ), $current_url ) ), + __( 'Previous page' ), + '‹' + ); + } + + if ( 'bottom' === $which ) { + $html_current_page = $current; + $total_pages_before = '' . __( 'Current Page' ) . ''; + } else { + $html_current_page = sprintf( + "%s", + '', $current, strlen( $total_pages ) ); - + } $html_total_pages = sprintf( "%s", number_format_i18n( $total_pages ) ); - $page_links[] = '' . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . ''; + $page_links[] = $total_pages_before . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . $total_pages_after; - $page_links[] = sprintf( "%s", - 'next-page' . $disable_last, - esc_attr__( 'Go to the next page' ), - esc_url( add_query_arg( 'paged', min( $total_pages, $current+1 ), $current_url ) ), - '›' - ); + if ( $disable_next ) { + $page_links[] = ''; + } else { + $page_links[] = sprintf( + "%s", + esc_url( add_query_arg( 'paged', min( $total_pages, $current + 1 ), $current_url ) ), + __( 'Next page' ), + '›' + ); + } - $page_links[] = sprintf( "%s", - 'last-page' . $disable_last, - esc_attr__( 'Go to the last page' ), - esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ), - '»' - ); + if ( $disable_last ) { + $page_links[] = ''; + } else { + $page_links[] = sprintf( + "%s", + esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ), + __( 'Last page' ), + '»' + ); + } $pagination_links_class = 'pagination-links'; - if ( ! empty( $infinite_scroll ) ) - $pagination_links_class = ' hide-if-js'; + if ( ! empty( $infinite_scroll ) ) { + $pagination_links_class .= ' hide-if-js'; + } $output .= "\n" . join( "\n", $page_links ) . ''; - if ( $total_pages ) + if ( $total_pages ) { $page_class = $total_pages < 2 ? ' one-page' : ''; - else + } else { $page_class = ' no-pages'; - + } $this->_pagination = "
$output
"; echo $this->_pagination; @@ -554,12 +904,11 @@ function pagination( $which ) { * 'internal-name' => 'Title' * * @since 3.1.0 - * @access protected * @abstract * * @return array */ - function get_columns() { + public function get_columns() { die( 'function AIOWPSecurity_List_Table::get_columns() must be over-ridden in a sub-class.' ); } @@ -572,44 +921,139 @@ function get_columns() { * The second format will make the initial sorting order be descending * * @since 3.1.0 - * @access protected * * @return array */ - function get_sortable_columns() { + protected function get_sortable_columns() { return array(); } + /** + * Gets the name of the default primary column. + * + * @since 4.3.0 + * + * @return string Name of the default primary column, in this case, an empty string. + */ + protected function get_default_primary_column_name() { + $columns = $this->get_columns(); + $column = ''; + + if ( empty( $columns ) ) { + return $column; + } + + // We need a primary defined so responsive views show something, + // so let's fall back to the first non-checkbox column. + foreach ( $columns as $col => $column_name ) { + if ( 'cb' === $col ) { + continue; + } + + $column = $col; + break; + } + + return $column; + } + + /** + * Public wrapper for AIOWPSecurity_List_Table::get_default_primary_column_name(). + * + * @since 4.4.0 + * + * @return string Name of the default primary column. + */ + public function get_primary_column() { + return $this->get_primary_column_name(); + } + + /** + * Gets the name of the primary column. + * + * @since 4.3.0 + * + * @return string The name of the primary column. + */ + protected function get_primary_column_name() { + $columns = get_column_headers( $this->screen ); + $default = $this->get_default_primary_column_name(); + + // If the primary column doesn't exist fall back to the + // first non-checkbox column. + if ( ! isset( $columns[ $default ] ) ) { + $default = AIOWPSecurity_List_Table::get_default_primary_column_name(); + } + + /** + * Filters the name of the primary column for the current list table. + * + * @since 4.3.0 + * + * @param string $default Column name default for the specific list table, e.g. 'name'. + * @param string $context Screen ID for specific list table, e.g. 'plugins'. + */ + $column = apply_filters( 'list_table_primary_column', $default, $this->screen->id ); + + if ( empty( $column ) || ! isset( $columns[ $column ] ) ) { + $column = $default; + } + + return $column; + } + /** * Get a list of all, hidden and sortable columns, with filter applied * * @since 3.1.0 - * @access protected * * @return array */ - function get_column_info() { - if ( isset( $this->_column_headers ) ) - return $this->_column_headers; + protected function get_column_info() { + // $_column_headers is already set / cached + if ( isset( $this->_column_headers ) && is_array( $this->_column_headers ) ) { + // Back-compat for list tables that have been manually setting $_column_headers for horse reasons. + // In 4.3, we added a fourth argument for primary column. + $column_headers = array( array(), array(), array(), $this->get_primary_column_name() ); + foreach ( $this->_column_headers as $key => $value ) { + $column_headers[ $key ] = $value; + } - $columns = get_column_headers( $this->screen ); - $hidden = get_hidden_columns( $this->screen ); + return $column_headers; + } - $_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $this->get_sortable_columns() ); + $columns = get_column_headers( $this->screen ); + $hidden = get_hidden_columns( $this->screen ); + + $sortable_columns = $this->get_sortable_columns(); + /** + * Filters the list table sortable columns for a specific screen. + * + * The dynamic portion of the hook name, `$this->screen->id`, refers + * to the ID of the current screen, usually a string. + * + * @since 3.5.0 + * + * @param array $sortable_columns An array of sortable columns. + */ + $_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns ); $sortable = array(); foreach ( $_sortable as $id => $data ) { - if ( empty( $data ) ) + if ( empty( $data ) ) { continue; + } $data = (array) $data; - if ( !isset( $data[1] ) ) + if ( ! isset( $data[1] ) ) { $data[1] = false; + } - $sortable[$id] = $data; + $sortable[ $id ] = $data; } - $this->_column_headers = array( $columns, $hidden, $sortable ); + $primary = $this->get_primary_column_name(); + $this->_column_headers = array( $columns, $hidden, $sortable, $primary ); return $this->_column_headers; } @@ -618,13 +1062,12 @@ function get_column_info() { * Return number of visible columns * * @since 3.1.0 - * @access public * * @return int */ - function get_column_count() { + public function get_column_count() { list ( $columns, $hidden ) = $this->get_column_info(); - $hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) ); + $hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) ); return count( $columns ) - count( $hidden ); } @@ -632,29 +1075,32 @@ function get_column_count() { * Print column headers, accounting for hidden and sortable columns. * * @since 3.1.0 - * @access protected + * + * @staticvar int $cb_counter * * @param bool $with_id Whether to set the id attribute or not */ - function print_column_headers( $with_id = true ) { - list( $columns, $hidden, $sortable ) = $this->get_column_info(); + public function print_column_headers( $with_id = true ) { + list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info(); $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); $current_url = remove_query_arg( 'paged', $current_url ); - if ( isset( $_GET['orderby'] ) ) + if ( isset( $_GET['orderby'] ) ) { $current_orderby = $_GET['orderby']; - else + } else { $current_orderby = ''; + } - if ( isset( $_GET['order'] ) && 'desc' == $_GET['order'] ) + if ( isset( $_GET['order'] ) && 'desc' === $_GET['order'] ) { $current_order = 'desc'; - else + } else { $current_order = 'asc'; + } if ( ! empty( $columns['cb'] ) ) { static $cb_counter = 1; - $columns['cb'] = '' + $columns['cb'] = '' . ''; $cb_counter++; } @@ -662,26 +1108,29 @@ function print_column_headers( $with_id = true ) { foreach ( $columns as $column_key => $column_display_name ) { $class = array( 'manage-column', "column-$column_key" ); - $style = ''; - if ( in_array( $column_key, $hidden ) ) - $style = 'display:none;'; - - $style = ' style="' . $style . '"'; + if ( in_array( $column_key, $hidden ) ) { + $class[] = 'hidden'; + } - if ( 'cb' == $column_key ) + if ( 'cb' === $column_key ) { $class[] = 'check-column'; - elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) ) + } 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 ( isset( $sortable[ $column_key ] ) ) { + list( $orderby, $desc_first ) = $sortable[ $column_key ]; - if ( $current_orderby == $orderby ) { - $order = 'asc' == $current_order ? 'desc' : 'asc'; + if ( $current_orderby === $orderby ) { + $order = 'asc' === $current_order ? 'desc' : 'asc'; $class[] = 'sorted'; $class[] = $current_order; } else { - $order = $desc_first ? 'desc' : 'asc'; + $order = $desc_first ? 'desc' : 'asc'; $class[] = 'sortable'; $class[] = $desc_first ? 'asc' : 'desc'; } @@ -689,12 +1138,15 @@ function print_column_headers( $with_id = true ) { $column_display_name = '' . $column_display_name . ''; } - $id = $with_id ? "id='$column_key'" : ''; + $tag = ( 'cb' === $column_key ) ? 'td' : 'th'; + $scope = ( 'th' === $tag ) ? 'scope="col"' : ''; + $id = $with_id ? "id='$column_key'" : ''; - if ( !empty( $class ) ) + if ( ! empty( $class ) ) { $class = "class='" . join( ' ', $class ) . "'"; + } - echo "$column_display_name"; + echo "<$tag $scope $id $class>$column_display_name"; } } @@ -702,91 +1154,99 @@ function print_column_headers( $with_id = true ) { * Display the table * * @since 3.1.0 - * @access public */ - function display() { - extract( $this->_args ); + public function display() { + $singular = $this->_args['singular']; $this->display_tablenav( 'top' ); -?> - + $this->screen->render_screen_reader_content( 'heading_list' ); + ?> +
print_column_headers(); ?> + + > + display_rows_or_placeholder(); ?> + + print_column_headers( false ); ?> - > - display_rows_or_placeholder(); ?> -
-display_tablenav( 'bottom' ); } /** - * Get a list of CSS classes for the tag + * Get a list of CSS classes for the AIOWPSecurity_List_Table table tag. * * @since 3.1.0 - * @access protected * - * @return array + * @return array List of CSS classes for the table tag. */ - function get_table_classes() { - return array( 'widefat', 'fixed', $this->_args['plural'] ); + protected function get_table_classes() { + return array( 'widefat', 'fixed', 'striped', $this->_args['plural'] ); } /** * Generate the table navigation above or below the table * * @since 3.1.0 - * @access protected + * @param string $which */ - function display_tablenav( $which ) { - if ( 'top' == $which ) + protected function display_tablenav( $which ) { + if ( 'top' === $which ) { wp_nonce_field( 'bulk-' . $this->_args['plural'] ); -?> + } + ?>
-
- bulk_actions(); ?> + has_items() ) : ?> +
+ bulk_actions( $which ); ?>
-extra_tablenav( $which ); $this->pagination( $which ); -?> + ?>
- part of the table + * Generate the tbody element for the list table. * * @since 3.1.0 - * @access protected */ - function display_rows_or_placeholder() { + public function display_rows_or_placeholder() { if ( $this->has_items() ) { $this->display_rows(); } else { - list( $columns, $hidden ) = $this->get_column_info(); echo '
'; @@ -797,115 +1257,148 @@ function display_rows_or_placeholder() { * Generate the table rows * * @since 3.1.0 - * @access protected */ - function display_rows() { - foreach ( $this->items as $item ) + public function display_rows() { + foreach ( $this->items as $item ) { $this->single_row( $item ); + } } /** * Generates content for a single row of the table * * @since 3.1.0 - * @access protected * * @param object $item The current item */ - function single_row( $item ) { - static $row_class = ''; - $row_class = ( $row_class == '' ? ' class="alternate"' : '' ); - - echo ''; - echo $this->single_row_columns( $item ); + public function single_row( $item ) { + echo ''; + $this->single_row_columns( $item ); echo ''; } + /** + * @param object $item + * @param string $column_name + */ + protected function column_default( $item, $column_name ) {} + + /** + * @param object $item + */ + protected function column_cb( $item ) {} + /** * Generates the columns for a single row of the table * * @since 3.1.0 - * @access protected * * @param object $item The current item */ - function single_row_columns( $item ) { - list( $columns, $hidden ) = $this->get_column_info(); + protected function single_row_columns( $item ) { + list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info(); foreach ( $columns as $column_name => $column_display_name ) { - $class = "class='$column_name column-$column_name'"; + $classes = "$column_name column-$column_name"; + if ( $primary === $column_name ) { + $classes .= ' has-row-actions column-primary'; + } + + if ( in_array( $column_name, $hidden ) ) { + $classes .= ' hidden'; + } - $style = ''; - if ( in_array( $column_name, $hidden ) ) - $style = ' style="display:none;"'; + // Comments column uses HTML in the display name with screen reader text. + // Instead of using esc_attr(), we strip tags to get closer to a user-friendly string. + $data = 'data-colname="' . wp_strip_all_tags( $column_display_name ) . '"'; - $attributes = "$class$style"; + $attributes = "class='$classes' $data"; - if ( 'cb' == $column_name ) { + if ( 'cb' === $column_name ) { echo ''; - } - elseif ( method_exists( $this, 'column_' . $column_name ) ) { + } elseif ( method_exists( $this, '_column_' . $column_name ) ) { + echo call_user_func( + array( $this, '_column_' . $column_name ), + $item, + $classes, + $data, + $primary + ); + } elseif ( method_exists( $this, 'column_' . $column_name ) ) { echo ""; - } - else { + echo call_user_func( array( $this, 'column_' . $column_name ), $item ); + echo $this->handle_row_actions( $item, $column_name, $primary ); + echo ''; + } else { echo ""; + echo $this->handle_row_actions( $item, $column_name, $primary ); + echo ''; } } } + /** + * Generates and display row actions links for the list table. + * + * @since 4.3.0 + * + * @param object $item The item being acted upon. + * @param string $column_name Current column name. + * @param string $primary Primary column name. + * @return string The row actions HTML, or an empty string if the current column is the primary column. + */ + protected function handle_row_actions( $item, $column_name, $primary ) { + return $column_name === $primary ? '' : ''; + } + /** * Handle an incoming ajax request (called from admin-ajax.php) * * @since 3.1.0 - * @access public */ - function ajax_response() { + public function ajax_response() { $this->prepare_items(); - extract( $this->_args ); - extract( $this->_pagination_args, EXTR_SKIP ); - ob_start(); - if ( ! empty( $_REQUEST['no_placeholder'] ) ) + if ( ! empty( $_REQUEST['no_placeholder'] ) ) { $this->display_rows(); - else + } else { $this->display_rows_or_placeholder(); + } $rows = ob_get_clean(); $response = array( 'rows' => $rows ); - if ( isset( $total_items ) ) - $response['total_items_i18n'] = sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) ); - - if ( isset( $total_pages ) ) { - $response['total_pages'] = $total_pages; - $response['total_pages_i18n'] = number_format_i18n( $total_pages ); + if ( isset( $this->_pagination_args['total_items'] ) ) { + $response['total_items_i18n'] = sprintf( + _n( '%s item', '%s items', $this->_pagination_args['total_items'] ), + number_format_i18n( $this->_pagination_args['total_items'] ) + ); + } + if ( isset( $this->_pagination_args['total_pages'] ) ) { + $response['total_pages'] = $this->_pagination_args['total_pages']; + $response['total_pages_i18n'] = number_format_i18n( $this->_pagination_args['total_pages'] ); } - die( json_encode( $response ) ); + die( wp_json_encode( $response ) ); } /** * Send required variables to JavaScript land - * - * @access private */ - function _js_vars() { + public function _js_vars() { $args = array( 'class' => get_class( $this ), 'screen' => array( 'id' => $this->screen->id, 'base' => $this->screen->base, - ) + ), ); - printf( "\n", json_encode( $args ) ); + printf( "\n", wp_json_encode( $args ) ); } } diff --git a/all-in-one-wp-security/admin/wp-security-admin-menu.php b/all-in-one-wp-security/admin/wp-security-admin-menu.php index 5b58079..e42a7a4 100644 --- a/all-in-one-wp-security/admin/wp-security-admin-menu.php +++ b/all-in-one-wp-security/admin/wp-security-admin-menu.php @@ -95,4 +95,15 @@ function end_buffer_and_collect() ob_end_clean(); return $output; } + + static function display_bulk_result_message() + { + if(isset($_GET['bulk_count'])) { + AIOWPSecurity_Admin_Menu::show_msg_updated_st(__('The bulk action was successful', 'all-in-one-wp-security-and-firewall')); + } + + if(isset($_GET['bulk_error'])) { + AIOWPSecurity_Admin_Menu::show_msg_error_st(__('The bulk action failed', 'all-in-one-wp-security-and-firewall')); + } + } } \ No newline at end of file diff --git a/all-in-one-wp-security/admin/wp-security-dashboard-menu.php b/all-in-one-wp-security/admin/wp-security-dashboard-menu.php index 2f21d75..2c22614 100644 --- a/all-in-one-wp-security/admin/wp-security-dashboard-menu.php +++ b/all-in-one-wp-security/admin/wp-security-dashboard-menu.php @@ -304,6 +304,7 @@ function render_tab4() $blocked_ip_list->unblock_ip_address(strip_tags($_REQUEST['blocked_id'])); } } + AIOWPSecurity_Admin_Menu::display_bulk_result_message(); ?>
@@ -323,7 +324,7 @@ function render_tab4() //Fetch, prepare, sort, and filter our data... $blocked_ip_list->prepare_items(); ?> -
+ configs->get_value('aiowps_enable_brute_force_attack_prevention') == '1' || $aio_wp_security->configs->get_value('aiowps_enable_rename_login_page') == '1') { wp_add_dashboard_widget( 'brute_force', __( 'Brute Force Prevention Login Page' ), array(&$this, 'widget_brute_force') ); } - wp_add_dashboard_widget( 'logged_in_users', __( 'Logged In Users' ), array(&$this, 'widget_logged_in_users') ); - wp_add_dashboard_widget( 'locked_ip_addresses', __( 'Locked IP Addresses' ), array(&$this, 'widget_locked_ip_addresses') ); + wp_add_dashboard_widget( 'logged_in_users', __( 'Logged In Users', 'all-in-one-wp-security-and-firewall' ), array(&$this, 'widget_logged_in_users') ); + wp_add_dashboard_widget( 'locked_ip_addresses', __( 'Locked IP Addresses', 'all-in-one-wp-security-and-firewall' ), array(&$this, 'widget_locked_ip_addresses') ); do_action( 'aiowps_dashboard_setup' ); $dashboard_widgets = apply_filters( 'aiowps_dashboard_widgets', array() ); diff --git a/all-in-one-wp-security/admin/wp-security-database-menu.php b/all-in-one-wp-security/admin/wp-security-database-menu.php index d453de6..04ee422 100644 --- a/all-in-one-wp-security/admin/wp-security-database-menu.php +++ b/all-in-one-wp-security/admin/wp-security-database-menu.php @@ -575,11 +575,12 @@ function alter_table_views($old_db_prefix, $new_db_prefix) { global $wpdb; $table_count = 0; + $db_name = $wpdb->dbname; $info_msg_string = '

'.__('Checking for MySQL tables of type "view".....', 'all-in-one-wp-security-and-firewall').'

'; echo ($info_msg_string); //get tables which are views - $query = "SELECT * FROM INFORMATION_SCHEMA.VIEWS"; + $query = "SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA LIKE '".$db_name."'"; $res = $wpdb->get_results($query); if(empty($res)) return; $view_count = 0; diff --git a/all-in-one-wp-security/admin/wp-security-list-acct-activity.php b/all-in-one-wp-security/admin/wp-security-list-acct-activity.php index c5be7ae..e0ad149 100644 --- a/all-in-one-wp-security/admin/wp-security-list-acct-activity.php +++ b/all-in-one-wp-security/admin/wp-security-list-acct-activity.php @@ -108,16 +108,24 @@ function delete_login_activity_records($entries) if (isset($_REQUEST['_wp_http_referer'])) { //Delete multiple records + $tab = strip_tags($_REQUEST['tab']); + $entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values $id_list = "(" .implode(",",$entries) .")"; //Create comma separate list for DB operation $delete_command = "DELETE FROM ".$login_activity_table." WHERE id IN ".$id_list; $result = $wpdb->query($delete_command); - if($result != NULL) + if($result !== false) { - $success_msg = '

'; - $success_msg .= __('The selected entries were deleted successfully!','all-in-one-wp-security-and-firewall'); - $success_msg .= '

'; - _e($success_msg); + $redir_url = sprintf('admin.php?page=%s&tab=%s&bulk_count=%s', AIOWPSEC_USER_LOGIN_MENU_SLUG, $tab, count($entries)); + wp_redirect($redir_url); + exit; + } else { + // error on bulk delete + $aio_wp_security->debug_logger->log_debug("DB error: ".$wpdb->last_error,4); + $redir_url = sprintf('admin.php?page=%s&tab=%s&bulk_error=%s', AIOWPSEC_USER_LOGIN_MENU_SLUG, $tab, 1); + wp_redirect($redir_url); + exit; + } } } @@ -132,12 +140,12 @@ function delete_login_activity_records($entries) //Delete single record $delete_command = "DELETE FROM ".$login_activity_table." WHERE id = '".absint($entries)."'"; $result = $wpdb->query($delete_command); - if($result != NULL) + if($result !== false) { $success_msg = '

'; $success_msg .= __('The selected entry was deleted successfully!','all-in-one-wp-security-and-firewall'); $success_msg .= '

'; - _e($success_msg); + echo $success_msg; } } } @@ -150,6 +158,7 @@ function prepare_items($ignore_pagination = false) { $columns = $this->get_columns(); $hidden = array(); $sortable = $this->get_sortable_columns(); + $search = isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : ''; $this->_column_headers = array($columns, $hidden, $sortable); @@ -170,7 +179,12 @@ function prepare_items($ignore_pagination = false) { $orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable); $order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1')); - $data = $wpdb->get_results($wpdb->prepare("SELECT * FROM $login_activity_table ORDER BY $orderby $order LIMIT %d", 50), ARRAY_A); //Get the last 50 records + if(empty($search)) { + $data = $wpdb->get_results("SELECT * FROM $login_activity_table ORDER BY $orderby $order", ARRAY_A); + } else { + $data = $wpdb->get_results($wpdb->prepare("SELECT * FROM $login_activity_table WHERE `user_login` LIKE '%%%s%%' OR `login_ip` LIKE '%%%s%%' ORDER BY $orderby $order LIMIT %d", $search, $search, 50), ARRAY_A); + } + if (!$ignore_pagination) { $current_page = $this->get_pagenum(); $total_items = count($data); diff --git a/all-in-one-wp-security/admin/wp-security-list-login-fails.php b/all-in-one-wp-security/admin/wp-security-list-login-fails.php index ac154d1..1c7218e 100644 --- a/all-in-one-wp-security/admin/wp-security-list-login-fails.php +++ b/all-in-one-wp-security/admin/wp-security-list-login-fails.php @@ -108,16 +108,23 @@ function delete_login_failed_records($entries) if (isset($_REQUEST['_wp_http_referer'])) { //Delete multiple records + $tab = strip_tags($_REQUEST['tab']); $entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values $id_list = "(" .implode(",",$entries) .")"; //Create comma separate list for DB operation $delete_command = "DELETE FROM ".$failed_login_table." WHERE ID IN ".$id_list; $result = $wpdb->query($delete_command); - if($result != NULL) + if($result !== false) { - $success_msg = '

'; - $success_msg .= __('The selected entries were deleted successfully!','all-in-one-wp-security-and-firewall'); - $success_msg .= '

'; - _e($success_msg); + $redir_url = sprintf('admin.php?page=%s&tab=%s&bulk_count=%s', AIOWPSEC_USER_LOGIN_MENU_SLUG, $tab, count($entries)); + wp_redirect($redir_url); + exit; + } else { + // error on bulk delete + $aio_wp_security->debug_logger->log_debug("DB error: ".$wpdb->last_error,4); + $redir_url = sprintf('admin.php?page=%s&tab=%s&bulk_error=%s', AIOWPSEC_USER_LOGIN_MENU_SLUG, $tab, 1); + wp_redirect($redir_url); + exit; + } } @@ -132,7 +139,7 @@ function delete_login_failed_records($entries) //Delete single record $delete_command = "DELETE FROM ".$failed_login_table." WHERE ID = '".absint($entries)."'"; $result = $wpdb->query($delete_command); - if($result != NULL) + if($result !== false) { $success_msg = '

'; $success_msg .= __('The selected entry was deleted successfully!','all-in-one-wp-security-and-firewall'); @@ -150,6 +157,7 @@ function prepare_items($ignore_pagination = false) { $columns = $this->get_columns(); $hidden = array(); $sortable = $this->get_sortable_columns(); + $search = isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : ''; $this->_column_headers = array($columns, $hidden, $sortable); @@ -168,8 +176,12 @@ function prepare_items($ignore_pagination = false) { $orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable); $order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1')); + if(empty($search)) { + $data = $wpdb->get_results("SELECT * FROM " . $failed_logins_table_name . " ORDER BY $orderby $order", ARRAY_A); + } else { + $data = $wpdb->get_results($wpdb->prepare("SELECT * FROM $failed_logins_table_name WHERE `user_login` LIKE '%%%s%%' OR `login_attempt_ip` LIKE '%%%s%%' ORDER BY $orderby $order", $search, $search), ARRAY_A); + } - $data = $wpdb->get_results("SELECT * FROM $failed_logins_table_name ORDER BY $orderby $order", ARRAY_A); if (!$ignore_pagination) { $current_page = $this->get_pagenum(); $total_items = count($data); diff --git a/all-in-one-wp-security/admin/wp-security-list-permanent-blocked-ip.php b/all-in-one-wp-security/admin/wp-security-list-permanent-blocked-ip.php index 6998618..a4c5c80 100644 --- a/all-in-one-wp-security/admin/wp-security-list-permanent-blocked-ip.php +++ b/all-in-one-wp-security/admin/wp-security-list-permanent-blocked-ip.php @@ -110,13 +110,25 @@ function unblock_ip_address($entries) global $wpdb, $aio_wp_security; if (is_array($entries)) { if (isset($_REQUEST['_wp_http_referer'])) { - //Delete multiple records + // multiple records + $tab = strip_tags($_REQUEST['tab']); + $entries = array_filter($entries, 'is_numeric'); //discard non-numeric ID values $id_list = "(" . implode(",", $entries) . ")"; //Create comma separate list for DB operation $delete_command = "DELETE FROM " . AIOWPSEC_TBL_PERM_BLOCK . " WHERE id IN " . $id_list; $result = $wpdb->query($delete_command); - if ($result != NULL) { - AIOWPSecurity_Admin_Menu::show_msg_record_deleted_st(); + if($result !== false) + { + $redir_url = sprintf('admin.php?page=%s&tab=%s&bulk_count=%s', AIOWPSEC_MAIN_MENU_SLUG, $tab, count($entries)); + wp_redirect($redir_url); + exit; + } else { + // error on bulk delete + $aio_wp_security->debug_logger->log_debug("DB error: ".$wpdb->last_error,4); + $redir_url = sprintf('admin.php?page=%s&tab=%s&bulk_error=%s', AIOWPSEC_MAIN_MENU_SLUG, $tab, 1); + wp_redirect($redir_url); + exit; + } } } elseif ($entries != NULL) { @@ -128,7 +140,7 @@ function unblock_ip_address($entries) //Delete single record $delete_command = "DELETE FROM " . AIOWPSEC_TBL_PERM_BLOCK . " WHERE id = '" . absint($entries) . "'"; $result = $wpdb->query($delete_command); - if ($result != NULL) { + if ($result !== false) { AIOWPSecurity_Admin_Menu::show_msg_record_deleted_st(); } } @@ -143,6 +155,7 @@ function prepare_items() $columns = $this->get_columns(); $hidden = array(); $sortable = $this->get_sortable_columns(); + $search = isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : ''; $this->_column_headers = array($columns, $hidden, $sortable); @@ -162,11 +175,10 @@ function prepare_items() $orderby = AIOWPSecurity_Utility::sanitize_value_by_array($orderby, $sortable); $order = AIOWPSecurity_Utility::sanitize_value_by_array($order, array('DESC' => '1', 'ASC' => '1')); - if (isset($_POST['s'])) { - $search_term = trim($_POST['s']); - $data = $wpdb->get_results($wpdb->prepare("SELECT * FROM " . $block_table_name . " WHERE `blocked_ip` LIKE '%%%s%%' OR `block_reason` LIKE '%%%s%%' OR `country_origin` LIKE '%%%s%%' OR `blocked_date` LIKE '%%%s%%'", $search_term, $search_term, $search_term, $search_term), ARRAY_A); - } else { + if(empty($search)) { $data = $wpdb->get_results("SELECT * FROM " . $block_table_name . " ORDER BY $orderby $order", ARRAY_A); + } else { + $data = $wpdb->get_results($wpdb->prepare("SELECT * FROM " . $block_table_name . " WHERE `blocked_ip` LIKE '%%%s%%' OR `block_reason` LIKE '%%%s%%' OR `country_origin` LIKE '%%%s%%' OR `blocked_date` LIKE '%%%s%%' ORDER BY $orderby $order", $search, $search, $search, $search), ARRAY_A); } $current_page = $this->get_pagenum(); diff --git a/all-in-one-wp-security/admin/wp-security-list-registered-users.php b/all-in-one-wp-security/admin/wp-security-list-registered-users.php index 77f1747..8e97774 100644 --- a/all-in-one-wp-security/admin/wp-security-list-registered-users.php +++ b/all-in-one-wp-security/admin/wp-security-list-registered-users.php @@ -304,13 +304,14 @@ function prepare_items() { $columns = $this->get_columns(); $hidden = array(); $sortable = $this->get_sortable_columns(); + $search = isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : ''; $this->_column_headers = array($columns, $hidden, $sortable); $this->process_bulk_action(); //Get registered users which have the special 'aiowps_account_status' meta key set to 'pending' - $data = $this->get_registered_user_data('pending'); + $data = $this->get_registered_user_data('pending', $search); $current_page = $this->get_pagenum(); $total_items = count($data); @@ -324,7 +325,7 @@ function prepare_items() { } //Returns all users who have the special 'aiowps_account_status' meta key - function get_registered_user_data($status='') + function get_registered_user_data($status='', $search='') { $user_fields = array( 'ID', 'user_login', 'user_email', 'user_registered'); $user_query = new WP_User_Query(array('meta_key' => 'aiowps_account_status', 'meta_value' => $status, 'fields' => $user_fields)); @@ -337,7 +338,14 @@ function get_registered_user_data($status='') $temp_array['account_status'] = get_user_meta($temp_array['ID'], 'aiowps_account_status', true); $ip = get_user_meta($temp_array['ID'], 'aiowps_registrant_ip', true); $temp_array['ip_address'] = empty($ip)?'':$ip; - $final_data[] = $temp_array; + if(empty($search)) { + $final_data[] = $temp_array; + } else { + $input = preg_quote($search, '~'); // don't forget to quote input string! + + $result = preg_grep('~' . $input . '~', $temp_array); + if(!empty($result)) $final_data[] = $temp_array; + } } return $final_data; } diff --git a/all-in-one-wp-security/admin/wp-security-user-accounts-menu.php b/all-in-one-wp-security/admin/wp-security-user-accounts-menu.php index ece4ef6..c393804 100644 --- a/all-in-one-wp-security/admin/wp-security-user-accounts-menu.php +++ b/all-in-one-wp-security/admin/wp-security-user-accounts-menu.php @@ -116,9 +116,7 @@ function render_tab1() if (AIOWPSecurity_Utility::check_user_exists('admin') || AIOWPSecurity_Utility::check_user_exists('Admin')) { - echo '

'.__('Your site currently has an account which uses the default "admin" username. - It is highly recommended that you change this name to something else. - Use the following field to change the admin username.', 'all-in-one-wp-security-and-firewall').'

'; + echo '

'.__('Your site currently has an account which uses the default "admin" username. It is highly recommended that you change this name to something else. Use the following field to change the admin username.', 'all-in-one-wp-security-and-firewall').'

'; ?> diff --git a/all-in-one-wp-security/admin/wp-security-user-login-menu.php b/all-in-one-wp-security/admin/wp-security-user-login-menu.php index 7c738a5..86b05f2 100644 --- a/all-in-one-wp-security/admin/wp-security-user-login-menu.php +++ b/all-in-one-wp-security/admin/wp-security-user-login-menu.php @@ -404,6 +404,8 @@ function render_tab2() $failed_login_list->delete_login_failed_records(strip_tags($_REQUEST['failed_login_id'])); } } + + AIOWPSecurity_Admin_Menu::display_bulk_result_message(); ?>
prepare_items(); //echo "put table of locked entries here"; ?> - + - + search_box('Search', 'search_failed_login'); + if (isset($_REQUEST["tab"])) { + echo ''; + } + ?> display(); ?> @@ -551,10 +558,8 @@ function render_tab4() $acct_activity_list->delete_login_activity_records(strip_tags($_REQUEST['activity_login_rec'])); } } - if (isset($_POST['aiowpsec_export_to_csv'])) { - echo'yo'; - die; - } + + AIOWPSecurity_Admin_Menu::display_bulk_result_message(); ?>
prepare_items(); //echo "put table of locked entries here"; ?> -
+ - + search_box('Search', 'search_login_activity'); + if (isset($_REQUEST["tab"])) { + echo ''; + } + ?> display(); ?> diff --git a/all-in-one-wp-security/admin/wp-security-user-registration-menu.php b/all-in-one-wp-security/admin/wp-security-user-registration-menu.php index 64764d7..6cc05d3 100644 --- a/all-in-one-wp-security/admin/wp-security-user-registration-menu.php +++ b/all-in-one-wp-security/admin/wp-security-user-registration-menu.php @@ -164,11 +164,18 @@ function render_tab1() //Fetch, prepare, sort, and filter our data... $user_list->prepare_items(); ?> -
+ + search_box('Search', 'search_user_registration'); + if (isset($_REQUEST["tab"])) { + echo ''; + } + ?> display(); ?> +
verify_math_captcha_answer($captcha_answer); - if ( $verify_captcha === false ) { - return false; // wrong answer was entered - } - } else if (array_key_exists('g-recaptcha-response', $_POST)) { - $g_recaptcha_response = isset($_POST['g-recaptcha-response'])?sanitize_text_field($_POST['g-recaptcha-response']):''; - $verify_captcha = $this->verify_google_recaptcha($g_recaptcha_response); - if($verify_captcha === false) { - return false; // wrong answer was entered - } + if($aio_wp_security->configs->get_value('aiowps_enable_login_captcha') && $aio_wp_security->configs->get_value('aiowps_default_recaptcha')){ + //Google reCaptcha enabled + if (array_key_exists('g-recaptcha-response', $_POST)) { + $g_recaptcha_response = isset($_POST['g-recaptcha-response'])?sanitize_text_field($_POST['g-recaptcha-response']):''; + $verify_captcha = $this->verify_google_recaptcha($g_recaptcha_response); + if($verify_captcha === false) { + return false; // wrong answer was entered + } + }else { + //no captcha form data submitted + return false; + } + }else if($aio_wp_security->configs->get_value('aiowps_enable_login_captcha')) { + // this means basic math captcha is enabled + if (array_key_exists('aiowps-captcha-answer', $_POST)) { + $captcha_answer = isset($_POST['aiowps-captcha-answer'])?sanitize_text_field($_POST['aiowps-captcha-answer']):''; + + $verify_captcha = $this->verify_math_captcha_answer($captcha_answer); + if ( $verify_captcha === false ) { + return false; // wrong answer was entered + } + } else { + //no captcha form data submitted + return false; + } } return true; } diff --git a/all-in-one-wp-security/classes/wp-security-general-init-tasks.php b/all-in-one-wp-security/classes/wp-security-general-init-tasks.php index ba80466..60da378 100644 --- a/all-in-one-wp-security/classes/wp-security-general-init-tasks.php +++ b/all-in-one-wp-security/classes/wp-security-general-init-tasks.php @@ -15,9 +15,10 @@ function __construct(){ add_action( 'permalink_structure_changed', array(&$this, 'refresh_firewall_rules' ), 10, 2); - if ($aio_wp_security->configs->get_value('aiowps_enable_autoblock_spam_ip') == '1') { - AIOWPSecurity_Blocking::check_visitor_ip_and_perform_blocking(); + // Check permanent block list and block if applicable (ie, do PHP blocking) + AIOWPSecurity_Blocking::check_visitor_ip_and_perform_blocking(); + if ($aio_wp_security->configs->get_value('aiowps_enable_autoblock_spam_ip') == '1') { //add_action( 'spammed_comment', array(&$this, 'process_spammed_comment' )); //this hook gets fired when admin marks comment as spam //add_action( 'akismet_submit_spam_comment', array(&$this, 'process_akismet_submit_spam_comment' ), 10, 2); //this hook gets fired when akismet marks a comment as spam add_action( 'comment_post', array(&$this, 'spam_detect_process_comment_post' ), 10, 2); //this hook gets fired just after comment is saved to DB @@ -204,7 +205,9 @@ function __construct(){ switch_to_blog($blog_id); if($aio_wp_security->configs->get_value('aiowps_enable_comment_captcha') == '1'){ if (!is_user_logged_in()) { - add_action('wp_head', array(&$this, 'add_recaptcha_script')); + if($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) { + add_action('wp_head', array(&$this, 'add_recaptcha_script')); + } add_action( 'comment_form_after_fields', array(&$this, 'insert_captcha_question_form'), 1 ); add_action( 'comment_form_logged_in_after', array(&$this, 'insert_captcha_question_form'), 1 ); add_filter( 'preprocess_comment', array(&$this, 'process_comment_post') ); @@ -214,7 +217,9 @@ function __construct(){ }else{ if($aio_wp_security->configs->get_value('aiowps_enable_comment_captcha') == '1'){ if (!is_user_logged_in()) { - add_action('wp_head', array(&$this, 'add_recaptcha_script')); + if($aio_wp_security->configs->get_value('aiowps_default_recaptcha')) { + add_action('wp_head', array(&$this, 'add_recaptcha_script')); + } add_action( 'comment_form_after_fields', array(&$this, 'insert_captcha_question_form'), 1 ); add_action( 'comment_form_logged_in_after', array(&$this, 'insert_captcha_question_form'), 1 ); add_filter( 'preprocess_comment', array(&$this, 'process_comment_post') ); diff --git a/all-in-one-wp-security/classes/wp-security-user-login.php b/all-in-one-wp-security/classes/wp-security-user-login.php index 6f1a233..ad4f614 100644 --- a/all-in-one-wp-security/classes/wp-security-user-login.php +++ b/all-in-one-wp-security/classes/wp-security-user-login.php @@ -18,7 +18,7 @@ function __construct() // Check whether user needs to be manually approved after default WordPress authenticate hooks (with priority 20). add_filter('authenticate', array($this, 'check_manual_registration_approval'), 30, 1); // Check login captcha - add_filter('authenticate', array($this, 'check_captcha'), 1, 1); + add_filter('authenticate', array($this, 'check_captcha'), 20, 1); // As a last authentication step, perform post authentication steps add_filter('authenticate', array($this, 'post_authenticate'), 100, 3); add_action('aiowps_force_logout_check', array($this, 'aiowps_force_logout_action_handler')); @@ -604,4 +604,4 @@ function get_unlock_request_form() $unlock_request_form .= '
'; return $unlock_request_form; } -} +} \ No newline at end of file diff --git a/all-in-one-wp-security/classes/wp-security-utility-file.php b/all-in-one-wp-security/classes/wp-security-utility-file.php index a2c9113..c487c9a 100644 --- a/all-in-one-wp-security/classes/wp-security-utility-file.php +++ b/all-in-one-wp-security/classes/wp-security-utility-file.php @@ -29,7 +29,7 @@ function __construct(){ array('name'=>'wp-content/plugins/','path'=>ABSPATH."wp-content/plugins",'permissions'=>'0755'), array('name'=>'wp-admin/','path'=>ABSPATH."wp-admin",'permissions'=>'0755'), array('name'=>'wp-content/','path'=>ABSPATH."wp-content",'permissions'=>'0755'), - array('name'=>'wp-config.php','path'=>$wp_config_path,'permissions'=>'0644') + array('name'=>'wp-config.php','path'=>$wp_config_path,'permissions'=>'0640') //Add as many files or dirs as needed by following the convention above ); diff --git a/all-in-one-wp-security/classes/wp-security-utility-ip-address.php b/all-in-one-wp-security/classes/wp-security-utility-ip-address.php index a553992..da561db 100644 --- a/all-in-one-wp-security/classes/wp-security-utility-ip-address.php +++ b/all-in-one-wp-security/classes/wp-security-utility-ip-address.php @@ -76,7 +76,7 @@ static function get_sanitized_ip_range($ip) static function create_ip_list_array_from_string_with_newline($ip_addresses) { - $ip_list_array = explode(PHP_EOL, $ip_addresses); + $ip_list_array = preg_split("/\R/", $ip_addresses); return $ip_list_array; } @@ -220,6 +220,8 @@ static function is_ip_whitelisted($ip_address, $whitelisted_ips){ $ip_list_array = AIOWPSecurity_Utility_IP::create_ip_list_array_from_string_with_newline($whitelisted_ips); + if(empty($ip_list_array)) return false; + $visitor_ipParts = explode('.', $ip_address); foreach ($ip_list_array as $white_ip){ $ipParts = explode('.', $white_ip); diff --git a/all-in-one-wp-security/css/wp-security-admin-styles.css b/all-in-one-wp-security/css/wp-security-admin-styles.css index 1482ae8..c891e05 100644 --- a/all-in-one-wp-security/css/wp-security-admin-styles.css +++ b/all-in-one-wp-security/css/wp-security-admin-styles.css @@ -397,3 +397,19 @@ vertical-align: baseline; white-space: nowrap; } + +/* Fix for wp list table nav buttons style messed up in 5.1 */ +.tablenav .tablenav-pages .pagination-links a { + display: inline-block; + padding: 4px 5px 6px; + font-size: 16px; + line-height: 1; + text-align: center; + text-decoration: none; +} + +.tablenav .tablenav-pages .pagination-links a { + min-width: 17px; + border: 1px solid #ccc; + background: #f7f7f7; +} \ No newline at end of file diff --git a/all-in-one-wp-security/readme.txt b/all-in-one-wp-security/readme.txt index 153be02..c34edfd 100644 --- a/all-in-one-wp-security/readme.txt +++ b/all-in-one-wp-security/readme.txt @@ -3,7 +3,7 @@ Contributors: Tips and Tricks HQ, wpsolutions, Peter Petreski, Ruhul Amin, mbrso Donate link: https://www.tipsandtricks-hq.com Tags: security, secure, Anti Virus, antivirus, ban, ban hacker, virus, firewall, firewall security, login, lockdown, htaccess, hack, malware, vulnerability, protect, protection, phishing, database, backup, plugin, sql injection, ssl, restrict, login captcha, bot, hotlink, 404 detection, admin, rename, all in one, scan, scanner, iframe, Requires at least: 4.7 -Tested up to: 5.0 +Tested up to: 5.2 Stable tag: trunk License: GPLv3 @@ -112,7 +112,6 @@ or malicious bots who do not have a special cookie in their browser. You (the si = Security Scanner = * The file change detection scanner can alert you if any files have changed in your WordPress system. You can then investigate and see if that was a legitimate change or some bad code was injected. -* Database scanner feature can be used to scan your database tables. It will look for any common suspicious-looking strings, javascript and html code in some of the WordPress core tables. = Comment SPAM Security = * Monitor the most active IP addresses which persistently produce the most SPAM comments and instantly block them with the click of a button. @@ -188,6 +187,23 @@ None == Changelog == += 4.3.9 = +- Fixed captcha bug. +- Fixed PHP_EOL issue where some IPv6 and v4 addresses saved in settings were incorrectly deemed invalid. +- Tightened file permission for wp-config.php to "640" +- Fixed DB prefix change bug for cases where DB had tables of type "view". +- Fixed some translation string issues. +- Minor style fix for wp list table pagination nav buttons. + += 4.3.8.3 = +- Trying again - Fixed login captcha authentication bug. + += 4.3.8.2 = +- Fixed login captcha authentication bug. + += 4.3.8.1 = +- Minor bug fix - added missing check to enqueue recaptcha script only if that feature is enabled. + = 4.3.8 = - Added ability to hide secret rename login page link when sending emails to people asking for personal data export. - Fixed Google reCaptcha not showing on comment page. diff --git a/all-in-one-wp-security/wp-security-core.php b/all-in-one-wp-security/wp-security-core.php index c9747d2..b08cbe4 100644 --- a/all-in-one-wp-security/wp-security-core.php +++ b/all-in-one-wp-security/wp-security-core.php @@ -7,7 +7,7 @@ if (!class_exists('AIO_WP_Security')){ class AIO_WP_Security{ - var $version = '4.3.8'; + var $version = '4.3.9'; var $db_version = '1.9'; var $plugin_url; var $plugin_path; diff --git a/all-in-one-wp-security/wp-security.php b/all-in-one-wp-security/wp-security.php index 7a58055..38e7609 100644 --- a/all-in-one-wp-security/wp-security.php +++ b/all-in-one-wp-security/wp-security.php @@ -1,7 +1,7 @@
'; $this->no_items(); echo '
'; echo $this->column_cb( $item ); echo '"; - echo call_user_func( array( &$this, 'column_' . $column_name ), $item ); - echo ""; echo $this->column_default( $item, $column_name ); - echo "