Merged in feature/280-dev-dev01 (pull request #21)
auto-patch 280-dev-dev01-2024-01-19T16_41_58 * auto-patch 280-dev-dev01-2024-01-19T16_41_58
This commit is contained in:
@@ -0,0 +1,920 @@
|
||||
<?php
|
||||
|
||||
// Test for restore_network()
|
||||
define( 'TEST_RESTORE_NETWORK', FALSE );
|
||||
define( 'TEST_NETWORK_BLOG_COUNT', 30 );
|
||||
|
||||
class IP_Geo_Block_Admin_Ajax {
|
||||
|
||||
/**
|
||||
* Admin ajax sub functions
|
||||
*
|
||||
* @param string $which name of the geolocation api provider (should be validated by whitelist)
|
||||
*/
|
||||
public static function search_ip( $which ) {
|
||||
require_once IP_GEO_BLOCK_PATH . 'classes/class-ip-geo-block-lkup.php';
|
||||
|
||||
// check format
|
||||
if ( filter_var( $ip = trim( $_POST['ip'] ), FILTER_VALIDATE_IP ) ) {
|
||||
// get option settings and compose request headers
|
||||
$options = IP_Geo_Block::get_option();
|
||||
$tmp = IP_Geo_Block::get_request_headers( $options );
|
||||
|
||||
// create object for provider and get location
|
||||
if ( $geo = IP_Geo_Block_API::get_instance( $which, $options ) )
|
||||
$res = $geo->get_location( $ip, $tmp );
|
||||
else
|
||||
$res = array( 'errorMessage' => 'Unknown service.' );
|
||||
} else {
|
||||
$res = array( 'errorMessage' => 'Invalid IP address.' );
|
||||
}
|
||||
|
||||
if ( empty( $res['errorMessage'] ) ) {
|
||||
if ( $geo = IP_Geo_Block_API::get_instance( 'Maxmind', $options ) ) {
|
||||
$tmp = microtime( TRUE );
|
||||
$geo = $geo->get_location( $ip, array( 'ASN' => TRUE ) );
|
||||
$tmp = microtime( TRUE ) - $tmp;
|
||||
|
||||
$res['AS number'] = isset( $geo['ASN'] ) ? esc_html( $geo['ASN'] ) : '';
|
||||
$res['AS number'] .= sprintf( ' (%.1f [msec])', $tmp * 1000.0 );
|
||||
}
|
||||
|
||||
$tmp = microtime( TRUE );
|
||||
$res['host (DNS)'] = esc_html( IP_Geo_Block_Lkup::gethostbyaddr( $ip ) );
|
||||
$tmp = microtime( TRUE ) - $tmp;
|
||||
$res['host (DNS)'] .= sprintf( ' (%.1f [msec])', $tmp * 1000.0 );
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get country code from providers
|
||||
*
|
||||
* @param string $which 'ip_client' or 'ip_server' (not in use)
|
||||
*/
|
||||
public static function scan_country( $which ) {
|
||||
// scan all the country code using selected APIs
|
||||
$options = IP_Geo_Block::get_option();
|
||||
$ip = IP_Geo_Block::get_ip_address();
|
||||
$args = IP_Geo_Block::get_request_headers( $options );
|
||||
$type = IP_Geo_Block_Provider::get_providers( 'type', FALSE, FALSE );
|
||||
$providers = IP_Geo_Block_Provider::get_valid_providers( $options, FALSE, FALSE );
|
||||
|
||||
$res['IP address'] = esc_html( $ip );
|
||||
|
||||
foreach ( $providers as $provider ) {
|
||||
if ( $geo = IP_Geo_Block_API::get_instance( $provider, $options ) ) {
|
||||
$ret = $geo->get_location( $ip, $args );
|
||||
$res[ $provider ] = array(
|
||||
'type' => $type[ $provider ],
|
||||
'code' => esc_html(
|
||||
FALSE === $ret ? __( 'n/a', 'ip-geo-block' ) : (
|
||||
! empty( $ret['errorMessage'] ) ? $ret['errorMessage'] : (
|
||||
! empty( $ret['countryCode' ] ) ? $ret['countryCode' ] :
|
||||
__( 'n/a', 'ip-geo-block' ) ) )
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert array
|
||||
*
|
||||
*/
|
||||
private static function array_insert( &$base_array, $insert_value, $position = null ) {
|
||||
if ( ! is_array( $insert_value ) )
|
||||
$insert_value = array( $insert_value );
|
||||
|
||||
$position = is_null( $position ) ? count( $base_array ) : intval( $position );
|
||||
$base_array = array_merge( array_splice( $base_array, 0, $position ), $insert_value, $base_array );
|
||||
}
|
||||
|
||||
/**
|
||||
* Export logs from MySQL DB
|
||||
*
|
||||
* @param string $which 'comment', 'xmlrpc', 'login', 'admin' or 'public'
|
||||
*/
|
||||
public static function export_logs( $which ) {
|
||||
$csv = '#';
|
||||
$time = $_SERVER['REQUEST_TIME'];
|
||||
|
||||
$csv .= implode( ',', array(
|
||||
__( 'Time', 'ip-geo-block' ),
|
||||
__( 'IP address', 'ip-geo-block' ),
|
||||
__( 'Code', 'ip-geo-block' ),
|
||||
__( 'ASN', 'ip-geo-block' ),
|
||||
__( 'Target', 'ip-geo-block' ),
|
||||
__( 'Result', 'ip-geo-block' ),
|
||||
__( 'Request', 'ip-geo-block' ),
|
||||
__( 'User agent', 'ip-geo-block' ),
|
||||
__( 'HTTP headers', 'ip-geo-block' ),
|
||||
__( '$_POST data', 'ip-geo-block' ),
|
||||
) ) . PHP_EOL;
|
||||
|
||||
foreach ( IP_Geo_Block_Logs::restore_logs( $which ) as $data ) {
|
||||
$hook = array_shift( $data ); // remove `No`
|
||||
$hook = array_shift( $data ); // extract `hook`
|
||||
self::array_insert( $data, $hook, 3 );
|
||||
$data[0] = IP_Geo_Block_Util::localdate( $data[0], 'Y-m-d H:i:s' );
|
||||
$data[7] = str_replace( ',', '‚', $data[7] ); // , --> ‚
|
||||
$data[8] = str_replace( ',', '‚', $data[8] ); // , --> ‚
|
||||
$data[9] = str_replace( ',', '‚', $data[9] ); // , --> ‚
|
||||
$csv .= implode( ',', $data ) . PHP_EOL;
|
||||
}
|
||||
|
||||
// Send as file
|
||||
header( 'Content-Description: File Transfer' );
|
||||
header( 'Content-Type: application/octet-stream' );
|
||||
header( 'Content-Disposition: attachment; filename="' . IP_Geo_Block::PLUGIN_NAME . '_' . IP_Geo_Block_Util::localdate( $time, 'Y-m-d_H-i-s' ) . '.csv"' );
|
||||
header( 'Pragma: public' );
|
||||
header( 'Expires: 0' );
|
||||
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
|
||||
header( 'Content-Length: ' . strlen( $csv ) );
|
||||
echo $csv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format logs from rows array
|
||||
*
|
||||
*/
|
||||
private static function format_logs( $rows ) {
|
||||
$options = IP_Geo_Block::get_option();
|
||||
$res = array();
|
||||
|
||||
foreach ( $rows as $row ) {
|
||||
array_shift( $row ); // remove `No`
|
||||
$row = array_map( 'esc_html', $row );
|
||||
|
||||
if ( $options['anonymize'] && FALSE === strpos( $row[2], '***' ) ) {
|
||||
$row[2] = IP_Geo_Block_Util::anonymize_ip( $row[2], TRUE );
|
||||
$row[8] = IP_Geo_Block_Util::anonymize_ip( $row[8], FALSE );
|
||||
}
|
||||
|
||||
$res[] = array(
|
||||
/* 0 Checkbox */ '',
|
||||
/* 1 Time (raw) */ $row[1],
|
||||
/* 2 Date */ '’' . IP_Geo_Block_Util::localdate( $row[1], 'y-m-d H:i:s' ),
|
||||
/* 3 IP address */ '<span><a href="#!">' . $row[2] . '</a></span>',
|
||||
/* 4 Country code */ '<span>' . $row[3] . '</span>',
|
||||
/* 5 AS number */ '<span>' . $row[5] . '</span>',
|
||||
/* 6 Target */ '<span>' . $row[0] . '</span>',
|
||||
/* 7 Status */ '<span>' . $row[4] . '</span>',
|
||||
/* 8 Request */ '<span>' . $row[6] . '</span>',
|
||||
/* 9 User agent */ '<span>' . $row[7] . '</span>',
|
||||
/* 10 HTTP headers */ '<span>' . $row[8] . '</span>',
|
||||
/* 11 $_POST data */ '<span>' . $row[9] . '</span>',
|
||||
);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore logs from MySQL DB
|
||||
*
|
||||
* @param string $which 'comment', 'xmlrpc', 'login', 'admin' or 'public'
|
||||
*/
|
||||
public static function restore_logs( $which ) {
|
||||
return array( 'data' => self::format_logs(
|
||||
apply_filters( IP_Geo_Block::PLUGIN_NAME . '-logs', IP_Geo_Block_Logs::restore_logs( $which ) )
|
||||
) ); // DataTables requires `data`
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch and release the authority for live log
|
||||
*
|
||||
* @return TRUE or WP_Error
|
||||
*/
|
||||
public static function catch_live_log() {
|
||||
$user = IP_Geo_Block_Util::get_current_user_id();
|
||||
$auth = IP_Geo_Block::get_live_log();
|
||||
|
||||
if ( $auth === FALSE || $user === (int)$auth ) {
|
||||
set_transient( IP_Geo_Block::PLUGIN_NAME . '-live-log', $user, IP_Geo_Block_Admin::TIMEOUT_LIVE_UPDATE );
|
||||
return TRUE;
|
||||
} else {
|
||||
$info = get_userdata( $auth );
|
||||
return new WP_Error( 'Warn', sprintf( __( 'The user %s (user ID: %d) is in use.', 'ip-geo-block' ), $info->user_login, $auth ) );
|
||||
}
|
||||
}
|
||||
|
||||
public static function release_live_log() {
|
||||
if ( is_wp_error( $result = self::catch_live_log() ) )
|
||||
return $result;
|
||||
|
||||
delete_transient( IP_Geo_Block::PLUGIN_NAME . '-live-log' );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore and reset live log in SQLite
|
||||
*
|
||||
*/
|
||||
public static function reset_live_log() {
|
||||
return IP_Geo_Block_Logs::reset_sqlite_db();
|
||||
}
|
||||
|
||||
public static function restore_live_log( $hook, $settings ) {
|
||||
if ( is_wp_error( $ret = self::catch_live_log() ) )
|
||||
return $ret;
|
||||
|
||||
if ( ! is_wp_error( $res = IP_Geo_Block_Logs::restore_live_log( $hook, $settings ) ) )
|
||||
return array( 'data' => self::format_logs( apply_filters( IP_Geo_Block::PLUGIN_NAME . '-logs', $res ) ) );
|
||||
else
|
||||
return array( 'error' => $res->get_error_message() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Export IP address in cache from MySQL DB
|
||||
*
|
||||
*/
|
||||
public static function export_cache( $anonymize = TRUE ) {
|
||||
$csv = '#';
|
||||
$time = $_SERVER['REQUEST_TIME'];
|
||||
|
||||
$csv .= implode( ',', array(
|
||||
__( 'IP address', 'ip-geo-block' ),
|
||||
__( 'Code', 'ip-geo-block' ),
|
||||
__( 'ASN', 'ip-geo-block' ),
|
||||
__( 'Host name', 'ip-geo-block' ),
|
||||
__( 'Target', 'ip-geo-block' ),
|
||||
__( 'Failure / Total', 'ip-geo-block' ),
|
||||
__( 'Elapsed[sec]', 'ip-geo-block' ),
|
||||
) ) . PHP_EOL;
|
||||
|
||||
foreach ( IP_Geo_Block_Logs::restore_cache() as $key => $val ) {
|
||||
if ( $anonymize ) {
|
||||
$key = IP_Geo_Block_Util::anonymize_ip( $key, TRUE );
|
||||
$val['host'] = IP_Geo_Block_Util::anonymize_ip( $val['host'], FALSE );
|
||||
}
|
||||
|
||||
$csv .= implode( ',', array(
|
||||
/* IP address */ $key,
|
||||
/* Country code */ $val['code'],
|
||||
/* AS number */ $val['asn' ],
|
||||
/* Host name */ $val['host'],
|
||||
/* Target */ $val['hook'],
|
||||
/* Failure / Total */ sprintf( '%d / %d', (int)$val['fail'], (int)$val['reqs'] ),
|
||||
/* Elapsed[sec] */ $time - (int)$val['time'],
|
||||
) ) . PHP_EOL;
|
||||
}
|
||||
|
||||
// Send as file
|
||||
header( 'Content-Description: File Transfer' );
|
||||
header( 'Content-Type: application/octet-stream' );
|
||||
header( 'Content-Disposition: attachment; filename="' . IP_Geo_Block::PLUGIN_NAME . '_' . IP_Geo_Block_Util::localdate( $time, 'Y-m-d_H-i-s' ) . '.csv"' );
|
||||
header( 'Pragma: public' );
|
||||
header( 'Expires: 0' );
|
||||
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
|
||||
header( 'Content-Length: ' . strlen( $csv ) );
|
||||
echo $csv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore cache from MySQL DB
|
||||
*
|
||||
*/
|
||||
public static function restore_cache( $anonymize = TRUE ) {
|
||||
$res = array();
|
||||
$time = $_SERVER['REQUEST_TIME'];
|
||||
|
||||
foreach ( IP_Geo_Block_Logs::restore_cache() as $key => $val ) {
|
||||
if ( $anonymize ) {
|
||||
$key = IP_Geo_Block_Util::anonymize_ip( $key, TRUE );
|
||||
$val['host'] = IP_Geo_Block_Util::anonymize_ip( $val['host'], FALSE );
|
||||
}
|
||||
|
||||
$res[] = array(
|
||||
/* Checkbox */ '',
|
||||
/* IP address */ '<span><a href="#!" data-hash="' . esc_attr( $val['hash'] ). '">' . esc_html( $key ) . '</a></span>',
|
||||
/* Country code */ '<span>' . esc_html( $val['code'] ) . '</span>',
|
||||
/* AS number */ '<span>' . esc_html( $val['asn' ] ) . '</span>',
|
||||
/* Host name */ '<span>' . esc_html( $val['host'] ) . '</span>',
|
||||
/* Target */ '<span>' . esc_html( $val['hook'] ) . '</span>',
|
||||
/* Fails/Calls */ '<span>' . sprintf( '%d / %d', (int)$val['fail'], (int)$val['reqs'] ) . '</span>',
|
||||
/* Elapsed[sec] */ '<span>' . ( $time - (int)$val['time'] ) . '</span>',
|
||||
);
|
||||
}
|
||||
|
||||
return array( 'data' => $res ); // DataTables requires `data`
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of active sites on your installation
|
||||
*/
|
||||
public static function get_network_count() {
|
||||
if ( ! defined( 'TEST_RESTORE_NETWORK' ) or ! TEST_RESTORE_NETWORK ):
|
||||
if ( is_plugin_active_for_network( IP_GEO_BLOCK_BASE ) ) {
|
||||
return get_blog_count(); // get_sites( array( 'count' => TRUE ) ) @since 4.6
|
||||
} else {
|
||||
$count = 0;
|
||||
global $wpdb;
|
||||
foreach ( $wpdb->get_col( "SELECT `blog_id` FROM `$wpdb->blogs`" ) as $id ) {
|
||||
switch_to_blog( $id );
|
||||
is_plugin_active( IP_GEO_BLOCK_BASE ) and ++$count;
|
||||
restore_current_blog();
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
else:
|
||||
return TEST_NETWORK_BLOG_COUNT;
|
||||
endif;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore blocked per target in logs
|
||||
*
|
||||
* @param string $duration the number of selected duration
|
||||
* @param int $offset the start of blog to restore logs
|
||||
* @param int $length the number of blogs to restore logs from $offset
|
||||
* @param int $literal JavaScript literal notation
|
||||
*/
|
||||
public static function restore_network( $duration, $offset = 0, $length = 100, $literal = FALSE ) {
|
||||
$zero = array(
|
||||
'comment' => 0,
|
||||
'xmlrpc' => 0,
|
||||
'login' => 0,
|
||||
'admin' => 0,
|
||||
'public' => 0,
|
||||
);
|
||||
|
||||
$time = array(
|
||||
YEAR_IN_SECONDS, // All
|
||||
HOUR_IN_SECONDS, // Latest 1 hour
|
||||
DAY_IN_SECONDS, // Latest 24 hours
|
||||
WEEK_IN_SECONDS, // Latest 1 week
|
||||
30 * DAY_IN_SECONDS // Latest 1 month (MONTH_IN_SECONDS is since WP 4.4+)
|
||||
);
|
||||
|
||||
$i = 0;
|
||||
$length += $offset;
|
||||
$json = $count = array();
|
||||
$duration = isset( $time[ $duration ] ) ? $time[ $duration ] : $time[0];
|
||||
|
||||
if ( ! defined( 'TEST_RESTORE_NETWORK' ) or ! TEST_RESTORE_NETWORK ):
|
||||
global $wpdb;
|
||||
foreach ( $wpdb->get_col( "SELECT `blog_id` FROM `$wpdb->blogs`" ) as $id ) {
|
||||
switch_to_blog( $id );
|
||||
|
||||
if ( is_plugin_active( IP_GEO_BLOCK_BASE ) && $offset <= $i && $i < $length ) {
|
||||
// array of ( `time`, `ip`, `hook`, `code`, `method`, `data` )
|
||||
$name = get_bloginfo( 'name' );
|
||||
$logs = IP_Geo_Block_Logs::get_recent_logs( $duration );
|
||||
|
||||
$count[ $name ] = $zero;
|
||||
|
||||
// Blocked hooks by time
|
||||
foreach( $logs as $val ) {
|
||||
++$count[ $name ][ $val['hook'] ];
|
||||
}
|
||||
|
||||
// link over network
|
||||
$count[ $name ]['link'] = esc_url( add_query_arg(
|
||||
array( 'page' => IP_Geo_Block::PLUGIN_NAME ),
|
||||
admin_url( 'options-general.php' )
|
||||
) );
|
||||
}
|
||||
|
||||
restore_current_blog();
|
||||
}
|
||||
else:
|
||||
for ( $i = 0; $i < TEST_NETWORK_BLOG_COUNT; ++$i ) {
|
||||
if ( $offset <= $i && $i < $length ) {
|
||||
$count[ 'site-' . $i ] = array(
|
||||
$i, $i, $i, $i, $i,
|
||||
esc_url( add_query_arg(
|
||||
array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 1 ),
|
||||
admin_url( 'options-general.php' )
|
||||
) )
|
||||
);
|
||||
}
|
||||
}
|
||||
endif; // TEST_RESTORE_NETWORK
|
||||
|
||||
if ( $literal ) {
|
||||
// https://stackoverflow.com/questions/17327022/create-line-chart-using-google-chart-api-and-json-for-datatable
|
||||
foreach ( $count as $key => $val ) {
|
||||
$json['rows'][]['c'] = array(
|
||||
array( 'v' => $key ),
|
||||
array( 'v' => $val['comment'] ),
|
||||
array( 'v' => $val['xmlrpc' ] ),
|
||||
array( 'v' => $val['login' ] ),
|
||||
array( 'v' => $val['admin' ] ),
|
||||
array( 'v' => $val['public' ] ),
|
||||
array( 'v' => $val['link' ] ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
// https://developers.google.com/chart/interactive/docs/datatables_dataviews#arraytodatatable
|
||||
foreach ( $count as $key => $val ) {
|
||||
array_push( $json, array_merge( array( $key ), array_values( $val ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate json from the client and respond safe data
|
||||
*
|
||||
*/
|
||||
public static function validate_settings( $parent ) {
|
||||
// restore escaped characters (see wp_magic_quotes() in wp-includes/load.php)
|
||||
$json = json_decode(
|
||||
str_replace(
|
||||
array( '\\"', '\\\\', "\'" ),
|
||||
array( '"', '\\', "'" ),
|
||||
isset( $_POST['data'] ) ? $_POST['data'] : ''
|
||||
), TRUE
|
||||
);
|
||||
|
||||
if ( NULL === $json )
|
||||
wp_die( 'Illegal JSON format.', '', array( 'response' => 500, 'back_link' => TRUE ) ); // @Since 2.0.4
|
||||
|
||||
// Convert json to setting data
|
||||
$input = self::json_to_settings( $json );
|
||||
|
||||
// Integrate posted data into current settings because if can be a part of hole data
|
||||
$input = $parent->array_replace_recursive(
|
||||
$parent->preprocess_options( IP_Geo_Block::get_option(), IP_Geo_Block::get_default() ), $input
|
||||
);
|
||||
|
||||
// Validate options and convert to json
|
||||
$output = $parent->sanitize_options( $input );
|
||||
$json = self::json_unsafe_encode( self::settings_to_json( $output ) );
|
||||
|
||||
mbstring_binary_safe_encoding(); // @since 3.7.0
|
||||
$length = strlen( $json );
|
||||
reset_mbstring_encoding(); // @since 3.7.0
|
||||
|
||||
// Send json as file
|
||||
header( 'Content-Description: File Transfer' );
|
||||
header( 'Content-Type: application/octet-stream' );
|
||||
header( 'Content-Disposition: attachment; filename="' . IP_Geo_Block::PLUGIN_NAME . '-settings.json"' );
|
||||
header( 'Pragma: public' );
|
||||
header( 'Expires: 0' );
|
||||
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
|
||||
header( 'Content-Length: ' . $length );
|
||||
echo $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert json associative array to settings array
|
||||
*
|
||||
*/
|
||||
private static function json_to_settings( $input ) {
|
||||
$settings = $m = array();
|
||||
$prfx = IP_Geo_Block::OPTION_NAME;
|
||||
|
||||
try {
|
||||
foreach ( $input as $key => $val ) {
|
||||
if ( preg_match( "/${prfx}\[(.+?)\](?:\[(.+?)\](?:\[(.+?)\])?)?/", $key, $m ) ) {
|
||||
switch ( count( $m ) ) {
|
||||
case 2:
|
||||
$settings[ $m[1] ] = $val;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$settings[ $m[1] ][ $m[2] ] = $val;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ( is_numeric( $m[3] ) ) {
|
||||
if ( empty( $settings[ $m[1] ][ $m[2] ] ) )
|
||||
$settings[ $m[1] ][ $m[2] ] = 0;
|
||||
$settings[ $m[1] ][ $m[2] ] |= $val;
|
||||
} else { // [*]:checkbox
|
||||
$settings[ $m[1] ][ $m[2] ][ $m[3] ] = $val;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch ( Exception $e ) { // should be returned as ajax response
|
||||
wp_die( sprintf( __( 'illegal format at %s. Please delete the corresponding line and try again.', 'ip-geo-block' ), print_r( @$m[0], TRUE ) ) );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert settings array to json associative array
|
||||
*
|
||||
*/
|
||||
public static function settings_to_json( $input, $overwrite = TRUE ) {
|
||||
// [*]:list of checkboxes, [$]:comma separated text to array, [%]:associative array
|
||||
$keys = array(
|
||||
'[version]',
|
||||
'[matching_rule]',
|
||||
'[white_list]',
|
||||
'[black_list]',
|
||||
'[extra_ips][white_list]',
|
||||
'[extra_ips][black_list]',
|
||||
'[anonymize]',
|
||||
'[restrict_api]', // 3.0.13
|
||||
'[simulate]', // 3.0.14
|
||||
'[signature]',
|
||||
'[login_fails]',
|
||||
'[response_code]',
|
||||
'[response_msg]', // 3.0.0
|
||||
'[redirect_uri]', // 3.0.0
|
||||
'[validation][timing]', // 2.2.9
|
||||
'[validation][proxy]',
|
||||
'[validation][comment]',
|
||||
'[validation][xmlrpc]',
|
||||
'[validation][login]',
|
||||
'[login_action][login]', // 2.2.8
|
||||
'[login_action][register]', // 2.2.8
|
||||
'[login_action][resetpass]', // 2.2.8
|
||||
'[login_action][lostpassword]', // 2.2.8
|
||||
'[login_action][postpass]', // 2.2.8
|
||||
'[validation][admin][1]',
|
||||
'[validation][admin][2]',
|
||||
'[validation][ajax][1]',
|
||||
'[validation][ajax][2]',
|
||||
'[validation][plugins]',
|
||||
'[validation][themes]',
|
||||
'[validation][includes]', // 3.0.0
|
||||
'[validation][uploads]', // 3.0.0
|
||||
'[validation][languages]', // 3.0.0
|
||||
'[validation][public]', // 3.0.0
|
||||
'[validation][restapi]', // 3.0.3
|
||||
'[validation][mimetype]', // 3.0.3
|
||||
'[rewrite][plugins]',
|
||||
'[rewrite][themes]',
|
||||
'[rewrite][includes]', // 3.0.0
|
||||
'[rewrite][uploads]', // 3.0.0
|
||||
'[rewrite][languages]', // 3.0.0
|
||||
'[exception][plugins][*]', // 2.2.5
|
||||
'[exception][themes][*]', // 2.2.5
|
||||
'[exception][admin][$]', // 3.0.0
|
||||
'[exception][public][$]', // 3.0.0
|
||||
'[exception][includes][$]', // 3.0.0
|
||||
'[exception][uploads][$]', // 3.0.0
|
||||
'[exception][languages][$]', // 3.0.0
|
||||
'[exception][restapi][$]', // 3.0.3
|
||||
'[public][matching_rule]', // 3.0.0
|
||||
'[public][white_list]', // 3.0.0
|
||||
'[public][black_list]', // 3.0.0
|
||||
'[public][target_rule]', // 3.0.0
|
||||
'[public][target_pages][$]', // 3.0.0
|
||||
'[public][target_posts][$]', // 3.0.0
|
||||
'[public][target_cates][$]', // 3.0.0
|
||||
'[public][target_tags][$]', // 3.0.0
|
||||
'[public][ua_list]', // 3.0.0
|
||||
'[public][dnslkup]', // 3.0.3
|
||||
'[public][response_code]', // 3.0.3
|
||||
'[public][response_msg]', // 3.0.3
|
||||
'[public][redirect_uri]', // 3.0.3
|
||||
'[public][behavior]', // 3.0.10
|
||||
'[behavior][time]', // 3.0.10
|
||||
'[behavior][view]', // 3.0.10
|
||||
'[save_statistics]',
|
||||
'[validation][recdays]', // 2.2.9
|
||||
'[validation][reclogs]',
|
||||
'[validation][maxlogs]',
|
||||
'[validation][explogs]', // 3.0.12
|
||||
'[validation][postkey]',
|
||||
'[update][auto]',
|
||||
'[cache_time_gc]', // 3.0.0
|
||||
'[cache_hold]',
|
||||
'[cache_time]',
|
||||
'[comment][pos]',
|
||||
'[comment][msg]',
|
||||
'[clean_uninstall]',
|
||||
'[api_key][GoogleMap]', // 2.2.7
|
||||
'[network_wide]', // 3.0.0
|
||||
'[mimetype][white_list][%]', // 3.0.3
|
||||
'[mimetype][black_list]', // 3.0.3
|
||||
'[mimetype][capability][$]', // 3.0.4
|
||||
'[Maxmind][use_asn]', // 3.0.4
|
||||
'[live_update][in_memory]', // 3.0.5
|
||||
'[monitor][updated_option]', // 3.0.18
|
||||
'[monitor][update_site_option]', // 3.0.18
|
||||
'[metadata][pre_update_option][$]', // 3.0.17
|
||||
'[metadata][pre_update_site_option][$]', // 3.0.17
|
||||
);
|
||||
$json = array();
|
||||
$prfx = IP_Geo_Block::OPTION_NAME;
|
||||
|
||||
// add providers
|
||||
foreach ( array_keys( IP_Geo_Block_Provider::get_providers( 'key' ) ) as $key ) {
|
||||
$keys[] = '[providers][' . $key . ']';
|
||||
}
|
||||
|
||||
foreach ( $keys as $key ) {
|
||||
if ( preg_match( "/\[(.+?)\](?:\[(.+?)\](?:\[(.+?)\])?)?/", $key, $m ) ) {
|
||||
switch ( count( $m ) ) {
|
||||
case 2:
|
||||
if ( isset( $input[ $m[1] ] ) ) {
|
||||
$json[ $prfx.'['.$m[1].']' ] = strval( $input[ $m[1] ] );
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if ( '%' === $m[2] ) { // [%]:associative array
|
||||
foreach ( isset( $input[ $m[1] ] ) ? $input[ $m[1] ] : array() as $key => $val ) {
|
||||
$json[ $prfx.'['.$m[1].']['.$key.']' ] = $val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ( isset( $input[ $m[1] ][ $m[2] ] ) || $overwrite ) {
|
||||
$json[ $prfx.'['.$m[1].']['.$m[2].']' ] = (
|
||||
isset( $input[ $m[1] ][ $m[2] ] ) &&
|
||||
'@' !== $input[ $m[1] ][ $m[2] ] ?
|
||||
strval( $input[ $m[1] ][ $m[2] ] ) : ''
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if ( is_numeric( $m[3] ) ) {
|
||||
if ( isset( $input[ $m[1] ][ $m[2] ] ) )
|
||||
$json[ $prfx.'['.$m[1].']['.$m[2].']'.'['.$m[3].']' ] =
|
||||
strval( $input[ $m[1] ][ $m[2] ] ) & (int)$m[3];
|
||||
}
|
||||
elseif ( isset( $input[ $m[1] ][ $m[2] ] ) ) {
|
||||
if ( '*' === $m[3] ) { // [*]:checkbox
|
||||
foreach ( $input[ $m[1] ][ $m[2] ] as $val ) {
|
||||
$json[ $prfx.'['.$m[1].']['.$m[2].']'.'['.$val.']' ] = '1';
|
||||
}
|
||||
} elseif ( '%' === $m[3] ) { // [%]:associative array
|
||||
foreach ( $input[ $m[1] ][ $m[2] ] as $key => $val ) {
|
||||
$json[ $prfx.'['.$m[1].']['.$m[2].']'.'['.$key.']' ] = $val;
|
||||
}
|
||||
} elseif ( is_array( $input[ $m[1] ][ $m[2] ] ) ) { // [$]:comma separated text to array
|
||||
$json[ $prfx.'['.$m[1].']['.$m[2].']' ] = implode( ',', $input[ $m[1] ][ $m[2] ] );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make preferred settings with formatted json
|
||||
*
|
||||
*/
|
||||
public static function preferred_to_json() {
|
||||
return self::settings_to_json(
|
||||
array(
|
||||
'login_fails' => 10, // Limited number of login attempts
|
||||
'validation' => array( // Action hook for validation
|
||||
'comment' => TRUE, // Validate on comment post
|
||||
'login' => 1, // Validate on login
|
||||
'admin' => 3, // Validate on admin (1:country 2:ZEP)
|
||||
'ajax' => 3, // Validate on ajax/post (1:country 2:ZEP)
|
||||
'xmlrpc' => 1, // Validate on xmlrpc (1:country 2:close)
|
||||
'postkey' => 'action,comment,log,pwd,FILES', // Keys in $_POST and $_FILES
|
||||
'plugins' => 2, // Validate on wp-content/plugins
|
||||
'themes' => 2, // Validate on wp-content/themes
|
||||
'timing' => 1, // 0:init, 1:mu-plugins, 2:drop-in
|
||||
'mimetype' => 1, // 0:disable, 1:white_list, 2:black_list
|
||||
),
|
||||
'signature' => "../,/wp-config.php,/passwd\ncurl,wget,eval,base64\nselect:.5,where:.5,union:.5\nload_file:.5,create:.6,password:.4",
|
||||
'rewrite' => array( // Apply rewrite rule
|
||||
'plugins' => TRUE, // for wp-content/plugins
|
||||
'themes' => TRUE, // for wp-content/themes
|
||||
),
|
||||
),
|
||||
FALSE // should not overwrite the existing parameters
|
||||
);
|
||||
}
|
||||
|
||||
// Encode json without JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT
|
||||
// Note: It should not be rendered via jQuery .html() at client side
|
||||
private static function json_unsafe_encode( $data ) {
|
||||
if ( version_compare( PHP_VERSION, '5.4', '>=' ) ) {
|
||||
$opts = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
|
||||
if ( function_exists( 'wp_json_encode' ) ) // @since 4.1.0
|
||||
$json = wp_json_encode( $data, $opts );
|
||||
else
|
||||
$json = json_encode( $data, $opts );
|
||||
}
|
||||
|
||||
else { // JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES are not supported in PHP 5.3 and under
|
||||
$json = self::json_unescaped_unicode( $data );
|
||||
$json = preg_replace(
|
||||
array( '!{"!', '!":!', '!("?),"!', '!"}!', '!\\\\/!' ),
|
||||
array( '{'.PHP_EOL.' "', '": ', '$1,'.PHP_EOL.' "', '"'.PHP_EOL.'}', '/' ),
|
||||
$json
|
||||
);
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
// Fallback function for PHP 5.3 and under
|
||||
// @link https://qiita.com/keromichan16/items/5ff45a77fb0d48e046cc
|
||||
// @link https://stackoverflow.com/questions/16498286/why-does-the-php-json-encode-function-convert-utf-8-strings-to-hexadecimal-entit/
|
||||
private static function json_unescaped_unicode( $input ) {
|
||||
return preg_replace_callback(
|
||||
'/(?:\\\\u[0-9a-zA-Z]{4})++/',
|
||||
array( __CLASS__, 'convert_encoding' ),
|
||||
json_encode( $input )
|
||||
);
|
||||
}
|
||||
|
||||
// Fallback function for PHP 5.3 and under
|
||||
private static function convert_encoding( $matches ) {
|
||||
return mb_convert_encoding(
|
||||
pack( 'H*', str_replace( '\\u', '', $matches[0] ) ), 'UTF-8', 'UTF-16'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blocked action and pages
|
||||
*
|
||||
* @param string $which 'page', 'action', 'plugin', 'theme'
|
||||
* @return array of the name of action/page, plugin or theme
|
||||
*/
|
||||
private static function get_blocked_queries( $which ) {
|
||||
$result = array();
|
||||
|
||||
switch ( $which ) {
|
||||
case 'page':
|
||||
case 'action':
|
||||
$dir = IP_Geo_Block_Util::slashit( str_replace( site_url(), '', admin_url() ) ); /* `/wp-admin/` */
|
||||
|
||||
foreach ( IP_Geo_Block_Logs::search_blocked_logs( 'method', $dir ) as $log ) {
|
||||
foreach ( array( 'method', 'data' ) as $key ) {
|
||||
if ( preg_match( '!' . $which . '=([\-\w]+)!', $log[ $key ], $matches ) ) {
|
||||
$result += array( $matches[1] => $which );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'plugins':
|
||||
case 'themes':
|
||||
// make a list of installed plugins/themes
|
||||
if ( 'plugins' === $which ) {
|
||||
$key = array();
|
||||
foreach ( get_plugins() as $pat => $log ) {
|
||||
$pat = explode( '/', $pat, 2 );
|
||||
$key[] = $pat[0];
|
||||
}
|
||||
} else {
|
||||
$key = wp_get_themes();
|
||||
}
|
||||
|
||||
$dir = 'plugins' === $which ? plugins_url() : get_theme_root_uri();
|
||||
$dir = IP_Geo_Block_Util::slashit( str_replace( site_url(), '', $dir ) );
|
||||
$pat = preg_quote( $dir, '!' ); /* `/wp-content/(plugins|themes)/` */
|
||||
|
||||
foreach ( IP_Geo_Block_Logs::search_blocked_logs( 'method', $dir ) as $log ) {
|
||||
if ( preg_match( '!' . $pat . '(.+?)/!', $log['method'], $matches ) && in_array( $matches[1], $key, TRUE ) ) {
|
||||
$result += array( $matches[1] => $which );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get slug in blocked requests for exceptions
|
||||
*
|
||||
*/
|
||||
public static function find_exceptions( $target ) {
|
||||
switch ( $target ) {
|
||||
case 'find-admin':
|
||||
$res = array();
|
||||
foreach ( array( 'action', 'page' ) as $which ) {
|
||||
$res += self::get_blocked_queries( $which );
|
||||
}
|
||||
return $res;
|
||||
|
||||
case 'find-plugins':
|
||||
return self::get_blocked_queries( 'plugins' );
|
||||
|
||||
case 'find-themes':
|
||||
return self::get_blocked_queries( 'themes' );
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get debug information related to WordPress
|
||||
*
|
||||
*/
|
||||
public static function get_wp_info() {
|
||||
require_once IP_GEO_BLOCK_PATH . 'classes/class-ip-geo-block-lkup.php';
|
||||
require_once IP_GEO_BLOCK_PATH . 'classes/class-ip-geo-block-file.php';
|
||||
$fs = IP_Geo_Block_FS::init( __FUNCTION__ );
|
||||
|
||||
// DNS reverse lookup
|
||||
$key = microtime( TRUE );
|
||||
$val = IP_Geo_Block_Lkup::gethostbyaddr( '8.8.8.8' );
|
||||
$key = microtime( TRUE ) - $key;
|
||||
|
||||
// MySQL (supress WordPress error: Unknown system variable 'block_encryption_mode')
|
||||
$buf = @ini_set( 'output_buffering', 0 );
|
||||
$dsp = @ini_set( 'display_errors', 0 );
|
||||
$log = @ini_set( 'error_log', '/' . 'dev' . '/' . 'null' );
|
||||
$err = @error_reporting( 0 );
|
||||
$ver = $GLOBALS['wpdb']->get_var( 'SELECT @@GLOBAL.version' );
|
||||
$bem = $GLOBALS['wpdb']->get_var( 'SELECT @@GLOBAL.block_encryption_mode' ); // `aes-128-ecb` @since MySQL 5.6.17
|
||||
@ini_set( 'output_buffering', $buf );
|
||||
@ini_set( 'display_errors', $dsp );
|
||||
@ini_set( 'error_log', $log );
|
||||
@error_reporting( $err );
|
||||
|
||||
// Human readable size, Proces owner
|
||||
// https://gist.github.com/mehdichaouch/341a151dd5f469002a021c9396aa2615
|
||||
// https://secure.php.net/manual/function.get-current-user.php#57624
|
||||
// https://secure.php.net/manual/function.posix-getpwuid.php#82387
|
||||
$siz = array( 'B', 'K', 'M', 'G', 'T', 'P' );
|
||||
$usr = function_exists( 'posix_getpwuid' ) ? posix_getpwuid( posix_geteuid() ) : array( 'name' => getenv( 'USERNAME' ) );
|
||||
|
||||
// Server, PHP, WordPress
|
||||
$res = array_map( 'esc_html', array(
|
||||
'Server:' => $_SERVER['SERVER_SOFTWARE'],
|
||||
'MySQL:' => $ver . ( defined( 'IP_GEO_BLOCK_DEBUG' ) && IP_GEO_BLOCK_DEBUG && $bem ? ' (' . $bem . ')' : '' ),
|
||||
'PHP:' => PHP_VERSION,
|
||||
'PHP SAPI:' => php_sapi_name(),
|
||||
'Memory limit:' => ini_get( 'memory_limit' ),
|
||||
'Peak usage:' => @round( ( $m = memory_get_peak_usage() ) / pow( 1024, ( $i = floor( log( $m, 1024 ) ) ) ), 2 ) . $siz[ $i ],
|
||||
'WordPress:' => $GLOBALS['wp_version'],
|
||||
'Multisite:' => is_multisite() ? 'yes' : 'no',
|
||||
'File system:' => $fs->get_method(),
|
||||
'Temp folder:' => get_temp_dir(),
|
||||
'Process owner:' => $usr['name'],
|
||||
'File owner:' => get_current_user(), // Gets the name of the owner of the current PHP script
|
||||
'Umask:' => sprintf( '%o', umask() ^ 511 /* 0777 */ ),
|
||||
'Zlib:' => function_exists( 'gzopen' ) ? 'yes' : 'no',
|
||||
'ZipArchive:' => class_exists( 'ZipArchive', FALSE ) ? 'yes' : 'no',
|
||||
'PECL phar:' => class_exists( 'PharData', FALSE ) ? 'yes' : 'no',
|
||||
'BC Math:' => (extension_loaded('gmp') ? 'gmp ' : '') . (function_exists('bcadd') ? 'yes' : 'no'),
|
||||
'mb_strcut:' => function_exists( 'mb_strcut' ) ? 'yes' : 'no', // @since PHP 4.0.6
|
||||
'OpenSSL:' => defined( 'OPENSSL_RAW_DATA' ) ? 'yes' : 'no', // @since PHP 5.3.3
|
||||
'SQLite(PDO):' => extension_loaded( 'pdo_sqlite' ) ? 'yes' : 'no',
|
||||
'DNS lookup:' => ('8.8.8.8' !== $val ? 'available' : 'n/a') . sprintf( ' [%.1f msec]', $key * 1000.0 ),
|
||||
'User agent:' => $_SERVER['HTTP_USER_AGENT'],
|
||||
) );
|
||||
|
||||
// Child and parent themes
|
||||
$activated = wp_get_theme(); // @since 3.4.0
|
||||
$res += array( esc_html( $activated->get( 'Name' ) ) => esc_html( $activated->get( 'Version' ) ) );
|
||||
|
||||
if ( $installed = $activated->get( 'Template' ) ) {
|
||||
$activated = wp_get_theme( $installed );
|
||||
$res += array( esc_html( $activated->get( 'Name' ) ) => esc_html( $activated->get( 'Version' ) ) );
|
||||
}
|
||||
|
||||
// Plugins
|
||||
$installed = get_plugins(); // @since 1.5.0
|
||||
$activated = get_site_option( 'active_sitewide_plugins' ); // @since 2.8.0
|
||||
! is_array( $activated ) and $activated = array();
|
||||
$activated = array_merge( $activated, array_fill_keys( get_option( 'active_plugins' ), TRUE ) );
|
||||
|
||||
foreach ( $installed as $key => $val ) {
|
||||
if ( isset( $activated[ $key ] ) ) {
|
||||
$res += array( esc_html( $val['Name'] ) => esc_html( $val['Version'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Blocked self requests
|
||||
$installed = array_reverse( IP_Geo_Block_Logs::search_logs( IP_Geo_Block::get_ip_address(), IP_Geo_Block::get_option() ) );
|
||||
foreach ( $installed as $val ) {
|
||||
if ( IP_Geo_Block::is_blocked( $val['result'] ) ) {
|
||||
// hide port and nonce
|
||||
$method = preg_replace( '/\[\d+\]/', '', $val['method'] );
|
||||
$method = preg_replace( '/(' . IP_Geo_Block::get_auth_key() . ')(?:=|%3D)([\w]+)/', '$1=...', $method );
|
||||
|
||||
// add post data
|
||||
$query = array();
|
||||
foreach ( explode( ',', $val['data'] ) as $str ) {
|
||||
FALSE !== strpos( $str, '=' ) and $query[] = $str;
|
||||
}
|
||||
|
||||
if ( ! empty( $query ) )
|
||||
$method .= '(' . implode( ',', $query ) . ')';
|
||||
|
||||
$res += array(
|
||||
esc_html( IP_Geo_Block_Util::localdate( $val['time'], 'Y-m-d H:i:s' ) ) =>
|
||||
esc_html( str_pad( $val['result'], 8 ) . $method )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,470 @@
|
||||
<?php
|
||||
class IP_Geo_Block_Admin_Rewrite {
|
||||
|
||||
/**
|
||||
* Instance of this class.
|
||||
*/
|
||||
private static $instance = NULL;
|
||||
|
||||
// private values
|
||||
private $doc_root = NULL; // document root
|
||||
private $base_uri = NULL; // plugins base uri
|
||||
private $config_file = NULL; // `.htaccess` or `.user.ini`
|
||||
private $wp_dirs = array(); // path to `plugins` and `themes` from document root
|
||||
|
||||
// template of rewrite rule in wp-content/(plugins|themes)/
|
||||
private $rewrite_rule = array(
|
||||
'.htaccess' => array(
|
||||
'plugins' => array(
|
||||
'# BEGIN IP Geo Block',
|
||||
'<IfModule mod_rewrite.c>',
|
||||
'RewriteEngine on',
|
||||
'RewriteBase %REWRITE_BASE%',
|
||||
'RewriteCond %{REQUEST_URI} !ip-geo-block/rewrite.php$',
|
||||
'RewriteRule ^.*\.php$ rewrite.php [L]',
|
||||
'</IfModule>',
|
||||
'# END IP Geo Block',
|
||||
),
|
||||
'themes' => array(
|
||||
'# BEGIN IP Geo Block',
|
||||
'<IfModule mod_rewrite.c>',
|
||||
'RewriteEngine on',
|
||||
'RewriteBase %REWRITE_BASE%',
|
||||
'RewriteRule ^.*\.php$ rewrite.php [L]',
|
||||
'</IfModule>',
|
||||
'# END IP Geo Block',
|
||||
),
|
||||
),
|
||||
'.user.ini' => array(
|
||||
'plugins' => array(
|
||||
'; BEGIN IP Geo Block%ADDITIONAL%',
|
||||
'auto_prepend_file = "%IP_GEO_BLOCK_PATH%rewrite-ini.php"',
|
||||
'; END IP Geo Block',
|
||||
),
|
||||
'themes' => array(
|
||||
'; BEGIN IP Geo Block%ADDITIONAL%',
|
||||
'auto_prepend_file = "%IP_GEO_BLOCK_PATH%rewrite-ini.php"',
|
||||
'; END IP Geo Block',
|
||||
),
|
||||
),
|
||||
// https://www.wordfence.com/blog/2014/05/nginx-wordfence-falcon-engine-php-fpm-fastcgi-fast-cgi/
|
||||
// 'nginx' => array(
|
||||
// 'plugins' => array(
|
||||
// '# BEGIN IP Geo Block',
|
||||
// 'location ~ %REWRITE_BASE%rewrite.php$ {}',
|
||||
// 'location %WP_CONTENT_DIR%/plugins/ {',
|
||||
// ' rewrite ^%WP_CONTENT_DIR%/plugins/.*\.php$ %REWRITE_BASE%rewrite.php break;',
|
||||
// '}',
|
||||
// '# END IP Geo Block',
|
||||
// 'themes' => array(
|
||||
// '# BEGIN IP Geo Block',
|
||||
// 'location %WP_CONTENT_DIR%/themes/ {',
|
||||
// ' rewrite ^%WP_CONTENT_DIR%/themes/.*\.php$ %REWRITE_BASE%rewrite.php break;',
|
||||
// '}',
|
||||
// '# END IP Geo Block',
|
||||
// ),
|
||||
// ),
|
||||
);
|
||||
|
||||
private function __construct() {
|
||||
// https://stackoverflow.com/questions/25017381/setting-php-document-root-on-webserver
|
||||
$this->doc_root = str_replace( DIRECTORY_SEPARATOR, '/', str_replace( $_SERVER['SCRIPT_NAME'], '', $_SERVER['SCRIPT_FILENAME'] ) );
|
||||
$this->base_uri = str_replace( $this->doc_root, '', str_replace( DIRECTORY_SEPARATOR, '/', IP_GEO_BLOCK_PATH ) );
|
||||
|
||||
// target directories (WP_CONTENT_DIR can be defined in wp-config.php as an aliased or symbolic linked path)
|
||||
$path = str_replace( $this->doc_root, '', str_replace( DIRECTORY_SEPARATOR, '/', realpath( WP_CONTENT_DIR ) ) );
|
||||
$this->wp_dirs = array(
|
||||
'plugins' => $path . '/plugins/',
|
||||
'themes' => $path . '/themes/',
|
||||
);
|
||||
|
||||
// Apache in wp-includes/vars.php
|
||||
global $is_apache;
|
||||
if ( ! empty( $is_apache ) )
|
||||
$this->config_file = '.htaccess';
|
||||
|
||||
// CGI/FastCGI SAPI (cgi, cgi-fcgi, fpm-fcgi)
|
||||
elseif ( version_compare( PHP_VERSION, '5.3' ) >= 0 && FALSE !== strpos( php_sapi_name(), 'cgi' ) )
|
||||
$this->config_file = ini_get( 'user_ini.filename' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of this class.
|
||||
*
|
||||
*/
|
||||
private static function get_instance() {
|
||||
return self::$instance ? self::$instance : ( self::$instance = new self );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove empty element from the array
|
||||
*
|
||||
* @param array contents of configuration file
|
||||
* @return array updated array of contents
|
||||
*/
|
||||
private function remove_empty( $content ) {
|
||||
while ( FALSE !== ( $tmp = reset( $content ) ) ) {
|
||||
if ( strlen( trim( $tmp ) ) ) {
|
||||
break;
|
||||
} else {
|
||||
array_shift( $content );
|
||||
}
|
||||
}
|
||||
|
||||
while ( FALSE !== ( $tmp = end( $content ) ) ) {
|
||||
if ( strlen( trim( $tmp ) ) ) {
|
||||
break;
|
||||
} else {
|
||||
array_pop( $content );
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the block of rewrite rule
|
||||
*
|
||||
* @param array contents of configuration file
|
||||
* @return array list of begin and end
|
||||
*/
|
||||
private function find_rewrite_block( $content ) {
|
||||
return preg_grep(
|
||||
'/^\s*?[#;]\s*?(?:BEGIN|END)\s*?IP Geo Block\s*?$/i', (array)$content
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path of .htaccess in wp-content/plugins/themes/
|
||||
*
|
||||
* @param string 'plugins' or 'themes'
|
||||
* @return string absolute path to the .htaccess or NULL
|
||||
*/
|
||||
private function get_rewrite_file( $which ) {
|
||||
if ( $this->config_file )
|
||||
return $this->doc_root . $this->wp_dirs[ $which ] . $this->config_file;
|
||||
else
|
||||
return NULL; /* NOT SUPPORTED */
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contents in .htaccess in wp-content/(plugins|themes)/
|
||||
*
|
||||
* @param string 'plugins' or 'themes'
|
||||
* @return array contents of configuration file or WP_Error
|
||||
*/
|
||||
private function get_rewrite_rule( $which ) {
|
||||
require_once IP_GEO_BLOCK_PATH . 'classes/class-ip-geo-block-file.php';
|
||||
$fs = IP_Geo_Block_FS::init( __FUNCTION__ );
|
||||
|
||||
// check the existence of configuration file
|
||||
$file = $this->get_rewrite_file( $which );
|
||||
$exist = $file ? $fs->exists( $file ) : FALSE;
|
||||
|
||||
// check permission
|
||||
if ( $exist ) {
|
||||
if ( ! $fs->is_readable( $file ) ) {
|
||||
return new WP_Error( 'Error',
|
||||
sprintf( __( 'Unable to read <code>%s</code>. Please check the permission.', 'ip-geo-block' ), $file ) . ' ' .
|
||||
sprintf( __( 'Or please refer to %s to set it manually.', 'ip-geo-block' ), '<a href="https://www.ipgeoblock.com/codex/how-to-fix-permission-troubles.html" title="How to fix permission troubles? | IP Geo Block">How to fix permission troubles?</a>' )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// get file contents as an array
|
||||
$exist = $fs->get_contents_array( $file );
|
||||
return FALSE !== $exist ? $exist : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Put contents to .htaccess in wp-content/(plugins|themes)/
|
||||
*
|
||||
* @param string $which 'plugins' or 'themes'
|
||||
* @param array contents of configuration file
|
||||
* @return bool TRUE (success) or FALSE (failure)
|
||||
*/
|
||||
private function put_rewrite_rule( $which, $content ) {
|
||||
require_once IP_GEO_BLOCK_PATH . 'classes/class-ip-geo-block-file.php';
|
||||
$fs = IP_Geo_Block_FS::init( __FUNCTION__ );
|
||||
|
||||
$file = $this->get_rewrite_file( $which );
|
||||
|
||||
if ( ! $file || FALSE === $fs->put_contents( $file, implode( PHP_EOL, $content ) ) ) {
|
||||
$this->show_message(
|
||||
sprintf( __( 'Unable to write <code>%s</code>. Please check the permission.', 'ip-geo-block' ), $file ) . ' ' .
|
||||
sprintf( __( 'Or please refer to %s to set it manually.', 'ip-geo-block' ), '<a href="https://www.ipgeoblock.com/codex/how-to-fix-permission-troubles.html" title="How to fix permission troubles? | IP Geo Block">How to fix permission troubles?</a>' )
|
||||
);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// if content is empty then remove file
|
||||
$content = $this->remove_empty( $content );
|
||||
return empty( $content ) ? $fs->delete( $file ) : TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the block of rewrite rule exists
|
||||
*
|
||||
* @param string 'plugins' or 'themes'
|
||||
* @return bool TRUE (found), FALSE (not found or unavailable) or WP_Error
|
||||
*/
|
||||
private function get_rewrite_stat( $which ) {
|
||||
if ( $this->config_file ) {
|
||||
$content = $this->get_rewrite_rule( $which );
|
||||
|
||||
if ( is_wp_error( $content ) )
|
||||
return $content;
|
||||
|
||||
$block = $this->find_rewrite_block( $content );
|
||||
|
||||
if ( '.htaccess' === $this->config_file ) {
|
||||
return empty( $block ) ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
else {
|
||||
if ( empty( $block ) ) {
|
||||
$block = preg_grep( '/auto_prepend_file/i', $content );
|
||||
|
||||
if ( empty( $block ) ) {
|
||||
return FALSE; // rewrite rule is not found in configuration file
|
||||
}
|
||||
|
||||
else {
|
||||
return new WP_Error( 'Error', sprintf(
|
||||
__( '“auto_prepend_file” already defined in %s.', 'ip-geo-block' ),
|
||||
$this->get_rewrite_file( $which )
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
return TRUE; // rewrite rule already exists in configuration file
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1; /* NOT SUPPORTED */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the block of rewrite rule
|
||||
*
|
||||
* @param array contents of configuration file
|
||||
* @param array contents to be removed
|
||||
* @return array array of contents without rewrite rule
|
||||
*/
|
||||
private function remove_rewrite_block( $content, $block ) {
|
||||
$block = array_reverse( $block, TRUE );
|
||||
|
||||
reset( $block );
|
||||
while( FALSE !== current( $block ) ) {
|
||||
$key_end = key( $block ); $val_end = current( $block ); next( $block );
|
||||
$key_begin = key( $block ); $val_begin = current( $block ); next( $block );
|
||||
if ( NULL !== $key_end && NULL !== $key_begin ) {
|
||||
array_splice( $content, $key_begin, $key_end - $key_begin + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the block of rewrite rule
|
||||
*
|
||||
* @param string 'plugins' or 'themes'
|
||||
* @param array contents of configuration file
|
||||
* @return array array of contents with the block of rewrite rule
|
||||
*/
|
||||
private function append_rewrite_block( $which, $content ) {
|
||||
if ( $type = $this->config_file ) {
|
||||
// in case that `.user.ini` is configured differently
|
||||
if ( '.htaccess' !== $type && '.user.ini' !== $type )
|
||||
$type = '.user.ini';
|
||||
|
||||
// in case that another `.user.ini` in ascendant directory
|
||||
$additional = '';
|
||||
if ( '.user.ini' === $type ) {
|
||||
require_once IP_GEO_BLOCK_PATH . 'classes/class-ip-geo-block-file.php';
|
||||
$fs = IP_Geo_Block_FS::init( __FUNCTION__ );
|
||||
|
||||
$dir = dirname( IP_GEO_BLOCK_PATH ); // `/wp-content/plugins`
|
||||
$ini = $this->config_file;
|
||||
$doc = $this->doc_root;
|
||||
|
||||
do {
|
||||
// avoid loop just in case
|
||||
if ( ( $next = dirname( $dir ) ) !== $dir )
|
||||
$dir = $next;
|
||||
else
|
||||
break;
|
||||
|
||||
if ( $fs->exists( "$dir/$ini" ) ) {
|
||||
$tmp = $fs->get_contents_array( "$dir/$ini" );
|
||||
$tmp = preg_replace( '/^\s*(auto_prepend_file.*)$/', '; $1', $tmp );
|
||||
$tmp = $this->remove_empty( $tmp );
|
||||
|
||||
if ( ! empty( $tmp ) )
|
||||
$additional = PHP_EOL . PHP_EOL . implode( PHP_EOL, $tmp ) . PHP_EOL;
|
||||
|
||||
break;
|
||||
}
|
||||
} while ( $dir !== $doc );
|
||||
}
|
||||
|
||||
return array_merge(
|
||||
$content,
|
||||
str_replace(
|
||||
array( '%REWRITE_BASE%', '%WP_CONTENT_DIR%', '%IP_GEO_BLOCK_PATH%', '%ADDITIONAL%' ),
|
||||
array( $this->base_uri, WP_CONTENT_DIR, IP_GEO_BLOCK_PATH, $additional ),
|
||||
$this->rewrite_rule[ $type ][ $which ]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add rewrite rule to server configration
|
||||
*
|
||||
* @param string 'plugins' or 'themes'
|
||||
* @return bool TRUE (found), FALSE (not found or unavailable)
|
||||
*/
|
||||
private function add_rewrite_rule( $which ) {
|
||||
$stat = $this->get_rewrite_stat( $which );
|
||||
|
||||
if ( is_wp_error( $stat ) ) {
|
||||
$this->show_message( $stat->get_error_message() );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
elseif ( TRUE === $stat ) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
elseif ( FALSE === $stat ) {
|
||||
$content = $this->get_rewrite_rule( $which );
|
||||
|
||||
if ( is_wp_error( $content ) ) {
|
||||
$this->show_message( $content->get_error_message() );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$content = $this->append_rewrite_block( $which, $content );
|
||||
return $this->put_rewrite_rule( $which, $content );
|
||||
}
|
||||
|
||||
return -1; /* NOT SUPPORTED */
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete rewrite rule to server configration
|
||||
*
|
||||
* @param string 'plugins' or 'themes'
|
||||
* @return bool TRUE (found), FALSE (not found or unavailable)
|
||||
*/
|
||||
private function del_rewrite_rule( $which ) {
|
||||
$stat = $this->get_rewrite_stat( $which );
|
||||
|
||||
if ( is_wp_error( $stat ) ) {
|
||||
$this->show_message( $stat->get_error_message() );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
elseif ( FALSE === $stat ) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
elseif ( TRUE === $stat ) {
|
||||
$content = $this->get_rewrite_rule( $which );
|
||||
|
||||
if ( is_wp_error( $content ) ) {
|
||||
$this->show_message( $content->get_error_message() );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$block = $this->find_rewrite_block( $content );
|
||||
$content = $this->remove_rewrite_block( $content, $block );
|
||||
return $this->put_rewrite_rule( $which, $content );
|
||||
}
|
||||
|
||||
return -1; /* NOT SUPPORTED */
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notice message
|
||||
*
|
||||
*/
|
||||
private function show_message( $msg ) {
|
||||
if ( class_exists( 'IP_Geo_Block_Admin', FALSE ) )
|
||||
IP_Geo_Block_Admin::add_admin_notice( 'error', $msg );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check rewrite rules
|
||||
*
|
||||
*/
|
||||
public static function check_rewrite_all() {
|
||||
$rewrite = self::get_instance();
|
||||
|
||||
$status = array();
|
||||
foreach ( array_keys( $rewrite->rewrite_rule['.htaccess'] ) as $key ) {
|
||||
$stat = $rewrite->get_rewrite_stat( $key );
|
||||
$status[ $key ] = is_wp_error( $stat ) ? FALSE : $stat;
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate all rewrite rules according to the settings
|
||||
*
|
||||
*/
|
||||
public static function activate_rewrite_all( $options ) {
|
||||
$rewrite = self::get_instance();
|
||||
|
||||
foreach ( array_keys( $rewrite->rewrite_rule['.htaccess'] ) as $key ) {
|
||||
if ( $options[ $key ] )
|
||||
// if it fails to write, then return FALSE
|
||||
$options[ $key ] = $rewrite->add_rewrite_rule( $key ) ? TRUE : FALSE;
|
||||
else
|
||||
// regardless of the result, return FALSE
|
||||
$options[ $key ] = $rewrite->del_rewrite_rule( $key ) ? FALSE : FALSE;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivate all rewrite rules
|
||||
*
|
||||
*/
|
||||
public static function deactivate_rewrite_all() {
|
||||
$rewrite = self::get_instance();
|
||||
|
||||
foreach ( array_keys( $rewrite->rewrite_rule['.htaccess'] ) as $key ) {
|
||||
$rewrite->del_rewrite_rule( $key );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of target directories.
|
||||
*
|
||||
*/
|
||||
public static function get_dirs() {
|
||||
$rewrite = self::get_instance();
|
||||
return str_replace( $rewrite->doc_root, '', $rewrite->wp_dirs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return configuration file type.
|
||||
*
|
||||
*/
|
||||
public static function get_config_file() {
|
||||
$rewrite = self::get_instance();
|
||||
return $rewrite->config_file;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
class IP_Geo_Block_Admin_Tab {
|
||||
|
||||
public static function tab_setup( $context, $tab ) {
|
||||
$cookie = $context->get_cookie();
|
||||
$options = IP_Geo_Block::get_option();
|
||||
$plugin_slug = IP_Geo_Block::PLUGIN_NAME;
|
||||
|
||||
register_setting(
|
||||
$option_slug = IP_Geo_Block::PLUGIN_NAME,
|
||||
$option_name = IP_Geo_Block::OPTION_NAME
|
||||
);
|
||||
|
||||
/*----------------------------------------*
|
||||
* Validation logs
|
||||
*----------------------------------------*/
|
||||
add_settings_section(
|
||||
$section = $plugin_slug . '-logs',
|
||||
array( __( 'Validation logs', 'ip-geo-block' ), '<a href="https://www.ipgeoblock.com/codex/record-settings-and-logs.html" title="Validation logs | IP Geo Block">' . __( 'Help', 'ip-geo-block' ) . '</a>' ),
|
||||
( $options['validation']['reclogs'] ?
|
||||
array( __CLASS__, 'validation_logs' ) :
|
||||
array( __CLASS__, 'warn_accesslog' )
|
||||
),
|
||||
$option_slug
|
||||
);
|
||||
|
||||
if ( $options['validation']['reclogs'] ):
|
||||
|
||||
if ( extension_loaded( 'pdo_sqlite' ) ):
|
||||
$html = '<ul id="ip-geo-block-live-log">';
|
||||
$html .= '<li><input type="radio" name="ip-geo-block-live-log" id="ip-geo-block-live-log-start" value="start"><label for="ip-geo-block-live-log-start" title="Start"><span class="ip-geo-block-icon-play"></span></label></li>';
|
||||
$html .= '<li><input type="radio" name="ip-geo-block-live-log" id="ip-geo-block-live-log-pause" value="pause"><label for="ip-geo-block-live-log-pause" title="Pause"><span class="ip-geo-block-icon-pause"></span></label></li>';
|
||||
$html .= '<li><input type="radio" name="ip-geo-block-live-log" id="ip-geo-block-live-log-stop" value="stop" checked><label for="ip-geo-block-live-log-stop" title="Stop"><span class="ip-geo-block-icon-stop"></span></label></li>';
|
||||
$html .= '</ul>';
|
||||
|
||||
// Live update
|
||||
add_settings_field(
|
||||
$option_name.'_live-log',
|
||||
__( 'Live update', 'ip-geo-block' ) . '<div id="ip-geo-block-live-loading"><div></div><div></div></div>',
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'html',
|
||||
'option' => $option_name,
|
||||
'field' => 'live-log',
|
||||
'value' => $html,
|
||||
'class' => isset( $cookie[ $tab ][1] ) && $cookie[ $tab ][1] === 'o' ? '' : 'ip-geo-block-hide',
|
||||
)
|
||||
);
|
||||
endif; // extension_loaded( 'pdo_sqlite' )
|
||||
|
||||
// make a list of target (same as in tab-accesslog.php)
|
||||
$target = array(
|
||||
'comment' => __( 'Comment post', 'ip-geo-block' ),
|
||||
'xmlrpc' => __( 'XML-RPC', 'ip-geo-block' ),
|
||||
'login' => __( 'Login form', 'ip-geo-block' ),
|
||||
'admin' => __( 'Admin area', 'ip-geo-block' ),
|
||||
'public' => __( 'Public facing pages', 'ip-geo-block' ),
|
||||
);
|
||||
|
||||
$html = "\n".'<li><label><input type="radio" name="' . $plugin_slug . '-target" value="all" checked="checked" />' . __( 'All', 'ip-geo-block' ) . '</label></li>' . "\n";
|
||||
foreach ( $target as $key => $val ) {
|
||||
$html .= '<li><label><input type="radio" name="' . $plugin_slug . '-target" value="' . $key . '" />';
|
||||
$html .= '<dfn title="' . $val . '">' . $key . '</dfn>' . '</label></li>' . "\n";
|
||||
}
|
||||
|
||||
// Select target
|
||||
add_settings_field(
|
||||
$option_name.'_select_target',
|
||||
__( 'Select target', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'html',
|
||||
'option' => $option_name,
|
||||
'field' => 'select_target',
|
||||
'value' => '<ul id="' . $plugin_slug . '-select-target">' . $html . '</ul>',
|
||||
)
|
||||
);
|
||||
|
||||
// Search in logs
|
||||
add_settings_field(
|
||||
$option_name.'_search_filter',
|
||||
__( 'Search in logs', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'text',
|
||||
'option' => $option_name,
|
||||
'field' => 'search_filter',
|
||||
'value' => isset( $_GET['s'] ) ? esc_html( $_GET['s'] ) : '', // preset filter
|
||||
'after' => '<a class="button button-secondary" id="ip-geo-block-reset-filter" title="' . __( 'Reset', 'ip-geo-block' ) . '" href="#!">'. __( 'Reset', 'ip-geo-block' ) . '</a>',
|
||||
)
|
||||
);
|
||||
|
||||
// Preset filters
|
||||
$filters = has_filter( $plugin_slug . '-logs-preset' ) ? apply_filters( $plugin_slug . '-logs-preset', array() ) : $context->preset_filters();
|
||||
if ( ! empty( $filters ) ) {
|
||||
// allowed tags and attributes
|
||||
$allow_tags = array(
|
||||
'span' => array(
|
||||
'class' => 1,
|
||||
'title' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
$html = '<ul id="ip-geo-block-logs-preset">';
|
||||
foreach ( $filters as $filter ) {
|
||||
$html .= '<li><a href="#!" data-value="' . esc_attr( $filter['value'] ) . '">' . IP_Geo_Block_Util::kses( $filter['title'], $allow_tags ) . '</a></li>';
|
||||
}
|
||||
|
||||
add_settings_field(
|
||||
$option_name.'_logs_preset',
|
||||
'<div class="ip-geo-block-subitem">' . __( 'Preset filters', 'ip-geo-block' ) . '</div>',
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'html',
|
||||
'option' => $option_name,
|
||||
'field' => 'logs_preset',
|
||||
'value' => $html,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Bulk action
|
||||
add_settings_field(
|
||||
$option_name.'_bulk_action',
|
||||
__( 'Bulk action', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'select',
|
||||
'option' => $option_name,
|
||||
'field' => 'bulk_action',
|
||||
'value' => 0,
|
||||
'list' => array(
|
||||
0 => NULL,
|
||||
'bulk-action-ip-erase' => __( 'Remove entries by IP address', 'ip-geo-block' ),
|
||||
'bulk-action-ip-white' => __( 'Add IP address to “Whitelist”', 'ip-geo-block' ),
|
||||
'bulk-action-ip-black' => __( 'Add IP address to “Blacklist”', 'ip-geo-block' ), ) + ( $options['Maxmind']['use_asn'] <= 0 ? array() : array(
|
||||
'bulk-action-as-white' => __( 'Add AS number to “Whitelist”', 'ip-geo-block' ),
|
||||
'bulk-action-as-black' => __( 'Add AS number to “Blacklist”', 'ip-geo-block' ),
|
||||
) ),
|
||||
'after' => '<a class="button button-secondary" id="ip-geo-block-bulk-action" title="' . __( 'Apply', 'ip-geo-block' ) . '" href="#!">'. __( 'Apply', 'ip-geo-block' ) . '</a>' . '<div id="'.$plugin_slug.'-loading"></div>',
|
||||
)
|
||||
);
|
||||
|
||||
// Clear logs
|
||||
add_settings_field(
|
||||
$option_name.'_clear_all',
|
||||
__( 'Clear logs', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'button',
|
||||
'option' => $option_name,
|
||||
'field' => 'clear_all',
|
||||
'value' => __( 'Clear all', 'ip-geo-block' ),
|
||||
'after' => '<div id="'.$plugin_slug.'-logs"></div>',
|
||||
'class' => empty( $cookie[ $tab ][1] ) || $cookie[ $tab ][1] !== 'o' ? '' : 'ip-geo-block-hide',
|
||||
)
|
||||
);
|
||||
|
||||
// Export logs
|
||||
add_settings_field(
|
||||
$option_name.'_export_logs',
|
||||
__( 'Export logs', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'none',
|
||||
'before' => '<a class="button button-secondary" id="ip-geo-block-export-logs" title="' . __( 'Export to the local file', 'ip-geo-block' ) . '" href="#!">'. __( 'Export csv', 'ip-geo-block' ) . '</a>',
|
||||
'after' => '<div id="'.$plugin_slug.'-export"></div>',
|
||||
'class' => empty( $cookie[ $tab ][1] ) || $cookie[ $tab ][1] !== 'o' ? '' : 'ip-geo-block-hide',
|
||||
)
|
||||
);
|
||||
|
||||
endif; // $options['validation']['reclogs']
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that fills the section with the desired content.
|
||||
*
|
||||
*/
|
||||
private static function dashboard_url() {
|
||||
$options = IP_Geo_Block::get_option();
|
||||
$context = IP_Geo_Block_Admin::get_instance();
|
||||
return $context->dashboard_url( $options['network_wide'] );
|
||||
}
|
||||
|
||||
public static function validation_logs() {
|
||||
echo '<table id="', IP_Geo_Block::PLUGIN_NAME, '-validation-logs" class="', IP_Geo_Block::PLUGIN_NAME, '-dataTable display" cellspacing="0" width="100%">', "\n", '<thead></thead><tbody></tbody></table>', "\n";
|
||||
}
|
||||
|
||||
public static function warn_accesslog() {
|
||||
$url = esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => '0', 'sec' => 3 ), self::dashboard_url() ) . '#' . IP_Geo_Block::PLUGIN_NAME . '-section-3' );
|
||||
echo '<p style="padding:0 1em">', sprintf( __( '[ %sRecord “Validation logs”%s ] is disabled.', 'ip-geo-block' ), '<a href="' . $url . '">', '</a>' ), '</p>', "\n";
|
||||
echo '<p style="padding:0 1em">', __( 'Please set the proper condition to record and analyze the validation logs.', 'ip-geo-block' ), '</p>', "\n";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
class IP_Geo_Block_Admin_Tab {
|
||||
|
||||
public static function tab_setup( $context, $tab ) {
|
||||
|
||||
register_setting(
|
||||
$option_slug = IP_Geo_Block::PLUGIN_NAME,
|
||||
$option_name = IP_Geo_Block::OPTION_NAME
|
||||
);
|
||||
|
||||
add_settings_section(
|
||||
$section = IP_Geo_Block::PLUGIN_NAME . '-attribution',
|
||||
__( 'Attribution links', 'ip-geo-block' ),
|
||||
NULL,
|
||||
$option_slug
|
||||
);
|
||||
|
||||
foreach ( IP_Geo_Block_Provider::get_providers( 'link' ) as $provider => $key ) {
|
||||
add_settings_field(
|
||||
$option_name.'_attribution_'.$provider,
|
||||
$provider,
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'html',
|
||||
'option' => $option_name,
|
||||
'field' => 'attribution',
|
||||
'value' => $key,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
class IP_Geo_Block_Admin_Tab {
|
||||
|
||||
public static function tab_setup( $context, $tab ) {
|
||||
$options = IP_Geo_Block::get_option();
|
||||
|
||||
register_setting(
|
||||
$option_slug = IP_Geo_Block::PLUGIN_NAME,
|
||||
$option_name = IP_Geo_Block::OPTION_NAME
|
||||
);
|
||||
|
||||
/*----------------------------------------*
|
||||
* Geolocation
|
||||
*----------------------------------------*/
|
||||
add_settings_section(
|
||||
$section = IP_Geo_Block::PLUGIN_NAME . '-search',
|
||||
__( 'Search IP address geolocation', 'ip-geo-block' ),
|
||||
NULL,
|
||||
$option_slug
|
||||
);
|
||||
|
||||
// make providers list
|
||||
$list = array();
|
||||
$providers = IP_Geo_Block_Provider::get_providers( 'key' );
|
||||
foreach ( $providers as $provider => $key ) {
|
||||
if ( ! is_string( $key ) || // provider that does not need api key
|
||||
! empty( $options['providers'][ $provider ] ) ) { // provider that has api key
|
||||
$list += array( $provider => $provider );
|
||||
}
|
||||
}
|
||||
|
||||
// get selected item
|
||||
$provider = array();
|
||||
$providers = array_keys( $providers );
|
||||
$cookie = $context->get_cookie();
|
||||
if ( isset( $cookie[ $tab ] ) ) {
|
||||
foreach ( array_slice( (array)$cookie[ $tab ], 3 ) as $key => $val ) {
|
||||
if ( 'o' === $val ) {
|
||||
$provider[] = $providers[ $key ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_settings_field(
|
||||
$option_name.'_service',
|
||||
__( 'Geolocation API', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'select',
|
||||
'attr' => 'multiple="multiple"',
|
||||
'option' => $option_name,
|
||||
'field' => 'service',
|
||||
'value' => ! empty( $provider ) ? $provider : $providers[0],
|
||||
'list' => $list,
|
||||
)
|
||||
);
|
||||
|
||||
// preset IP address
|
||||
if ( isset( $_GET['s'] ) ) {
|
||||
$list = preg_replace(
|
||||
array( '/\.\*+$/', '/:\w*\*+$/', '/(::.*)::$/' ),
|
||||
array( '.0', '::', '$1' ),
|
||||
trim( $_GET['s'] )
|
||||
); // de-anonymize if `***` exists
|
||||
$list = filter_var( $list, FILTER_VALIDATE_IP ) ? $list : '';
|
||||
} else {
|
||||
$list = '';
|
||||
}
|
||||
|
||||
add_settings_field(
|
||||
$option_name.'_ip_address',
|
||||
__( 'IP address', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'text',
|
||||
'option' => $option_name,
|
||||
'field' => 'ip_address',
|
||||
'value' => $list,
|
||||
)
|
||||
);
|
||||
|
||||
// Anonymize IP address
|
||||
add_settings_field(
|
||||
$option_name.'_anonymize',
|
||||
__( '<dfn title="IP address is always encrypted on recording in Cache and Logs. Moreover, this option replaces the end of IP address with “***” to make it anonymous.">Anonymize IP address</dfn>', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'checkbox',
|
||||
'option' => $option_name,
|
||||
'field' => 'anonymize',
|
||||
'value' => ( ! empty( $options['anonymize'] ) || ! empty( $options['restrict_api'] ) ) ? TRUE : FALSE,
|
||||
)
|
||||
);
|
||||
|
||||
// Search geolocation
|
||||
add_settings_field(
|
||||
$option_name.'_get_location',
|
||||
__( 'Search geolocation', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'button',
|
||||
'option' => $option_name,
|
||||
'field' => 'get_location',
|
||||
'value' => __( 'Search now', 'ip-geo-block' ),
|
||||
'after' => '<div id="ip-geo-block-loading"></div>',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
class IP_Geo_Block_Admin_Tab {
|
||||
|
||||
// UI control parameters
|
||||
static $controls = array(
|
||||
'time' => 0, // Duration to retrieve
|
||||
'rows' => 2, // Rows
|
||||
'cols' => 1, // Columns
|
||||
'warn' => FALSE,
|
||||
);
|
||||
|
||||
public static function tab_setup( $context, $tab ) {
|
||||
/*----------------------------------------*
|
||||
* Control parameters in cookie
|
||||
*----------------------------------------*/
|
||||
$options = IP_Geo_Block::get_option();
|
||||
$cookie = $context->get_cookie(); // [0]:Section, [1]:Open a new window, [2]:Duration to retrieve, [3]:Row, [4]:Column
|
||||
self::$controls['time'] = empty( $cookie[ $tab ][2] ) ? self::$controls['time'] : min( 3, max( 0, (int)$cookie[ $tab ][2] ) );
|
||||
self::$controls['rows'] = empty( $cookie[ $tab ][3] ) ? self::$controls['rows'] : min( 4, max( 1, (int)$cookie[ $tab ][3] ) );
|
||||
self::$controls['cols'] = empty( $cookie[ $tab ][4] ) ? self::$controls['cols'] : min( 5, max( 1, (int)$cookie[ $tab ][4] ) );
|
||||
self::$controls['warn'] = ! $options['validation']['reclogs'];
|
||||
|
||||
/*----------------------------------------*
|
||||
* Blocked by target in logs section
|
||||
*----------------------------------------*/
|
||||
register_setting(
|
||||
$option_slug = IP_Geo_Block::PLUGIN_NAME,
|
||||
$option_name = IP_Geo_Block::OPTION_NAME
|
||||
);
|
||||
|
||||
add_settings_section(
|
||||
$section = IP_Geo_Block::PLUGIN_NAME . '-network',
|
||||
__( 'Blocked by target in logs', 'ip-geo-block' ),
|
||||
array( __CLASS__, 'render_network' ),
|
||||
$option_slug
|
||||
);
|
||||
|
||||
/*----------------------------------------*
|
||||
* Chart display layout
|
||||
*----------------------------------------*/
|
||||
$html = '<ul id="ip-geo-block-select-layout">';
|
||||
$html .= '<li>' . __( 'Rows', 'ip-geo-block' ) . ' : <select name="rows">';
|
||||
$html .= '<option value="1"' . selected( 1, self::$controls['rows'], FALSE ) . '> 5</option>';
|
||||
$html .= '<option value="2"' . selected( 2, self::$controls['rows'], FALSE ) . '>10</option>';
|
||||
$html .= '<option value="4"' . selected( 4, self::$controls['rows'], FALSE ) . '>20</option>';
|
||||
$html .= '</select></li>';
|
||||
$html .= '<li>' .__( 'Columns', 'ip-geo-block' ) . ' : <select name="cols">';
|
||||
$html .= '<option value="1"' . selected( 1, self::$controls['cols'], FALSE ) . '>1</option>';
|
||||
$html .= '<option value="2"' . selected( 2, self::$controls['cols'], FALSE ) . '>2</option>';
|
||||
$html .= '<option value="3"' . selected( 3, self::$controls['cols'], FALSE ) . '>3</option>';
|
||||
$html .= '<option value="4"' . selected( 4, self::$controls['cols'], FALSE ) . '>4</option>';
|
||||
$html .= '<option value="5"' . selected( 5, self::$controls['cols'], FALSE ) . '>5</option>';
|
||||
$html .= '</select></li>';
|
||||
$html .= '<li><a id="ip-geo-block-apply-layout" class="button button-secondary" href="';
|
||||
$html .= esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 5 ), network_admin_url( 'admin.php' ) ) );
|
||||
$html .= '">' . __( 'Apply', 'ip-geo-block' ) . '</a></li>';
|
||||
$html .= '</ul>';
|
||||
|
||||
add_settings_field(
|
||||
$option_name.'_chart-size',
|
||||
__( 'Chart display layout', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'html',
|
||||
'value' => $html,
|
||||
)
|
||||
);
|
||||
|
||||
/*----------------------------------------*
|
||||
* Duration to retrieve
|
||||
*----------------------------------------*/
|
||||
$time = array(
|
||||
__( 'All', 'ip-geo-block' ),
|
||||
__( 'Latest 1 hour', 'ip-geo-block' ),
|
||||
__( 'Latest 24 hours', 'ip-geo-block' ),
|
||||
__( 'Latest 1 week', 'ip-geo-block' ),
|
||||
);
|
||||
|
||||
// make a list of duration
|
||||
$html = "\n";
|
||||
foreach ( $time as $key => $val ) {
|
||||
$html .= '<li><label><input type="radio" name="' . $option_slug . '-duration" value="' . $key . '"'
|
||||
. ($key == self::$controls['time'] ? ' checked="checked"' : '') . ' />' . $val . '</label></li>' . "\n";
|
||||
}
|
||||
|
||||
add_settings_field(
|
||||
$option_name.'_select_duration',
|
||||
__( 'Duration to retrieve', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'html',
|
||||
'value' => '<ul id="' . $option_slug . '-select-duration">' . $html . '</ul>',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render log data
|
||||
*
|
||||
* @param array $args associative array of `id`, `title`, `callback`.
|
||||
*/
|
||||
public static function render_network( $args ) {
|
||||
require_once IP_GEO_BLOCK_PATH . 'admin/includes/class-admin-ajax.php';
|
||||
|
||||
if ( self::$controls['warn'] ) {
|
||||
$context = IP_Geo_Block_Admin::get_instance();
|
||||
$url = esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => '0', 'sec' => 5 ), $context->dashboard_url() ) . '#' . IP_Geo_Block::PLUGIN_NAME . '-section-5' );
|
||||
echo '<p style="padding:0 1em">', sprintf( __( '[ %sRecord “Validation logs”%s ] is disabled.', 'ip-geo-block' ), '<a href="' . $url . '"><strong>', '</strong></a>' ), '</p>', "\n";
|
||||
echo '<p style="padding:0 1em">', __( 'Please set the proper condition to record and analyze the validation logs.', 'ip-geo-block' ), '</p>', "\n";
|
||||
}
|
||||
|
||||
$row = self::$controls['rows'] * 5;
|
||||
$col = self::$controls['cols'];
|
||||
$page = empty( $_REQUEST['p']) ? 0 : (int)$_REQUEST['p'];
|
||||
$start = $page * ( $row * $col );
|
||||
$count = min( $total = IP_Geo_Block_Admin_Ajax::get_network_count(), $row * $col );
|
||||
|
||||
// [0]:site, [1]:comment, [2]:xmlrpc, [3]:login, [4]:admin, [5]:public, [6]:link
|
||||
$json = IP_Geo_Block_Admin_Ajax::restore_network( self::$controls['time'], $start, $count, FALSE );
|
||||
|
||||
// Max value on hAxis
|
||||
$max = 0;
|
||||
$num = count( $json );
|
||||
for ( $i = 0; $i < $num; ++$i ) {
|
||||
$max = max( $max, array_sum( array_slice( $json[ $i ], 1, 5 ) ) );
|
||||
}
|
||||
|
||||
// Split the array into chunks
|
||||
$arr = array_chunk( $json, $row );
|
||||
$num = (int)floor( count( $arr ) / $col );
|
||||
|
||||
// Embed array into data attribute as json
|
||||
echo '<div class="ip-geo-block-row ip-geo-block-range" data-ip-geo-block-range="[0,', $max, ']">', "\n";
|
||||
for ( $i = 0; $i < $col; ++$i ) {
|
||||
if ( isset( $arr[ $i ] ) ) {
|
||||
echo '<div class="ip-geo-block-network ip-geo-block-column" ',
|
||||
'id="', $args['id'], '-', $i, '" ',
|
||||
'data-', $args['id'], '-', $i, '=\'', json_encode( $arr[ $i ] ), '\'>',
|
||||
'</div>', "\n";
|
||||
} else {
|
||||
echo '<div class="ip-geo-block-column"></div>';
|
||||
}
|
||||
}
|
||||
echo '</div>', "\n";
|
||||
|
||||
// pagination
|
||||
$url = esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 5 ), network_admin_url( 'admin.php' ) ) );
|
||||
echo '<div class="dataTables_wrapper"><div class="dataTables_paginate">', "\n",
|
||||
'<a class="paginate_button first', ($page === 0 ? ' disabled' : ''), '" href="', $url, '&p=', (0 ), '">«</a>',
|
||||
'<a class="paginate_button previous', ($page === 0 ? ' disabled' : ''), '" href="', $url, '&p=', (0 < $page ? $page-1 : 0), '">‹</a><span>';
|
||||
|
||||
$num = (int)ceil( $total / ( $row * $col ) );
|
||||
for ( $i = 0; $i < $num; ++$i ) {
|
||||
echo '<a class="paginate_button', ($i === $page ? ' current' : ''), '" href="', $url, '&p=', $i, '">', $i+1, '</a>';
|
||||
}
|
||||
$num -= 1;
|
||||
|
||||
echo '</span>',
|
||||
'<a class="paginate_button next', ($page === $num ? ' disabled' : ''), '" href="', $url, '&p=', ($num > $page ? $page+1 : $page), '">›</a>',
|
||||
'<a class="paginate_button last', ($page === $num ? ' disabled' : ''), '" href="', $url, '&p=', ($num ), '">»</a>',
|
||||
'</div></div>', "\n"; // paginate wrapper
|
||||
}
|
||||
|
||||
}
|
||||
1668
wp/wp-content/plugins/ip-geo-block/admin/includes/tab-settings.php
Normal file
1668
wp/wp-content/plugins/ip-geo-block/admin/includes/tab-settings.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,420 @@
|
||||
<?php
|
||||
class IP_Geo_Block_Admin_Tab {
|
||||
|
||||
public static function tab_setup( $context, $tab ) {
|
||||
$options = IP_Geo_Block::get_option();
|
||||
$plugin_slug = IP_Geo_Block::PLUGIN_NAME;
|
||||
|
||||
register_setting(
|
||||
$option_slug = IP_Geo_Block::PLUGIN_NAME,
|
||||
$option_name = IP_Geo_Block::OPTION_NAME
|
||||
);
|
||||
|
||||
/*----------------------------------------*
|
||||
* Statistics of validation
|
||||
*----------------------------------------*/
|
||||
add_settings_section(
|
||||
$section = $plugin_slug . '-statistics',
|
||||
__( 'Statistics of validation', 'ip-geo-block' ),
|
||||
( $options['save_statistics'] ?
|
||||
NULL :
|
||||
array( __CLASS__, 'warn_statistics' )
|
||||
),
|
||||
$option_slug
|
||||
);
|
||||
|
||||
if ( $options['save_statistics'] ) :
|
||||
$statistics = IP_Geo_Block_Logs::restore_stat();
|
||||
|
||||
// Number of blocked access
|
||||
add_settings_field(
|
||||
$option_name.'_blocked',
|
||||
__( 'Blocked', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'html',
|
||||
'option' => $option_name,
|
||||
'field' => 'blocked',
|
||||
'value' => (int)$statistics['blocked'],
|
||||
)
|
||||
);
|
||||
|
||||
// Blocked by countries
|
||||
$count = array();
|
||||
|
||||
arsort( $statistics['countries'] );
|
||||
foreach ( $statistics['countries'] as $key => $val ) {
|
||||
$count[] = array( esc_html( $key ), (int)$val );
|
||||
}
|
||||
|
||||
$html = '<div id="' . $plugin_slug . '-chart-countries" data-' . $plugin_slug . '-chart-countries=\'' . json_encode( $count ) . '\'></div>';
|
||||
|
||||
add_settings_field(
|
||||
$option_name.'_countries',
|
||||
__( 'Blocked by countries', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'html',
|
||||
'option' => $option_name,
|
||||
'field' => 'countries',
|
||||
'value' => $html,
|
||||
)
|
||||
);
|
||||
|
||||
// Blocked hooks by date
|
||||
$zero = array(
|
||||
'comment' => 0,
|
||||
'xmlrpc' => 0,
|
||||
'login' => 0,
|
||||
'admin' => 0,
|
||||
'public' => 0,
|
||||
);
|
||||
|
||||
$prev = 0;
|
||||
$count = array();
|
||||
|
||||
// make array( `time`, `comment`, `xlmrpc`, `login`, `admin`, `public` )
|
||||
foreach ( $statistics['daystats'] as $key => $val ) {
|
||||
while ( $prev && $key - $prev > DAY_IN_SECONDS ) {
|
||||
$count[] = array( $prev += DAY_IN_SECONDS, 0, 0, 0, 0, 0 );
|
||||
}
|
||||
$count[] = array_merge(
|
||||
array( $prev = $key ),
|
||||
array_values( array_merge( $zero, $val ) )
|
||||
);
|
||||
}
|
||||
|
||||
// embed array into data attribute as json
|
||||
$html = '<div id="' . $plugin_slug . '-chart-daily" data-' . $plugin_slug . '-chart-daily=\'' . json_encode( $count ) . '\'></div>';
|
||||
|
||||
add_settings_field(
|
||||
$option_name.'_daily',
|
||||
__( 'Blocked per day', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'html',
|
||||
'option' => $option_name,
|
||||
'field' => 'daily',
|
||||
'value' => $html,
|
||||
)
|
||||
);
|
||||
|
||||
// Blocked by type of IP address
|
||||
add_settings_field(
|
||||
$option_name.'_type',
|
||||
__( 'Blocked by type of IP address', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'html',
|
||||
'option' => $option_name,
|
||||
'field' => 'type',
|
||||
'value' => '<table class="'.$option_slug.'-statistics-table">' .
|
||||
'<thead><tr><th>IPv4</th><th>IPv6</th></tr></thead><tbody><tr>' .
|
||||
'<td>' . esc_html( $statistics['IPv4'] ) . '</td>' .
|
||||
'<td>' . esc_html( $statistics['IPv6'] ) . '</td>' .
|
||||
'</tr></tbody></table>',
|
||||
)
|
||||
);
|
||||
|
||||
$html = '<table class="'.$option_slug.'-statistics-table"><thead><tr>';
|
||||
$html .= '<th>' . __( 'Name of API', 'ip-geo-block' ) . '</th>';
|
||||
$html .= '<th>' . __( 'Call', 'ip-geo-block' ) . '</th>';
|
||||
$html .= '<th>' . __( 'Response [msec]', 'ip-geo-block' ) . '</th>';
|
||||
$html .= '</tr></thead><tbody>';
|
||||
|
||||
foreach ( $statistics['providers'] as $key => $val ) {
|
||||
$html .= '<tr><td>' . esc_html( $key ) . '</td>';
|
||||
$html .= '<td>' . sprintf( '%5d', (int)$val['count'] ) . '</td><td>';
|
||||
$html .= sprintf( '%4.1f', (float)(1000.0 * $val['time'] / $val['count']) );
|
||||
$html .= '</td></tr>';
|
||||
}
|
||||
$html .= "</tbody></table>";
|
||||
|
||||
// Average response time of each API
|
||||
add_settings_field(
|
||||
$option_name.'_service',
|
||||
__( 'Average response time of each API', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'html',
|
||||
'option' => $option_name,
|
||||
'field' => 'service',
|
||||
'value' => $html,
|
||||
)
|
||||
);
|
||||
|
||||
// Clear statistics
|
||||
add_settings_field(
|
||||
$option_name.'_clear_statistics',
|
||||
__( 'Clear statistics', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'button',
|
||||
'option' => $option_name,
|
||||
'field' => 'clear_statistics',
|
||||
'value' => __( 'Clear all', 'ip-geo-block' ),
|
||||
'after' => '<div id="'.$plugin_slug.'-statistics"></div>',
|
||||
)
|
||||
);
|
||||
|
||||
endif;
|
||||
|
||||
/*----------------------------------------*
|
||||
* Statistics in Validation logs
|
||||
*----------------------------------------*/
|
||||
add_settings_section(
|
||||
$section = $plugin_slug . '-stat-logs',
|
||||
__( 'Statistics in validation logs', 'ip-geo-block' ),
|
||||
( $options['validation']['reclogs'] ?
|
||||
array( __CLASS__, 'statistics_logs' ) :
|
||||
array( __CLASS__, 'warn_validation' )
|
||||
),
|
||||
$option_slug
|
||||
);
|
||||
|
||||
if ( $options['validation']['reclogs'] ) :
|
||||
|
||||
add_settings_field(
|
||||
$option_name.'_clear_logs',
|
||||
__( 'Clear logs', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'button',
|
||||
'option' => $option_name,
|
||||
'field' => 'clear_logs',
|
||||
'value' => __( 'Clear all', 'ip-geo-block' ),
|
||||
)
|
||||
);
|
||||
|
||||
endif;
|
||||
|
||||
/*----------------------------------------*
|
||||
* Statistics in IP address cache
|
||||
*----------------------------------------*/
|
||||
add_settings_section(
|
||||
$section = $plugin_slug . '-cache',
|
||||
__( 'Statistics in IP address cache', 'ip-geo-block' ),
|
||||
( $options['cache_hold'] ?
|
||||
array( __CLASS__, 'statistics_cache' ) :
|
||||
array( __CLASS__, 'warn_ipadr_cache' )
|
||||
),
|
||||
$option_slug
|
||||
);
|
||||
|
||||
if ( $options['cache_hold'] ) :
|
||||
|
||||
add_settings_field(
|
||||
$option_name.'_search_filter',
|
||||
__( 'Search in cache', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'text',
|
||||
'option' => $option_name,
|
||||
'field' => 'search_filter',
|
||||
'value' => '',
|
||||
'after' => '<a class="button button-secondary" id="ip-geo-block-reset-filter" title="'
|
||||
. __( 'Reset', 'ip-geo-block' ) . '" href="#!">'. __( 'Reset', 'ip-geo-block' ) . '</a>',
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
$option_name.'_bulk_action',
|
||||
__( 'Bulk action', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'select',
|
||||
'option' => $option_name,
|
||||
'field' => 'bulk_action',
|
||||
'value' => 0,
|
||||
'list' => array(
|
||||
0 => NULL,
|
||||
'bulk-action-remove' => __( 'Remove entries by IP address', 'ip-geo-block' ),
|
||||
'bulk-action-ip-white' => __( 'Add IP address to “Whitelist”', 'ip-geo-block' ),
|
||||
'bulk-action-ip-black' => __( 'Add IP address to “Blacklist”', 'ip-geo-block' ), ) + ( $options['Maxmind']['use_asn'] <= 0 ? array() : array(
|
||||
'bulk-action-as-white' => __( 'Add AS number to “Whitelist”', 'ip-geo-block' ),
|
||||
'bulk-action-as-black' => __( 'Add AS number to “Blacklist”', 'ip-geo-block' ),
|
||||
) ),
|
||||
'after' => '<a class="button button-secondary" id="ip-geo-block-bulk-action" title="' . __( 'Apply', 'ip-geo-block' ) . '" href="#!">' . __( 'Apply', 'ip-geo-block' ) . '</a>' . '<div id="'.$plugin_slug.'-loading"></div>',
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
$option_name.'_clear_all',
|
||||
__( 'Clear cache', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'button',
|
||||
'option' => $option_name,
|
||||
'field' => 'clear_all',
|
||||
'value' => __( 'Clear all', 'ip-geo-block' ),
|
||||
'after' => '<div id="'.$plugin_slug.'-cache"></div>',
|
||||
)
|
||||
);
|
||||
|
||||
// Export cache
|
||||
add_settings_field(
|
||||
$option_name.'_export_cache',
|
||||
__( 'Export cache', 'ip-geo-block' ),
|
||||
array( $context, 'callback_field' ),
|
||||
$option_slug,
|
||||
$section,
|
||||
array(
|
||||
'type' => 'none',
|
||||
'before' => '<a class="button button-secondary" id="ip-geo-block-export-cache" title="' . __( 'Export to the local file', 'ip-geo-block' ) . '" href="#!">'. __( 'Export csv', 'ip-geo-block' ) . '</a>',
|
||||
'after' => '<div id="'.$plugin_slug.'-export"></div>',
|
||||
)
|
||||
);
|
||||
|
||||
endif;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Render top list in logs
|
||||
*
|
||||
*/
|
||||
public static function statistics_logs() {
|
||||
// Count by key
|
||||
$count = array();
|
||||
$keys = array(
|
||||
'code' => __( 'Country (Top 10)', 'ip-geo-block' ),
|
||||
'asn' => __( 'AS number (Top 10)', 'ip-geo-block' ),
|
||||
'ip' => __( 'IP address (Top 10)', 'ip-geo-block' ),
|
||||
'slug' => __( 'Slug in back-end', 'ip-geo-block' ),
|
||||
);
|
||||
|
||||
// Count by keys ($log: `time`, `ip`, `hook`, `code`, `method`, `data`)
|
||||
foreach( IP_Geo_Block_Logs::get_recent_logs( YEAR_IN_SECONDS ) as $log ) {
|
||||
$log['ip'] = '[' . $log['code'] . '] ' . $log['ip'];
|
||||
$key = $log['method'] . ' ' . $log['data'];
|
||||
|
||||
// <methodName>...</methodName>
|
||||
if ( preg_match( '#<methodName>(.*?)</methodName>#', $key, $matches ) )
|
||||
$log['slug'] = '/xmlrpc.php ' . $matches[1];
|
||||
|
||||
// /wp-content/(plugins|themes)/...
|
||||
elseif ( preg_match( '#(/wp-content/(?:plugins|themes)/.*?/)#', $key, $matches ) )
|
||||
$log['slug'] = $matches[1];
|
||||
|
||||
// /wp-admin/admin*.php?action=...
|
||||
elseif ( preg_match( '#(/wp-admin/admin.*?\.php).*((?:page|action)=[-\w]+)#', $key, $matches ) )
|
||||
$log['slug'] = $matches[1] . ' ' . $matches[2];
|
||||
|
||||
// /wp-admin/*.php
|
||||
elseif ( preg_match( '#(/wp-admin/(?!admin).*?\.php)#', $key, $matches ) )
|
||||
$log['slug'] = $matches[1];
|
||||
|
||||
// file uploading *.(zip|tar|rar|gz|php|...)
|
||||
elseif ( preg_match( '#(\[name\]\s*?=>\s*?[^\s]+)#', $key, $matches ) )
|
||||
$log['slug'] = $matches[1];
|
||||
|
||||
// other *.php file with or without query string
|
||||
elseif ( preg_match( '#(/[^/]*\.php)[^/\w]#', $key, $matches ) && FALSE === strpos( $key, '/wp-admin/' ) )
|
||||
$log['slug'] = $matches[1];
|
||||
|
||||
foreach ( array_keys( $keys ) as $key ) {
|
||||
if ( ! empty( $log[ $key ] ) )
|
||||
$count[ $key ][] = $log[ $key ];
|
||||
}
|
||||
}
|
||||
|
||||
$options = IP_Geo_Block::get_option();
|
||||
|
||||
// Statistics by keys
|
||||
foreach ( $keys as $slug => $log ) {
|
||||
if ( 'slug' !== $slug )
|
||||
echo '<ol class="ip-geo-block-top-list"><h4>', esc_html( $log ), '</h4>';
|
||||
else
|
||||
echo '<ol class="ip-geo-block-top-list"><h4>', esc_html( $log ), ' <a class="ip-geo-block-icon ip-geo-block-icon-cycle" id="ip-geo-block-sort-slug" title="', __( 'Toggle sorting order', 'ip-geo-block' ) ,'"><span></span></a></h4>';
|
||||
|
||||
if ( isset( $count[ $slug ] ) ) {
|
||||
$logs = array_count_values( $count[ $slug ] );
|
||||
arsort( $logs );
|
||||
|
||||
if ( 'slug' !== $slug )
|
||||
$logs = array_slice( $logs, 0, 10 ); // Make list of top 10
|
||||
|
||||
foreach ( $logs as $key => $log ) {
|
||||
$link = explode( ' ', $key );
|
||||
$link = esc_html( end( $link ) );
|
||||
$key = esc_html( $key );
|
||||
|
||||
if ( 'ip' === $slug && $options['anonymize'] )
|
||||
$link = $key = IP_Geo_Block_Util::anonymize_ip( $link );
|
||||
|
||||
echo '<li><code>';
|
||||
echo str_replace(
|
||||
$link,
|
||||
'<a href="' .
|
||||
esc_url( add_query_arg(
|
||||
array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 4, 's' => $link ),
|
||||
admin_url( 'options-general.php' )
|
||||
) ) .
|
||||
'" target=_blank>' . $link . '</a>',
|
||||
$key
|
||||
);
|
||||
echo '</code> (', (int)$log, ')</li>', "\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo '</ol>', "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render IP address cache
|
||||
*
|
||||
*/
|
||||
public static function statistics_cache() {
|
||||
echo '<table id="', IP_Geo_Block::PLUGIN_NAME, '-statistics-cache" class="', IP_Geo_Block::PLUGIN_NAME, '-dataTable display" cellspacing="0" width="100%">', "\n", '<thead></thead><tbody></tbody></table>', "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that fills the section with the desired content.
|
||||
*
|
||||
*/
|
||||
private static function dashboard_url() {
|
||||
$options = IP_Geo_Block::get_option();
|
||||
$context = IP_Geo_Block_Admin::get_instance();
|
||||
return $context->dashboard_url( $options['network_wide'] );
|
||||
}
|
||||
|
||||
public static function warn_statistics() {
|
||||
$url = esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => '0', 'sec' => 3 ), self::dashboard_url() ) . '#' . IP_Geo_Block::PLUGIN_NAME . '-section-3' );
|
||||
echo '<p>', sprintf( __( '[ %sRecord “Statistics of validation”%s ] is disabled.', 'ip-geo-block' ), '<a href="' . $url . '">', '</a>' ), '</p>', "\n";
|
||||
echo '<p>', __( 'Please set the proper condition to record and analyze the validation statistics.', 'ip-geo-block' ), '</p>', "\n";
|
||||
}
|
||||
|
||||
public static function warn_validation() {
|
||||
$url = esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => '0', 'sec' => 3 ), self::dashboard_url() ) . '#' . IP_Geo_Block::PLUGIN_NAME . '-section-3' );
|
||||
echo '<p>', sprintf( __( '[ %sRecord “Validation logs”%s ] is disabled.', 'ip-geo-block' ), '<a href="' . $url . '">', '</a>' ), '</p>', "\n";
|
||||
echo '<p>', __( 'Please set the proper condition to record and analyze the validation logs.', 'ip-geo-block' ), '</p>', "\n";
|
||||
}
|
||||
|
||||
public static function warn_ipadr_cache() {
|
||||
$url = esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => '0', 'sec' => 3 ), self::dashboard_url() ) . '#' . IP_Geo_Block::PLUGIN_NAME . '-section-3' );
|
||||
echo '<p style="padding:0 1em">', sprintf( __( '[ %sRecord “IP address cache”%s ] is disabled.', 'ip-geo-block' ), '<a href="' . $url . '">', '</a>' ), '</p>', "\n";
|
||||
echo '<p style="padding:0 1em">', __( 'Please set the proper condition to record IP address in cache.', 'ip-geo-block' ), '</p>', "\n";
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user