65 Commits

Author SHA1 Message Date
a5e4225261 prepare release of v1.6.0 2020-12-09 12:44:14 +01:00
1a621b8274 add PHP 8.0 to CI roster 2020-12-09 12:13:51 +01:00
f424909515 reduce redundancies for recurring matching loops
Referer, target and user agent filter share most of their logic
for different matching methods. We introduce a common routine for
all of them to not repeat ourselves. Passing a value extractor by
reference allows lazy evaluation (filter might be disabled) and
overrides for different cases (i.e. domain extractor for exact match).
2020-10-26 19:23:32 +01:00
a6cc821089 implement user agent filter
A new live-only filter block for user agent strings is now available.
It features the known exact, keyword and regular expression modes.
2020-10-26 19:23:32 +01:00
e5c30c2183 rename test class files to comply with PHPUnit 8.5+ conventions 2020-10-19 16:19:23 +02:00
2f8939b363 ui: correct label association for target matching method 2020-10-19 12:01:23 +02:00
06a7b1677a rename plugin to "Statify Filter"
The plugins purpose is to exclude or filter certain requests from
tracking by Statify. However the current name "Statify Blacklist" is not
actually inline with today's understanding of such terms. In WordPress
Core 5.5 the word "blacklist" among others has been replaced by more
precise wording where possible.

The term "filter" has been used in various places already and clearly
describes the behavior of this plugin. So we rename the plugin to
"Statify Filter" and rephrase front-end texts.

Plugin slug (permalink), textdomain and all public class and constant
names left untouched for now, to not introduce breaking changes at this
point. To be cleaned up with next major release.
2020-10-19 10:34:09 +02:00
af2d2c5142 docs: update Travis CI badge 2020-09-09 08:58:08 +02:00
c30f07e02f prepare release of 1.5.2 and declare WP 5.5 compatibility 2020-09-03 20:49:01 +02:00
cb61210685 minor (dev-)dependency updates 2020-09-03 20:49:01 +02:00
e4fd34d036 do not rely on WP core translation and add textdomain for all texts 2020-09-03 20:49:01 +02:00
2dd8e60bd8 prepare release 1.5.1 2020-05-20 10:33:05 +02:00
902e211552 postpone jump out on AJAX calls for Statify 1.7 compatibility (#22)
Statify 1.7 changed the JS tacking endpoint to WP AJAX, so we must not
skip the complete initialization on AJAX calls anymore. The routine now
breaks after adding the filter (if necessary).
2020-05-20 10:26:57 +02:00
9caa7b0678 Merge branch 'release/1.5.0' 2020-05-13 19:08:14 +02:00
9e70acbace Bump version to 1.5.0 and prepare relaase 2020-05-13 18:41:34 +02:00
d3eda0fc47 remove keyword description from referer blacklist settings section
This mode is not actually available, so is must not be documented.
Plus minor rewording of copy&paste mistakes.
2020-05-13 18:34:14 +02:00
a3741d939e README++
* minor corrections
* update Statify versions
* add FAQ section for IP subnets
* CHANGELOG++
2020-05-13 18:23:12 +02:00
aa9980106e update phpcs ignore statements; PHPdoc indentation 2020-05-10 12:13:39 +02:00
31c04d6b92 sanitize referer URI 2020-05-10 12:00:41 +02:00
d343dda6ff update settings page screenshot 2020-05-10 11:46:25 +02:00
4a6cc49fce fix use of $options variable in settings view
Underscore prefix has been removed from this field, but the change
did not reach the settings page yet.
2020-05-10 11:37:17 +02:00
ac73b2316d typo fixes 2020-05-10 11:35:18 +02:00
7f0523a647 declare compatibility with WP 5.4
skip ci
2020-04-09 10:51:44 +02:00
736cec1d12 fix use of esc_html__() for translated escape in settings page 2020-01-07 19:30:41 +01:00
253d2fadd2 use only supported PHP versions + 5.6 for CI builds 2020-01-07 19:30:40 +01:00
ebc44c722e use long array syntax
For some reason short syntax is discouraged in the latest WPCS ruleset.
To stay in line with WPCS we use long syntax now.
2020-01-07 19:30:38 +01:00
4c9d96e5a0 Merge branch 'master' into develop 2020-01-07 19:30:14 +01:00
c84eae50dd declare compatibility with WP 5.3
[skip ci]
2019-11-13 17:12:23 +01:00
3f5990f1f3 update PHPCS ruleset and re-enable warnings 2019-10-06 18:07:42 +02:00
84cf79fd04 remove underscore prefix from options field 2019-10-06 17:52:08 +02:00
a88a89c442 update WP Codex and license links [skip ci] 2019-10-06 17:34:32 +02:00
82667dcf93 update Composer dependencies 2019-08-18 18:48:46 +02:00
0b07697db8 check if POST values are actually set before sanitization 2019-08-18 18:21:57 +02:00
353ca4792f Declare compatibility with WordPress 5.2 [skip ci] 2019-05-30 15:34:18 +02:00
22373d2308 CONTRIBUTING++ [skip ci]
Adapt branch names to git flow and add a sentence on pull requests.
2019-03-17 17:43:29 +01:00
44ee7ee839 Check regular expressions and prevent saving invalid settings (#13) 2019-03-17 17:34:57 +01:00
1c69ba31bb Preprocessing of regular expression in separate funciton 2019-03-17 17:34:47 +01:00
39dcce3eeb Harmonize helper funcitons to snake_case 2019-03-17 17:25:43 +01:00
84ce89b127 Add .gitattributes
Set development files, tests and assets to export ignore list to clean
up the package distributed via Composer/Packagist.
2019-03-17 16:46:59 +01:00
124b4ecb75 dependency corrections for PHP 5.5
composer-copy-file 0.3 requires PHP 5.6, so reverted back to ~0.2
2019-03-12 19:39:43 +01:00
b7c3b51873 implement keyword filter for referer blacklist (closes #15)
In addition to the pre-existing normal and regular expression filters a
keyword mode is added. This filter matches if the referer string
contains a given keyword (case insensitive).
2019-03-12 19:37:48 +01:00
0822537f0e adjustments for PHPUnit 8
Added result cache to .gitignore and replaced assertInternalType() by
assertIsArray() with backwords compatibility for PHP 5 builds.
2019-03-12 17:57:26 +01:00
2eb08ce673 update dev dependencies 2019-03-12 17:32:32 +01:00
b691f2c618 adjust sanitization of settings and warning messages 2019-03-06 17:23:06 +01:00
c511dcb517 rework settings page
The settings page now features the 2 column layout like generated by  WP
settings API. The regular expression selects are slightly rewritten in
preparation of additional mathing methods.
2019-03-06 15:06:47 +01:00
1c146a9d72 Merge branch 'master' into develop 2019-03-06 14:18:53 +01:00
f14ceac400 Bump WP compat to 5.1 [skip CI] 2019-03-02 17:08:20 +01:00
4ce3a8f336 Add Slack notification to Travis 2018-11-02 16:05:15 +01:00
abcaab7a33 Fixed ReadMe badge links [skip ci] 2018-11-01 21:58:06 +01:00
36a65482e2 Add badges to ReadMe [skip ci] 2018-11-01 20:31:58 +01:00
f60c6ec2ff Fixed textdomain for compatibility notice 2018-10-30 19:32:52 +01:00
7e51c7d63e Add PHP 7.3 to CI matrix 2018-10-27 19:09:34 +02:00
35b6d5592b Cleaned up labels and added PHPCS rule for settings view 2018-10-27 19:05:09 +02:00
74f2e0f9a7 Removed deprecated instance() and __construct() methods from base class 2018-10-27 18:42:46 +02:00
74826384a8 Moved admin initialization to admin class 2018-10-27 18:34:23 +02:00
8e6cb5c553 Added compatibility check for WP and PHP version (closes #17) 2018-10-27 18:33:00 +02:00
59ff52cdef Merge if-clauses for cron job detection 2018-10-27 17:44:13 +02:00
4dcd52e137 Merge branch 'master' into develop 2018-10-27 17:38:41 +02:00
14ad793baf Bump WP compat to 5.0 2018-10-20 10:15:08 +02:00
bcd42bde2a Minor code style fixes 2018-10-20 10:12:38 +02:00
f34b761942 Removed load_plugin_textdomain and domain path header
Translation is handled via translate.wordpress.org and minimum required
version is greater than 4.6, so the local translation artifacts are
dropped.
2018-05-19 15:09:57 +02:00
74be5a2334 Merge branch 'hf12-regexSkip' into develop 2018-05-19 14:31:47 +02:00
c77e1ee012 Apply coding standards to unit test (except some mocks) 2018-05-19 13:53:27 +02:00
5e2dd4b6e1 Removed Gulp build script
Build process is now handled by Composer and Robo, so clean up old stuff
2018-03-21 18:27:42 +01:00
8c556ca509 Removed legacy code for WP prior to 4.6
Statify itself requires WP 4.7, so no reason to stick to legacy code
anymore.
2018-03-21 18:16:25 +01:00
19 changed files with 1320 additions and 680 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/
.idea
tests-clover.xml
tests-junit.xml
tests-junit.xml
.phpunit.result.cache

View File

@ -1,12 +1,13 @@
language: php
dist: trusty
php:
- '5.5'
- '5.6'
- '7.0'
- '7.1'
- '7.2'
- '7.3'
- '7.4'
- '8.0'
before_script:
- composer install
script:
- 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).
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
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.
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.
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.
Feel free to adapt these naming scheme to your forks.
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 this naming scheme to your forks.
### 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
applications with the library. If this is what you want to do, use the
[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.

102
README.md
View File

@ -1,33 +1,41 @@
# Statify Blacklist #
[![Build Status](https://travis-ci.com/stklcode/statify-blacklist.svg?branch=master)](https://travis-ci.com/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 Filter #
* Contributors: Stefan Kalscheuer
* Requires at least: 4.4
* Tested up to: 4.9
* Requires at least: 4.7
* Tested up to: 5.6
* Requires PHP: 5.5
* Stable tag: 1.4.4
* Stable tag: 1.6.0
* 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 ##
A blacklist extension for the famous [Statify](https://wordpress.org/plugins/statify/) Wordpress plugin.
A filter 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 customizable filters to Statify to allow blocking of referer spam or internal interactions.
### Features ##
#### Referer Blacklist ####
#### Referer Filter ####
Add a list of domains (for simplicity only second-level, e.g. _example.com_ which blocks _everything.example.com_).
#### Target Blacklist ####
#### Target Filter ####
Add a list of target pages (e.g. _/test/page/_, _/?page_id=123_) that will be excluded from tracking.
#### IP Blacklist ####
#### IP Filter ####
Add a list of IP addresses or subnets (e.g. _192.0.2.123_, _198.51.100.0/24_, _2001:db8:a0b:12f0::/64_).
#### User Agent Filter ####
Add a list of (partial) user agent strings to exclude (e.g. _curl_, _my/bot_, _Firefox_).
#### CleanUp Database ####
Filters can be applied to data stored in database after modifying filter rules or for one-time clean-up.
#### 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.8
The plugin is capable of handling multisite installations.
### Support & Contributions ###
@ -37,51 +45,87 @@ The plugin is capable of handling multisite installations.
### Credits ###
* 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 ##
* If you dont know how to install a plugin for WordPress, [heres how](http://codex.wordpress.org/Managing_Plugins#Installing_Plugins).
* Make sure _Statify_ plugin is installed and active
* Goto _Settings_ -> _Statify Blacklist_ to configure the plugin
* 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
* Goto _Settings_ -> _Statify Filter_ to configure the plugin
### Requirements ###
* PHP 5.5 or above
* WordPress 4.4 or above
* Statify plugin installed and activated (1.5.0 or above)
* WordPress 4.7 or above
* _Statify_ plugin installed and activated (1.5 or above)
## Frequently Asked Questions ##
### 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 filters 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,
visitors from search engines, just "false" referers from 301 redirects or you own IP address used for testing only depends on you.
A default filter is not provided, as the plugin itself is totally neutral. If you want to filter out referer spam,
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? ###
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? ###
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.
### Is any personal data collected? ###
No. The privacy policy of _Statify_ is untouched. Data is only processed, not stored or exposed to anyone.
### 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 and User Agent filtering only available as live filter? ###
As you might know, _Statify_ does not store any personal information, including IP addresses in the database.
Because of this, these filters can only be applied while processing the request and not afterwards.
### 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.
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 filters using CIDR notation.
For example _198.51.100.0/24_ filters all sources from _198.51.100.1_ to _198.51.100.254_.
Same for IPv6 prefixes like _2001:db8:a0b:12f0::/64_.
## Screenshots ##
1. Statify Blacklist settings page
1. Statify Filter settings page
## Upgrade Notice ##
### 1.6.0 ###
The plugin has been renamed from _Statify Blacklist_ to _Statify Filter_.
This does not imply any changes in functionality, rather than using a better wording.
In addition, there is a new filter by User Agent along with some minor corrections.
This version should be compatible with latest WordPress 5.6.
## Changelog ##
### 1.6.0 / 09.12.2020 ###
Plugin renamed to _Statify Filter_.
* Minor accessibility fixes on settings page
* Introduced new user agent filter (#20)
* Declared compatibility with WordPress 5.6
### 1.5.2 / 03.09.2020 ###
* Minor translation updates
* Declared compatibility with WordPress 5.5
### 1.5.1 / 20.05.2020 ###
* Fix initialization on AJAX calls for _Statify_ 1.7 compatibility (#22)
### 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 ###
* Fix live filter chain when regular expressions are active (#12)
@ -115,7 +159,7 @@ Because of this, an IP blacklist can only be applied while processing the reques
### 1.2.0 / 29.08.2016 ###
* Switched from `in_array()` to faster `isset()` for referer checking
* Optional cron execiton implemented
* Optional cron execution implemented
### 1.1.2 / 17.08.2016 ###
* Prepared for localization

View File

@ -1,6 +1,6 @@
<?php
/**
* Statify Blacklist Robo build script.
* Statify Filter Robo build script.
*
* This file contains the Robo tasks for building a distributable plugin package.
* Should not be included in final package.
@ -8,7 +8,7 @@
* @author Stefan Kalscheuer <stefan@stklcode.de>
*
* @package Statify_Blacklist
* @version 1.4.4
* @version 1.0.0
*/
use Robo\Exception\TaskException;
@ -19,10 +19,10 @@ use Robo\Tasks;
*/
class RoboFile extends Tasks {
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_SKIPTEST = 'skipTests';
const OPT_TARGET = 'target';
const OPT_SKIPTEST = 'skipTests';
const OPT_SKIPSTYLE = 'skipStyle';
/**
@ -134,13 +134,21 @@ class RoboFile extends Tasks {
*/
private function bundle() {
$this->say( 'Bundling resources...' );
$this->taskCopyDir( [
'inc' => $this->target_dir . '/' . $this->final_name . '/inc',
'views' => $this->target_dir . '/' . $this->final_name . '/views',
] )->run();
$this->taskCopyDir(
[
'inc' => $this->target_dir . '/' . $this->final_name . '/inc',
'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( 'README.md', $this->target_dir . '/' . $this->final_name . '/README.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,12 +1,12 @@
{
"name": "stklcode/statify-blacklist",
"version": "1.4.4",
"description": "A blacklist extension for the famous Statify WordPress plugin",
"version": "1.6.0",
"description": "A filter extension for the famous Statify WordPress plugin",
"keywords": [
"wordpress",
"plugin",
"statistics",
"blacklist"
"filter"
],
"license": "GPL-2.0-or-later",
"authors": [
@ -19,17 +19,17 @@
"type": "wordpress-plugin",
"require": {
"php": ">=5.5",
"composer/installers": "~1.0"
"composer/installers": "~1.9"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.4",
"consolidation/robo": "^1.0.0",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7",
"consolidation/robo": "^1.4",
"phpunit/phpunit": "*",
"phpunit/php-code-coverage": "*",
"slowprog/composer-copy-file": "~0.2",
"squizlabs/php_codesniffer": "^3.1",
"wimg/php-compatibility": "^8.0",
"wp-coding-standards/wpcs": "~0.14"
"slowprog/composer-copy-file": "~0.3",
"squizlabs/php_codesniffer": "^3.5",
"phpcompatibility/phpcompatibility-wp": "^2.1",
"wp-coding-standards/wpcs": "^2.3"
},
"scripts": {
"build": [

View File

@ -1,6 +1,6 @@
<?php
/**
* Statify Blacklist: StatifyBlacklist_Admin class
* Statify Filter: StatifyBlacklist_Admin class
*
* This file contains the derived class for the plugin's administration features.
*
@ -9,46 +9,112 @@
* @since 1.0.0
*/
// Quit.
defined( 'ABSPATH' ) || exit;
// Quit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Statify Blacklist admin configuration.
* Statify Filter admin configuration.
*
* @since 1.0.0
*/
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.
*
* @since 1.1.1
*
* @param array $options Optional. New options to save.
*
* @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 ) {
if ( isset( $options ) && current_user_can( 'manage_options' ) ) {
// Sanitize URLs and remove empty inputs.
$given_referer = $options['referer']['blacklist'];
if ( 0 === $options['referer']['regexp'] ) {
$sanitized_referer = self::sanitizeURLs( $given_referer );
// Sanitize referer list.
$given_referer = $options['referer']['blacklist'];
$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 {
$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'];
$sanitized_ip = self::sanitizeIPs( $given_ip );
$sanitized_ip = self::sanitize_ips( $given_ip );
// Abort on errors.
if ( ! empty( array_diff( array_keys( $given_referer ), array_keys( $sanitized_referer ) ) ) ) {
return array(
'referer' => $sanitized_referer,
);
} elseif ( ! empty( array_diff( $given_ip, $sanitized_ip ) ) ) {
return array(
'ip' => array_diff( $given_ip, $sanitized_ip ),
);
$errors = array(
'referer' => array(
'sanitized' => $sanitized_referer,
'diff' => array_diff( $given_referer, $sanitized_referer ),
'invalid' => $invalid_referer,
),
'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.
@ -71,17 +137,27 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
* @since 1.0.0
*/
public static function add_menu_page() {
$title = __( 'Statify Blacklist', 'statify-blacklist' );
$title = __( 'Statify Filter', 'statify-blacklist' );
if ( self::$multisite ) {
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',
'settings_page',
)
);
} else {
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',
'settings_page',
)
@ -133,7 +209,7 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
if ( STATIFYBLACKLIST_BASE === $file && current_user_can( 'manage_options' ) ) {
array_unshift(
$links,
sprintf( '<a href="%s">%s</a>', esc_attr( add_query_arg( 'page', 'statify-blacklist', $base ) ), __( 'Settings' ) )
sprintf( '<a href="%s">%s</a>', esc_attr( add_query_arg( 'page', 'statify-blacklist', $base ) ), __( 'Settings', 'statify-blacklist' ) )
);
}
@ -150,24 +226,24 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
public static function cleanup_database() {
// Check user permissions.
if ( ! current_user_can( 'manage_options' ) && ! ( defined( 'DOING_CRON' ) && DOING_CRON ) ) {
die( esc_html__( 'Are you sure you want to do this?' ) );
die( esc_html__( 'Are you sure you want to do this?', 'statify-blacklist' ) );
}
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
$clean_ref = ( 1 === self::$_options['referer']['cron'] );
$clean_trg = ( 1 === self::$_options['target']['cron'] );
$clean_ref = ( 1 === self::$options['referer']['cron'] );
$clean_trg = ( 1 === self::$options['target']['cron'] );
} else {
$clean_ref = true;
$clean_trg = true;
}
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.
$referer_regexp = implode( '|', array_keys( self::$_options['referer']['blacklist'] ) );
$referer_regexp = implode( '|', array_keys( self::$options['referer']['blacklist'] ) );
} else {
// Sanitize URLs.
$referer = self::sanitizeURLs( self::$_options['referer']['blacklist'] );
$referer = self::sanitize_urls( self::$options['referer']['blacklist'] );
// Build filter regexp.
$referer_regexp = str_replace( '.', '\.', implode( '|', array_flip( $referer ) ) );
@ -175,12 +251,12 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
}
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.
$target_regexp = implode( '|', array_keys( self::$_options['target']['blacklist'] ) );
$target_regexp = implode( '|', array_keys( self::$options['target']['blacklist'] ) );
} else {
// 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;
// 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 ) ) {
$wpdb->query(
$wpdb->prepare(
"DELETE FROM `$wpdb->statify` WHERE "
. ( ( 1 === self::$_options['referer']['regexp'] ) ? ' BINARY ' : '' )
. 'referrer REGEXP %s', $referer_regexp
. ( ( 1 === self::$options['referer']['regexp'] ) ? ' BINARY ' : '' )
. 'referrer REGEXP %s',
$referer_regexp
)
);
}
@ -202,12 +279,13 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
$wpdb->query(
$wpdb->prepare(
"DELETE FROM `$wpdb->statify` WHERE "
. ( ( 1 === self::$_options['target']['regexp'] ) ? ' BINARY ' : '' )
. 'target REGEXP %s', $target_regexp
. ( ( 1 === self::$options['target']['regexp'] ) ? ' BINARY ' : '' )
. 'target REGEXP %s',
$target_regexp
)
);
}
// @codingStandardsIgnoreEnd
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
// Optimize DB.
$wpdb->query( "OPTIMIZE TABLE `$wpdb->statify`" );
@ -227,7 +305,7 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
*
* @return array sanitized array.
*/
private static function sanitizeURLs( $urls ) {
private static function sanitize_urls( $urls ) {
return array_flip(
array_filter(
array_map(
@ -249,15 +327,39 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
*
* @return array sanitized array.
*/
private static function sanitizeIPs( $ips ) {
private static function sanitize_ips( $ips ) {
return array_filter(
$ips, function ( $ip ) {
$ips,
function ( $ip ) {
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(
'/^(([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
);
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
);
}
);
}
/**
* 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
/**
* Statify Blacklist: StatifyBlacklist_Syste, class
* Statify Filter: StatifyBlacklist_System class
*
* This file contains the derived class for the plugin's system operations.
*
@ -9,11 +9,13 @@
* @since 1.0.0
*/
// Quit.
defined( 'ABSPATH' ) || exit;
// Quit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Statify Blacklist system configuration.
* Statify Filter system configuration.
*
* @since 1.0.0
*/
@ -25,15 +27,14 @@ class StatifyBlacklist_System extends StatifyBlacklist {
* @since 1.0.0
*
* @param bool $network_wide Whether the plugin was activated network-wide or not.
*
* @return void
*/
public static function install( $network_wide = false ) {
// Create tables for each site in a network.
if ( $network_wide && is_multisite() ) {
if ( function_exists( 'get_sites' ) ) {
$sites = get_sites();
} elseif ( function_exists( 'wp_get_sites' ) ) {
// @codingStandardsIgnoreLine Legacy support for WP < 4.6.
$sites = wp_get_sites();
} else {
return;
}
@ -62,6 +63,8 @@ class StatifyBlacklist_System extends StatifyBlacklist {
* @since 1.4.3
*
* @param integer $site_id Site ID.
*
* @return void
*/
public static function install_site( $site_id ) {
switch_to_blog( (int) $site_id );
@ -77,6 +80,8 @@ class StatifyBlacklist_System extends StatifyBlacklist {
* Plugin uninstall handler.
*
* @since 1.0.0
*
* @return void
*/
public static function uninstall() {
if ( is_multisite() ) {
@ -85,7 +90,7 @@ class StatifyBlacklist_System extends StatifyBlacklist {
if ( function_exists( 'get_sites' ) ) {
$sites = 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();
} else {
return;
@ -112,6 +117,8 @@ class StatifyBlacklist_System extends StatifyBlacklist {
* @since 1.4.3
*
* @param integer $site_id Site ID.
*
* @return void
*/
public static function uninstall_site( $site_id ) {
$old = get_current_blog_id();
@ -124,14 +131,16 @@ class StatifyBlacklist_System extends StatifyBlacklist {
* Upgrade plugin options.
*
* @since 1.2.0
*
* @return void
*/
public static function upgrade() {
self::update_options();
// 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.
$options = self::$_options;
$options['referer'] = array_flip( self::$_options['referer'] );
$options = self::$options;
$options['referer'] = array_flip( self::$options['referer'] );
if ( self::$multisite ) {
update_site_option( 'statify-blacklist', $options );
} else {
@ -140,14 +149,14 @@ class StatifyBlacklist_System extends StatifyBlacklist {
}
// 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.
$options = array(
'referer' => array(
'active' => self::$_options['active_referer'],
'cron' => self::$_options['cron_referer'],
'regexp' => self::$_options['referer_regexp'],
'blacklist' => self::$_options['referer'],
'active' => self::$options['active_referer'],
'cron' => self::$options['cron_referer'],
'regexp' => self::$options['referer_regexp'],
'blacklist' => self::$options['referer'],
),
'target' => array(
'active' => 0,
@ -170,9 +179,9 @@ class StatifyBlacklist_System extends StatifyBlacklist {
}
// 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.
$options = array_merge_recursive( self::default_options(), self::$_options );
$options = array_merge_recursive( self::default_options(), self::$options );
$options['version'] = self::VERSION_MAIN;
if ( self::$multisite ) {
update_site_option( 'statify-blacklist', $options );

View File

@ -1,6 +1,6 @@
<?php
/**
* Statify Blacklist: StatifyBlacklist class
* Statify Filter: StatifyBlacklist class
*
* This file contains the plugin's base class.
*
@ -8,13 +8,13 @@
* @since 1.0.0
*/
// Quit.
defined( 'ABSPATH' ) || exit;
// Quit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Statify Blacklist.
*
* @since 1.0.0
* Statify Filter.
*/
class StatifyBlacklist {
@ -26,13 +26,42 @@ class StatifyBlacklist {
*/
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.
*
* @since 1.0.0
* @var array $_options
* @var array $options
*/
public static $_options;
public static $options;
/**
* Multisite Status.
@ -42,34 +71,16 @@ class StatifyBlacklist {
*/
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.
*
* @since 1.4.2
*
* @return void
*/
public static function init() {
// Skip on autosave or AJAX.
if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
// Skip on autosave.
if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) ) {
return;
}
@ -80,41 +91,27 @@ class StatifyBlacklist {
self::update_options();
// 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'] ||
0 !== self::$options['ua']['active'] ) {
add_filter( 'statify__skip_tracking', array( 'StatifyBlacklist', 'apply_blacklist_filter' ) );
}
// Statify uses WP AJAX as of 1.7, so we need to reach this point. But there are no further admin/cron actions.
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
return;
}
// Admin only filters.
if ( is_admin() ) {
// Load Textdomain (only needed for backend.
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 );
}
StatifyBlacklist_Admin::init();
}
// CronJob to clean up database.
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
if ( 1 === self::$_options['referer']['cron'] || 1 === self::$_options['target']['cron'] ) {
add_action( 'statify_cleanup', array( 'StatifyBlacklist_Admin', 'cleanup_database' ) );
}
if ( defined( 'DOING_CRON' ) && DOING_CRON &&
( 1 === self::$options['referer']['cron'] || 1 === self::$options['target']['cron'] ) ) {
add_action( 'statify_cleanup', array( 'StatifyBlacklist_Admin', 'cleanup_database' ) );
}
}
@ -125,6 +122,8 @@ class StatifyBlacklist {
* @since 1.2.1 update_options($options = null) Parameter with default value introduced.
*
* @param array $options Optional. New options to save.
*
* @return void
*/
public static function update_options( $options = null ) {
if ( self::$multisite ) {
@ -132,7 +131,7 @@ class StatifyBlacklist {
} else {
$o = get_option( 'statify-blacklist' );
}
self::$_options = wp_parse_args( $o, self::default_options() );
self::$options = wp_parse_args( $o, self::default_options() );
}
/**
@ -160,89 +159,46 @@ class StatifyBlacklist {
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => 0,
'blacklist' => array(),
),
'version' => self::VERSION_MAIN,
);
}
/**
* Apply the blacklist filter if active
* Apply the filter if active
*
* @since 1.0.0
*
* @return bool TRUE if referer matches blacklist.
* @return bool TRUE if referer matches filter.
*/
public static function apply_blacklist_filter() {
// Referer blacklist.
if ( isset( self::$_options['referer']['active'] ) && 0 !== self::$_options['referer']['active'] ) {
// Regular Expression filtering since 1.3.0.
if ( isset( self::$_options['referer']['regexp'] ) && 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).
if ( 1 === preg_match( $regexp, $referer ) ) {
return true;
}
} else {
// Extract relevant domain parts.
$referer = wp_parse_url( wp_get_raw_referer() );
$referer = strtolower( ( isset( $referer['host'] ) ? $referer['host'] : '' ) );
// Get blacklist.
$blacklist = self::$_options['referer']['blacklist'];
// Check blacklist.
if ( isset( $blacklist[ $referer ] ) ) {
return true;
}
}
// Referer filter.
if (
self::apply_single_filter(
self::$options['referer'],
array(
__CLASS__,
( ! isset( self::$options['referer']['regexp'] ) || self::MODE_NORMAL === self::$options['referer']['regexp'] ) ? 'get_referer_domain' : 'get_referer',
)
)
) {
return true;
}
// Target blacklist (since 1.4.0).
if ( isset( self::$_options['target']['active'] ) && 0 !== self::$_options['target']['active'] ) {
// Regular Expression filtering since 1.3.0.
if ( isset( self::$_options['target']['regexp'] ) && 0 < self::$_options['target']['regexp'] ) {
// Get full referer string.
// @codingStandardsIgnoreStart The globals are checked.
$target = ( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '/' );
// @codingStandardsIgnoreEnd
// Merge given regular expressions into one.
$regexp = '/' . implode( '|', array_keys( self::$_options['target']['blacklist'] ) ) . '/';
if ( 2 === self::$_options['target']['regexp'] ) {
$regexp .= 'i';
}
// Check blacklist (no return to continue filtering #12).
if ( 1 === preg_match( $regexp, $target ) ) {
return true;
}
} else {
// Extract target page.
// @codingStandardsIgnoreStart The globals are checked.
$target = ( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '/' );
// @codingStandardsIgnoreEnd
// Get blacklist.
$blacklist = self::$_options['target']['blacklist'];
// Check blacklist.
if ( isset( $blacklist[ $target ] ) ) {
return true;
}
}
// Target filter (since 1.4.0).
if ( self::apply_single_filter( self::$options['target'], array( __CLASS__, 'get_target' ) ) ) {
return true;
}
// IP blacklist (since 1.4.0).
if ( isset( self::$_options['ip']['active'] ) && 0 !== self::$_options['ip']['active'] ) {
// IP filter (since 1.4.0).
if ( isset( self::$options['ip']['active'] ) && 0 !== self::$options['ip']['active'] ) {
$ip = self::get_ip();
if ( false !== ( $ip ) ) {
foreach ( self::$_options['ip']['blacklist'] as $net ) {
foreach ( self::$options['ip']['blacklist'] as $net ) {
if ( self::cidr_match( $ip, $net ) ) {
return true;
}
@ -250,10 +206,145 @@ class StatifyBlacklist {
}
}
// Skip and continue (return NULL), if all blacklists are inactive.
// User agent filter (since 1.6).
if ( self::apply_single_filter( self::$options['ua'], array( __CLASS__, 'get_user_agent' ) ) ) {
return true;
}
// Skip and continue (return NULL), if all filters are inactive.
return null;
}
/**
* Apply a single filter, if active.
*
* @param array $config Configuration array from plugin options.
* @param callable $value_fn Extractor function for filterable value.
*
* @return bool TRUE if referer matches filter.
*
* @since 1.6 Extracted from "apply_blacklist_filter" to reduce redundancies.
*/
private static function apply_single_filter( $config, $value_fn ) {
// Is the filter active?
if ( ! isset( $config['active'] ) || 0 === $config['active'] ) {
return false;
}
// Extract the filterable value.
$value = call_user_func( $value_fn );
$mode = isset( $config['regexp'] ) ? intval( $config['regexp'] ) : self::MODE_NORMAL;
switch ( $mode ) {
case self::MODE_REGEX:
case self::MODE_REGEX_CI:
// Regular Expression filtering since 1.3.0.
// Merge given regular expressions into one.
$regexp = self::regex(
array_keys( $config['blacklist'] ),
self::MODE_REGEX_CI === $config['regexp']
);
// Check filter (no return to continue filtering #12).
if ( 1 === preg_match( $regexp, $value ) ) {
return true;
}
break;
case self::MODE_KEYWORD:
// Keyword filter since 1.5.0 (#15).
foreach ( array_keys( $config['blacklist'] ) as $keyword ) {
if ( false !== strpos( strtolower( $value ), strtolower( $keyword ) ) ) {
return true;
}
}
break;
default:
// Standard exact filter.
if ( isset( $config['blacklist'][ $value ] ) ) {
return true;
}
}
return false;
}
/**
* 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 referer.
*
* @return string The referer.
*/
private static function get_referer() {
$referer = wp_get_raw_referer();
if ( ! $referer ) {
$referer = '';
}
return $referer;
}
/**
* Helper method to determine the host part of the client's referer.
*
* @return string Referer domain.
*/
private static function get_referer_domain() {
$referer = wp_parse_url( self::get_referer() );
return strtolower( ( isset( $referer['host'] ) ? $referer['host'] : '' ) );
}
/**
* Helper method to determine the client's referer.
*
* @return string The referer.
*/
private static function get_target() {
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
$target = filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_URL );
if ( $target ) {
return $target;
}
}
return '';
}
/**
* Helper method to determine the client's IP address.
*
@ -277,20 +368,35 @@ class StatifyBlacklist {
'REMOTE_ADDR',
) as $k
) {
// @codingStandardsIgnoreStart The globals are checked.
if ( isset( $_SERVER[ $k ] ) ) {
// phpcs:ignore
foreach ( explode( ',', $_SERVER[ $k ] ) as $ip ) {
if ( false !== filter_var( $ip, FILTER_VALIDATE_IP ) ) {
return $ip;
}
}
}
// @codingStandardsIgnoreEnd
}
return false;
}
/**
* Helper method to determine the user agent.
*
* @return string The user agent string.
*/
private static function get_user_agent() {
if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
$user_agent = filter_var( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ), FILTER_SANITIZE_STRING );
if ( $user_agent ) {
return $user_agent;
}
}
return '';
}
/**
* Helper function to check if an IP address matches a given subnet.
*
@ -361,6 +467,6 @@ class StatifyBlacklist {
}
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",
"version": "1.4.4",
"description": "A blacklist extension for the famous Statify WordPress plugin",
"version": "1.6.0",
"description": "A filter extension for the famous Statify WordPress plugin",
"author": "Stefan Kalscheuer",
"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"
}
"license": "GPL-2.0+"
}

View File

@ -2,26 +2,29 @@
<ruleset name="StatifyBlacklist">
<description>Derived from WordPress Coding Standard</description>
<arg value="psvn"/>
<arg value="psv"/>
<arg name="colors"/>
<!-- Files to sniff -->
<file>inc</file>
<file>statify-blacklist.php</file>
<file>inc</file>
<file>views</file>
<!-- 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">
<!-- 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. -->
<exclude name="WordPress.VIP.DirectDatabaseQuery.DirectQuery"/>
<exclude name="WordPress.VIP.DirectDatabaseQuery.NoCaching"/>
<exclude name="WordPress.DB.DirectDatabaseQuery.DirectQuery"/>
<exclude name="WordPress.DB.DirectDatabaseQuery.NoCaching"/>
</rule>
<rule ref="WordPress.WP.I18n">
<properties>
<property name="text_domain" type="array" value="statify-blacklist"/>
</properties>
</rule>
<!-- PHP compatibility level -->
<config name="testVersion" value="5.5-"/>
<rule ref="PHPCompatibility"/>
<rule ref="PHPCompatibilityWP"/>
</ruleset>

View File

@ -2,7 +2,7 @@
<phpunit bootstrap="./vendor/autoload.php">
<testsuites>
<testsuite name="Statify Blacklist TestSuite">
<directory suffix="-test.php">./test/</directory>
<directory suffix="_Test.php">./test/</directory>
</testsuite>
</testsuites>
<filter>
@ -12,6 +12,6 @@
</filter>
<logging>
<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>
</phpunit>

View File

@ -1,61 +1,68 @@
<?php
/**
* Statify Blacklist
* Statify Filter
*
* @package PluginPackage
* @author Stefan Kalscheuer <stefan@stklcode.de>
* @license GPL-2.0+
*
* @wordpress-plugin
* Plugin Name: Statify Blacklist
* Plugin Name: Statify Filter
* Plugin URI: https://wordpress.org/plugins/statify-blacklist/
* Description: Extension for the Statify plugin to add a customizable blacklists.
* Version: 1.4.4
* Description: Extension for the Statify plugin to add customizable filters. (formerly "Statify Blacklist)
* Version: 1.6.0
* Author: Stefan Kalscheuer (@stklcode)
* Author URI: https://www.stklcode.de
* Text Domain: statify-blacklist
* Domain Path: /lang
* License: GPLv2 or later
*
* Statify Blacklist is free software: you can redistribute it and/or modify
* Statify Filter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* any later version.
*
* Statify Blacklist is distributed in the hope that it will be useful,
* Statify Filter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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 Filter. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
*/
// Quit.
defined( 'ABSPATH' ) || exit;
// Quit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Constants.
define( 'STATIFYBLACKLIST_FILE', __FILE__ );
define( 'STATIFYBLACKLIST_DIR', dirname( __FILE__ ) );
define( 'STATIFYBLACKLIST_BASE', plugin_basename( __FILE__ ) );
// System Hooks.
add_action( 'plugins_loaded', array( 'StatifyBlacklist', 'init' ) );
// Check for compatibility.
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.
register_activation_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'upgrade' ) );
// Upgrade hook.
register_activation_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'upgrade' ) );
// Autoload.
spl_autoload_register( 'statify_blacklist_autoload' );
// Autoload.
spl_autoload_register( 'statify_blacklist_autoload' );
} else {
// Disable plugin, if active.
add_action( 'admin_init', 'statify_blacklist_disable' );
}
/**
* 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
*/
@ -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 Filter 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

@ -1,6 +1,6 @@
<?php
/**
* Statify Blacklist: Unit Test
* Statify Filter: Unit Test
*
* This is a PHPunit test class for the plugin's functionality
*
@ -20,17 +20,17 @@ const ABSPATH = false;
/**
* The StatifyBlacklist base class.
*/
require_once( 'inc/class-statifyblacklist.php' );
require_once __DIR__ . '/../inc/class-statifyblacklist.php';
/**
* The StatifyBlacklist system class.
*/
require_once( 'inc/class-statifyblacklist-system.php' );
require_once __DIR__ . '/../inc/class-statifyblacklist-system.php';
/**
* The StatifyBlacklist admin class.
*/
require_once( 'inc/class-statifyblacklist-admin.php' );
require_once __DIR__ . '/../inc/class-statifyblacklist-admin.php';
/**
* Class StatifyBlacklistTest.
@ -43,10 +43,12 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
/**
* Test simple referer filter.
*
* @return void
*/
public function test_referer_filter() {
// Prepare Options: 2 blacklisted domains, disabled.
StatifyBlacklist::$_options = array(
// Prepare Options: 2 filtered domains, disabled.
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
'cron' => 0,
@ -66,6 +68,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
@ -75,18 +82,18 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// No referer.
unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-blacklisted referer.
// Non-filtered referer.
$_SERVER['HTTP_REFERER'] = 'http://example.org';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer.
// Filtered referer.
$_SERVER['HTTP_REFERER'] = 'http://example.com';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer with path.
// Filtered referer with path.
$_SERVER['HTTP_REFERER'] = 'http://example.net/foo/bar.html';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Activate filter and run tests again.
StatifyBlacklist::$_options['referer']['active'] = 1;
StatifyBlacklist::$options['referer']['active'] = 1;
unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
@ -103,10 +110,12 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
/**
* Test referer filter using regular expressions.
*
* @return void
*/
public function testRefererRegexFilter() {
public function test_referer_regex_filter() {
// Prepare Options: 2 regular expressions.
StatifyBlacklist::$_options = array(
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 1,
'cron' => 0,
@ -126,6 +135,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
@ -135,31 +149,91 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// No referer.
unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-blacklisted referer.
// Non-filtered referer.
$_SERVER['HTTP_REFERER'] = 'http://not.evil';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer.
// Filtered referer.
$_SERVER['HTTP_REFERER'] = 'http://example.com';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer with path.
// Filtered 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() );
// Mathinc with wrong case.
// Matching with wrong case.
$_SERVER['HTTP_REFERER'] = 'http://eXaMpLe.NeT/tEsT/mE';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// 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(),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
// No multisite.
StatifyBlacklist::$multisite = false;
// No referer.
unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-filtered referer.
$_SERVER['HTTP_REFERER'] = 'http://not.evil';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Filtered referer.
$_SERVER['HTTP_REFERER'] = 'http://example.com';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Filtered 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() );
}
/**
* Test the upgrade methodology for configuration options.
*
* @return void
*/
public function testUpgrade() {
public function test_upgrade() {
// Create configuration of version 1.3.
$options13 = array(
'active_referer' => 1,
@ -179,138 +253,141 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
StatifyBlacklist_System::upgrade();
// Retrieve updated options.
$optionsUpdated = get_option( 'statify-blacklist' );
$options_updated = get_option( 'statify-blacklist' );
// Verify size against default options (no junk left).
$this->assertEquals( 4, count( $optionsUpdated ) );
$this->assertEquals( 4, count( $optionsUpdated['referer'] ) );
$this->assertEquals( 4, count( $optionsUpdated['target'] ) );
$this->assertEquals( 2, count( $optionsUpdated['ip'] ) );
$this->assertEquals( 4, count( $options_updated ) );
$this->assertEquals( 4, count( $options_updated['referer'] ) );
$this->assertEquals( 4, count( $options_updated['target'] ) );
$this->assertEquals( 2, count( $options_updated['ip'] ) );
// Verify that original attributes are unchanged.
$this->assertEquals( $options13['active_referer'], $optionsUpdated['referer']['active'] );
$this->assertEquals( $options13['cron_referer'], $optionsUpdated['referer']['cron'] );
$this->assertEquals( $options13['referer'], $optionsUpdated['referer']['blacklist'] );
$this->assertEquals( $options13['referer_regexp'], $optionsUpdated['referer']['regexp'] );
$this->assertEquals( $options13['active_referer'], $options_updated['referer']['active'] );
$this->assertEquals( $options13['cron_referer'], $options_updated['referer']['cron'] );
$this->assertEquals( $options13['referer'], $options_updated['referer']['blacklist'] );
$this->assertEquals( $options13['referer_regexp'], $options_updated['referer']['regexp'] );
// Verify that new attributes are present in config and filled with default values (disabled, empty).
$this->assertEquals( 0, $optionsUpdated['target']['active'] );
$this->assertEquals( 0, $optionsUpdated['target']['cron'] );
$this->assertEquals( 0, $optionsUpdated['target']['regexp'] );
$this->assertEquals( array(), $optionsUpdated['target']['blacklist'] );
$this->assertEquals( 0, $optionsUpdated['ip']['active'] );
$this->assertEquals( array(), $optionsUpdated['ip']['blacklist'] );
$this->assertEquals( 0, $options_updated['target']['active'] );
$this->assertEquals( 0, $options_updated['target']['cron'] );
$this->assertEquals( 0, $options_updated['target']['regexp'] );
$this->assertEquals( array(), $options_updated['target']['blacklist'] );
$this->assertEquals( 0, $options_updated['ip']['active'] );
$this->assertEquals( array(), $options_updated['ip']['blacklist'] );
// 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.
$this->assertTrue( invokeStatic( 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' ) ) );
$this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '127.0.0.1', '127.0.0.1/32' ) ) );
$this->assertFalse(
invokeStatic(
StatifyBlacklist::class, 'cidr_match', array(
'127.0.0.1',
'127.0.0.1/33',
)
invoke_static(
StatifyBlacklist::class,
'cidr_match',
array( '127.0.0.1', '127.0.0.1/33' )
)
);
$this->assertFalse(
invokeStatic(
StatifyBlacklist::class, 'cidr_match', array(
'127.0.0.1',
'127.0.0.1/-1',
)
invoke_static(
StatifyBlacklist::class,
'cidr_match',
array( '127.0.0.1', '127.0.0.1/-1' )
)
);
$this->assertTrue(
invokeStatic(
StatifyBlacklist::class, 'cidr_match', array(
'192.0.2.123',
'192.0.2.0/24',
)
invoke_static(
StatifyBlacklist::class,
'cidr_match',
array( '192.0.2.123', '192.0.2.0/24' )
)
);
$this->assertFalse(
invokeStatic(
StatifyBlacklist::class, 'cidr_match', array(
'192.0.3.123',
'192.0.2.0/24',
)
invoke_static(
StatifyBlacklist::class,
'cidr_match',
array( '192.0.3.123', '192.0.2.0/24' )
)
);
$this->assertTrue(
invokeStatic(
StatifyBlacklist::class, 'cidr_match', array(
'192.0.2.123',
'192.0.2.120/29',
)
invoke_static(
StatifyBlacklist::class,
'cidr_match',
array( '192.0.2.123', '192.0.2.120/29' )
)
);
$this->assertFalse(
invokeStatic(
StatifyBlacklist::class, 'cidr_match', array(
'192.0.2.128',
'192.0.2.120/29',
)
invoke_static(
StatifyBlacklist::class,
'cidr_match',
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(
invokeStatic(
StatifyBlacklist::class, 'cidr_match', array(
'10.11.12.345',
'10.0.0.0/8',
)
invoke_static(
StatifyBlacklist::class,
'cidr_match',
array( '10.11.12.345', '10.0.0.0/8' )
)
);
// IPv6 tests.
$this->assertTrue( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1' ) ) );
$this->assertTrue( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/128' ) ) );
$this->assertFalse( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/129' ) ) );
$this->assertFalse( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/-1' ) ) );
$this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1' ) ) );
$this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/128' ) ) );
$this->assertFalse( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/129' ) ) );
$this->assertFalse( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/-1' ) ) );
$this->assertTrue(
invokeStatic(
StatifyBlacklist::class, 'cidr_match', array(
'2001:db8:a0b:12f0:1:2:3:4',
'2001:db8:a0b:12f0::1/64 ',
)
invoke_static(
StatifyBlacklist::class,
'cidr_match',
array( '2001:db8:a0b:12f0:1:2:3:4', '2001:db8:a0b:12f0::1/64 ' )
)
);
$this->assertTrue(
invokeStatic(
StatifyBlacklist::class, 'cidr_match', array(
'2001:db8:a0b:12f0::123:456',
'2001:db8:a0b:12f0::1/96 ',
)
invoke_static(
StatifyBlacklist::class,
'cidr_match',
array( '2001:db8:a0b:12f0::123:456', '2001:db8:a0b:12f0::1/96 ' )
)
);
$this->assertFalse(
invokeStatic(
StatifyBlacklist::class, 'cidr_match', array(
'2001:db8:a0b:12f0::1:132:465',
'2001:db8:a0b:12f0::1/96 ',
)
invoke_static(
StatifyBlacklist::class,
'cidr_match',
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.
$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' );
$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->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 );
// IPv6 tests.
@ -327,28 +404,34 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'2001:db8:a0b:12f0::/129',
'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->assertInternalType( 'array', $result );
if ( method_exists( $this, 'assertIsArray' ) ) {
$this->assertIsArray( $result );
} else {
$this->assertInternalType( 'array', $result );
}
$this->assertEquals( $valid, $result );
}
/**
* Test IP filter (#7).
*
* @return void
*/
public function testIPFilter() {
// Prepare Options: 2 blacklisted IPs, disabled.
StatifyBlacklist::$_options = array(
public function test_ip_filter() {
// Prepare Options: 2 filtered IPs, disabled.
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
'cron' => 0,
'regexp' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'target' => array(
'active' => 0,
'cron' => 0,
'regexp' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'ip' => array(
@ -358,6 +441,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'2001:db8:a0b:12f0::1',
),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
@ -368,7 +456,7 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
$_SERVER['REMOTE_ADDR'] = '192.0.2.123';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Activate filter.
StatifyBlacklist::$_options['ip']['active'] = 1;
StatifyBlacklist::$options['ip']['active'] = 1;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Try matching v6 address.
$_SERVER['REMOTE_ADDR'] = '2001:db8:a0b:12f0::1';
@ -379,11 +467,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
$_SERVER['REMOTE_ADDR'] = '2001:db8:a0b:12f0::2';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Subnet matching.
StatifyBlacklist::$_options['ip']['blacklist'] = array(
StatifyBlacklist::$options['ip']['blacklist'] = array(
'192.0.2.0/25',
'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() );
$_SERVER['REMOTE_ADDR'] = '192.0.2.234';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
@ -405,20 +493,22 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
/**
* Test simple target filter.
*
* @return void
*/
public function testTargetFilter() {
// Prepare Options: 2 blacklisted domains, disabled.
StatifyBlacklist::$_options = array(
public function test_target_filter() {
// Prepare Options: 2 filtered domains, disabled.
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
'cron' => 0,
'regexp' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'target' => array(
'active' => 0,
'cron' => 0,
'regexp' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(
'/excluded/page/' => 0,
'/?page_id=3' => 1,
@ -428,6 +518,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
@ -437,21 +532,21 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// Empty target.
unset( $_SERVER['REQUEST_URI'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-blacklisted targets.
// Non-filtered targets.
$_SERVER['REQUEST_URI'] = '';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['REQUEST_URI'] = '/';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['REQUEST_URI'] = '/?page_id=1';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Blacklisted referer.
// Filtered referer.
$_SERVER['REQUEST_URI'] = '/excluded/page/';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['REQUEST_URI'] = '/?page_id=3';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Activate filter and run tests again.
StatifyBlacklist::$_options['target']['active'] = 1;
StatifyBlacklist::$options['target']['active'] = 1;
unset( $_SERVER['REQUEST_URI'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
@ -474,6 +569,69 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// TODO: Test target regex filter.
/**
* Test user agent filter (#20).
*
* @return void
*/
public function test_ua_filter() {
// Prepare Options: 2 filtered IPs, disabled.
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
'cron' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'target' => array(
'active' => 0,
'cron' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'ip' => array(
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(
'TestBot/1.23' => 0,
),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
// No multisite.
StatifyBlacklist::$multisite = false;
// Set matching user agent.
$_SERVER['HTTP_USER_AGENT'] = 'TestBot/1.23';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Activate filter.
StatifyBlacklist::$options['ua']['active'] = 1;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Non-matching addresses.
$_SERVER['HTTP_USER_AGENT'] = 'Another Browser 4.5.6 (Linux)';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['HTTP_USER_AGENT'] = 'TestBot/2.34';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Keyword matching.
StatifyBlacklist::$options['ua']['blacklist'] = array( 'TestBot' => 0 );
StatifyBlacklist::$options['ua']['regexp'] = StatifyBlacklist::MODE_KEYWORD;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// RegEx.
StatifyBlacklist::$options['ua']['blacklist'] = array( 'T[a-z]+B[a-z]+' => 0 );
StatifyBlacklist::$options['ua']['regexp'] = StatifyBlacklist::MODE_REGEX;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
StatifyBlacklist::$options['ua']['blacklist'] = array( 't[a-z]+' => 0 );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
StatifyBlacklist::$options['ua']['regexp'] = StatifyBlacklist::MODE_REGEX_CI;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
}
/**
* Test combined filters.
*
@ -483,11 +641,11 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
*/
public function test_combined_filters() {
// Prepare Options: simple referer + simple target + ip.
StatifyBlacklist::$_options = array(
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 1,
'cron' => 0,
'regexp' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(
'example.com' => 0,
),
@ -495,17 +653,22 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'target' => array(
'active' => 1,
'cron' => 0,
'regexp' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(
'/excluded/page/' => 0
'/excluded/page/' => 0,
),
),
'ip' => array(
'active' => 1,
'blacklist' => array(
'192.0.2.123'
'192.0.2.123',
),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
@ -514,8 +677,8 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// No match.
$_SERVER['HTTP_REFERER'] = 'https://example.net';
$_SERVER['REQUEST_URI'] = '/normal/page/';
$_SERVER['REMOTE_ADDR'] = '192.0.2.234';
$_SERVER['REQUEST_URI'] = '/normal/page/';
$_SERVER['REMOTE_ADDR'] = '192.0.2.234';
unset( $_SERVER['HTTP_X_FORWARDED_FOR'] );
unset( $_SERVER['HTTP_X_REAL_IP'] );
@ -525,7 +688,7 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// Matching target.
$_SERVER['HTTP_REFERER'] = 'https://example.net';
$_SERVER['REQUEST_URI'] = '/excluded/page/';
$_SERVER['REQUEST_URI'] = '/excluded/page/';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Matching IP.
@ -535,16 +698,21 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
$_SERVER['REMOTE_ADDR'] = '192.0.2.234';
// Same for RegExp filters.
StatifyBlacklist::$_options['referer']['regexp'] = 1;
StatifyBlacklist::$_options['referer']['blacklist'] = array( 'example\.com' => 0 );
StatifyBlacklist::$_options['target']['regexp'] = 1;
StatifyBlacklist::$_options['target']['blacklist'] = array( '\/excluded\/.*' => 0 );
StatifyBlacklist::$options['referer']['regexp'] = StatifyBlacklist::MODE_REGEX;
StatifyBlacklist::$options['referer']['blacklist'] = array( 'example\.com' => 0 );
StatifyBlacklist::$options['target']['regexp'] = StatifyBlacklist::MODE_REGEX;
StatifyBlacklist::$options['target']['blacklist'] = array( '/excluded/.*' => 0 );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['HTTP_REFERER'] = 'https://example.com';
$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['REQUEST_URI'] = '/excluded/page/';
$_SERVER['REQUEST_URI'] = '/excluded/page/';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['REQUEST_URI'] = '/normal/page/';
$_SERVER['REMOTE_ADDR'] = '192.0.2.123';
@ -556,9 +724,9 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
/** @ignore */
function invokeStatic( $class, $methodName, $parameters = array() ) {
function invoke_static( $class, $method_name, $parameters = array() ) {
$reflection = new \ReflectionClass( $class );
$method = $reflection->getMethod( $methodName );
$method = $reflection->getMethod( $method_name );
$method->setAccessible( true );
return $method->invokeArgs( null, $parameters );

View File

@ -1,6 +1,6 @@
<?php
/**
* Statify Blacklist: Settings View
* Statify Filter: Settings View
*
* This file contains the dynamic HTML skeleton for the plugin's settings page.
*
@ -9,6 +9,8 @@
* @since 1.0.0
*/
// phpcs:disable WordPress.WhiteSpace.PrecisionAlignment.Found
// Quit.
defined( 'ABSPATH' ) || exit;
@ -19,7 +21,7 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
// Check user capabilities.
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?', 'statify-blacklist' ) );
}
if ( ! empty( $_POST['cleanUp'] ) ) {
@ -27,24 +29,83 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
StatifyBlacklist_Admin::cleanup_database();
} else {
// 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();
} 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.
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();
} 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.
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();
} 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 );
}
);
}
// TODO: Extract user agent array.
if ( isset( $_POST['statifyblacklist']['ua']['blacklist'] ) ) {
$ua_string = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['ua']['blacklist'] ) );
}
if ( empty( trim( $ua_string ) ) ) {
$ua = array();
} else {
$ua = array_filter(
array_map(
function ( $a ) {
return trim( $a );
},
explode( "\r\n", str_replace( '\\\\', '\\', $ua_string ) )
),
function ( $a ) {
return ! empty( $a );
}
);
}
// Update options (data will be sanitized).
@ -73,27 +134,46 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
? (int) $_POST['statifyblacklist']['ip']['active'] : 0,
'blacklist' => $ip,
),
'ua' => array(
'active' => isset( $_POST['statifyblacklist']['ua']['active'] )
? (int) $_POST['statifyblacklist']['ua']['active'] : 0,
'regexp' => isset( $_POST['statifyblacklist']['ua']['regexp'] )
? (int) $_POST['statifyblacklist']['ua']['regexp'] : 0,
'blacklist' => $ua,
),
'version' => StatifyBlacklist::VERSION_MAIN,
)
);
// Generate messages.
if ( false !== $statifyblacklist_update_result ) {
if ( array_key_exists( 'referer', $statifyblacklist_update_result ) ) {
$statifyblacklist_post_warning = __( 'Some URLs are invalid and have been sanitized.', 'statify-blacklist' );
} elseif ( array_key_exists( 'ip', $statifyblacklist_update_result ) ) {
$statifyblacklist_post_warning = array();
if ( ! empty( $statifyblacklist_update_result['referer']['diff'] ) ) {
$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).
$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 {
$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">
<h1><?php esc_html_e( 'Statify Blacklist', 'statify-blacklist' ) ?></h1>
<h1><?php esc_html_e( 'Statify Filter', 'statify-blacklist' ); ?></h1>
<?php
if ( is_plugin_inactive( 'statify/statify.php' ) ) {
print '<div class="notice notice-warning"><p>';
@ -101,11 +181,12 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
print '</p></div>';
}
if ( isset( $statifyblacklist_post_warning ) ) {
print '<div class="notice notice-warning"><p>' .
esc_html( $statifyblacklist_post_warning );
print '<br/>';
esc_html_e( 'Settings have not been saved yet.', 'statify-blacklist' );
print '</p></div>';
foreach ( $statifyblacklist_post_warning as $w ) {
print '<div class="notice notice-warning"><p>' .
wp_kses( $w, array( 'br' => array() ) ) .
'</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 ) ) {
print '<div class="notice notice-success"><p>' .
@ -114,179 +195,294 @@ if ( ! empty( $_POST['statifyblacklist'] ) ) {
}
?>
<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' ); ?>
<h2><?php esc_html_e( 'Referer filter', '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 filter', '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 filter', '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_target_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 filter', '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 filter', '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 filter', '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>
<h2><?php esc_html_e( 'User agent filter', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="statify-blacklist_active_ua">
<?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[ua][active]" id="statify-blacklist_active_ua"
value="1" <?php checked( StatifyBlacklist::$options['ua']['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 user agent filter, because the user agent is stored.', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_ua_regexp"><?php esc_html_e( 'Matching method', 'statify-blacklist' ); ?></label>
</th>
<td>
<select name="statifyblacklist[ua][regexp]" id="statify-blacklist_ua_regexp">
<option value="<?php print esc_attr( StatifyBlacklist::MODE_NORMAL ); ?>" <?php selected( StatifyBlacklist::$options['ua']['regexp'], StatifyBlacklist::MODE_NORMAL ); ?>>
<?php esc_html_e( 'Exact', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_KEYWORD ); ?>" <?php selected( StatifyBlacklist::$options['ua']['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['ua']['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['ua']['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 user agents', '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 user agent by regular expression', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_ua"><?php esc_html_e( 'User agent filter', 'statify-blacklist' ); ?></label>:
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[ua][blacklist]" id="statify-blacklist_ua"><?php
if ( empty( $statifyblacklist_update_result['ua'] ) ) {
print esc_html( implode( "\r\n", StatifyBlacklist::$options['ua']['blacklist'] ) );
} else {
print esc_html( implode( "\r\n", $statifyblacklist_update_result['ua']['sanitized'] ) );
}
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one user agent string per line, e.g.', 'statify-blacklist' ); ?>
MyBot/1.23
</p>
</td>
</tr>
</tbody>
</table>
<p class="submit">
<input class="button-primary" type="submit" name="submit" value="<?php esc_html_e( 'Save Changes' ) ?>">
<hr />
<input class="button-secondary" type="submit" name="cleanUp"
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.');">
<br />
<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></small>
<input class="button-primary" type="submit" name="submit" value="<?php esc_html_e( 'Save Changes', 'statify-blacklist' ); ?>">
<hr>
<input class="button-secondary" type="submit" name="cleanUp"
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.');">
<br>
<p class="description">
<?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>
</form>
</div>