Merge branch 'release/1.5.0'

This commit is contained in:
Stefan Kalscheuer 2020-05-13 19:08:14 +02:00
commit f946d3415a
19 changed files with 956 additions and 606 deletions

12
.gitattributes vendored Normal file
View File

@ -0,0 +1,12 @@
/assets export-ignore
/test export-ignore
.gitattributes export-ignore
.gitignore export-ignore
.travis.yml export-ignore
composer.json export-ignore
composer.lock export-ignore
CONTRIBUTING.md export-ignore
package.json export-ignore
phpcs.xml export-ignore
phpunit.xml export-ignore
RoboFile.php export-ignore

3
.gitignore vendored
View File

@ -4,4 +4,5 @@ composer.lock
/dist/ /dist/
.idea .idea
tests-clover.xml tests-clover.xml
tests-junit.xml tests-junit.xml
.phpunit.result.cache

View File

@ -1,12 +1,13 @@
language: php language: php
dist: trusty
php: php:
- '5.5'
- '5.6' - '5.6'
- '7.0'
- '7.1'
- '7.2' - '7.2'
- '7.3'
- '7.4'
before_script: before_script:
- composer install - composer install
script: script:
- composer test-all - composer test-all
notifications:
slack:
secure: "ScXTSMO65veI1jA6TBHGDUtvDqEMkqJykaNf7vLLbb7YIxPIHHNBiX/wcjOHVFfQXZCV3qxQrflB7Lbm9qVUsAv861jTO9x/ZkECl5QhRoc0DIznejwZoypx0HJ9tBZFYT6qNUkViXRKZ/ILAiBLU9Yw52WACtQB9hu3FNFZwmKsjipvV8Sne1qEyTkLYLaMphsbC5mtXYdKMHvdt39jsYsk91UWGeYbXQ37LkMbsaG/8YHXF724d5JO7BRGoThw6p5knKAO5fk29V7GfNqg2h+hnGyNIUOcmxujgMDMFLyFCGMZpPoBa+3jyWWgq4PgpQt0F5VZtJFGoXCGcoMQm5IbVfqkSKJ4jYhqiSIrqSebLmzoPHepWX3yn8tpfOiBWjC6K9w9esp6vcZf26rnAJcjcGkA01rMrHRwR+UEMCLvj7q0DR0qzi/AFeED6gtpODzUf93Rp42Tz1iGvWIbgeCtkCWjfPO6XLuNiqGVPEVaT5BDKqlqbijdKxxp7yh1fdt8s0fInWdIsgoWTbU9DC1W4ZiqtQW7oYO+QtFZMaD6kZWpSqJUwB3kW5JL3odAUEm8bLbRWBvK5ZjGdaGqSbOs6f9gAKcf86iQQhwzCJSOgFlLlKFv9smicjPC+BGOxgx32pgseHNPWn6tmEo/ihmmr/NbbqoOusUKX9gQbA4="

View File

@ -33,17 +33,19 @@ If the changes introduce new functionality or affect major parts of existing cod
For adding new functionality a new test case the corresponding PHPUnit test would be nice (no hard criterion though). For adding new functionality a new test case the corresponding PHPUnit test would be nice (no hard criterion though).
The `master` branch should also be target for most pull requests.
However it it features new functionality you might want to target the `develop` branch instead (see next section for details on branches).
### Branches ### Branches
The `master` branch represents the current state of development. The `master` branch represents the current state of development.
Please ensure your initial code is up to date with it at the time you start development. Please ensure your initial code is up to date with it at the time you start development.
The `master` should also be target for most pull requests.
In addition, this project features a `develop` branch, which holds bleeding edge developments, not necessarily considered stable or even compatible. In addition, this project features a `develop` branch, which holds bleeding edge developments, not necessarily considered stable or even compatible.
Do not expect this code to run smoothly, but you might have a look into the history to see if some work on an issue has already been started there. Do not expect this code to run smoothly, but you might have a look into the history to see if some work on an issue has already been started there.
For fixes and features, there might be additional branches, likely prefixed by `ft-` (feature) or `hf-` (hotfix) followed by an issue number (if applicable) and/or a title. For fixes and features, there might be additional branches, likely prefixed by `hotfix/` or `feature/` followed by an issue number (if applicable) and/or a title.
Feel free to adapt these naming scheme to your forks. Feel free to adapt this naming scheme to your forks.
### Merge Requirements ### Merge Requirements

View File

@ -1,65 +0,0 @@
var gulp = require('gulp');
var clean = require('gulp-clean');
var copy = require('gulp-copy');
var zip = require('gulp-zip');
var composer = require('gulp-composer');
var phpunit = require('gulp-phpunit');
var exec = require('child_process').exec;
var phpcs = require('gulp-phpcs');
var config = require('./package.json');
// Clean the target directory.
gulp.task('clean', function () {
console.log('Cleaning up target directory ...');
return gulp.src('dist', {read: false})
.pipe(clean());
});
// Prepare composer.
gulp.task('compose', function () {
console.log('Preparing Composer ...');
return composer('install');
});
// Execute unit tests.
gulp.task('test', ['compose'], function () {
console.log('Running PHPUnit tests ...');
return gulp.src('phpunit.xml')
.pipe(phpunit('./vendor/bin/phpunit', {debug: false}));
});
// Execute PHP Code Sniffer.
gulp.task('test-cs', function (cb) {
return exec('./vendor/bin/phpcs --config-set installed_paths vendor/wimg/php-compatibility,vendor/wp-coding-standards/wpcs', function (err, stdout, stderr) {
console.log(stdout);
console.log(stderr);
if (null === err) {
console.log('Running PHP Code Sniffer tests ...');
// exec('./vendor/bin/phpcs --standard=phpcs.xml', function(err, stdout, stderr) {
// console.log(stdout);
// console.log(stderr);
// });
gulp.src(['statify-blacklist.php', 'inc/**/*.php'])
.pipe(phpcs({bin: './vendor/bin/phpcs', standard: 'phpcs.xml'}))
.pipe(phpcs.reporter('log'));
}
cb(err);
});
});
// Bundle files as required for plugin distribution..
gulp.task('bundle', ['clean'], function () {
console.log('Collecting files for package dist/' + config.name + config.version + ' ...');
return gulp.src(['**/*.php', '!RoboFile.php', '!test/**', '!vendor/**', 'README.md', 'LICENSE.md'], {base: './'})
.pipe(copy('./dist/' + config.name + '.' + config.version + '/' + config.name));
});
// Create a ZIP package of the relevant files for plugin distribution.
gulp.task('package', ['bundle'], function () {
console.log('Building package dist/' + config.name + config.version + '.zip ...');
return gulp.src('./dist/' + config.name + '.' + config.version + '/**')
.pipe(zip(config.name + '.' + config.version + '.zip'))
.pipe(gulp.dest('./dist'));
});
gulp.task('default', ['clean', 'compose', 'test', 'test-cs', 'bundle', 'package']);

View File

@ -357,5 +357,5 @@ into proprietary programs. If your program is a subroutine library,
you may consider it more useful to permit linking proprietary you may consider it more useful to permit linking proprietary
applications with the library. If this is what you want to do, use the applications with the library. If this is what you want to do, use the
[GNU Lesser General Public [GNU Lesser General Public
License](http://www.gnu.org/licenses/lgpl.html) instead of this License](https://www.gnu.org/licenses/lgpl.html) instead of this
License. License.

View File

@ -1,16 +1,21 @@
[![Build Status](https://travis-ci.org/stklcode/statify-blacklist.svg?branch=master)](https://travis-ci.org/stklcode/statify-blacklist)
[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=de.stklcode.web.wordpress.plugins%3Astatify-blacklist&metric=alert_status)](https://sonarcloud.io/dashboard?id=de.stklcode.web.wordpress.plugins%3Astatify-blacklist)
[![Packagist Version](https://img.shields.io/packagist/v/stklcode/statify-blacklist.svg)](https://packagist.org/packages/stklcode/statify-blacklist)
[![License](https://img.shields.io/badge/license-GPL%20v2-blue.svg)](https://github.com/stklcode/statify-blacklist/blob/master/LICENSE.md)
# Statify Blacklist # # Statify Blacklist #
* Contributors: Stefan Kalscheuer * Contributors: Stefan Kalscheuer
* Requires at least: 4.4 * Requires at least: 4.7
* Tested up to: 5.4 * Tested up to: 5.4
* Requires PHP: 5.5 * Requires PHP: 5.5
* Stable tag: 1.4.4 * Stable tag: 1.5.0
* License: GPLv2 or later * License: GPLv2 or later
* License URI: http://www.gnu.org/licenses/gpl-2.0.html * License URI: https://www.gnu.org/licenses/gpl-2.0.html
## Description ## ## Description ##
A blacklist extension for the famous [Statify](https://wordpress.org/plugins/statify/) Wordpress plugin. A blacklist extension for the famous [Statify](https://wordpress.org/plugins/statify/) Wordpress plugin.
This plugin adds customizable blacklist to Statify to allow blocking of referer spam or internal interactions. This plugin adds a customizable blacklist to Statify to allow blocking of referer spam or internal interactions.
### Features ## ### Features ##
@ -27,7 +32,7 @@ Add a list of IP addresses or subnets (e.g. _192.0.2.123_, _198.51.100.0/24_, _2
Filters can be applied to data stored in database after modifying filter rules or for one-time clean-up. Filters can be applied to data stored in database after modifying filter rules or for one-time clean-up.
#### Compatibility #### #### Compatibility ####
This plugin requires Statify to be installed. The extension has been tested with Statify up to version 1.5.1 This plugin requires Statify to be installed. The extension has been tested with Statify up to version 1.7
The plugin is capable of handling multisite installations. The plugin is capable of handling multisite installations.
### Support & Contributions ### ### Support & Contributions ###
@ -37,51 +42,62 @@ The plugin is capable of handling multisite installations.
### Credits ### ### Credits ###
* Author: Stefan Kalscheuer * Author: Stefan Kalscheuer
* Special Thanks to [pluginkollektiv](https://github.com/pluginkollektiv) for maintaining _Statify_ * Special Thanks to [pluginkollektiv](https://pluginkollektiv.org/) for maintaining _Statify_
## Installation ## ## Installation ##
* If you dont know how to install a plugin for WordPress, [heres how](http://codex.wordpress.org/Managing_Plugins#Installing_Plugins). * If you dont know how to install a plugin for WordPress, [heres how](https://wordpress.org/support/article/managing-plugins/#installing-plugins).
* Make sure _Statify_ plugin is installed and active * Make sure _Statify_ plugin is installed and active
* Goto _Settings_ -> _Statify Blacklist_ to configure the plugin * Goto _Settings_ -> _Statify Blacklist_ to configure the plugin
### Requirements ### ### Requirements ###
* PHP 5.5 or above * PHP 5.5 or above
* WordPress 4.4 or above * WordPress 4.7 or above
* Statify plugin installed and activated (1.5.0 or above) * _Statify_ plugin installed and activated (1.5 or above)
## Frequently Asked Questions ## ## Frequently Asked Questions ##
### What is blocked by default? ### ### What is blocked by default? ###
Nothing. By default all blacklists are empty and disabled. They can and have to be filled by the blog administrator. Nothing. By default, all blacklists are empty and disabled. They can and have to be filled by the blog administrator.
A default blacklist is not provided, as the plugin itself is totally neutral. If you want to filter out referer spam, A default blacklist is not provided, as the plugin itself is totally neutral. If you want to filter out referer spam,
visitors from search engines, just "false" referers from 301 redirects or you own IP address used for testing only depends on you. visitors from search engines, just "false" referrers from 301 redirects or you own IP address used for testing only depends on you.
### Does the filter effect user experience? ### ### Does the filter effect user experience? ###
No. It only prevent's _Statify_ from tracking, nothing more or less. No. It only prevents _Statify_ from tracking, nothing more or less.
### Does live filtering impact performance? ### ### Does live filtering impact performance? ###
Yes, but probalby not noticeable. Checking a single referer string against a (usually small) list should be negligible compared to the total loading procedure. Yes, but probably not noticeable. Checking a single referer string against a (usually small) list should be negligible compared to the total loading procedure.
If this still is an issue for you, consider deactivating the filter and only run the one-time-cleanup or activate the cron job. If this still is an issue for you, consider deactivating the filter and only run the one-time-cleanup or activate the cron job.
### Is any personal data collected? ### ### Is any personal data collected? ###
No. The privacy policy of _Statify_ is untouched. Data is only processed, not stored or exposed to anyone. No. The privacy policy of _Statify_ is untouched. Data is only processed, not stored or exposed to anyone.
### Are regular expression filters possible? ### ### Are regular expression filters possible? ###
Yes, it is. Just select if you want to filter using regular expressions case sensitive or insensitive. Yes, it is. Just select regular expressions (case-sensitive or insensitive) as matching method instead of exact or keyword match.
Note, that regular expression matching is significantly slower than the plain domain filter. Hence it is only recommended for asynchronous cron or manual execution and not for live filtering.
### Why is IP filtering only available as live filter? ### ### Why is IP filtering only available as live filter? ###
As you might know, Statify does not store any personal information, including IP addresses in the database. As you might know, _Statify_ does not store any personal information, including IP addresses in the database.
Because of this, an IP blacklist can only be applied while processing the request and not afterwards. Because of this, an IP blacklist can only be applied while processing the request and not afterwards.
### Can whole IP subnet be blocked? ###
Yes. The plugin features subnet blacklists using CIDR notation.
For example _198.51.100.0/24_ blacklists all sources from _198.51.100.1_ to _198.51.100.254_.
Same for IPv6 prefixes like _2001:db8:a0b:12f0::/64_.
## Screenshots ## ## Screenshots ##
1. Statify Blacklist settings page 1. Statify Blacklist settings page
## Changelog ## ## Changelog ##
### 1.5.0 / 13.05.2020 ###
* Minimum required WordPress version is 4.7
* Removed `load_plugin_textdomain()` and `Domain Path` header
* Added automatic compatibility check for WP and PHP version (#17)
* Added keyword filter mode for referer blacklist (#15)
* Layout adjustments on settings page
* Regular expression filters are validated before saving (#13)
### 1.4.4 / 19.05.2018 ### ### 1.4.4 / 19.05.2018 ###
* Fix live filter chain when regular expressions are active (#12) * Fix live filter chain when regular expressions are active (#12)
@ -115,7 +131,7 @@ Because of this, an IP blacklist can only be applied while processing the reques
### 1.2.0 / 29.08.2016 ### ### 1.2.0 / 29.08.2016 ###
* Switched from `in_array()` to faster `isset()` for referer checking * Switched from `in_array()` to faster `isset()` for referer checking
* Optional cron execiton implemented * Optional cron execution implemented
### 1.1.2 / 17.08.2016 ### ### 1.1.2 / 17.08.2016 ###
* Prepared for localization * Prepared for localization

View File

@ -8,7 +8,7 @@
* @author Stefan Kalscheuer <stefan@stklcode.de> * @author Stefan Kalscheuer <stefan@stklcode.de>
* *
* @package Statify_Blacklist * @package Statify_Blacklist
* @version 1.4.4 * @version 1.5.0
*/ */
use Robo\Exception\TaskException; use Robo\Exception\TaskException;
@ -19,10 +19,10 @@ use Robo\Tasks;
*/ */
class RoboFile extends Tasks { class RoboFile extends Tasks {
const PROJECT_NAME = 'statify-blacklist'; const PROJECT_NAME = 'statify-blacklist';
const SVN_URL = 'https://plugins.svn.wordpress.org/statify-blacklist'; const SVN_URL = 'https://plugins.svn.wordpress.org/statify-blacklist';
const OPT_TARGET = 'target'; const OPT_TARGET = 'target';
const OPT_SKIPTEST = 'skipTests'; const OPT_SKIPTEST = 'skipTests';
const OPT_SKIPSTYLE = 'skipStyle'; const OPT_SKIPSTYLE = 'skipStyle';
/** /**
@ -134,13 +134,21 @@ class RoboFile extends Tasks {
*/ */
private function bundle() { private function bundle() {
$this->say( 'Bundling resources...' ); $this->say( 'Bundling resources...' );
$this->taskCopyDir( [ $this->taskCopyDir(
'inc' => $this->target_dir . '/' . $this->final_name . '/inc', [
'views' => $this->target_dir . '/' . $this->final_name . '/views', 'inc' => $this->target_dir . '/' . $this->final_name . '/inc',
] )->run(); 'views' => $this->target_dir . '/' . $this->final_name . '/views',
]
)->run();
$this->_copy( 'statify-blacklist.php', $this->target_dir . '/' . $this->final_name . '/statify-blacklist.php' ); $this->_copy( 'statify-blacklist.php', $this->target_dir . '/' . $this->final_name . '/statify-blacklist.php' );
$this->_copy( 'README.md', $this->target_dir . '/' . $this->final_name . '/README.md' );
$this->_copy( 'LICENSE.md', $this->target_dir . '/' . $this->final_name . '/LICENSE.md' ); $this->_copy( 'LICENSE.md', $this->target_dir . '/' . $this->final_name . '/LICENSE.md' );
$this->_copy( 'README.md', $this->target_dir . '/' . $this->final_name . '/README.md' );
// Remove content before title (e.g. badges) from README file.
$this->taskReplaceInFile( $this->target_dir . '/' . $this->final_name . '/README.md' )
->regex( '/^[^\\#]*/' )
->to( '' )
->run();
} }
/** /**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 93 KiB

View File

@ -1,6 +1,6 @@
{ {
"name": "stklcode/statify-blacklist", "name": "stklcode/statify-blacklist",
"version": "1.4.4", "version": "1.5.0",
"description": "A blacklist extension for the famous Statify WordPress plugin", "description": "A blacklist extension for the famous Statify WordPress plugin",
"keywords": [ "keywords": [
"wordpress", "wordpress",
@ -19,17 +19,17 @@
"type": "wordpress-plugin", "type": "wordpress-plugin",
"require": { "require": {
"php": ">=5.5", "php": ">=5.5",
"composer/installers": "~1.0" "composer/installers": "~1.7"
}, },
"require-dev": { "require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.4", "dealerdirect/phpcodesniffer-composer-installer": "^0.5",
"consolidation/robo": "^1.0.0", "consolidation/robo": "^1.4",
"phpunit/phpunit": "*", "phpunit/phpunit": "*",
"phpunit/php-code-coverage": "*", "phpunit/php-code-coverage": "*",
"slowprog/composer-copy-file": "~0.2", "slowprog/composer-copy-file": "~0.2",
"squizlabs/php_codesniffer": "^3.1", "squizlabs/php_codesniffer": "^3.5",
"wimg/php-compatibility": "^8.0", "phpcompatibility/php-compatibility": "^9.3",
"wp-coding-standards/wpcs": "~0.14" "wp-coding-standards/wpcs": "^2.1"
}, },
"scripts": { "scripts": {
"build": [ "build": [

View File

@ -9,8 +9,10 @@
* @since 1.0.0 * @since 1.0.0
*/ */
// Quit. // Quit if accessed directly.
defined( 'ABSPATH' ) || exit; if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/** /**
* Statify Blacklist admin configuration. * Statify Blacklist admin configuration.
@ -18,37 +20,101 @@ defined( 'ABSPATH' ) || exit;
* @since 1.0.0 * @since 1.0.0
*/ */
class StatifyBlacklist_Admin extends StatifyBlacklist { class StatifyBlacklist_Admin extends StatifyBlacklist {
/**
* Initialize admin-only components of the plugin.
*
* @since 1.5.0
*
* @return void
*/
public static function init() {
// Add actions.
add_action( 'wpmu_new_blog', array( 'StatifyBlacklist_System', 'install_site' ) );
add_action( 'delete_blog', array( 'StatifyBlacklist_System', 'uninstall_site' ) );
add_filter( 'plugin_row_meta', array( 'StatifyBlacklist_Admin', 'plugin_meta_link' ), 10, 2 );
if ( self::$multisite ) {
add_action( 'network_admin_menu', array( 'StatifyBlacklist_Admin', 'add_menu_page' ) );
add_filter(
'network_admin_plugin_action_links',
array(
'StatifyBlacklist_Admin',
'plugin_actions_links',
),
10,
2
);
} else {
add_action( 'admin_menu', array( 'StatifyBlacklist_Admin', 'add_menu_page' ) );
add_filter( 'plugin_action_links', array( 'StatifyBlacklist_Admin', 'plugin_actions_links' ), 10, 2 );
}
}
/** /**
* Update options. * Update options.
* *
* @since 1.1.1
*
* @param array $options Optional. New options to save. * @param array $options Optional. New options to save.
* *
* @return array|bool array of sanitized array on errors, FALSE if there were none. * @return array|bool array of sanitized array on errors, FALSE if there were none.
* @since 1.1.1
*/ */
public static function update_options( $options = null ) { public static function update_options( $options = null ) {
if ( isset( $options ) && current_user_can( 'manage_options' ) ) { if ( isset( $options ) && current_user_can( 'manage_options' ) ) {
// Sanitize URLs and remove empty inputs.
$given_referer = $options['referer']['blacklist']; // Sanitize referer list.
if ( 0 === $options['referer']['regexp'] ) { $given_referer = $options['referer']['blacklist'];
$sanitized_referer = self::sanitizeURLs( $given_referer ); $invalid_referer = array();
if ( self::MODE_NORMAL === $options['referer']['regexp'] ) {
// Sanitize URLs and remove empty inputs.
$sanitized_referer = self::sanitize_urls( $given_referer );
} elseif ( self::MODE_REGEX === $options['referer']['regexp'] || self::MODE_REGEX_CI === $options['referer']['regexp'] ) {
$sanitized_referer = $given_referer;
// Check regular expressions.
$invalid_referer = self::sanitize_regex( $given_referer );
} else { } else {
$sanitized_referer = $given_referer; $sanitized_referer = $given_referer;
} }
// Sanitize IPs and Subnets and remove empty inputs. // Sanitize target list.
$given_target = $options['target']['blacklist'];
$invalid_target = array();
if ( self::MODE_REGEX === $options['target']['regexp'] || self::MODE_REGEX_CI === $options['target']['regexp'] ) {
$sanitized_target = $given_target;
// Check regular expressions.
$invalid_target = self::sanitize_regex( $given_target );
} else {
$sanitized_target = $given_target;
}
// Sanitize IPs and subnets and remove empty inputs.
$given_ip = $options['ip']['blacklist']; $given_ip = $options['ip']['blacklist'];
$sanitized_ip = self::sanitizeIPs( $given_ip ); $sanitized_ip = self::sanitize_ips( $given_ip );
// Abort on errors. // Abort on errors.
if ( ! empty( array_diff( array_keys( $given_referer ), array_keys( $sanitized_referer ) ) ) ) { $errors = array(
return array( 'referer' => array(
'referer' => $sanitized_referer, 'sanitized' => $sanitized_referer,
); 'diff' => array_diff( $given_referer, $sanitized_referer ),
} elseif ( ! empty( array_diff( $given_ip, $sanitized_ip ) ) ) { 'invalid' => $invalid_referer,
return array( ),
'ip' => array_diff( $given_ip, $sanitized_ip ), 'target' => array(
); 'sanitized' => $sanitized_target,
'diff' => array_diff( $given_target, $sanitized_target ),
'invalid' => $invalid_target,
),
'ip' => array(
'sanitized' => $sanitized_ip,
'diff' => array_diff( $given_ip, $sanitized_ip ),
),
);
if ( ! empty( $errors['referer']['diff'] )
|| ! empty( $errors['referer']['invalid'] )
|| ! empty( $errors['target']['diff'] )
|| ! empty( $errors['target']['invalid'] )
|| ! empty( $errors['ip']['diff'] ) ) {
return $errors;
} }
// Update database on success. // Update database on success.
@ -74,14 +140,24 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
$title = __( 'Statify Blacklist', 'statify-blacklist' ); $title = __( 'Statify Blacklist', 'statify-blacklist' );
if ( self::$multisite ) { if ( self::$multisite ) {
add_submenu_page( add_submenu_page(
'settings.php', $title, $title, 'manage_network_plugins', 'statify-blacklist-settings', array( 'settings.php',
$title,
$title,
'manage_network_plugins',
'statify-blacklist-settings',
array(
'StatifyBlacklist_Admin', 'StatifyBlacklist_Admin',
'settings_page', 'settings_page',
) )
); );
} else { } else {
add_submenu_page( add_submenu_page(
'options-general.php', $title, $title, 'manage_options', 'statify-blacklist', array( 'options-general.php',
$title,
$title,
'manage_options',
'statify-blacklist',
array(
'StatifyBlacklist_Admin', 'StatifyBlacklist_Admin',
'settings_page', 'settings_page',
) )
@ -154,20 +230,20 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
} }
if ( defined( 'DOING_CRON' ) && DOING_CRON ) { if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
$clean_ref = ( 1 === self::$_options['referer']['cron'] ); $clean_ref = ( 1 === self::$options['referer']['cron'] );
$clean_trg = ( 1 === self::$_options['target']['cron'] ); $clean_trg = ( 1 === self::$options['target']['cron'] );
} else { } else {
$clean_ref = true; $clean_ref = true;
$clean_trg = true; $clean_trg = true;
} }
if ( $clean_ref ) { if ( $clean_ref ) {
if ( isset( self::$_options['referer']['regexp'] ) && self::$_options['referer']['regexp'] > 0 ) { if ( isset( self::$options['referer']['regexp'] ) && self::$options['referer']['regexp'] > 0 ) {
// Merge given regular expressions into one. // Merge given regular expressions into one.
$referer_regexp = implode( '|', array_keys( self::$_options['referer']['blacklist'] ) ); $referer_regexp = implode( '|', array_keys( self::$options['referer']['blacklist'] ) );
} else { } else {
// Sanitize URLs. // Sanitize URLs.
$referer = self::sanitizeURLs( self::$_options['referer']['blacklist'] ); $referer = self::sanitize_urls( self::$options['referer']['blacklist'] );
// Build filter regexp. // Build filter regexp.
$referer_regexp = str_replace( '.', '\.', implode( '|', array_flip( $referer ) ) ); $referer_regexp = str_replace( '.', '\.', implode( '|', array_flip( $referer ) ) );
@ -175,12 +251,12 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
} }
if ( $clean_trg ) { if ( $clean_trg ) {
if ( isset( self::$_options['target']['regexp'] ) && self::$_options['target']['regexp'] > 0 ) { if ( isset( self::$options['target']['regexp'] ) && self::$options['target']['regexp'] > 0 ) {
// Merge given regular expressions into one. // Merge given regular expressions into one.
$target_regexp = implode( '|', array_keys( self::$_options['target']['blacklist'] ) ); $target_regexp = implode( '|', array_keys( self::$options['target']['blacklist'] ) );
} else { } else {
// Build filter regexp. // Build filter regexp.
$target_regexp = str_replace( '.', '\.', implode( '|', array_flip( self::$_options['target']['blacklist'] ) ) ); $target_regexp = str_replace( '.', '\.', implode( '|', array_flip( self::$options['target']['blacklist'] ) ) );
} }
} }
@ -188,13 +264,14 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
global $wpdb; global $wpdb;
// Execute filter on database. // Execute filter on database.
// @codingStandardsIgnoreStart These statements prouce warnings, rework in future release (TODO). // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- These statements produce warnings, rework in future release (TODO).
if ( ! empty( $referer_regexp ) ) { if ( ! empty( $referer_regexp ) ) {
$wpdb->query( $wpdb->query(
$wpdb->prepare( $wpdb->prepare(
"DELETE FROM `$wpdb->statify` WHERE " "DELETE FROM `$wpdb->statify` WHERE "
. ( ( 1 === self::$_options['referer']['regexp'] ) ? ' BINARY ' : '' ) . ( ( 1 === self::$options['referer']['regexp'] ) ? ' BINARY ' : '' )
. 'referrer REGEXP %s', $referer_regexp . 'referrer REGEXP %s',
$referer_regexp
) )
); );
} }
@ -202,12 +279,13 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
$wpdb->query( $wpdb->query(
$wpdb->prepare( $wpdb->prepare(
"DELETE FROM `$wpdb->statify` WHERE " "DELETE FROM `$wpdb->statify` WHERE "
. ( ( 1 === self::$_options['target']['regexp'] ) ? ' BINARY ' : '' ) . ( ( 1 === self::$options['target']['regexp'] ) ? ' BINARY ' : '' )
. 'target REGEXP %s', $target_regexp . 'target REGEXP %s',
$target_regexp
) )
); );
} }
// @codingStandardsIgnoreEnd // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
// Optimize DB. // Optimize DB.
$wpdb->query( "OPTIMIZE TABLE `$wpdb->statify`" ); $wpdb->query( "OPTIMIZE TABLE `$wpdb->statify`" );
@ -227,7 +305,7 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
* *
* @return array sanitized array. * @return array sanitized array.
*/ */
private static function sanitizeURLs( $urls ) { private static function sanitize_urls( $urls ) {
return array_flip( return array_flip(
array_filter( array_filter(
array_map( array_map(
@ -249,15 +327,39 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
* *
* @return array sanitized array. * @return array sanitized array.
*/ */
private static function sanitizeIPs( $ips ) { private static function sanitize_ips( $ips ) {
return array_filter( return array_filter(
$ips, function ( $ip ) { $ips,
function ( $ip ) {
return preg_match( return preg_match(
'/^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])(\/([0-9]|[1-2][0-9]|3[0-2]))?$/', $ip '/^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])(\/([0-9]|[1-2][0-9]|3[0-2]))?$/',
$ip
) || ) ||
preg_match( preg_match(
'/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$/', $ip '/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$/',
); $ip
);
}
);
}
/**
* Validate regular expressions, i.e. remove duplicates and empty values and validate others.
*
* @since 1.5.0 #13
*
* @param array $expressions Given pre-sanitized array of regular expressions.
*
* @return array Array of invalid expressions.
*/
private static function sanitize_regex( $expressions ) {
return array_filter(
array_flip( $expressions ),
function ( $re ) {
// Check of preg_match() fails (warnings suppressed).
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
return false === @preg_match( StatifyBlacklist::regex( $re, false ), null );
} }
); );
} }

View File

@ -1,6 +1,6 @@
<?php <?php
/** /**
* Statify Blacklist: StatifyBlacklist_Syste, class * Statify Blacklist: StatifyBlacklist_System class
* *
* This file contains the derived class for the plugin's system operations. * This file contains the derived class for the plugin's system operations.
* *
@ -9,8 +9,10 @@
* @since 1.0.0 * @since 1.0.0
*/ */
// Quit. // Quit if accessed directly.
defined( 'ABSPATH' ) || exit; if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/** /**
* Statify Blacklist system configuration. * Statify Blacklist system configuration.
@ -25,15 +27,14 @@ class StatifyBlacklist_System extends StatifyBlacklist {
* @since 1.0.0 * @since 1.0.0
* *
* @param bool $network_wide Whether the plugin was activated network-wide or not. * @param bool $network_wide Whether the plugin was activated network-wide or not.
*
* @return void
*/ */
public static function install( $network_wide = false ) { public static function install( $network_wide = false ) {
// Create tables for each site in a network. // Create tables for each site in a network.
if ( $network_wide && is_multisite() ) { if ( $network_wide && is_multisite() ) {
if ( function_exists( 'get_sites' ) ) { if ( function_exists( 'get_sites' ) ) {
$sites = get_sites(); $sites = get_sites();
} elseif ( function_exists( 'wp_get_sites' ) ) {
// @codingStandardsIgnoreLine Legacy support for WP < 4.6.
$sites = wp_get_sites();
} else { } else {
return; return;
} }
@ -62,6 +63,8 @@ class StatifyBlacklist_System extends StatifyBlacklist {
* @since 1.4.3 * @since 1.4.3
* *
* @param integer $site_id Site ID. * @param integer $site_id Site ID.
*
* @return void
*/ */
public static function install_site( $site_id ) { public static function install_site( $site_id ) {
switch_to_blog( (int) $site_id ); switch_to_blog( (int) $site_id );
@ -77,6 +80,8 @@ class StatifyBlacklist_System extends StatifyBlacklist {
* Plugin uninstall handler. * Plugin uninstall handler.
* *
* @since 1.0.0 * @since 1.0.0
*
* @return void
*/ */
public static function uninstall() { public static function uninstall() {
if ( is_multisite() ) { if ( is_multisite() ) {
@ -85,7 +90,7 @@ class StatifyBlacklist_System extends StatifyBlacklist {
if ( function_exists( 'get_sites' ) ) { if ( function_exists( 'get_sites' ) ) {
$sites = get_sites(); $sites = get_sites();
} elseif ( function_exists( 'wp_get_sites' ) ) { } elseif ( function_exists( 'wp_get_sites' ) ) {
// @codingStandardsIgnoreLine Legacy support for WP < 4.6. // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound -- Legacy support for WP < 4.6.
$sites = wp_get_sites(); $sites = wp_get_sites();
} else { } else {
return; return;
@ -112,6 +117,8 @@ class StatifyBlacklist_System extends StatifyBlacklist {
* @since 1.4.3 * @since 1.4.3
* *
* @param integer $site_id Site ID. * @param integer $site_id Site ID.
*
* @return void
*/ */
public static function uninstall_site( $site_id ) { public static function uninstall_site( $site_id ) {
$old = get_current_blog_id(); $old = get_current_blog_id();
@ -124,14 +131,16 @@ class StatifyBlacklist_System extends StatifyBlacklist {
* Upgrade plugin options. * Upgrade plugin options.
* *
* @since 1.2.0 * @since 1.2.0
*
* @return void
*/ */
public static function upgrade() { public static function upgrade() {
self::update_options(); self::update_options();
// Check if config array is not associative (pre 1.2.0). // Check if config array is not associative (pre 1.2.0).
if ( array_keys( self::$_options['referer'] ) === range( 0, count( self::$_options['referer'] ) - 1 ) ) { if ( array_keys( self::$options['referer'] ) === range( 0, count( self::$options['referer'] ) - 1 ) ) {
// Flip referer array to make domains keys. // Flip referer array to make domains keys.
$options = self::$_options; $options = self::$options;
$options['referer'] = array_flip( self::$_options['referer'] ); $options['referer'] = array_flip( self::$options['referer'] );
if ( self::$multisite ) { if ( self::$multisite ) {
update_site_option( 'statify-blacklist', $options ); update_site_option( 'statify-blacklist', $options );
} else { } else {
@ -140,14 +149,14 @@ class StatifyBlacklist_System extends StatifyBlacklist {
} }
// Version not set (pre 1.3.0) or older than 1.4. // Version not set (pre 1.3.0) or older than 1.4.
if ( ! isset( self::$_options['version'] ) || self::$_options['version'] < 1.4 ) { if ( ! isset( self::$options['version'] ) || self::$options['version'] < 1.4 ) {
// Upgrade options to new schema. // Upgrade options to new schema.
$options = array( $options = array(
'referer' => array( 'referer' => array(
'active' => self::$_options['active_referer'], 'active' => self::$options['active_referer'],
'cron' => self::$_options['cron_referer'], 'cron' => self::$options['cron_referer'],
'regexp' => self::$_options['referer_regexp'], 'regexp' => self::$options['referer_regexp'],
'blacklist' => self::$_options['referer'], 'blacklist' => self::$options['referer'],
), ),
'target' => array( 'target' => array(
'active' => 0, 'active' => 0,
@ -170,9 +179,9 @@ class StatifyBlacklist_System extends StatifyBlacklist {
} }
// Version older than current major release. // Version older than current major release.
if ( self::VERSION_MAIN > self::$_options['version'] ) { if ( self::VERSION_MAIN > self::$options['version'] ) {
// Merge default options with current config, assuming only additive changes. // Merge default options with current config, assuming only additive changes.
$options = array_merge_recursive( self::default_options(), self::$_options ); $options = array_merge_recursive( self::default_options(), self::$options );
$options['version'] = self::VERSION_MAIN; $options['version'] = self::VERSION_MAIN;
if ( self::$multisite ) { if ( self::$multisite ) {
update_site_option( 'statify-blacklist', $options ); update_site_option( 'statify-blacklist', $options );

View File

@ -8,8 +8,10 @@
* @since 1.0.0 * @since 1.0.0
*/ */
// Quit. // Quit if accessed directly.
defined( 'ABSPATH' ) || exit; if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/** /**
* Statify Blacklist. * Statify Blacklist.
@ -26,13 +28,42 @@ class StatifyBlacklist {
*/ */
const VERSION_MAIN = 1.4; const VERSION_MAIN = 1.4;
/**
* Operation mode "normal".
*
* @var integer MODE_NORMAL
*/
const MODE_NORMAL = 0;
/**
* Operation mode "regular expression".
*
* @var integer MODE_REGEX
*/
const MODE_REGEX = 1;
/**
* Operation mode "regular expression case insensitive".
*
* @var integer MODE_REGEX_CI
*/
const MODE_REGEX_CI = 2;
/**
* Operation mode "keyword".
*
* @since 1.5.0
* @var integer MODE_KEYWORD
*/
const MODE_KEYWORD = 3;
/** /**
* Plugin options. * Plugin options.
* *
* @since 1.0.0 * @since 1.0.0
* @var array $_options * @var array $options
*/ */
public static $_options; public static $options;
/** /**
* Multisite Status. * Multisite Status.
@ -42,30 +73,12 @@ class StatifyBlacklist {
*/ */
public static $multisite; public static $multisite;
/**
* Class self initialize.
*
* @since 1.0.0
* @deprecated 1.4.2 Replaced by init().
*/
public static function instance() {
self::init();
}
/**
* Class constructor.
*
* @since 1.0.0
* @deprecated 1.4.2 Replaced by init().
*/
public function __construct() {
self::init();
}
/** /**
* Plugin initialization. * Plugin initialization.
* *
* @since 1.4.2 * @since 1.4.2
*
* @return void
*/ */
public static function init() { public static function init() {
// Skip on autosave or AJAX. // Skip on autosave or AJAX.
@ -80,41 +93,19 @@ class StatifyBlacklist {
self::update_options(); self::update_options();
// Add Filter to statify hook if enabled. // Add Filter to statify hook if enabled.
if ( 0 !== self::$_options['referer']['active'] || 0 !== self::$_options['target']['active'] || 0 !== self::$_options['ip']['active'] ) { if ( 0 !== self::$options['referer']['active'] || 0 !== self::$options['target']['active'] || 0 !== self::$options['ip']['active'] ) {
add_filter( 'statify__skip_tracking', array( 'StatifyBlacklist', 'apply_blacklist_filter' ) ); add_filter( 'statify__skip_tracking', array( 'StatifyBlacklist', 'apply_blacklist_filter' ) );
} }
// Admin only filters. // Admin only filters.
if ( is_admin() ) { if ( is_admin() ) {
// Load Textdomain (only needed for backend. StatifyBlacklist_Admin::init();
load_plugin_textdomain( 'statifyblacklist', false, STATIFYBLACKLIST_DIR . '/lang/' );
// Add actions.
add_action( 'wpmu_new_blog', array( 'StatifyBlacklist_System', 'install_site' ) );
add_action( 'delete_blog', array( 'StatifyBlacklist_System', 'uninstall_site' ) );
add_filter( 'plugin_row_meta', array( 'StatifyBlacklist_Admin', 'plugin_meta_link' ), 10, 2 );
if ( self::$multisite ) {
add_action( 'network_admin_menu', array( 'StatifyBlacklist_Admin', 'add_menu_page' ) );
add_filter(
'network_admin_plugin_action_links', array(
'StatifyBlacklist_Admin',
'plugin_actions_links',
),
10,
2
);
} else {
add_action( 'admin_menu', array( 'StatifyBlacklist_Admin', 'add_menu_page' ) );
add_filter( 'plugin_action_links', array( 'StatifyBlacklist_Admin', 'plugin_actions_links' ), 10, 2 );
}
} }
// CronJob to clean up database. // CronJob to clean up database.
if ( defined( 'DOING_CRON' ) && DOING_CRON ) { if ( defined( 'DOING_CRON' ) && DOING_CRON &&
if ( 1 === self::$_options['referer']['cron'] || 1 === self::$_options['target']['cron'] ) { ( 1 === self::$options['referer']['cron'] || 1 === self::$options['target']['cron'] ) ) {
add_action( 'statify_cleanup', array( 'StatifyBlacklist_Admin', 'cleanup_database' ) ); add_action( 'statify_cleanup', array( 'StatifyBlacklist_Admin', 'cleanup_database' ) );
}
} }
} }
@ -125,6 +116,8 @@ class StatifyBlacklist {
* @since 1.2.1 update_options($options = null) Parameter with default value introduced. * @since 1.2.1 update_options($options = null) Parameter with default value introduced.
* *
* @param array $options Optional. New options to save. * @param array $options Optional. New options to save.
*
* @return void
*/ */
public static function update_options( $options = null ) { public static function update_options( $options = null ) {
if ( self::$multisite ) { if ( self::$multisite ) {
@ -132,7 +125,7 @@ class StatifyBlacklist {
} else { } else {
$o = get_option( 'statify-blacklist' ); $o = get_option( 'statify-blacklist' );
} }
self::$_options = wp_parse_args( $o, self::default_options() ); self::$options = wp_parse_args( $o, self::default_options() );
} }
/** /**
@ -173,52 +166,72 @@ class StatifyBlacklist {
*/ */
public static function apply_blacklist_filter() { public static function apply_blacklist_filter() {
// Referer blacklist. // Referer blacklist.
if ( isset( self::$_options['referer']['active'] ) && 0 !== self::$_options['referer']['active'] ) { if ( isset( self::$options['referer']['active'] ) && 0 !== self::$options['referer']['active'] ) {
// Regular Expression filtering since 1.3.0. // Determine filter mode.
if ( isset( self::$_options['referer']['regexp'] ) && self::$_options['referer']['regexp'] > 0 ) { $mode = isset( self::$options['referer']['regexp'] ) ? intval( self::$options['referer']['regexp'] ) : 0;
// Get full referer string.
$referer = wp_get_raw_referer();
if ( ! $referer ) {
$referer = '';
}
// Merge given regular expressions into one.
$regexp = '/' . implode( '|', array_keys( self::$_options['referer']['blacklist'] ) ) . '/';
if ( 2 === self::$_options['referer']['regexp'] ) {
$regexp .= 'i';
}
// Check blacklist (no return to continue filtering #12). // Get full referer string.
if ( 1 === preg_match( $regexp, $referer ) ) { $referer = wp_get_raw_referer();
return true; if ( ! $referer ) {
} $referer = '';
} else { }
// Extract relevant domain parts.
$referer = wp_parse_url( wp_get_raw_referer() );
$referer = strtolower( ( isset( $referer['host'] ) ? $referer['host'] : '' ) );
// Get blacklist. switch ( $mode ) {
$blacklist = self::$_options['referer']['blacklist'];
// Check blacklist. // Regular Expression filtering since 1.3.0.
if ( isset( $blacklist[ $referer ] ) ) { case self::MODE_REGEX:
return true; case self::MODE_REGEX_CI:
} // Merge given regular expressions into one.
$regexp = self::regex(
array_keys( self::$options['referer']['blacklist'] ),
self::MODE_REGEX_CI === self::$options['referer']['regexp']
);
// Check blacklist (no return to continue filtering #12).
if ( 1 === preg_match( $regexp, $referer ) ) {
return true;
}
break;
// Keyword filter since 1.5.0 (#15).
case self::MODE_KEYWORD:
// Get blacklist.
$blacklist = self::$options['referer']['blacklist'];
foreach ( array_keys( $blacklist ) as $keyword ) {
if ( false !== strpos( strtolower( $referer ), strtolower( $keyword ) ) ) {
return true;
}
}
break;
// Standard domain filter.
default:
// Extract relevant domain parts.
$referer = wp_parse_url( $referer );
$referer = strtolower( ( isset( $referer['host'] ) ? $referer['host'] : '' ) );
// Get blacklist.
$blacklist = self::$options['referer']['blacklist'];
// Check blacklist.
if ( isset( $blacklist[ $referer ] ) ) {
return true;
}
} }
} }
// Target blacklist (since 1.4.0). // Target blacklist (since 1.4.0).
if ( isset( self::$_options['target']['active'] ) && 0 !== self::$_options['target']['active'] ) { if ( isset( self::$options['target']['active'] ) && 0 !== self::$options['target']['active'] ) {
// Regular Expression filtering since 1.3.0. // Regular Expression filtering since 1.3.0.
if ( isset( self::$_options['target']['regexp'] ) && 0 < self::$_options['target']['regexp'] ) { if ( isset( self::$options['target']['regexp'] ) && 0 < self::$options['target']['regexp'] ) {
// Get full referer string. // Get full referer string.
// @codingStandardsIgnoreStart The globals are checked. $target = ( isset( $_SERVER['REQUEST_URI'] ) ? filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_URL ) : '/' );
$target = ( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '/' );
// @codingStandardsIgnoreEnd
// Merge given regular expressions into one. // Merge given regular expressions into one.
$regexp = '/' . implode( '|', array_keys( self::$_options['target']['blacklist'] ) ) . '/'; $regexp = self::regex(
if ( 2 === self::$_options['target']['regexp'] ) { array_keys( self::$options['target']['blacklist'] ),
$regexp .= 'i'; self::MODE_REGEX_CI === self::$options['target']['regexp']
} );
// Check blacklist (no return to continue filtering #12). // Check blacklist (no return to continue filtering #12).
if ( 1 === preg_match( $regexp, $target ) ) { if ( 1 === preg_match( $regexp, $target ) ) {
@ -226,11 +239,9 @@ class StatifyBlacklist {
} }
} else { } else {
// Extract target page. // Extract target page.
// @codingStandardsIgnoreStart The globals are checked. $target = ( isset( $_SERVER['REQUEST_URI'] ) ? filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_URL ) : '/' );
$target = ( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '/' );
// @codingStandardsIgnoreEnd
// Get blacklist. // Get blacklist.
$blacklist = self::$_options['target']['blacklist']; $blacklist = self::$options['target']['blacklist'];
// Check blacklist. // Check blacklist.
if ( isset( $blacklist[ $target ] ) ) { if ( isset( $blacklist[ $target ] ) ) {
return true; return true;
@ -239,10 +250,10 @@ class StatifyBlacklist {
} }
// IP blacklist (since 1.4.0). // IP blacklist (since 1.4.0).
if ( isset( self::$_options['ip']['active'] ) && 0 !== self::$_options['ip']['active'] ) { if ( isset( self::$options['ip']['active'] ) && 0 !== self::$options['ip']['active'] ) {
$ip = self::get_ip(); $ip = self::get_ip();
if ( false !== ( $ip ) ) { if ( false !== ( $ip ) ) {
foreach ( self::$_options['ip']['blacklist'] as $net ) { foreach ( self::$options['ip']['blacklist'] as $net ) {
if ( self::cidr_match( $ip, $net ) ) { if ( self::cidr_match( $ip, $net ) ) {
return true; return true;
} }
@ -254,6 +265,37 @@ class StatifyBlacklist {
return null; return null;
} }
/**
* Preprocess regular expression provided by the user, i.e. add delimiters and optional ci flag.
*
* @param string|array $expression Original expression string or array of expressions.
* @param string|array $case_insensitive Make expression match case-insensitive.
*
* @return string Preprocessed expression ready for preg_match().
*/
protected static function regex( $expression, $case_insensitive ) {
$res = '/';
if ( is_string( $expression ) ) {
$res .= str_replace( '/', '\/', $expression );
} elseif ( is_array( $expression ) ) {
$res .= implode(
'|',
array_map(
function ( $e ) {
return str_replace( '/', '\/', $e );
},
$expression
)
);
}
$res .= '/';
if ( $case_insensitive ) {
$res .= 'i';
}
return $res;
}
/** /**
* Helper method to determine the client's IP address. * Helper method to determine the client's IP address.
* *
@ -277,15 +319,14 @@ class StatifyBlacklist {
'REMOTE_ADDR', 'REMOTE_ADDR',
) as $k ) as $k
) { ) {
// @codingStandardsIgnoreStart The globals are checked.
if ( isset( $_SERVER[ $k ] ) ) { if ( isset( $_SERVER[ $k ] ) ) {
// phpcs:ignore
foreach ( explode( ',', $_SERVER[ $k ] ) as $ip ) { foreach ( explode( ',', $_SERVER[ $k ] ) as $ip ) {
if ( false !== filter_var( $ip, FILTER_VALIDATE_IP ) ) { if ( false !== filter_var( $ip, FILTER_VALIDATE_IP ) ) {
return $ip; return $ip;
} }
} }
} }
// @codingStandardsIgnoreEnd
} }
return false; return false;
@ -361,6 +402,6 @@ class StatifyBlacklist {
} }
return ( 0 === substr_compare( sprintf( '%032b', ip2long( $ip ) ), sprintf( '%032b', ip2long( $base ) ), 0, $mask ) ); return ( 0 === substr_compare( sprintf( '%032b', ip2long( $ip ) ), sprintf( '%032b', ip2long( $base ) ), 0, $mask ) );
} // End if(). }
} }
} }

View File

@ -1,17 +1,7 @@
{ {
"name": "statify-blacklist", "name": "statify-blacklist",
"version": "1.4.4", "version": "1.5.0",
"description": "A blacklist extension for the famous Statify WordPress plugin", "description": "A blacklist extension for the famous Statify WordPress plugin",
"author": "Stefan Kalscheuer", "author": "Stefan Kalscheuer",
"license": "GPL-2.0+", "license": "GPL-2.0+"
"devDependencies": {
"gulp": "^3.9.1",
"gulp-clean": "^0.3.2",
"gulp-copy": "^1.0.1",
"gulp-zip": "^4.0.0",
"gulp-composer": "^0.4.4",
"gulp-phpunit": "^0.24.1",
"gulp-phpcs": "^2.1.0",
"child_process": "^1.0.2"
}
} }

View File

@ -2,23 +2,20 @@
<ruleset name="StatifyBlacklist"> <ruleset name="StatifyBlacklist">
<description>Derived from WordPress Coding Standard</description> <description>Derived from WordPress Coding Standard</description>
<arg value="psvn"/> <arg value="psv"/>
<arg name="colors"/> <arg name="colors"/>
<!-- Files to sniff --> <!-- Files to sniff -->
<file>inc</file>
<file>statify-blacklist.php</file> <file>statify-blacklist.php</file>
<file>inc</file>
<file>views</file>
<!-- Compliance with WordPress Coding Standard --> <!-- Compliance with WordPress Coding Standard -->
<config name="minimum_supported_wp_version" value="4.4"/> <config name="minimum_supported_wp_version" value="4.7"/>
<rule ref="WordPress"> <rule ref="WordPress">
<!-- The plugin uses switch_to_blog for multisite handling. -->
<exclude name="WordPress.VIP.RestrictedFunctions.switch_to_blog"/>
<exclude name="WordPress.VIP.RestrictedFunctions.switch_to_blog_switch_to_blog"/>
<!-- Direct queries used to clean up statify table. --> <!-- Direct queries used to clean up statify table. -->
<exclude name="WordPress.VIP.DirectDatabaseQuery.DirectQuery"/> <exclude name="WordPress.DB.DirectDatabaseQuery.DirectQuery"/>
<exclude name="WordPress.VIP.DirectDatabaseQuery.NoCaching"/> <exclude name="WordPress.DB.DirectDatabaseQuery.NoCaching"/>
</rule> </rule>
<!-- PHP compatibility level --> <!-- PHP compatibility level -->

View File

@ -12,6 +12,6 @@
</filter> </filter>
<logging> <logging>
<log type="coverage-clover" target="tests-clover.xml"/> <log type="coverage-clover" target="tests-clover.xml"/>
<log type="junit" target="tests-junit.xml" logIncompleteSkipped="false"/> <log type="junit" target="tests-junit.xml"/>
</logging> </logging>
</phpunit> </phpunit>

View File

@ -10,11 +10,10 @@
* Plugin Name: Statify Blacklist * Plugin Name: Statify Blacklist
* Plugin URI: https://wordpress.org/plugins/statify-blacklist/ * Plugin URI: https://wordpress.org/plugins/statify-blacklist/
* Description: Extension for the Statify plugin to add a customizable blacklists. * Description: Extension for the Statify plugin to add a customizable blacklists.
* Version: 1.4.4 * Version: 1.5.0
* Author: Stefan Kalscheuer (@stklcode) * Author: Stefan Kalscheuer (@stklcode)
* Author URI: https://www.stklcode.de * Author URI: https://www.stklcode.de
* Text Domain: statify-blacklist * Text Domain: statify-blacklist
* Domain Path: /lang
* License: GPLv2 or later * License: GPLv2 or later
* *
* Statify Blacklist is free software: you can redistribute it and/or modify * Statify Blacklist is free software: you can redistribute it and/or modify
@ -28,34 +27,42 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Statify Blacklist. If not, see http://www.gnu.org/licenses/gpl-2.0.html. * along with Statify Blacklist. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
*/ */
// Quit. // Quit if accessed directly.
defined( 'ABSPATH' ) || exit; if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Constants. // Constants.
define( 'STATIFYBLACKLIST_FILE', __FILE__ ); define( 'STATIFYBLACKLIST_FILE', __FILE__ );
define( 'STATIFYBLACKLIST_DIR', dirname( __FILE__ ) ); define( 'STATIFYBLACKLIST_DIR', dirname( __FILE__ ) );
define( 'STATIFYBLACKLIST_BASE', plugin_basename( __FILE__ ) ); define( 'STATIFYBLACKLIST_BASE', plugin_basename( __FILE__ ) );
// System Hooks. // Check for compatibility.
add_action( 'plugins_loaded', array( 'StatifyBlacklist', 'init' ) ); if ( statify_blacklist_compatibility_check() ) {
// System Hooks.
add_action( 'plugins_loaded', array( 'StatifyBlacklist', 'init' ) );
register_activation_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'install' ) ); register_activation_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'install' ) );
register_uninstall_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'uninstall' ) ); register_uninstall_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'uninstall' ) );
// Upgrade hook. // Upgrade hook.
register_activation_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'upgrade' ) ); register_activation_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'upgrade' ) );
// Autoload. // Autoload.
spl_autoload_register( 'statify_blacklist_autoload' ); spl_autoload_register( 'statify_blacklist_autoload' );
} else {
// Disable plugin, if active.
add_action( 'admin_init', 'statify_blacklist_disable' );
}
/** /**
* Autoloader for StatifyBlacklist classes. * Autoloader for StatifyBlacklist classes.
* *
* @param string $class Name of the class to load. * @param string $class Name of the class to load.
* *
* @since 1.0.0 * @since 1.0.0
*/ */
@ -74,3 +81,59 @@ function statify_blacklist_autoload( $class ) {
); );
} }
} }
/**
* Check for compatibility with PHP and WP version.
*
* @since 1.5.0
*
* @return boolean Whether minimum WP and PHP versions are met.
*/
function statify_blacklist_compatibility_check() {
return version_compare( $GLOBALS['wp_version'], '4.7', '>=' ) &&
version_compare( phpversion(), '5.5', '>=' );
}
/**
* Disable plugin if active and incompatible.
*
* @since 1.5.0
*
* @return void
*/
function statify_blacklist_disable() {
if ( is_plugin_active( STATIFYBLACKLIST_BASE ) ) {
deactivate_plugins( STATIFYBLACKLIST_BASE );
add_action( 'admin_notices', 'statify_blacklist_disabled_notice' );
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( isset( $_GET['activate'] ) ) {
unset( $_GET['activate'] );
}
// phpcs:enable
}
}
/**
* Admin notification for unmet requirements.
*
* @since 1.5.0
*
* @return void
*/
function statify_blacklist_disabled_notice() {
echo '<div class="notice notice-error is-dismissible"><p><strong>';
printf(
/* translators: minimum version numbers for WordPress and PHP inserted at placeholders */
esc_html__( 'Statify Blacklist requires at least WordPress %1$s and PHP %2$s.', 'statify-blacklist' ),
'4.7',
'5.5'
);
echo '<br>';
printf(
/* translators: current version numbers for WordPress and PHP inserted at placeholders */
esc_html__( 'Your site is running WordPress %1$s on PHP %2$s, thus the plugin has been disabled.', 'statify-blacklist' ),
esc_html( $GLOBALS['wp_version'] ),
esc_html( phpversion() )
);
echo '</strong></p></div>';
}

View File

@ -20,17 +20,17 @@ const ABSPATH = false;
/** /**
* The StatifyBlacklist base class. * The StatifyBlacklist base class.
*/ */
require_once( 'inc/class-statifyblacklist.php' ); require_once __DIR__ . '/../inc/class-statifyblacklist.php';
/** /**
* The StatifyBlacklist system class. * The StatifyBlacklist system class.
*/ */
require_once( 'inc/class-statifyblacklist-system.php' ); require_once __DIR__ . '/../inc/class-statifyblacklist-system.php';
/** /**
* The StatifyBlacklist admin class. * The StatifyBlacklist admin class.
*/ */
require_once( 'inc/class-statifyblacklist-admin.php' ); require_once __DIR__ . '/../inc/class-statifyblacklist-admin.php';
/** /**
* Class StatifyBlacklistTest. * Class StatifyBlacklistTest.
@ -43,10 +43,12 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
/** /**
* Test simple referer filter. * Test simple referer filter.
*
* @return void
*/ */
public function test_referer_filter() { public function test_referer_filter() {
// Prepare Options: 2 blacklisted domains, disabled. // Prepare Options: 2 blacklisted domains, disabled.
StatifyBlacklist::$_options = array( StatifyBlacklist::$options = array(
'referer' => array( 'referer' => array(
'active' => 0, 'active' => 0,
'cron' => 0, 'cron' => 0,
@ -86,7 +88,7 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() ); $this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Activate filter and run tests again. // Activate filter and run tests again.
StatifyBlacklist::$_options['referer']['active'] = 1; StatifyBlacklist::$options['referer']['active'] = 1;
unset( $_SERVER['HTTP_REFERER'] ); unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() ); $this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
@ -103,10 +105,12 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
/** /**
* Test referer filter using regular expressions. * Test referer filter using regular expressions.
*
* @return void
*/ */
public function testRefererRegexFilter() { public function test_referer_regex_filter() {
// Prepare Options: 2 regular expressions. // Prepare Options: 2 regular expressions.
StatifyBlacklist::$_options = array( StatifyBlacklist::$options = array(
'referer' => array( 'referer' => array(
'active' => 1, 'active' => 1,
'cron' => 0, 'cron' => 0,
@ -147,19 +151,74 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// Matching both. // Matching both.
$_SERVER['HTTP_REFERER'] = 'http://example.net/test/me'; $_SERVER['HTTP_REFERER'] = 'http://example.net/test/me';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() ); $this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Mathinc with wrong case. // Matching with wrong case.
$_SERVER['HTTP_REFERER'] = 'http://eXaMpLe.NeT/tEsT/mE'; $_SERVER['HTTP_REFERER'] = 'http://eXaMpLe.NeT/tEsT/mE';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() ); $this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Set RegExp filter to case insensitive. // Set RegExp filter to case insensitive.
StatifyBlacklist::$_options['referer']['regexp'] = 2; StatifyBlacklist::$options['referer']['regexp'] = 2;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
}
/**
* Test referer filter using keywords.
*
* @return void
*/
public function test_referer_keyword_filter() {
// Prepare Options: 2 regular expressions.
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 1,
'cron' => 0,
'regexp' => StatifyBlacklist::MODE_KEYWORD,
'blacklist' => array(
'example' => 0,
'test' => 1,
),
),
'target' => array(
'active' => 0,
'cron' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'ip' => array(
'active' => 0,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
// No multisite.
StatifyBlacklist::$multisite = false;
// No referer.
unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-blacklisted referer.
$_SERVER['HTTP_REFERER'] = 'http://not.evil';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer.
$_SERVER['HTTP_REFERER'] = 'http://example.com';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer with path.
$_SERVER['HTTP_REFERER'] = 'http://foobar.net/test/me';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Matching both.
$_SERVER['HTTP_REFERER'] = 'http://example.net/test/me';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Matching with wrong case.
$_SERVER['HTTP_REFERER'] = 'http://eXaMpLe.NeT/tEsT/mE';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() ); $this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
} }
/** /**
* Test the upgrade methodology for configuration options. * Test the upgrade methodology for configuration options.
*
* @return void
*/ */
public function testUpgrade() { public function test_upgrade() {
// Create configuration of version 1.3. // Create configuration of version 1.3.
$options13 = array( $options13 = array(
'active_referer' => 1, 'active_referer' => 1,
@ -179,138 +238,141 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
StatifyBlacklist_System::upgrade(); StatifyBlacklist_System::upgrade();
// Retrieve updated options. // Retrieve updated options.
$optionsUpdated = get_option( 'statify-blacklist' ); $options_updated = get_option( 'statify-blacklist' );
// Verify size against default options (no junk left). // Verify size against default options (no junk left).
$this->assertEquals( 4, count( $optionsUpdated ) ); $this->assertEquals( 4, count( $options_updated ) );
$this->assertEquals( 4, count( $optionsUpdated['referer'] ) ); $this->assertEquals( 4, count( $options_updated['referer'] ) );
$this->assertEquals( 4, count( $optionsUpdated['target'] ) ); $this->assertEquals( 4, count( $options_updated['target'] ) );
$this->assertEquals( 2, count( $optionsUpdated['ip'] ) ); $this->assertEquals( 2, count( $options_updated['ip'] ) );
// Verify that original attributes are unchanged. // Verify that original attributes are unchanged.
$this->assertEquals( $options13['active_referer'], $optionsUpdated['referer']['active'] ); $this->assertEquals( $options13['active_referer'], $options_updated['referer']['active'] );
$this->assertEquals( $options13['cron_referer'], $optionsUpdated['referer']['cron'] ); $this->assertEquals( $options13['cron_referer'], $options_updated['referer']['cron'] );
$this->assertEquals( $options13['referer'], $optionsUpdated['referer']['blacklist'] ); $this->assertEquals( $options13['referer'], $options_updated['referer']['blacklist'] );
$this->assertEquals( $options13['referer_regexp'], $optionsUpdated['referer']['regexp'] ); $this->assertEquals( $options13['referer_regexp'], $options_updated['referer']['regexp'] );
// Verify that new attributes are present in config and filled with default values (disabled, empty). // Verify that new attributes are present in config and filled with default values (disabled, empty).
$this->assertEquals( 0, $optionsUpdated['target']['active'] ); $this->assertEquals( 0, $options_updated['target']['active'] );
$this->assertEquals( 0, $optionsUpdated['target']['cron'] ); $this->assertEquals( 0, $options_updated['target']['cron'] );
$this->assertEquals( 0, $optionsUpdated['target']['regexp'] ); $this->assertEquals( 0, $options_updated['target']['regexp'] );
$this->assertEquals( array(), $optionsUpdated['target']['blacklist'] ); $this->assertEquals( array(), $options_updated['target']['blacklist'] );
$this->assertEquals( 0, $optionsUpdated['ip']['active'] ); $this->assertEquals( 0, $options_updated['ip']['active'] );
$this->assertEquals( array(), $optionsUpdated['ip']['blacklist'] ); $this->assertEquals( array(), $options_updated['ip']['blacklist'] );
// Verify that version number has changed to current release. // Verify that version number has changed to current release.
$this->assertEquals( StatifyBlacklist::VERSION_MAIN, $optionsUpdated['version'] ); $this->assertEquals( StatifyBlacklist::VERSION_MAIN, $options_updated['version'] );
} }
/** /**
* Test CIDR address matching for IP filter (#7) * Test CIDR address matching for IP filter (#7).
*
* @return void
*/ */
public function testCidrMatch() { public function test_cidr_match() {
// IPv4 tests. // IPv4 tests.
$this->assertTrue( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '127.0.0.1', '127.0.0.1' ) ) ); $this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '127.0.0.1', '127.0.0.1' ) ) );
$this->assertTrue( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '127.0.0.1', '127.0.0.1/32' ) ) ); $this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '127.0.0.1', '127.0.0.1/32' ) ) );
$this->assertFalse( $this->assertFalse(
invokeStatic( invoke_static(
StatifyBlacklist::class, 'cidr_match', array( StatifyBlacklist::class,
'127.0.0.1', 'cidr_match',
'127.0.0.1/33', array( '127.0.0.1', '127.0.0.1/33' )
)
) )
); );
$this->assertFalse( $this->assertFalse(
invokeStatic( invoke_static(
StatifyBlacklist::class, 'cidr_match', array( StatifyBlacklist::class,
'127.0.0.1', 'cidr_match',
'127.0.0.1/-1', array( '127.0.0.1', '127.0.0.1/-1' )
)
) )
); );
$this->assertTrue( $this->assertTrue(
invokeStatic( invoke_static(
StatifyBlacklist::class, 'cidr_match', array( StatifyBlacklist::class,
'192.0.2.123', 'cidr_match',
'192.0.2.0/24', array( '192.0.2.123', '192.0.2.0/24' )
)
) )
); );
$this->assertFalse( $this->assertFalse(
invokeStatic( invoke_static(
StatifyBlacklist::class, 'cidr_match', array( StatifyBlacklist::class,
'192.0.3.123', 'cidr_match',
'192.0.2.0/24', array( '192.0.3.123', '192.0.2.0/24' )
)
) )
); );
$this->assertTrue( $this->assertTrue(
invokeStatic( invoke_static(
StatifyBlacklist::class, 'cidr_match', array( StatifyBlacklist::class,
'192.0.2.123', 'cidr_match',
'192.0.2.120/29', array( '192.0.2.123', '192.0.2.120/29' )
)
) )
); );
$this->assertFalse( $this->assertFalse(
invokeStatic( invoke_static(
StatifyBlacklist::class, 'cidr_match', array( StatifyBlacklist::class,
'192.0.2.128', 'cidr_match',
'192.0.2.120/29', array( '192.0.2.128', '192.0.2.120/29' )
)
) )
); );
$this->assertTrue( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '10.11.12.13', '10.0.0.0/8' ) ) ); $this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '10.11.12.13', '10.0.0.0/8' ) ) );
$this->assertFalse( $this->assertFalse(
invokeStatic( invoke_static(
StatifyBlacklist::class, 'cidr_match', array( StatifyBlacklist::class,
'10.11.12.345', 'cidr_match',
'10.0.0.0/8', array( '10.11.12.345', '10.0.0.0/8' )
)
) )
); );
// IPv6 tests. // IPv6 tests.
$this->assertTrue( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1' ) ) ); $this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1' ) ) );
$this->assertTrue( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/128' ) ) ); $this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/128' ) ) );
$this->assertFalse( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/129' ) ) ); $this->assertFalse( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/129' ) ) );
$this->assertFalse( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/-1' ) ) ); $this->assertFalse( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/-1' ) ) );
$this->assertTrue( $this->assertTrue(
invokeStatic( invoke_static(
StatifyBlacklist::class, 'cidr_match', array( StatifyBlacklist::class,
'2001:db8:a0b:12f0:1:2:3:4', 'cidr_match',
'2001:db8:a0b:12f0::1/64 ', array( '2001:db8:a0b:12f0:1:2:3:4', '2001:db8:a0b:12f0::1/64 ' )
)
) )
); );
$this->assertTrue( $this->assertTrue(
invokeStatic( invoke_static(
StatifyBlacklist::class, 'cidr_match', array( StatifyBlacklist::class,
'2001:db8:a0b:12f0::123:456', 'cidr_match',
'2001:db8:a0b:12f0::1/96 ', array( '2001:db8:a0b:12f0::123:456', '2001:db8:a0b:12f0::1/96 ' )
)
) )
); );
$this->assertFalse( $this->assertFalse(
invokeStatic( invoke_static(
StatifyBlacklist::class, 'cidr_match', array( StatifyBlacklist::class,
'2001:db8:a0b:12f0::1:132:465', 'cidr_match',
'2001:db8:a0b:12f0::1/96 ', array( '2001:db8:a0b:12f0::1:132:465', '2001:db8:a0b:12f0::1/96 ' )
)
) )
); );
} }
/** /**
* Test sanitization of IP addresses * Test sanitization of IP addresses.
*
* @return void
*/ */
public function testSanitizeIPs() { public function test_sanitize_ips() {
// IPv4 tests. // IPv4 tests.
$valid = array( '192.0.2.123', '192.0.2.123/32', '192.0.2.0/24', '192.0.2.128/25' ); $valid = array( '192.0.2.123', '192.0.2.123/32', '192.0.2.0/24', '192.0.2.128/25' );
$invalid = array( '12.34.56.789', '192.0.2.123/33', '192.0.2.123/-1' ); $invalid = array( '12.34.56.789', '192.0.2.123/33', '192.0.2.123/-1' );
$result = invokeStatic( StatifyBlacklist_Admin::class, 'sanitizeIPs', array( array_merge( $valid, $invalid ) ) ); $result = invoke_static( StatifyBlacklist_Admin::class, 'sanitize_ips', array( array_merge( $valid, $invalid ) ) );
$this->assertNotFalse( $result ); $this->assertNotFalse( $result );
$this->assertInternalType( 'array', $result );
/*
* Unfortunately this is necessary as long as we run PHP 5 tests, because "assertInternalType" is deprecated
* as of PHPUnit 8, but "assertIsArray" has been introduces in PHPUnit 7.5 which requires PHP >= 7.1.
*/
if ( method_exists( $this, 'assertIsArray' ) ) {
$this->assertIsArray( $result );
} else {
$this->assertInternalType( 'array', $result );
}
$this->assertEquals( $valid, $result ); $this->assertEquals( $valid, $result );
// IPv6 tests. // IPv6 tests.
@ -327,28 +389,34 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'2001:db8:a0b:12f0::/129', '2001:db8:a0b:12f0::/129',
'1:2:3:4:5:6:7:8:9', '1:2:3:4:5:6:7:8:9',
); );
$result = invokeStatic( StatifyBlacklist_Admin::class, 'sanitizeIPs', array( array_merge( $valid, $invalid ) ) ); $result = invoke_static( StatifyBlacklist_Admin::class, 'sanitize_ips', array( array_merge( $valid, $invalid ) ) );
$this->assertNotFalse( $result ); $this->assertNotFalse( $result );
$this->assertInternalType( 'array', $result ); if ( method_exists( $this, 'assertIsArray' ) ) {
$this->assertIsArray( $result );
} else {
$this->assertInternalType( 'array', $result );
}
$this->assertEquals( $valid, $result ); $this->assertEquals( $valid, $result );
} }
/** /**
* Test IP filter (#7). * Test IP filter (#7).
*
* @return void
*/ */
public function testIPFilter() { public function test_ip_filter() {
// Prepare Options: 2 blacklisted IPs, disabled. // Prepare Options: 2 blacklisted IPs, disabled.
StatifyBlacklist::$_options = array( StatifyBlacklist::$options = array(
'referer' => array( 'referer' => array(
'active' => 0, 'active' => 0,
'cron' => 0, 'cron' => 0,
'regexp' => 0, 'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(), 'blacklist' => array(),
), ),
'target' => array( 'target' => array(
'active' => 0, 'active' => 0,
'cron' => 0, 'cron' => 0,
'regexp' => 0, 'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(), 'blacklist' => array(),
), ),
'ip' => array( 'ip' => array(
@ -368,7 +436,7 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
$_SERVER['REMOTE_ADDR'] = '192.0.2.123'; $_SERVER['REMOTE_ADDR'] = '192.0.2.123';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() ); $this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Activate filter. // Activate filter.
StatifyBlacklist::$_options['ip']['active'] = 1; StatifyBlacklist::$options['ip']['active'] = 1;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() ); $this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Try matching v6 address. // Try matching v6 address.
$_SERVER['REMOTE_ADDR'] = '2001:db8:a0b:12f0::1'; $_SERVER['REMOTE_ADDR'] = '2001:db8:a0b:12f0::1';
@ -379,11 +447,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
$_SERVER['REMOTE_ADDR'] = '2001:db8:a0b:12f0::2'; $_SERVER['REMOTE_ADDR'] = '2001:db8:a0b:12f0::2';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() ); $this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Subnet matching. // Subnet matching.
StatifyBlacklist::$_options['ip']['blacklist'] = array( StatifyBlacklist::$options['ip']['blacklist'] = array(
'192.0.2.0/25', '192.0.2.0/25',
'2001:db8:a0b:12f0::/96', '2001:db8:a0b:12f0::/96',
); );
$_SERVER['REMOTE_ADDR'] = '192.0.2.123'; $_SERVER['REMOTE_ADDR'] = '192.0.2.123';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() ); $this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['REMOTE_ADDR'] = '192.0.2.234'; $_SERVER['REMOTE_ADDR'] = '192.0.2.234';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() ); $this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
@ -405,20 +473,22 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
/** /**
* Test simple target filter. * Test simple target filter.
*
* @return void
*/ */
public function testTargetFilter() { public function test_target_filter() {
// Prepare Options: 2 blacklisted domains, disabled. // Prepare Options: 2 blacklisted domains, disabled.
StatifyBlacklist::$_options = array( StatifyBlacklist::$options = array(
'referer' => array( 'referer' => array(
'active' => 0, 'active' => 0,
'cron' => 0, 'cron' => 0,
'regexp' => 0, 'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(), 'blacklist' => array(),
), ),
'target' => array( 'target' => array(
'active' => 0, 'active' => 0,
'cron' => 0, 'cron' => 0,
'regexp' => 0, 'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array( 'blacklist' => array(
'/excluded/page/' => 0, '/excluded/page/' => 0,
'/?page_id=3' => 1, '/?page_id=3' => 1,
@ -451,7 +521,7 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() ); $this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Activate filter and run tests again. // Activate filter and run tests again.
StatifyBlacklist::$_options['target']['active'] = 1; StatifyBlacklist::$options['target']['active'] = 1;
unset( $_SERVER['REQUEST_URI'] ); unset( $_SERVER['REQUEST_URI'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() ); $this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
@ -483,11 +553,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
*/ */
public function test_combined_filters() { public function test_combined_filters() {
// Prepare Options: simple referer + simple target + ip. // Prepare Options: simple referer + simple target + ip.
StatifyBlacklist::$_options = array( StatifyBlacklist::$options = array(
'referer' => array( 'referer' => array(
'active' => 1, 'active' => 1,
'cron' => 0, 'cron' => 0,
'regexp' => 0, 'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array( 'blacklist' => array(
'example.com' => 0, 'example.com' => 0,
), ),
@ -495,15 +565,15 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'target' => array( 'target' => array(
'active' => 1, 'active' => 1,
'cron' => 0, 'cron' => 0,
'regexp' => 0, 'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array( 'blacklist' => array(
'/excluded/page/' => 0 '/excluded/page/' => 0,
), ),
), ),
'ip' => array( 'ip' => array(
'active' => 1, 'active' => 1,
'blacklist' => array( 'blacklist' => array(
'192.0.2.123' '192.0.2.123',
), ),
), ),
'version' => StatifyBlacklist::VERSION_MAIN, 'version' => StatifyBlacklist::VERSION_MAIN,
@ -514,8 +584,8 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// No match. // No match.
$_SERVER['HTTP_REFERER'] = 'https://example.net'; $_SERVER['HTTP_REFERER'] = 'https://example.net';
$_SERVER['REQUEST_URI'] = '/normal/page/'; $_SERVER['REQUEST_URI'] = '/normal/page/';
$_SERVER['REMOTE_ADDR'] = '192.0.2.234'; $_SERVER['REMOTE_ADDR'] = '192.0.2.234';
unset( $_SERVER['HTTP_X_FORWARDED_FOR'] ); unset( $_SERVER['HTTP_X_FORWARDED_FOR'] );
unset( $_SERVER['HTTP_X_REAL_IP'] ); unset( $_SERVER['HTTP_X_REAL_IP'] );
@ -525,7 +595,7 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// Matching target. // Matching target.
$_SERVER['HTTP_REFERER'] = 'https://example.net'; $_SERVER['HTTP_REFERER'] = 'https://example.net';
$_SERVER['REQUEST_URI'] = '/excluded/page/'; $_SERVER['REQUEST_URI'] = '/excluded/page/';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() ); $this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Matching IP. // Matching IP.
@ -535,16 +605,21 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
$_SERVER['REMOTE_ADDR'] = '192.0.2.234'; $_SERVER['REMOTE_ADDR'] = '192.0.2.234';
// Same for RegExp filters. // Same for RegExp filters.
StatifyBlacklist::$_options['referer']['regexp'] = 1; StatifyBlacklist::$options['referer']['regexp'] = StatifyBlacklist::MODE_REGEX;
StatifyBlacklist::$_options['referer']['blacklist'] = array( 'example\.com' => 0 ); StatifyBlacklist::$options['referer']['blacklist'] = array( 'example\.com' => 0 );
StatifyBlacklist::$_options['target']['regexp'] = 1; StatifyBlacklist::$options['target']['regexp'] = StatifyBlacklist::MODE_REGEX;
StatifyBlacklist::$_options['target']['blacklist'] = array( '\/excluded\/.*' => 0 ); StatifyBlacklist::$options['target']['blacklist'] = array( '/excluded/.*' => 0 );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() ); $this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['HTTP_REFERER'] = 'https://example.com'; $_SERVER['HTTP_REFERER'] = 'https://example.com';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() ); $this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Check case-insensitive match.
$_SERVER['HTTP_REFERER'] = 'https://eXaMpLe.com';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
StatifyBlacklist::$options['referer']['regexp'] = StatifyBlacklist::MODE_REGEX_CI;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['HTTP_REFERER'] = 'https://example.net'; $_SERVER['HTTP_REFERER'] = 'https://example.net';
$_SERVER['REQUEST_URI'] = '/excluded/page/'; $_SERVER['REQUEST_URI'] = '/excluded/page/';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() ); $this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['REQUEST_URI'] = '/normal/page/'; $_SERVER['REQUEST_URI'] = '/normal/page/';
$_SERVER['REMOTE_ADDR'] = '192.0.2.123'; $_SERVER['REMOTE_ADDR'] = '192.0.2.123';
@ -556,9 +631,9 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
/** @ignore */ /** @ignore */
function invokeStatic( $class, $methodName, $parameters = array() ) { function invoke_static( $class, $method_name, $parameters = array() ) {
$reflection = new \ReflectionClass( $class ); $reflection = new \ReflectionClass( $class );
$method = $reflection->getMethod( $methodName ); $method = $reflection->getMethod( $method_name );
$method->setAccessible( true ); $method->setAccessible( true );
return $method->invokeArgs( null, $parameters ); return $method->invokeArgs( null, $parameters );

View File

@ -9,6 +9,8 @@
* @since 1.0.0 * @since 1.0.0
*/ */
// phpcs:disable WordPress.WhiteSpace.PrecisionAlignment.Found
// Quit. // Quit.
defined( 'ABSPATH' ) || exit; defined( 'ABSPATH' ) || exit;
@ -19,7 +21,7 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
// Check user capabilities. // Check user capabilities.
if ( ! current_user_can( 'manage_options' ) ) { if ( ! current_user_can( 'manage_options' ) ) {
die( __( 'Are you sure you want to do this?' ) ); die( esc_html__( 'Are you sure you want to do this?' ) );
} }
if ( ! empty( $_POST['cleanUp'] ) ) { if ( ! empty( $_POST['cleanUp'] ) ) {
@ -27,24 +29,63 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
StatifyBlacklist_Admin::cleanup_database(); StatifyBlacklist_Admin::cleanup_database();
} else { } else {
// Extract referer array. // Extract referer array.
if ( empty( trim( $_POST['statifyblacklist']['referer']['blacklist'] ) ) ) { if ( isset( $_POST['statifyblacklist']['referer']['blacklist'] ) ) {
$referer_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['referer']['blacklist'] ) );
}
if ( empty( trim( $referer_str ) ) ) {
$referer = array(); $referer = array();
} else { } else {
$referer = explode( "\r\n", $_POST['statifyblacklist']['referer']['blacklist'] ); $referer = array_filter(
array_map(
function ( $a ) {
return trim( $a );
},
explode( "\r\n", $referer_str )
),
function ( $a ) {
return ! empty( $a );
}
);
} }
// Extract target array. // Extract target array.
if ( empty( trim( $_POST['statifyblacklist']['target']['blacklist'] ) ) ) { if ( isset( $_POST['statifyblacklist']['target']['blacklist'] ) ) {
$target_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['target']['blacklist'] ) );
}
if ( empty( trim( $target_str ) ) ) {
$target = array(); $target = array();
} else { } else {
$target = explode( "\r\n", str_replace( '\\\\', '\\', $_POST['statifyblacklist']['target']['blacklist'] ) ); $target = array_filter(
array_map(
function ( $a ) {
return trim( $a );
},
explode( "\r\n", str_replace( '\\\\', '\\', $target_str ) )
),
function ( $a ) {
return ! empty( $a );
}
);
} }
// Extract IP array. // Extract IP array.
if ( empty( trim( $_POST['statifyblacklist']['ip']['blacklist'] ) ) ) { if ( isset( $_POST['statifyblacklist']['ip']['blacklist'] ) ) {
$ip_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['ip']['blacklist'] ) );
}
if ( empty( trim( $ip_str ) ) ) {
$ip = array(); $ip = array();
} else { } else {
$ip = explode( "\r\n", $_POST['statifyblacklist']['ip']['blacklist'] ); $ip = array_filter(
array_map(
function ( $a ) {
return trim( $a );
},
explode( "\r\n", $ip_str )
),
function ( $a ) {
return ! empty( $a );
}
);
} }
// Update options (data will be sanitized). // Update options (data will be sanitized).
@ -79,21 +120,33 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
// Generate messages. // Generate messages.
if ( false !== $statifyblacklist_update_result ) { if ( false !== $statifyblacklist_update_result ) {
if ( array_key_exists( 'referer', $statifyblacklist_update_result ) ) { $statifyblacklist_post_warning = array();
$statifyblacklist_post_warning = __( 'Some URLs are invalid and have been sanitized.', 'statify-blacklist' ); if ( ! empty( $statifyblacklist_update_result['referer']['diff'] ) ) {
} elseif ( array_key_exists( 'ip', $statifyblacklist_update_result ) ) { $statifyblacklist_post_warning[] = __( 'Some URLs are invalid and have been sanitized.', 'statify-blacklist' );
}
if ( ! empty( $statifyblacklist_update_result['referer']['invalid'] ) ) {
$statifyblacklist_post_warning[] = __( 'Some regular expressions are invalid:', 'statify-blacklist' ) . '<br>' . implode( '<br>', $statifyblacklist_update_result['referer']['invalid'] );
}
if ( ! empty( $statifyblacklist_update_result['ip']['diff'] ) ) {
// translators: List of invalid IP addresses (comma separated). // translators: List of invalid IP addresses (comma separated).
$statifyblacklist_post_warning = sprintf( __( 'Some IPs are invalid : %s', 'statify-blacklist' ), implode( ', ', $statifyblacklist_update_result['ip'] ) ); $statifyblacklist_post_warning[] = sprintf( __( 'Some IPs are invalid: %s', 'statify-blacklist' ), implode( ', ', $statifyblacklist_update_result['ip']['diff'] ) );
} }
} else { } else {
$statifyblacklist_post_success = __( 'Settings updated successfully.', 'statify-blacklist' ); $statifyblacklist_post_success = __( 'Settings updated successfully.', 'statify-blacklist' );
} }
} // End if(). }
} // End if(). }
/*
* Disable some code style rules that are impractical for textarea content:
*
* phpcs:disable Squiz.PHP.EmbeddedPhp.ContentBeforeOpen
* phpcs:disable Squiz.PHP.EmbeddedPhp.ContentAfterEnd
*/
?> ?>
<div class="wrap"> <div class="wrap">
<h1><?php esc_html_e( 'Statify Blacklist', 'statify-blacklist' ) ?></h1> <h1><?php esc_html_e( 'Statify Blacklist', 'statify-blacklist' ); ?></h1>
<?php <?php
if ( is_plugin_inactive( 'statify/statify.php' ) ) { if ( is_plugin_inactive( 'statify/statify.php' ) ) {
print '<div class="notice notice-warning"><p>'; print '<div class="notice notice-warning"><p>';
@ -101,11 +154,12 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
print '</p></div>'; print '</p></div>';
} }
if ( isset( $statifyblacklist_post_warning ) ) { if ( isset( $statifyblacklist_post_warning ) ) {
print '<div class="notice notice-warning"><p>' . foreach ( $statifyblacklist_post_warning as $w ) {
esc_html( $statifyblacklist_post_warning ); print '<div class="notice notice-warning"><p>' .
print '<br/>'; wp_kses( $w, array( 'br' => array() ) ) .
esc_html_e( 'Settings have not been saved yet.', 'statify-blacklist' ); '</p></div>';
print '</p></div>'; }
print '<div class="notice notice-warning"><p>' . esc_html__( 'Settings have not been saved yet.', 'statify-blacklist' ) . '</p></div>';
} }
if ( isset( $statifyblacklist_post_success ) ) { if ( isset( $statifyblacklist_post_success ) ) {
print '<div class="notice notice-success"><p>' . print '<div class="notice notice-success"><p>' .
@ -114,179 +168,223 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
} }
?> ?>
<form action="" method="post" id="statify-blacklist-settings"> <form action="" method="post" id="statify-blacklist-settings">
<fieldset>
<h2><?php esc_html_e( 'Referer blacklist', 'statify-blacklist' ); ?></h2>
<ul style="list-style: none;">
<li>
<label for="statify-blacklist_active_referer">
<input type="checkbox" name="statifyblacklist[referer][active]"
id="statifyblacklist_active_referer"
value="1" <?php checked( StatifyBlacklist::$_options['referer']['active'], 1 ); ?> />
<?php esc_html_e( 'Activate live fiter', 'statify-blacklist' ); ?>
</label>
</li>
<li>
<label for="statify-blacklist_cron_referer">
<input type="checkbox" name="statifyblacklist[referer][cron]" id="statifyblacklist_cron_referer"
value="1" <?php checked( StatifyBlacklist::$_options['referer']['cron'], 1 ); ?> />
<?php esc_html_e( 'CronJob execution', 'statify-blacklist' ); ?>
<small>(<?php esc_html_e( 'Clean database periodically in background', 'statify-blacklist' ); ?>
)
</small>
</label>
</li>
<li>
<label for="statify-blacklist_referer_regexp">
<?php esc_html_e( 'Use regular expressions', 'statify-blacklist' ); ?>:
<br />
<select name="statifyblacklist[referer][regexp]" id="statifyblacklist_referer_regexp">
<option value="0" <?php selected( StatifyBlacklist::$_options['referer']['regexp'], 0 ); ?>>
<?php esc_html_e( 'Disabled', 'statify-blacklist' ); ?>
</option>
<option value="1" <?php selected( StatifyBlacklist::$_options['referer']['regexp'], 1 ); ?>>
<?php esc_html_e( 'Case-sensitive', 'statify-blacklist' ); ?>
</option>
<option value="2" <?php selected( StatifyBlacklist::$_options['referer']['regexp'], 2 ); ?>>
<?php esc_html_e( 'Case-insensitive', 'statify-blacklist' ); ?>
</option>
</select>
<small>
(<?php esc_html_e( 'Performance slower than standard filter. Recommended for cron or manual execition only.', 'statify-blacklist' ); ?>
)
</small>
</label>
</li>
<li>
<label for="statify-blacklist_referer">
<?php esc_html_e( 'Referer blacklist', 'statify-blacklist' ); ?>:<br />
<textarea cols="40" rows="5" name="statifyblacklist[referer][blacklist]" id="statify-blacklist_referer"><?php
if ( isset( $statifyblacklist_update_result['referer'] ) ) {
print esc_html( implode( "\r\n", array_keys( $statifyblacklist_update_result['referer'] ) ) );
} else {
print esc_html( implode( "\r\n", array_keys( StatifyBlacklist::$_options['referer']['blacklist'] ) ) );
}
?></textarea>
<br />
<small>
(<?php esc_html_e( 'Add one domain (without subdomains) each line, e.g. example.com', 'statify-blacklist' ); ?>
)
</small>
</label>
</li>
</ul>
</fieldset>
<fieldset>
<h2><?php esc_html_e( 'Target blacklist', 'statify-blacklist' ); ?></h2>
<ul style="list-style: none;">
<li>
<label for="statify-blacklist_active_target">
<input type="checkbox" name="statifyblacklist[target][active]"
id="statifyblacklist_active_target"
value="1" <?php checked( StatifyBlacklist::$_options['target']['active'], 1 ); ?> />
<?php esc_html_e( 'Activate live fiter', 'statify-blacklist' ); ?>
</label>
</li>
<li>
<label for="statify-blacklist_cron_target">
<input type="checkbox" name="statifyblacklist[target][cron]" id="statifyblacklist_cron_target"
value="1" <?php checked( StatifyBlacklist::$_options['target']['cron'], 1 ); ?> />
<?php esc_html_e( 'CronJob execution', 'statify-blacklist' ); ?>
<small>(<?php esc_html_e( 'Clean database periodically in background', 'statify-blacklist' ); ?>
)
</small>
</label>
</li>
<li>
<label for="statify-blacklist_target_regexp">
<?php esc_html_e( 'Use regular expressions', 'statify-blacklist' ); ?>:
<br />
<select name="statifyblacklist[target][regexp]" id="statifyblacklist_target_regexp">
<option value="0" <?php selected( StatifyBlacklist::$_options['target']['regexp'], 0 ); ?>>
<?php esc_html_e( 'Disabled', 'statify-blacklist' ); ?>
</option>
<option value="1" <?php selected( StatifyBlacklist::$_options['target']['regexp'], 1 ); ?>>
<?php esc_html_e( 'Case-sensitive', 'statify-blacklist' ); ?>
</option>
<option value="2" <?php selected( StatifyBlacklist::$_options['target']['regexp'], 2 ); ?>>
<?php esc_html_e( 'Case-insensitive', 'statify-blacklist' ); ?>
</option>
</select>
<small>
(<?php esc_html_e( 'Performance slower than standard filter. Recommended for cron or manual execition only.', 'statify-blacklist' ); ?>
)
</small>
</label>
</li>
<li>
<label for="statify-blacklist_target">
<?php esc_html_e( 'Target blacklist', 'statify-blacklist' ); ?>:<br />
<textarea cols="40" rows="5" name="statifyblacklist[target][blacklist]" id="statify-blacklist_target"><?php
if ( isset( $statifyblacklist_update_result['target'] ) ) {
print esc_html( implode( "\r\n", array_keys( $statifyblacklist_update_result['target'] ) ) );
} else {
print esc_html( implode( "\r\n", array_keys( StatifyBlacklist::$_options['target']['blacklist'] ) ) );
}
?></textarea>
<br />
<small>
(<?php esc_html_e( 'Add one target URL each line, e.g.', 'statify-blacklist' );
print ' /, /test/page/, /?page_id=123' ?>
)
</small>
</label>
</li>
</ul>
</fieldset>
<fieldset>
<h2><?php esc_html_e( 'IP blacklist', 'statify-blacklist' ); ?></h2>
<ul style="list-style: none;">
<li>
<label for="statify-blacklist_active_ip">
<input type="checkbox" name="statifyblacklist[ip][active]" id="statifyblacklist_active_ip"
value="1" <?php checked( StatifyBlacklist::$_options['ip']['active'], 1 ); ?> />
<?php esc_html_e( 'Activate live fiter', 'statify-blacklist' ); ?>
</label>
</li>
<li>
<small>
(<?php esc_html_e( 'Cron execution is not possible for IP filter, because IP addresses are not stored.', 'statify-blacklist' ); ?>
)
</small>
</li>
<li>
<label for="statify-blacklist_ip">
<?php esc_html_e( 'IP blacklist', 'statify-blacklist' ); ?>:<br />
<textarea cols="40" rows="5" name="statifyblacklist[ip][blacklist]" id="statify-blacklist_ip"><?php
if ( isset( $statifyblacklist_update_result['ip'] ) ) {
print esc_html( $_POST['statifyblacklist']['ip']['blacklist'] );
} else {
print esc_html( implode( "\r\n", StatifyBlacklist::$_options['ip']['blacklist'] ) );
}
?></textarea>
<br />
<small>
(<?php esc_html_e( 'Add one IP address or range per line, e.g.', 'statify-blacklist' ) ?>
127.0.0.1, 192.168.123.0/24, 2001:db8:a0b:12f0::1/64
)
</small>
</label>
</li>
</ul>
</fieldset>
<?php wp_nonce_field( 'statify-blacklist-settings' ); ?> <?php wp_nonce_field( 'statify-blacklist-settings' ); ?>
<h2><?php esc_html_e( 'Referer blacklist', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="statify-blacklist_active_referer">
<?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[referer][active]"
id="statify-blacklist_active_referer"
value="1" <?php checked( StatifyBlacklist::$options['referer']['active'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_cron_referer">
<?php esc_html_e( 'CronJob execution', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[referer][cron]" id="statify-blacklist_cron_referer"
value="1" <?php checked( StatifyBlacklist::$options['referer']['cron'], 1 ); ?>>
<p class="description"><?php esc_html_e( 'Periodically clean up database in background', 'statify-blacklist' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_referer_regexp"><?php esc_html_e( 'Matching method', 'statify-blacklist' ); ?></label>
</th>
<td>
<select name="statifyblacklist[referer][regexp]" id="statify-blacklist_referer_regexp">
<option value="<?php print esc_attr( StatifyBlacklist::MODE_NORMAL ); ?>" <?php selected( StatifyBlacklist::$options['referer']['regexp'], StatifyBlacklist::MODE_NORMAL ); ?>>
<?php esc_html_e( 'Domain', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_KEYWORD ); ?>" <?php selected( StatifyBlacklist::$options['referer']['regexp'], StatifyBlacklist::MODE_KEYWORD ); ?>>
<?php esc_html_e( 'Keyword', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX ); ?>" <?php selected( StatifyBlacklist::$options['referer']['regexp'], StatifyBlacklist::MODE_REGEX ); ?>>
<?php esc_html_e( 'RegEx case-sensitive', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX_CI ); ?>" <?php selected( StatifyBlacklist::$options['referer']['regexp'], StatifyBlacklist::MODE_REGEX_CI ); ?>>
<?php esc_html_e( 'RegEx case-insensitive', 'statify-blacklist' ); ?>
</option>
</select>
<p class="description">
<?php esc_html_e( 'Domain', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match given domain including subdomains', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'Keyword', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match every referer that contains one of the keywords', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'RegEx', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match referer by regular expression', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_referer"><?php esc_html_e( 'Referer blacklist', 'statify-blacklist' ); ?></label>
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[referer][blacklist]" id="statify-blacklist_referer"><?php
if ( empty( $statifyblacklist_update_result['referer'] ) ) {
print esc_html( implode( "\r\n", array_keys( StatifyBlacklist::$options['referer']['blacklist'] ) ) );
} else {
print esc_html( implode( "\r\n", array_keys( $statifyblacklist_update_result['referer']['sanitized'] ) ) );
}
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one domain (without subdomains) each line, e.g. example.com', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
</tbody>
</table>
<h2><?php esc_html_e( 'Target blacklist', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="statify-blacklist_active_target">
<?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[target][active]"
id="statify-blacklist_active_target"
value="1" <?php checked( StatifyBlacklist::$options['target']['active'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_cron_target">
<?php esc_html_e( 'CronJob execution', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[target][cron]" id="statify-blacklist_cron_target"
value="1" <?php checked( StatifyBlacklist::$options['target']['cron'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Clean database periodically in background', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_target_regexp">
<?php esc_html_e( 'Matching method', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<select name="statifyblacklist[target][regexp]" id="statify-blacklist_referer_regexp">
<option value="<?php print esc_attr( StatifyBlacklist::MODE_NORMAL ); ?>" <?php selected( StatifyBlacklist::$options['target']['regexp'], StatifyBlacklist::MODE_NORMAL ); ?>>
<?php esc_html_e( 'Exact', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX ); ?>" <?php selected( StatifyBlacklist::$options['target']['regexp'], StatifyBlacklist::MODE_REGEX ); ?>>
<?php esc_html_e( 'RegEx case-sensitive', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX_CI ); ?>" <?php selected( StatifyBlacklist::$options['target']['regexp'], StatifyBlacklist::MODE_REGEX_CI ); ?>>
<?php esc_html_e( 'RegEx case-insensitive', 'statify-blacklist' ); ?>
</option>
</select>
<p class="description">
<?php esc_html_e( 'Exact', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match only given targets', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'RegEx', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match target by regular expression', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_target">
<?php esc_html_e( 'Target blacklist', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[target][blacklist]" id="statify-blacklist_target"><?php
if ( empty( $statifyblacklist_update_result['target'] ) ) {
print esc_html( implode( "\r\n", array_keys( StatifyBlacklist::$options['target']['blacklist'] ) ) );
} else {
print esc_html( implode( "\r\n", array_keys( $statifyblacklist_update_result['target']['sanitized'] ) ) );
}
?></textarea>
<p class="description">
(<?php esc_html_e( 'Add one target URL each line, e.g.', 'statify-blacklist' ); ?> /, /test/page/, /?page_id=123)
</p>
</td>
</tr>
</tbody>
</table>
<h2><?php esc_html_e( 'IP blacklist', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="statify-blacklist_active_ip">
<?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[ip][active]" id="statify-blacklist_active_ip"
value="1" <?php checked( StatifyBlacklist::$options['ip']['active'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'Cron execution is not possible for IP filter, because IP addresses are not stored.', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_ip"><?php esc_html_e( 'IP blacklist', 'statify-blacklist' ); ?></label>:
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[ip][blacklist]" id="statify-blacklist_ip"><?php
if ( empty( $statifyblacklist_update_result['ip'] ) ) {
print esc_html( implode( "\r\n", StatifyBlacklist::$options['ip']['blacklist'] ) );
} else {
print esc_html( implode( "\r\n", $statifyblacklist_update_result['ip']['sanitized'] ) );
}
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one IP address or range per line, e.g.', 'statify-blacklist' ); ?>
127.0.0.1, 192.168.123.0/24, 2001:db8:a0b:12f0::1/64
</p>
</td>
</tr>
</tbody>
</table>
<p class="submit"> <p class="submit">
<input class="button-primary" type="submit" name="submit" value="<?php esc_html_e( 'Save Changes' ) ?>"> <input class="button-primary" type="submit" name="submit" value="<?php esc_html_e( 'Save Changes' ); ?>">
<hr /> <hr>
<input class="button-secondary" type="submit" name="cleanUp" <input class="button-secondary" type="submit" name="cleanUp"
value="<?php esc_html_e( 'CleanUp Database', 'statify-blacklist' ) ?>" value="<?php esc_html_e( 'CleanUp Database', 'statify-blacklist' ); ?>"
onclick="return confirm('Do you really want to apply filters to database? This cannot be undone.');"> onclick="return confirm('Do you really want to apply filters to database? This cannot be undone.');">
<br /> <br>
<small><?php esc_html_e( 'Applies referer and target filter (even if disabled) to data stored in database.', 'statify-blacklist' ); ?> <p class="description">
<em><?php esc_html_e( 'This cannot be undone!', 'statify-blacklist' ); ?></em></small> <?php esc_html_e( 'Applies referer and target filter (even if disabled) to data stored in database.', 'statify-blacklist' ); ?>
<em><?php esc_html_e( 'This cannot be undone!', 'statify-blacklist' ); ?></em>
</p>
</p> </p>
</form> </form>
</div> </div>