Compare commits

..

No commits in common. "stable" and "v1.5.0" have entirely different histories.

25 changed files with 1338 additions and 1965 deletions

View File

@ -1,18 +0,0 @@
/.git
/.github
/assets
/dist
/test
/vendor
/.distignore
/.editorconfig
/.gitattributes
/.gitignore
/.travis.yml
/composer.json
/composer.lock
/CONTRIBUTING.md
/package.json
/package-lock.json
/phpcs.xml
/phpunit.xml

View File

@ -1,21 +0,0 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org
# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab
[{.jshintrc,*.json,*.yml,*.feature}]
indent_style = space
indent_size = 2
[{*.txt,wp-config-sample.php}]
end_of_line = crlf

4
.gitattributes vendored
View File

@ -1,8 +1,5 @@
/.github export-ignore
/assets export-ignore
/dist export-ignore
/test export-ignore
.distignore export-ignore
.gitattributes export-ignore
.gitignore export-ignore
.travis.yml export-ignore
@ -12,3 +9,4 @@ CONTRIBUTING.md export-ignore
package.json export-ignore
phpcs.xml export-ignore
phpunit.xml export-ignore
RoboFile.php export-ignore

View File

@ -1,55 +0,0 @@
name: CI
on: [ push, pull_request ]
jobs:
unit-test:
runs-on: ubuntu-latest
strategy:
matrix:
php: [ '5.6', '7.4', '8.0', '8.2', '8.4' ]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: xdebug
tools: composer
- name: Install
run: composer install --no-interaction
- name: Unit tests
run: |
composer test
sed -i "s#<file name=\"${GITHUB_WORKSPACE}#<file name=\"/github/workspace#g" tests-clover.xml
- name: Analyze with SonarCloud
if: matrix.php == '8.2' && env.SONAR_TOKEN != ''
uses: sonarsource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
args: >
-Dsonar.organization=stklcode-github
-Dsonar.projectKey=stklcode:statify-blacklist
-Dsonar.sources=inc,statify-blacklist.php
-Dsonar.tests=test
-Dsonar.php.tests.reportPath=tests-junit.xml
-Dsonar.php.coverage.reportPaths=tests-clover.xml
-Dsonar.coverage.exclusions=test/**/*.php
quality:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
tools: composer
- name: Install
run: composer install --no-interaction
- name: Code style checks for PHP
run: composer test-cs

View File

@ -1,20 +0,0 @@
name: Plugin asset/readme update
on:
push:
branches:
- stable
jobs:
master:
name: Push to stable
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Clean README.md
run: tail -n +6 README.md > README.md.tmp && mv README.md.tmp README.md
- name: WordPress.org plugin asset/readme update
uses: 10up/action-wordpress-plugin-asset-update@stable
env:
ASSETS_DIR: assets
README_NAME: README.md
SVN_PASSWORD: ${{ secrets.WP_SVN_PASSWORD }}
SVN_USERNAME: ${{ secrets.WP_SVN_USERNAME }}

View File

@ -1,23 +0,0 @@
name: Plugin check
on:
push:
branches: [ 'stable', 'release/*' ]
pull_request:
branches: [ 'stable' ]
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Package plugin
run: |
mkdir -p ./dist
tail -n +6 README.md > README.md.tmp && mv README.md.tmp README.md
rsync -rc --exclude-from=.distignore ./ ./dist/statify-blacklist --delete --delete-excluded
- name: Check WP plugin
uses: wordpress/plugin-check-action@v1
with:
build-dir: ./dist/statify-blacklist

View File

@ -1,20 +0,0 @@
name: Deploy to WordPress.org
on:
push:
tags:
- "v*"
- "!v*-*"
jobs:
tag:
name: New tag
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Clean README.md
run: tail -n +6 README.md > README.md.tmp && mv README.md.tmp README.md
- name: WordPress Plugin Deploy
uses: 10up/action-wordpress-plugin-deploy@stable
env:
ASSETS_DIR: assets
SVN_PASSWORD: ${{ secrets.WP_SVN_PASSWORD }}
SVN_USERNAME: ${{ secrets.WP_SVN_USERNAME }}

13
.travis.yml Normal file
View File

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

109
README.md
View File

@ -1,43 +1,38 @@
[![CI](https://github.com/stklcode/statify-blacklist/actions/workflows/test.yml/badge.svg?branch=stable)](https://github.com/stklcode/statify-blacklist/actions/workflows/test.yml)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=stklcode%3Astatify-blacklist&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=stklcode%3Astatify-blacklist)
[![Packagist Version](https://img.shields.io/packagist/v/stklcode/statify-blacklist)](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/stable/LICENSE.md)
[![Build Status](https://travis-ci.org/stklcode/statify-blacklist.svg?branch=master)](https://travis-ci.org/stklcode/statify-blacklist)
[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=de.stklcode.web.wordpress.plugins%3Astatify-blacklist&metric=alert_status)](https://sonarcloud.io/dashboard?id=de.stklcode.web.wordpress.plugins%3Astatify-blacklist)
[![Packagist Version](https://img.shields.io/packagist/v/stklcode/statify-blacklist.svg)](https://packagist.org/packages/stklcode/statify-blacklist)
[![License](https://img.shields.io/badge/license-GPL%20v2-blue.svg)](https://github.com/stklcode/statify-blacklist/blob/master/LICENSE.md)
# Statify Filter #
* Contributors: stklcode
# Statify Blacklist #
* Contributors: Stefan Kalscheuer
* Requires at least: 4.7
* Tested up to: 6.8
* Tested up to: 5.4
* Requires PHP: 5.5
* Stable tag: 1.7.2
* Stable tag: 1.5.0
* License: GPLv2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
Filter extension for the famous Statify WordPress plugin.
## Description ##
A filter extension for the famous [Statify](https://wordpress.org/plugins/statify/) WordPress plugin.
A blacklist extension for the famous [Statify](https://wordpress.org/plugins/statify/) Wordpress plugin.
This plugin adds customizable filters to Statify to allow blocking of referer spam or internal interactions.
This plugin adds a customizable blacklist to Statify to allow blocking of referer spam or internal interactions.
### Features ###
### Features ##
#### Referer Filter ####
#### Referer Blacklist ####
Add a list of domains (for simplicity only second-level, e.g. _example.com_ which blocks _everything.example.com_).
#### Target Filter ####
#### Target Blacklist ####
Add a list of target pages (e.g. _/test/page/_, _/?page_id=123_) that will be excluded from tracking.
#### IP Filter ####
#### IP Blacklist ####
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.8
This plugin requires Statify to be installed. The extension has been tested with Statify up to version 1.7
The plugin is capable of handling multisite installations.
### Support & Contributions ###
@ -52,7 +47,7 @@ The plugin is capable of handling multisite installations.
## Installation ##
* 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
* Goto _Settings_ -> _Statify Blacklist_ to configure the plugin
### Requirements ###
* PHP 5.5 or above
@ -62,9 +57,9 @@ The plugin is capable of handling multisite installations.
## Frequently Asked Questions ##
### What is blocked by default? ###
Nothing. By default, all filters are empty and disabled. They can and have to be filled by the blog administrator.
Nothing. By default, all blacklists are empty and disabled. They can and have to be filled by the blog administrator.
A default filter is not provided, as the plugin itself is totally neutral. If you want to filter out referer spam,
A default blacklist is not provided, as the plugin itself is totally neutral. If you want to filter out referer spam,
visitors from search engines, just "false" referrers from 301 redirects or you own IP address used for testing only depends on you.
### Does the filter effect user experience? ###
@ -73,81 +68,27 @@ No. It only prevents _Statify_ from tracking, nothing more or less.
### Does live filtering impact performance? ###
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 regular expressions (case-sensitive or insensitive) as matching method instead of exact or keyword match.
### Why is IP and User Agent filtering only available as live filter? ###
### Why is IP filtering only available as live filter? ###
As you might know, _Statify_ does not store any personal information, including IP addresses in the database.
Because of this, these filters can only be applied while processing the request and not afterwards.
Because of this, an IP blacklist can only be applied while processing the request and not afterwards.
### Can whole IP subnet be blocked? ###
Yes. The plugin features subnet filters using CIDR notation.
For example _198.51.100.0/24_ filters all sources from _198.51.100.1_ to _198.51.100.254_.
Yes. The plugin features subnet blacklists using CIDR notation.
For example _198.51.100.0/24_ blacklists all sources from _198.51.100.1_ to _198.51.100.254_.
Same for IPv6 prefixes like _2001:db8:a0b:12f0::/64_.
## Screenshots ##
1. Statify Filter settings page
1. Statify Blacklist settings page
## Upgrade Notice ##
### 1.7.2 ###
This is a bugfix release to restore the manual cleanup function that was broken since 1.7.0.
### 1.7.1 ###
This is a service release with minor corrections. Recommended for all users. Tested up to 6.5.
### 1.7.0 ###
This is a service release with primarily internal rework. Tested up to 6.4 and PHP 8.3.
## Changelog
### 1.7.2 / 06.06.2024 ###
* Restore manual database cleanup functionality
### 1.7.1 / 24.03.2024 ###
* Fix HTML syntax for checkboxes on settings page
* Simplify some internal control structures
* Add plugin dependency to Statify
* Declared compatibility with WordPress 6.5
### 1.7.0 / 11.03.2024 ###
* Internal rework of plugin settings
* Make the IP filter list unique
* Fix options upgrade routine
* Declared compatibility with WordPress 6.4
### 1.6.3 / 14.08.2023 ###
* Minor internal code cleanup
* Declared compatibility with WordPress 6.3
### 1.6.2 / 25.02.2023 ###
* Always process IPv6 addresses lowercase
* Optimize internally used regular expression
* Minor adjustments to prevent warnings during user agent filtering with PHP 8.2
### 1.6.1 / 28.05.2021 ###
* Fix storage of user agent filter list (#28, props @BananaSquishee)
### 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)
## Changelog ##
### 1.5.0 / 13.05.2020 ###
* Minimum required WordPress version is 4.7

396
RoboFile.php Normal file
View File

@ -0,0 +1,396 @@
<?php
/**
* Statify Blacklist Robo build script.
*
* This file contains the Robo tasks for building a distributable plugin package.
* Should not be included in final package.
*
* @author Stefan Kalscheuer <stefan@stklcode.de>
*
* @package Statify_Blacklist
* @version 1.5.0
*/
use Robo\Exception\TaskException;
use Robo\Tasks;
/**
* Class RoboFile
*/
class RoboFile extends Tasks {
const PROJECT_NAME = 'statify-blacklist';
const SVN_URL = 'https://plugins.svn.wordpress.org/statify-blacklist';
const OPT_TARGET = 'target';
const OPT_SKIPTEST = 'skipTests';
const OPT_SKIPSTYLE = 'skipStyle';
/**
* Version tag (read from composer.json).
*
* @var string
*/
private $version;
/**
* Target directory path.
*
* @var string
*/
private $target_dir;
/**
* Final package name.
*
* @var string
*/
private $final_name;
/**
* RoboFile constructor
*
* @param array $opts Options.
*
* @return void
*/
public function __construct( $opts = [ self::OPT_TARGET => 'dist' ] ) {
// Read composer configuration and extract version number..
$composer = json_decode( file_get_contents( __DIR__ . '/composer.json' ) );
// Extract parameter from options.
$this->version = $composer->version;
$this->target_dir = $opts[ self::OPT_TARGET ];
$this->final_name = self::PROJECT_NAME . '.' . $this->version;
}
/**
* Clean up target directory
*
* @param array $opts Options.
*
* @return void
*/
public function clean( $opts = [ self::OPT_TARGET => 'dist' ] ) {
$this->say( 'Cleaning target directory...' );
if ( is_dir( $this->target_dir . '/' . $this->final_name ) ) {
$this->_deleteDir( [ $this->target_dir . '/' . $this->final_name ] );
}
if ( is_file( $this->target_dir . '/' . $this->final_name . '.zip' ) ) {
$this->_remove( $this->target_dir . '/' . $this->final_name . '.zip' );
}
}
/**
* Run PHPUnit tests
*
* @return void
*/
public function test() {
$this->say( 'Executing PHPUnit tests...' );
$this->taskPhpUnit()->configFile( __DIR__ . '/phpunit.xml' )->run();
}
/**
* Run code style tests
*
* @return void
*/
public function testCS() {
$this->say( 'Executing PHPCS tests...' );
$this->_exec( __DIR__ . '/vendor/bin/phpcs --standard=phpcs.xml -s' );
}
/**
* Build a distributable bundle.
*
* @param array $opts Options.
*
* @return void
*/
public function build(
$opts = [
self::OPT_TARGET => 'dist',
self::OPT_SKIPTEST => false,
self::OPT_SKIPSTYLE => false,
]
) {
$this->clean( $opts );
if ( isset( $opts[ self::OPT_SKIPTEST ] ) && true === $opts[ self::OPT_SKIPTEST ] ) {
$this->say( 'Tests skipped' );
} else {
$this->test();
}
if ( isset( $opts[ self::OPT_SKIPSTYLE ] ) && true === $opts[ self::OPT_SKIPSTYLE ] ) {
$this->say( 'Style checks skipped' );
} else {
$this->testCS();
}
$this->bundle();
}
/**
* Bundle global resources.
*
* @return void
*/
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->_copy( 'statify-blacklist.php', $this->target_dir . '/' . $this->final_name . '/statify-blacklist.php' );
$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();
}
/**
* Create ZIP package from distribution bundle.
*
* @param array $opts Options.
*
* @return void
*/
public function package(
$opts = [
self::OPT_TARGET => 'dist',
self::OPT_SKIPTEST => false,
self::OPT_SKIPSTYLE => false,
]
) {
$this->build( $opts );
$this->say( 'Packaging...' );
$this->taskPack( $this->target_dir . '/' . $this->final_name . '.zip' )
->addDir( '', $this->target_dir . '/' . $this->final_name )
->run();
}
/**
* Deploy development version (trunk).
*
* @param array $opts Options.
*
* @return void
* @throws TaskException On errors.
*/
public function deployTrunk(
$opts = [
self::OPT_TARGET => 'dist',
self::OPT_SKIPTEST => false,
self::OPT_SKIPSTYLE => false,
]
) {
// First execute build job.
$this->build( $opts );
// Prepare VCS, either checkout or update local copy.
$this->prepareVCS();
$this->say( 'Preparing deployment directory...' );
$this->updateVCStrunk();
// Update remote repository.
$this->say( 'Deploying...' );
$this->commitVCS(
'--force trunk/*',
'Updated ' . self::PROJECT_NAME . ' trunk'
);
}
/**
* Deploy current version tag.
*
* @param array $opts Options.
*
* @return void
* @throws TaskException On errors.
*/
public function deployTag(
$opts = [
self::OPT_TARGET => 'dist',
self::OPT_SKIPTEST => false,
self::OPT_SKIPSTYLE => false,
]
) {
// First execute build job.
$this->build( $opts );
// Prepare VCS, either checkout or update local copy.
$this->prepareVCS();
$this->say( 'Preparing deployment directory...' );
$this->updateVCStag();
// Update remote repository.
$this->say( 'Deploying...' );
$this->commitVCS(
'tags/' . $this->version,
'Updated ' . self::PROJECT_NAME . ' v' . $this->version
);
}
/**
* Deploy current version tag.
*
* @param array $opts Options.
*
* @return void
* @throws TaskException On errors.
*/
public function deployReadme(
$opts = [
self::OPT_TARGET => 'dist',
self::OPT_SKIPTEST => false,
self::OPT_SKIPSTYLE => false,
]
) {
// First execute build job.
$this->build( $opts );
// Prepare VCS, either checkout or update local copy.
$this->prepareVCS();
$this->updateVCSreadme();
// Update remote repository.
$this->say( 'Deploying...' );
$this->commitVCS(
'--force trunk/README.md',
'Updated ' . self::PROJECT_NAME . ' ReadMe'
);
}
/**
* Deploy current version tag and trunk.
*
* @param array $opts Options.
*
* @return void
* @throws TaskException On errors.
*/
public function deployAll(
$opts = [
self::OPT_TARGET => 'dist',
self::OPT_SKIPTEST => false,
self::OPT_SKIPSTYLE => false,
]
) {
// First execute build job.
$this->build( $opts );
// Prepare VCS, either checkout or update local copy.
$this->prepareVCS();
$this->say( 'Preparing deployment directory...' );
$this->updateVCStrunk();
$this->updateVCStag();
// Update remote repository.
$this->say( 'Deploying...' );
$this->commitVCS(
[
'--force trunk/*',
'--force tags/' . $this->version,
],
'Updated ' . self::PROJECT_NAME . ' v' . $this->version
);
}
/**
* Prepare VCS direcory.
*
* Checkout or update local copy of SVN repository.
*
* @return void
* @throws TaskException On errors.
*/
private function prepareVCS() {
if ( is_dir( $this->target_dir . '/svn' ) ) {
$this->taskSvnStack()
->stopOnFail()
->dir( $this->target_dir . '/svn/statify-blacklist' )
->update()
->run();
} else {
$this->_mkdir( $this->target_dir . '/svn' );
$this->taskSvnStack()
->dir( $this->target_dir . '/svn' )
->checkout( self::SVN_URL )
->run();
}
}
/**
* Commit VCS changes
*
* @param string|array $to_add Files to add.
* @param string $msg Commit message.
*
* @return void
* @throws TaskException On errors.
*/
private function commitVCS( $to_add, $msg ) {
$task = $this->taskSvnStack()
->stopOnFail()
->dir( $this->target_dir . '/svn/statify-blacklist' );
if ( is_array( $to_add ) ) {
foreach ( $to_add as $ta ) {
$task = $task->add( $ta );
}
} else {
$task = $task->add( $to_add );
}
$task->commit( $msg )->run();
}
/**
* Update SVN readme file.
*
* @return void
*/
private function updateVCSreadme() {
$trunk_dir = $this->target_dir . '/svn/statify-blacklist/trunk';
$this->_copy( $this->target_dir . '/' . $this->final_name . '/README.md', $trunk_dir . '/README.md' );
}
/**
* Update SVN development version (trunk).
*
* @return void
*/
private function updateVCStrunk() {
// Clean trunk directory.
$trunk_dir = $this->target_dir . '/svn/statify-blacklist/trunk';
$this->taskCleanDir( $trunk_dir )->run();
// Copy built bundle to trunk.
$this->taskCopyDir( [ $this->target_dir . '/' . $this->final_name => $trunk_dir ] )->run();
}
/**
* Update current SVN version tag.
*
* @return void
*/
private function updateVCStag() {
// Clean tag directory if it exists.
$tag_dir = $this->target_dir . '/svn/statify-blacklist/tags/' . $this->version;
if ( is_dir( $tag_dir ) ) {
$this->taskCleanDir( $this->target_dir . '/svn/statify-blacklist/tags/' . $this->version )->run();
} else {
$this->_mkdir( $tag_dir );
}
// Copy built bundle to trunk.
$this->taskCopyDir( [ $this->target_dir . '/' . $this->final_name => $tag_dir ] )->run();
}
}

View File

@ -1,36 +0,0 @@
{
"$schema": "https://playground.wordpress.net/blueprint-schema.json",
"landingPage": "/wp-admin/options-general.php?page=statify-blacklist",
"features": {
"networking": true
},
"steps": [
{
"step": "login",
"username": "admin",
"password": "password"
},
{
"step": "installPlugin",
"pluginData": {
"resource": "wordpress.org/plugins",
"slug": "statify"
}
},
{
"step": "activatePlugin",
"pluginPath": "statify/statify.php"
},
{
"step": "installPlugin",
"pluginData": {
"resource": "wordpress.org/plugins",
"slug": "statify-blacklist"
}
},
{
"step": "activatePlugin",
"pluginPath": "statify-blacklist/statify-blacklist.php"
}
]
}

View File

@ -1,12 +1,12 @@
{
"name": "stklcode/statify-blacklist",
"version": "1.7.2",
"description": "A filter extension for the famous Statify WordPress plugin",
"version": "1.5.0",
"description": "A blacklist extension for the famous Statify WordPress plugin",
"keywords": [
"wordpress",
"plugin",
"statistics",
"filter"
"blacklist"
],
"license": "GPL-2.0-or-later",
"authors": [
@ -19,18 +19,28 @@
"type": "wordpress-plugin",
"require": {
"php": ">=5.5",
"composer/installers": "~v1.12|~v2.3"
"composer/installers": "~1.7"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^v1.0",
"phpunit/phpunit": "^5|^6|^7|^8|^9",
"dealerdirect/phpcodesniffer-composer-installer": "^0.5",
"consolidation/robo": "^1.4",
"phpunit/phpunit": "*",
"phpunit/php-code-coverage": "*",
"slowprog/composer-copy-file": "~0.3",
"squizlabs/php_codesniffer": "^3.12",
"phpcompatibility/phpcompatibility-wp": "^2.1",
"wp-coding-standards/wpcs": "^3.1"
"slowprog/composer-copy-file": "~0.2",
"squizlabs/php_codesniffer": "^3.5",
"phpcompatibility/php-compatibility": "^9.3",
"wp-coding-standards/wpcs": "^2.1"
},
"scripts": {
"build": [
"robo build"
],
"package": [
"robo package"
],
"deploy": [
"robo deploy:all"
],
"test-all": [
"@test",
"@test-cs"
@ -44,11 +54,5 @@
"fix-cs": [
"phpcbf --standard=phpcs.xml"
]
},
"config": {
"allow-plugins": {
"composer/installers": true,
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}

View File

@ -1,6 +1,6 @@
<?php
/**
* Statify Filter: StatifyBlacklist_Admin class
* Statify Blacklist: StatifyBlacklist_Admin class
*
* This file contains the derived class for the plugin's administration features.
*
@ -15,16 +15,18 @@ if ( ! defined( 'ABSPATH' ) ) {
}
/**
* Statify Filter admin configuration.
* Statify Blacklist admin configuration.
*
* @since 1.0.0
*/
class StatifyBlacklist_Admin extends StatifyBlacklist {
/**
* Initialize admin-only components of the plugin.
*
* @return void
*
* @since 1.5.0
*
* @return void
*/
public static function init() {
// Add actions.
@ -44,47 +46,144 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
2
);
} else {
add_action( 'admin_init', array( 'StatifyBlacklist_Settings', 'register_settings' ) );
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.
*/
public static function update_options( $options = null ) {
if ( isset( $options ) && current_user_can( 'manage_options' ) ) {
// 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 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::sanitize_ips( $given_ip );
// Abort on errors.
$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.
if ( self::$multisite ) {
update_site_option( 'statify-blacklist', $options );
} else {
update_option( 'statify-blacklist', $options );
}
}
// Refresh options.
parent::update_options( $options );
return false;
}
/**
* Add configuration page to admin menu.
*
* @since 1.0.0
*/
public static function add_menu_page() {
$title = __( 'Statify Filter', 'statify-blacklist' );
$title = __( 'Statify Blacklist', 'statify-blacklist' );
if ( self::$multisite ) {
add_options_page(
add_submenu_page(
'settings.php',
$title,
$title,
'manage_network_plugins',
'statify-blacklist',
array( 'StatifyBlacklist_Settings', 'create_settings_page' )
'statify-blacklist-settings',
array(
'StatifyBlacklist_Admin',
'settings_page',
)
);
} else {
add_options_page(
add_submenu_page(
'options-general.php',
$title,
$title,
'manage_options',
'statify-blacklist',
array( 'StatifyBlacklist_Settings', 'create_settings_page' )
array(
'StatifyBlacklist_Admin',
'settings_page',
)
);
}
}
/**
* Include the Statify-Blacklist settings page.
*
* @since 1.0.0
*/
public static function settings_page() {
include STATIFYBLACKLIST_DIR . '/views/settings-page.php';
}
/**
* Add plugin meta links
*
* @since 1.0.0
*
* @param array $links Registered links.
* @param string $file The filename.
*
* @return array Merged links.
*
* @since 1.0.0
*/
public static function plugin_meta_link( $links, $file ) {
if ( STATIFYBLACKLIST_BASE === $file ) {
@ -97,12 +196,12 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
/**
* Add plugin action links.
*
* @since 1.0.0
*
* @param array $links Registered links.
* @param string $file The filename.
*
* @return array Merged links.
*
* @since 1.0.0
*/
public static function plugin_actions_links( $links, $file ) {
$base = self::$multisite ? network_admin_url( 'settings.php' ) : admin_url( 'options-general.php' );
@ -110,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', 'statify-blacklist' ) )
sprintf( '<a href="%s">%s</a>', esc_attr( add_query_arg( 'page', 'statify-blacklist', $base ) ), __( 'Settings' ) )
);
}
@ -127,7 +226,7 @@ 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?', 'statify-blacklist' ) );
die( esc_html__( 'Are you sure you want to do this?' ) );
}
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
@ -200,11 +299,11 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
/**
* Sanitize URLs and remove empty results.
*
* @since 1.1.1
*
* @param array $urls given array of URLs.
*
* @return array sanitized array.
*
* @since 1.1.1
*/
private static function sanitize_urls( $urls ) {
return array_flip(
@ -218,4 +317,50 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
)
);
}
/**
* Sanitize IP addresses with optional CIDR notation and remove empty results.
*
* @since 1.4.0
*
* @param array $ips given array of URLs.
*
* @return array sanitized array.
*/
private static function sanitize_ips( $ips ) {
return array_filter(
$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
) ||
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,752 +0,0 @@
<?php
/**
* Statify Filter: StatifyBlacklist_Settings class
*
* This file contains the plugin's settings capabilities.
*
* @package Statify_Blacklist
* @since 1.7.0
*/
// Quit if accessed directly.
defined( 'ABSPATH' ) || exit;
/**
* Statify Filter settings handling.
*/
class StatifyBlacklist_Settings extends StatifyBlacklist {
/**
* Registers all options using the WP Settings API.
*
* @return void
*/
public static function register_settings() {
register_setting(
'statify-blacklist',
'statify-blacklist',
array(
'sanitize_callback' =>
array( __CLASS__, 'sanitize_options' ),
)
);
// Referer filter.
add_settings_section(
'statifyblacklist-referer',
__( 'Referer filter', 'statify-blacklist' ),
null,
'statify-blacklist'
);
add_settings_field(
'statifyblacklist-referer-active',
__( 'Activate live filter', 'statify-blacklist' ),
array( __CLASS__, 'option_referer_active' ),
'statify-blacklist',
'statifyblacklist-referer'
);
add_settings_field(
'statifyblacklist-referer-cron',
__( 'CronJob execution', 'statify-blacklist' ),
array( __CLASS__, 'option_referer_cron' ),
'statify-blacklist',
'statifyblacklist-referer'
);
add_settings_field(
'statifyblacklist-referer-regexp',
__( 'Matching method', 'statify-blacklist' ),
array( __CLASS__, 'option_referer_regexp' ),
'statify-blacklist',
'statifyblacklist-referer',
array( 'label_for' => 'statifyblacklist-referer-regexp' )
);
add_settings_field(
'statifyblacklist-referer-blacklist',
__( 'Referer filter', 'statify-blacklist' ),
array( __CLASS__, 'option_referer_blacklist' ),
'statify-blacklist',
'statifyblacklist-referer',
array( 'label_for' => 'statifyblacklist-referer-blacklist' )
);
// Target filter.
add_settings_section(
'statifyblacklist-target',
__( 'Target filter', 'statify-blacklist' ),
null,
'statify-blacklist'
);
add_settings_field(
'statifyblacklist-target-active',
__( 'Activate live filter', 'statify-blacklist' ),
array( __CLASS__, 'option_target_active' ),
'statify-blacklist',
'statifyblacklist-target'
);
add_settings_field(
'statifyblacklist-target-cron',
__( 'CronJob execution', 'statify-blacklist' ),
array( __CLASS__, 'option_target_cron' ),
'statify-blacklist',
'statifyblacklist-target'
);
add_settings_field(
'statifyblacklist-target-regexp',
__( 'Matching method', 'statify-blacklist' ),
array( __CLASS__, 'option_target_regexp' ),
'statify-blacklist',
'statifyblacklist-target',
array( 'label_for' => 'statifyblacklist-target-regexp' )
);
add_settings_field(
'statifyblacklist-target-blacklist',
__( 'Target filter', 'statify-blacklist' ),
array( __CLASS__, 'option_target_blacklist' ),
'statify-blacklist',
'statifyblacklist-target',
array( 'label_for' => 'statifyblacklist-target-blacklist' )
);
// IP filter.
add_settings_section(
'statifyblacklist-ip',
__( 'IP filter', 'statify-blacklist' ),
null,
'statify-blacklist'
);
add_settings_field(
'statifyblacklist-ip-active',
__( 'Activate live filter', 'statify-blacklist' ),
array( __CLASS__, 'option_ip_active' ),
'statify-blacklist',
'statifyblacklist-ip'
);
add_settings_field(
'statifyblacklist-ip-blacklist',
__( 'IP filter', 'statify-blacklist' ),
array( __CLASS__, 'option_ip_blacklist' ),
'statify-blacklist',
'statifyblacklist-ip',
array( 'label_for' => 'statifyblacklist-ip-blacklist' )
);
// User agent filter.
add_settings_section(
'statifyblacklist-ua',
__( 'User agent filter', 'statify-blacklist' ),
null,
'statify-blacklist'
);
add_settings_field(
'statifyblacklist-ua-active',
__( 'Activate live filter', 'statify-blacklist' ),
array( __CLASS__, 'option_ua_active' ),
'statify-blacklist',
'statifyblacklist-ua'
);
add_settings_field(
'statifyblacklist-ua-regexp',
__( 'Matching method', 'statify-blacklist' ),
array( __CLASS__, 'option_ua_regexp' ),
'statify-blacklist',
'statifyblacklist-ua',
array( 'label_for' => 'statifyblacklist-ua-regexp' )
);
add_settings_field(
'statifyblacklist-ua-blacklist',
__( 'User agent filter', 'statify-blacklist' ),
array( __CLASS__, 'option_ua_blacklist' ),
'statify-blacklist',
'statifyblacklist-ua',
array( 'label_for' => 'statifyblacklist-ua-blacklist' )
);
}
/**
* Creates the settings pages.
*
* @return void
*/
public static function create_settings_page() {
?>
<div class="wrap">
<h1><?php esc_html_e( 'Statify Filter', 'statify-blacklist' ); ?></h1>
<?php
if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] && ! empty( $_POST['cleanup'] ) ) {
// Database cleanup requested.
if ( isset( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'statify-blacklist-options' ) ) {
// Nonce verification successful, proceed with cleanup.
StatifyBlacklist_Admin::cleanup_database();
?>
<div class="notice notice-success is-dismissible">
<p><?php esc_html_e( 'Database cleanup successful', 'statify-blacklist' ); ?></p>
</div>
<?php
} else {
// Nonce verification failed.
?>
<div class="notice notice-error is-dismissible">
<p><?php esc_html_e( 'Database cleanup request failed', 'statify-blacklist' ); ?></p>
</div>
<?php
}
}
?>
<form id="statify-settings" method="post" action="options.php">
<?php
settings_fields( 'statify-blacklist' );
do_settings_sections( 'statify-blacklist' );
submit_button();
?>
<hr>
<input class="button-secondary" type="submit" name="cleanup"
formaction=""
value="<?php esc_html_e( 'CleanUp Database', 'statify-blacklist' ); ?>"
onclick="return confirm('<?php echo esc_js( __( 'Do you really want to apply filters to database? This cannot be undone.', 'statify-blacklist' ) ); ?>');">
<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>
</form>
</div>
<?php
}
/*
* Disable some code style rules that are impractical for textarea content:
*
* phpcs:disable Squiz.PHP.EmbeddedPhp.ContentBeforeOpen
* phpcs:disable Squiz.PHP.EmbeddedPhp.ContentAfterEnd
*/
/**
* Option for activating the live referer filter.
*
* @return void
*/
public static function option_referer_active() {
?>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?></legend>
<label for="statifyblacklist-referer-active">
<input id="statifyblacklist-referer-active" name="statify-blacklist[referer][active]" type="checkbox" value="1" <?php checked( StatifyBlacklist::$options['referer']['active'], 1 ); ?>>
<?php esc_html_e( 'Activate', 'statify-blacklist' ); ?>
</label>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
</p>
</fieldset>
<?php
}
/**
* Option for activating cron the referer filter.
*
* @return void
*/
public static function option_referer_cron() {
?>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'CronJob execution', 'statify-blacklist' ); ?></legend>
<label for="statifyblacklist-referer-cron">
<input id="statifyblacklist-referer-cron" name="statify-blacklist[referer][cron]" type="checkbox" value="1" <?php checked( StatifyBlacklist::$options['referer']['cron'], 1 ); ?>>
<?php esc_html_e( 'Activate', 'statify-blacklist' ); ?>
</label>
<p class="description">
<?php esc_html_e( 'Periodically clean up database in background', 'statify-blacklist' ); ?>
</p>
</fieldset>
<?php
}
/**
* Option for referer matching method.
*
* @return void
*/
public static function option_referer_regexp() {
?>
<select id="statifyblacklist-referer-regexp" name="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>
<?php
}
/**
* Option for the referer filter list.
*
* @return void
*/
public static function option_referer_blacklist() {
?>
<textarea id="statifyblacklist-referer-blacklist" name="statify-blacklist[referer][blacklist]" cols="40" rows="5"><?php
print esc_html( implode( "\r\n", array_keys( StatifyBlacklist::$options['referer']['blacklist'] ) ) );
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one domain (without subdomains) each line, e.g. example.com', 'statify-blacklist' ); ?>
</p>
<?php
}
/**
* Option for activating the live target filter.
*
* @return void
*/
public static function option_target_active() {
?>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?></legend>
<label for="statifyblacklist-target-active">
<input id="statifyblacklist-target-active" name="statify-blacklist[target][active]" type="checkbox" value="1" <?php checked( StatifyBlacklist::$options['target']['active'], 1 ); ?>>
<?php esc_html_e( 'Activate', 'statify-blacklist' ); ?>
</label>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
</p>
</fieldset>
<?php
}
/**
* Option for activating cron the target filter.
*
* @return void
*/
public static function option_target_cron() {
?>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'CronJob execution', 'statify-blacklist' ); ?></legend>
<label for="statifyblacklist-target-cron">
<input id="statifyblacklist-target-cron" name="statify-blacklist[target][cron]" type="checkbox" value="1" <?php checked( StatifyBlacklist::$options['target']['cron'], 1 ); ?>>
<?php esc_html_e( 'Activate', 'statify-blacklist' ); ?>
</label>
<p class="description">
<?php esc_html_e( 'Clean database periodically in background', 'statify-blacklist' ); ?>
</p>
</fieldset>
<?php
}
/**
* Option for target matching method.
*
* @return void
*/
public static function option_target_regexp() {
?>
<select id="statifyblacklist-target-regexp" name="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>
<?php
}
/**
* Option for the target filter list.
*
* @return void
*/
public static function option_target_blacklist() {
?>
<textarea id="statifyblacklist-target-blacklist" name="statify-blacklist[target][blacklist]" cols="40" rows="5"><?php
print esc_html( implode( "\r\n", array_keys( StatifyBlacklist::$options['target']['blacklist'] ) ) );
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one target URL each line, e.g.', 'statify-blacklist' ); ?> /, /test/page/, /?page_id=123
</p>
<?php
}
/**
* Option for activating the live IP filter.
*
* @return void
*/
public static function option_ip_active() {
?>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?></legend>
<label for="statifyblacklist-ip-active">
<input id="statifyblacklist-ip-active" name="statify-blacklist[ip][active]" type="checkbox" value="1" <?php checked( StatifyBlacklist::$options['ip']['active'], 1 ); ?>>
<?php esc_html_e( 'Activate', 'statify-blacklist' ); ?>
</label>
<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>
</fieldset>
<?php
}
/**
* Option for the IP filter list.
*
* @return void
*/
public static function option_ip_blacklist() {
?>
<textarea id="statifyblacklist-ip-blacklist" name="statify-blacklist[ip][blacklist]" cols="40" rows="5"><?php
print esc_html( implode( "\r\n", StatifyBlacklist::$options['ip']['blacklist'] ) );
?></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>
<?php
}
/**
* Option for activating the live user agent filter.
*
* @return void
*/
public static function option_ua_active() {
?>
<label for="statifyblacklist-ua-active">
<input id="statifyblacklist-ua-active" name="statify-blacklist[ua][active]" type="checkbox" value="1" <?php checked( StatifyBlacklist::$options['ua']['active'], 1 ); ?>>
<?php esc_html_e( 'Activate', 'statify-blacklist' ); ?>
</label>
<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>
<?php
}
/**
* Option for user agent matching method.
*
* @return void
*/
public static function option_ua_regexp() {
?>
<select id="statifyblacklist-ua-regexp" name="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>
<?php
}
/**
* Option for the user agent filter list.
*
* @return void
*/
public static function option_ua_blacklist() {
?>
<textarea name="statify-blacklist[ua][blacklist]" id="statifyblacklist-ua-blacklist" cols="40" rows="5"><?php
print esc_html( implode( "\r\n", StatifyBlacklist::$options['ua']['blacklist'] ) );
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one user agent string per line, e.g.', 'statify-blacklist' ); ?>
MyBot/1.23
</p>
<?php
}
/**
* Validate and sanitize submitted options.
*
* @param array $options Original options.
*
* @return array Validated and sanitized options.
*/
public static function sanitize_options( $options ) {
// Extract filter lists from multi-line inputs.
$referer = self::parse_multiline_option( $options['referer']['blacklist'] );
$target = self::parse_multiline_option( $options['target']['blacklist'] );
$ip = self::parse_multiline_option( $options['ip']['blacklist'] );
$ua = self::parse_multiline_option( $options['ua']['blacklist'] );
// Generate options.
$res = array(
'referer' => array(
'active' => isset( $options['referer']['active'] ) ? (int) $options['referer']['active'] : 0,
'cron' => isset( $options['referer']['cron'] ) ? (int) $options['referer']['cron'] : 0,
'regexp' => isset( $options['referer']['regexp'] ) ? (int) $options['referer']['regexp'] : 0,
'blacklist' => array_flip( $referer ),
),
'target' => array(
'active' => isset( $options['target']['active'] ) ? (int) $options['target']['active'] : 0,
'cron' => isset( $options['target']['cron'] ) ? (int) $options['target']['cron'] : 0,
'regexp' => isset( $options['target']['regexp'] ) ? (int) $options['target']['regexp'] : 0,
'blacklist' => array_flip( $target ),
),
'ip' => array(
'active' => isset( $options['ip']['active'] ) ? (int) $options['ip']['active'] : 0,
'blacklist' => $ip,
),
'ua' => array(
'active' => isset( $options['ua']['active'] ) ? (int) $options['ua']['active'] : 0,
'regexp' => isset( $options['ua']['regexp'] ) ? (int) $options['ua']['regexp'] : 0,
'blacklist' => array_flip( $ua ),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
// Apply sanitizations.
self::sanitize_referer_options( $res['referer'] );
self::sanitize_target_options( $res['target'] );
self::sanitize_ip_options( $res['ip'] );
return $res;
}
/**
* Sanitize referer options.
*
* @param array $options Original referer options.
*
* @return void
*
* @since 1.7.0
*/
private static function sanitize_referer_options( &$options ) {
$referer_given = $options['blacklist'];
$referer_invalid = array();
if ( StatifyBlacklist::MODE_NORMAL === $options['regexp'] ) {
// Sanitize URLs and remove empty inputs.
$referer_sanitized = self::sanitize_urls( $referer_given );
} elseif ( StatifyBlacklist::MODE_REGEX === $options['regexp'] || StatifyBlacklist::MODE_REGEX_CI === $options['regexp'] ) {
$referer_sanitized = $referer_given;
// Check regular expressions.
$referer_invalid = self::sanitize_regex( $referer_given );
} else {
$referer_sanitized = $referer_given;
}
$referer_diff = array_diff_key( $referer_given, $referer_sanitized );
$options['blacklist'] = $referer_sanitized;
// Generate messages.
if ( ! empty( $referer_diff ) ) {
add_settings_error(
'statify-blacklist',
'referer-diff',
__( 'Some URLs are invalid and have been sanitized.', 'statify-blacklist' ),
'warning'
);
}
if ( ! empty( $referer_invalid ) ) {
add_settings_error(
'statify-blacklist',
'referer-invalid',
__( 'Some regular expressions for referrers are invalid:', 'statify-blacklist' ) . '<br>' . implode( '<br>', $referer_invalid )
);
}
}
/**
* Sanitize target options.
*
* @param array $options Original target options.
*
* @return void
*
* @since 1.7.0
*/
private static function sanitize_target_options( &$options ) {
$target_given = $options['blacklist'];
$target_sanitized = $target_given;
if ( StatifyBlacklist::MODE_REGEX === $options['regexp'] || StatifyBlacklist::MODE_REGEX_CI === $options['regexp'] ) {
// Check regular expressions.
$target_invalid = self::sanitize_regex( $target_given );
} else {
$target_invalid = array();
}
$options['blacklist'] = $target_sanitized;
// Generate messages.
if ( ! empty( $target_invalid ) ) {
add_settings_error(
'statify-blacklist',
'target-invalid',
__( 'Some regular expressions for targets are invalid:', 'statify-blacklist' ) . '<br>' . implode( '<br>', $target_invalid )
);
}
}
/**
* Sanitize IPs and subnets and remove empty inputs.
*
* @param array $options Original IP options.
*
* @return void
*
* @since 1.7.0
*/
private static function sanitize_ip_options( &$options ) {
$given_ip = $options['blacklist'];
$sanitized_ip = self::sanitize_ips( $given_ip );
$ip_diff = array_diff( $given_ip, $sanitized_ip );
$options['blacklist'] = $sanitized_ip;
// Generate messages.
if ( ! empty( $ip_diff ) ) {
add_settings_error(
'statify-blacklist',
'ip-diff',
// translators: List of invalid IP addresses (comma separated).
sprintf( __( 'Some IPs are invalid: %s', 'statify-blacklist' ), implode( ', ', $ip_diff ) ),
'warning'
);
}
}
/**
* Sanitize URLs and remove empty results.
*
* @param array $urls given array of URLs.
*
* @return array sanitized array.
*
* @since 1.1.1
* @since 1.7.0 moved from StatifyBlacklist_Admin to StatifyBlacklist_Settings.
*/
private static function sanitize_urls( $urls ) {
return array_flip(
array_filter(
array_map(
function ( $r ) {
return preg_replace( '/[^\da-z\.-]/i', '', filter_var( $r, FILTER_SANITIZE_URL ) );
},
array_flip( $urls )
)
)
);
}
/**
* Sanitize IP addresses with optional CIDR notation and remove empty results.
*
* @param array $ips given array of URLs.
*
* @return array sanitized array.
*
* @since 1.4.0
* @since 1.7.0 moved from StatifyBlacklist_Admin to StatifyBlacklist_Settings.
*/
private static function sanitize_ips( $ips ) {
return array_values(
array_unique(
array_filter(
array_map( 'strtolower', $ips ),
function ( $ip ) {
return preg_match(
'/^((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9])(\/([0-9]|[1-2][0-9]|3[0-2]))?$/',
$ip
) ||
preg_match(
'/^(([0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|([0-9a-f]{1,4}:){1,7}:|([0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}' .
'|([0-9a-f]{1,4}:){1,5}(:[0-9a-f]{1,4}){1,2}|([0-9a-f]{1,4}:){1,4}(:[0-9a-f]{1,4}){1,3}' .
'|([0-9a-f]{1,4}:){1,3}(:[0-9a-f]{1,4}){1,4}|([0-9a-f]{1,4}:){1,2}(:[0-9a-f]{1,4}){1,5}' .
'|[0-9a-f]{1,4}:((:[0-9a-f]{1,4}){1,6})|:((:[0-9a-f]{1,4}){1,7}|:)' .
'|fe80:(:[0-9a-f]{0,4}){0,4}%[0-9a-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]' .
'|1?[0-9])?[0-9])|([0-9a-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[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.
*
* @param array $expressions Given pre-sanitized array of regular expressions.
*
* @return array Array of invalid expressions.
*
* @since 1.5.0 #13
* @since 1.7.0 moved from StatifyBlacklist_Admin to StatifyBlacklist_Settings.
*/
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 );
}
);
}
/**
* Parse multi-line option string.
*
* @param string $raw Input string.
*
* @return array Parsed options.
*/
private static function parse_multiline_option( $raw ) {
if ( empty( trim( $raw ) ) ) {
return array();
} else {
return array_filter(
array_map(
function ( $a ) {
return trim( $a );
},
explode( "\r\n", str_replace( '\\\\', '\\', $raw ) )
),
function ( $a ) {
return ! empty( $a );
}
);
}
}
}

View File

@ -1,6 +1,6 @@
<?php
/**
* Statify Filter: StatifyBlacklist_System class
* Statify Blacklist: StatifyBlacklist_System class
*
* This file contains the derived class for the plugin's system operations.
*
@ -15,7 +15,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
/**
* Statify Filter system configuration.
* Statify Blacklist system configuration.
*
* @since 1.0.0
*/
@ -89,6 +89,9 @@ class StatifyBlacklist_System extends StatifyBlacklist {
if ( function_exists( 'get_sites' ) ) {
$sites = get_sites();
} elseif ( function_exists( 'wp_get_sites' ) ) {
// phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_get_sitesFound -- Legacy support for WP < 4.6.
$sites = wp_get_sites();
} else {
return;
}
@ -175,34 +178,10 @@ class StatifyBlacklist_System extends StatifyBlacklist {
self::update_options();
}
// Version older than 1.6.
if ( self::$options['version'] < 1.6 ) {
$options = self::$options;
if ( ! isset( $options['ua'] ) ) {
$options['ua'] = array(
'active' => 0,
'regexp' => 0,
'blacklist' => array(),
);
} elseif ( ! isset( $options['ua']['blacklist'] ) ) {
$options['ua']['blacklist'] = array();
} else {
// User agent strings got stored incorrectly in 1.6.0 - luckily the version was not updated, either.
$options['ua']['blacklist'] = array_flip( $options['ua']['blacklist'] );
}
$options['version'] = 1.6;
if ( self::$multisite ) {
update_site_option( 'statify-blacklist', $options );
} else {
update_option( 'statify-blacklist', $options );
}
self::update_options();
}
// Version older than current major release.
if ( self::VERSION_MAIN > self::$options['version'] ) {
// Merge default options with current config, assuming only additive changes.
$options = array_replace_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 Filter: StatifyBlacklist class
* Statify Blacklist: StatifyBlacklist class
*
* This file contains the plugin's base class.
*
@ -14,7 +14,9 @@ if ( ! defined( 'ABSPATH' ) ) {
}
/**
* Statify Filter.
* Statify Blacklist.
*
* @since 1.0.0
*/
class StatifyBlacklist {
@ -22,9 +24,9 @@ class StatifyBlacklist {
* Plugin major version.
*
* @since 1.4.0
* @var float VERSION_MAIN
* @var int VERSION_MAIN
*/
const VERSION_MAIN = 1.7;
const VERSION_MAIN = 1.4;
/**
* Operation mode "normal".
@ -79,8 +81,8 @@ class StatifyBlacklist {
* @return void
*/
public static function init() {
// Skip on autosave.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
// Skip on autosave or AJAX.
if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
return;
}
@ -91,18 +93,10 @@ 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'] ||
0 !== self::$options['ua']['active'] ) {
if ( 0 !== self::$options['referer']['active'] || 0 !== self::$options['target']['active'] || 0 !== self::$options['ip']['active'] ) {
add_filter( 'statify__skip_tracking', array( 'StatifyBlacklist', 'apply_blacklist_filter' ) );
}
// 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() ) {
StatifyBlacklist_Admin::init();
@ -159,42 +153,103 @@ class StatifyBlacklist {
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => 0,
'blacklist' => array(),
),
'version' => self::VERSION_MAIN,
);
}
/**
* Apply the filter if active
* Apply the blacklist filter if active
*
* @since 1.0.0
*
* @return bool TRUE if referer matches filter.
* @return bool TRUE if referer matches blacklist.
*/
public static function apply_blacklist_filter() {
// 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;
// Referer blacklist.
if ( isset( self::$options['referer']['active'] ) && 0 !== self::$options['referer']['active'] ) {
// Determine filter mode.
$mode = isset( self::$options['referer']['regexp'] ) ? intval( self::$options['referer']['regexp'] ) : 0;
// Get full referer string.
$referer = wp_get_raw_referer();
if ( ! $referer ) {
$referer = '';
}
switch ( $mode ) {
// Regular Expression filtering since 1.3.0.
case self::MODE_REGEX:
case self::MODE_REGEX_CI:
// Merge given regular expressions into one.
$regexp = self::regex(
array_keys( self::$options['referer']['blacklist'] ),
self::MODE_REGEX_CI === self::$options['referer']['regexp']
);
// Check blacklist (no return to continue filtering #12).
if ( 1 === preg_match( $regexp, $referer ) ) {
return true;
}
break;
// Keyword filter since 1.5.0 (#15).
case self::MODE_KEYWORD:
// Get blacklist.
$blacklist = self::$options['referer']['blacklist'];
foreach ( array_keys( $blacklist ) as $keyword ) {
if ( false !== strpos( strtolower( $referer ), strtolower( $keyword ) ) ) {
return true;
}
}
break;
// Standard domain filter.
default:
// Extract relevant domain parts.
$referer = wp_parse_url( $referer );
$referer = strtolower( ( isset( $referer['host'] ) ? $referer['host'] : '' ) );
// Get blacklist.
$blacklist = self::$options['referer']['blacklist'];
// Check blacklist.
if ( isset( $blacklist[ $referer ] ) ) {
return true;
}
}
}
// Target filter (since 1.4.0).
if ( self::apply_single_filter( self::$options['target'], array( __CLASS__, 'get_target' ) ) ) {
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.
$target = ( isset( $_SERVER['REQUEST_URI'] ) ? filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_URL ) : '/' );
// Merge given regular expressions into one.
$regexp = self::regex(
array_keys( self::$options['target']['blacklist'] ),
self::MODE_REGEX_CI === self::$options['target']['regexp']
);
// Check blacklist (no return to continue filtering #12).
if ( 1 === preg_match( $regexp, $target ) ) {
return true;
}
} else {
// Extract target page.
$target = ( isset( $_SERVER['REQUEST_URI'] ) ? filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_URL ) : '/' );
// Get blacklist.
$blacklist = self::$options['target']['blacklist'];
// Check blacklist.
if ( isset( $blacklist[ $target ] ) ) {
return true;
}
}
}
// IP filter (since 1.4.0).
// IP blacklist (since 1.4.0).
if ( isset( self::$options['ip']['active'] ) && 0 !== self::$options['ip']['active'] ) {
$ip = self::get_ip();
if ( false !== ( $ip ) ) {
@ -206,73 +261,10 @@ class StatifyBlacklist {
}
}
// 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.
// Skip and continue (return NULL), if all blacklists 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.
*
@ -304,47 +296,6 @@ class StatifyBlacklist {
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.
*
@ -381,22 +332,6 @@ class StatifyBlacklist {
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'] ) );
if ( $user_agent ) {
return $user_agent;
}
}
return '';
}
/**
* Helper function to check if an IP address matches a given subnet.
*
@ -436,7 +371,7 @@ class StatifyBlacklist {
}
$ceil = ceil( $mask / 16 );
for ( $i = 1; $i <= $ceil; ++$i ) {
for ( $i = 1; $i <= $ceil; ++ $i ) {
$left = $mask - 16 * ( $i - 1 );
$left = ( $left <= 16 ) ? $left : 16;
$mask_b = ~( 0xffff >> $left ) & 0xffff;

View File

@ -1,7 +1,7 @@
{
"name": "statify-blacklist",
"version": "1.7.2",
"description": "A filter extension for the famous Statify WordPress plugin",
"version": "1.5.0",
"description": "A blacklist extension for the famous Statify WordPress plugin",
"author": "Stefan Kalscheuer",
"license": "GPL-2.0+"
}

View File

@ -8,6 +8,7 @@
<!-- Files to sniff -->
<file>statify-blacklist.php</file>
<file>inc</file>
<file>views</file>
<!-- Compliance with WordPress Coding Standard -->
<config name="minimum_supported_wp_version" value="4.7"/>
@ -17,13 +18,7 @@
<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="PHPCompatibilityWP"/>
<rule ref="PHPCompatibility"/>
</ruleset>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<phpunit bootstrap="test/bootstrap.php">
<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>

View File

@ -1,36 +1,33 @@
<?php
/**
* Statify Filter
* Statify Blacklist
*
* @package PluginPackage
* @author Stefan Kalscheuer <stefan@stklcode.de>
* @license GPL-2.0+
*
* @wordpress-plugin
* Plugin Name: Statify Filter
* Plugin URI: https://wordpress.org/plugins/statify-blacklist/
* Description: Extension for the Statify plugin to add customizable filters. (formerly "Statify Blacklist")
* Version: 1.7.2
* Requires at least: 4.7
* Requires PHP: 5.5
* Requires Plugins: statify
* Author: Stefan Kalscheuer (@stklcode)
* Author URI: https://www.stklcode.de
* Text Domain: statify-blacklist
* License: GPLv2 or later
* Plugin Name: Statify Blacklist
* Plugin URI: https://wordpress.org/plugins/statify-blacklist/
* Description: Extension for the Statify plugin to add a customizable blacklists.
* Version: 1.5.0
* Author: Stefan Kalscheuer (@stklcode)
* Author URI: https://www.stklcode.de
* Text Domain: statify-blacklist
* License: GPLv2 or later
*
* Statify Filter is free software: you can redistribute it and/or modify
* Statify Blacklist 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 Filter is distributed in the hope that it will be useful,
* Statify Blacklist 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 Filter. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
* along with Statify Blacklist. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
*/
// Quit if accessed directly.
@ -40,7 +37,7 @@ if ( ! defined( 'ABSPATH' ) ) {
// Constants.
define( 'STATIFYBLACKLIST_FILE', __FILE__ );
define( 'STATIFYBLACKLIST_DIR', __DIR__ );
define( 'STATIFYBLACKLIST_DIR', dirname( __FILE__ ) );
define( 'STATIFYBLACKLIST_BASE', plugin_basename( __FILE__ ) );
// Check for compatibility.
@ -65,23 +62,22 @@ if ( statify_blacklist_compatibility_check() ) {
/**
* Autoloader for StatifyBlacklist classes.
*
* @param string $class_name Name of the class to load.
* @param string $class Name of the class to load.
*
* @since 1.0.0
*/
function statify_blacklist_autoload( $class_name ) {
function statify_blacklist_autoload( $class ) {
$plugin_classes = array(
'StatifyBlacklist',
'StatifyBlacklist_Admin',
'StatifyBlacklist_Settings',
'StatifyBlacklist_System',
);
if ( in_array( $class_name, $plugin_classes, true ) ) {
if ( in_array( $class, $plugin_classes, true ) ) {
require_once sprintf(
'%s/inc/class-%s.php',
STATIFYBLACKLIST_DIR,
strtolower( str_replace( '_', '-', $class_name ) )
strtolower( str_replace( '_', '-', $class ) )
);
}
}
@ -128,7 +124,7 @@ 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' ),
esc_html__( 'Statify Blacklist requires at least WordPress %1$s and PHP %2$s.', 'statify-blacklist' ),
'4.7',
'5.5'
);

View File

@ -1,330 +0,0 @@
<?php
/**
* Statify Filter: Unit Test
*
* This is a PHPunit test class for the plugin's functionality
*
* @package Statify_Blacklist
*/
/**
* Class StatifyBlacklist_Settings_Test.
*
* PHPUnit test class for StatifyBlacklist_Settings.
*/
class StatifyBlacklist_Settings_Test extends PHPUnit\Framework\TestCase {
/**
* Test options sanitization.
*
* @return void
*/
public function test_sanitize_options() {
global $settings_error;
// Emulate default submission: nothing checked, all textareas empty.
$raw = array(
'referer' => array(
'blacklist' => '',
'regexp' => '0',
),
'target' => array(
'blacklist' => '',
'regexp' => '0',
),
'ip' => array( 'blacklist' => '' ),
'ua' => array(
'blacklist' => '',
'regexp' => '0',
),
);
$sanitized = StatifyBlacklist_Settings::sanitize_options( $raw );
self::assertEmpty( $settings_error );
self::assertEquals(
array(
'referer' => array(
'active' => 0,
'cron' => 0,
'blacklist' => array(),
'regexp' => StatifyBlacklist::MODE_NORMAL,
),
'target' => array(
'active' => 0,
'cron' => 0,
'blacklist' => array(),
'regexp' => StatifyBlacklist::MODE_NORMAL,
),
'ip' => array(
'active' => 0,
'blacklist' => array(),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
),
$sanitized
);
// Some checked options and some valid entries.
$raw = array(
'referer' => array(
'cron' => '1',
'blacklist' => "example.com\r\nexample.net\r\nexample.org",
'regexp' => '0',
),
'target' => array(
'active' => '1',
'blacklist' => "foo\r\nbar\r\ntest",
'regexp' => '3',
),
'ip' => array(
'active' => '1',
'blacklist' => "127.0.0.1/8\r\n::1",
),
'ua' => array(
'blacklist' => 'MyBot/1.23',
'regexp' => '1',
),
);
$sanitized = StatifyBlacklist_Settings::sanitize_options( $raw );
self::assertEmpty( $settings_error );
self::assertEquals(
array(
'referer' => array(
'active' => 0,
'cron' => 1,
'blacklist' => array(
'example.com' => 0,
'example.net' => 1,
'example.org' => 2,
),
'regexp' => StatifyBlacklist::MODE_NORMAL,
),
'target' => array(
'active' => 1,
'cron' => 0,
'blacklist' => array(
'foo' => 0,
'bar' => 1,
'test' => 2,
),
'regexp' => StatifyBlacklist::MODE_KEYWORD,
),
'ip' => array(
'active' => 1,
'blacklist' => array(
'127.0.0.1/8',
'::1',
),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_REGEX,
'blacklist' => array(
'MyBot/1.23' => 0,
),
),
'version' => StatifyBlacklist::VERSION_MAIN,
),
$sanitized
);
// Now we have some additional nonsense fields and invalid entries.
$raw = array(
'testme ' => 'whatever',
'referer' => array(
'cron' => '1',
'blacklist' => " example\\.com \r\nexample(\\.net\r\nexample\\.com",
'regexp' => '1',
),
'target' => array(
'active' => '1',
'blacklist' => "fo.\r\n[bar\r\n*test",
'regexp' => '2',
),
'ip' => array(
'active' => '1',
'blacklist' => "127.0.0.1/8\r\nthisisnotanip\r\n127.0.0.1/8",
),
'ua' => array(
'blacklist' => 'MyBot/1.23',
'regexp' => '1',
),
);
$sanitized = StatifyBlacklist_Settings::sanitize_options( $raw );
self::assertEquals(
array(
'referer' => array(
'active' => 0,
'cron' => 1,
'blacklist' => array(
'example\.com' => 2,
'example(\.net' => 1,
),
'regexp' => StatifyBlacklist::MODE_REGEX,
),
'target' => array(
'active' => 1,
'cron' => 0,
'blacklist' => array(
'fo.' => 0,
'[bar' => 1,
'*test' => 2,
),
'regexp' => StatifyBlacklist::MODE_REGEX_CI,
),
'ip' => array(
'active' => 1,
'blacklist' => array(
'127.0.0.1/8',
),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_REGEX,
'blacklist' => array(
'MyBot/1.23' => 0,
),
),
'version' => StatifyBlacklist::VERSION_MAIN,
),
$sanitized
);
self::assertEquals(
array(
array( 'statify-blacklist', 'referer-invalid', 'Some regular expressions for referrers are invalid:<br>example(\.net', 'error' ),
array( 'statify-blacklist', 'target-invalid', 'Some regular expressions for targets are invalid:<br>[bar<br>*test', 'error' ),
array( 'statify-blacklist', 'ip-diff', 'Some IPs are invalid: thisisnotanip', 'warning' ),
),
$settings_error
);
}
/**
* Test sanitization of IP addresses.
*
* @return void
*/
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 = invoke_static( StatifyBlacklist_Settings::class, 'sanitize_ips', array( array_merge( $valid, $invalid ) ) );
$this->assertNotFalse( $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.
$valid = array(
'2001:db8:a0b:12f0::',
'2001:db8:a0b:12f0::1',
'2001:db8:a0b:12f0::1/128',
'2001:DB8:A0B:12F0::/64',
'fe80::7645:6de2:ff:1',
'2001:db8:a0b:12f0::',
'::ffff:192.0.2.123',
);
$invalid = array(
'2001:db8:a0b:12f0::x',
'2001:db8:a0b:12f0:::',
'2001:fffff:a0b:12f0::1',
'2001:DB8:A0B:12F0::/129',
'1:2:3:4:5:6:7:8:9',
'::ffff:12.34.56.789',
);
$result = invoke_static( StatifyBlacklist_Settings::class, 'sanitize_ips', array( array_merge( $valid, $invalid ) ) );
$this->assertNotFalse( $result );
if ( method_exists( $this, 'assertIsArray' ) ) {
$this->assertIsArray( $result );
} else {
$this->assertInternalType( 'array', $result );
}
$this->assertEquals(
array(
'2001:db8:a0b:12f0::',
'2001:db8:a0b:12f0::1',
'2001:db8:a0b:12f0::1/128',
'2001:db8:a0b:12f0::/64',
'fe80::7645:6de2:ff:1',
'::ffff:192.0.2.123',
),
$result
);
}
/**
* Test settings registration.
*
* @return void
*/
public function test_register_settings() {
global $settings;
$settings = array();
StatifyBlacklist_Settings::register_settings();
$this->assertEquals( array( 'statify-blacklist' ), array_keys( $settings ), 'unexpected settings pages' );
$this->assertEquals(
array(
'statifyblacklist-referer',
'statifyblacklist-target',
'statifyblacklist-ip',
'statifyblacklist-ua',
),
array_keys( $settings['statify-blacklist']['sections'] ),
'unexpected settings sections'
);
$this->assertEquals(
array(
'statifyblacklist-referer-active',
'statifyblacklist-referer-cron',
'statifyblacklist-referer-regexp',
'statifyblacklist-referer-blacklist',
),
array_keys( $settings['statify-blacklist']['sections']['statifyblacklist-referer']['fields'] ),
'unexpected fields in referrer section'
);
$this->assertEquals(
array(
'statifyblacklist-target-active',
'statifyblacklist-target-cron',
'statifyblacklist-target-regexp',
'statifyblacklist-target-blacklist',
),
array_keys( $settings['statify-blacklist']['sections']['statifyblacklist-target']['fields'] ),
'unexpected fields in target section'
);
$this->assertEquals(
array( 'statifyblacklist-ip-active', 'statifyblacklist-ip-blacklist' ),
array_keys( $settings['statify-blacklist']['sections']['statifyblacklist-ip']['fields'] ),
'unexpected fields in ip section'
);
$this->assertEquals(
array(
'statifyblacklist-ua-active',
'statifyblacklist-ua-regexp',
'statifyblacklist-ua-blacklist',
),
array_keys( $settings['statify-blacklist']['sections']['statifyblacklist-ua']['fields'] ),
'unexpected fields in user agent section'
);
}
}

View File

@ -1,91 +0,0 @@
<?php
/**
* Statify Filter: Unit Test
*
* This is a PHPunit test class for the plugin's functionality
*
* @package Statify_Blacklist
*/
/**
* Class StatifyBlacklist_System_Test.
*
* PHPUnit test class for StatifyBlacklist_System.
*/
class StatifyBlacklist_System_Test extends PHPUnit\Framework\TestCase {
/**
* Test the upgrade methodology for configuration options.
*
* @return void
*/
public function test_upgrade() {
// Create configuration of version 1.3.
$options13 = array(
'active_referer' => 1,
'cron_referer' => 0,
'referer' => array(
'example.net' => 0,
'example.com' => 1,
),
'referer_regexp' => 0,
'version' => 1.3,
);
// Set options in mock.
update_option( 'statify-blacklist', $options13 );
// Execute upgrade.
StatifyBlacklist_System::upgrade();
// Retrieve updated options.
$options_updated = get_option( 'statify-blacklist' );
// Verify size against default options (no junk left).
$this->assertEquals( 5, count( $options_updated ) );
$this->assertEquals( 4, count( $options_updated['referer'] ) );
$this->assertEquals( 4, count( $options_updated['target'] ) );
$this->assertEquals( 2, count( $options_updated['ip'] ) );
$this->assertEquals( 3, count( $options_updated['ua'] ) );
$this->assertEquals( StatifyBlacklist::VERSION_MAIN, $options_updated['version'] );
// Verify that original attributes are unchanged.
$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, $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'] );
$this->assertEquals( 0, $options_updated['ua']['active'] );
$this->assertEquals( 0, $options_updated['ua']['regexp'] );
$this->assertEquals( array(), $options_updated['ua']['blacklist'] );
// Verify that version number has changed to current release.
$this->assertEquals( StatifyBlacklist::VERSION_MAIN, $options_updated['version'] );
// Test upgrade of incorrectly stored user agent list in 1.6.
$options_updated['version'] = 1.4;
$options_updated['ua']['blacklist'] = array( 'user agent 1', 'user agent 2' );
update_option( 'statify-blacklist', $options_updated );
// Execute upgrade.
StatifyBlacklist_System::upgrade();
// Retrieve updated options.
$options_updated = get_option( 'statify-blacklist' );
$this->assertEquals(
array(
'user agent 1' => 0,
'user agent 2' => 1,
),
$options_updated['ua']['blacklist']
);
$this->assertEquals( StatifyBlacklist::VERSION_MAIN, $options_updated['version'] );
}
}

View File

@ -1,134 +0,0 @@
<?php
/**
* PHPUnit bootstrap file
*
* @package Statify_Blacklist
*/
/**
* Simulating the ABSPATH constant.
*
* @var boolean ABSPATH
*/
const ABSPATH = false;
/*
* Include class files.
*/
require_once __DIR__ . '/../inc/class-statifyblacklist.php';
require_once __DIR__ . '/../inc/class-statifyblacklist-admin.php';
require_once __DIR__ . '/../inc/class-statifyblacklist-settings.php';
require_once __DIR__ . '/../inc/class-statifyblacklist-system.php';
// Include Composer autoloader.
require_once __DIR__ . '/../vendor/autoload.php';
/** @ignore */
function invoke_static( $class, $method_name, $parameters = array() ) {
$reflection = new \ReflectionClass( $class );
$method = $reflection->getMethod( $method_name );
$method->setAccessible( true );
return $method->invokeArgs( null, $parameters );
}
// Some mocked WP functions.
$mock_options = array();
$mock_multisite = false;
$settings_error = array();
$settings = array();
/** @ignore */
function is_multisite() {
global $mock_multisite;
return $mock_multisite;
}
/** @ignore */
function wp_parse_args( $args, $defaults = '' ) {
if ( is_object( $args ) ) {
$r = get_object_vars( $args );
} elseif ( is_array( $args ) ) {
$r =& $args;
} else {
parse_str( $args, $r );
}
if ( is_array( $defaults ) ) {
return array_merge( $defaults, $r );
}
return $r;
}
/** @ignore */
function get_option( $option, $default = false ) {
global $mock_options;
return isset( $mock_options[ $option ] ) ? $mock_options[ $option ] : $default;
}
/** @ignore */
function update_option( $option, $value, $autoload = null ) {
global $mock_options;
$mock_options[ $option ] = $value;
}
/** @ignore */
function wp_get_raw_referer() {
return isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '';
}
function wp_parse_url( $value ) {
return parse_url( $value );
}
/** @ignore */
function wp_unslash( $value ) {
return is_string( $value ) ? stripslashes( $value ) : $value;
}
/** @ignore */
function __( $text, $domain = 'default' ) {
return $text;
}
/** @ignore */
function add_settings_error( $setting, $code, $message, $type = 'error' ) {
global $settings_error;
$settings_error[] = array( $setting, $code, $message, $type );
}
/** @ignore */
function register_setting( $option_group, $option_name, $args = array() ) {
global $settings;
$settings[ $option_name ] = array(
'group' => $option_group,
'args' => $args,
'sections' => array(),
);
}
/** @ignore */
function add_settings_section( $id, $title, $callback, $page, $args = array() ) {
global $settings;
$settings[ $page ]['sections'][ $id ] = array(
'title' => $title,
'callback' => $callback,
'args' => $args,
'fields' => array(),
);
}
/** @ignore */
function add_settings_field( $id, $title, $callback, $page, $section = 'default', $args = array() ) {
global $settings;
$settings[ $page ]['sections'][ $section ]['fields'][ $id ] = array(
'title' => $title,
'callback' => $callback,
'args' => $args,
);
}

View File

@ -1,13 +1,37 @@
<?php
/**
* Statify Filter: Unit Test
* Statify Blacklist: Unit Test
*
* This is a PHPunit test class for the plugin's functionality
*
* @package Statify_Blacklist
* @since 1.3.0
* @package Statify_Blacklist
* @subpackage Admin
* @since 1.3.0
*/
/**
* Simulating the ABSPATH constant.
*
* @since 1.3.0
* @var bool ABSPATH
*/
const ABSPATH = false;
/**
* The StatifyBlacklist base class.
*/
require_once __DIR__ . '/../inc/class-statifyblacklist.php';
/**
* The StatifyBlacklist system class.
*/
require_once __DIR__ . '/../inc/class-statifyblacklist-system.php';
/**
* The StatifyBlacklist admin class.
*/
require_once __DIR__ . '/../inc/class-statifyblacklist-admin.php';
/**
* Class StatifyBlacklistTest.
*
@ -23,7 +47,7 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
* @return void
*/
public function test_referer_filter() {
// Prepare Options: 2 filtered domains, disabled.
// Prepare Options: 2 blacklisted domains, disabled.
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
@ -44,11 +68,6 @@ 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,
);
@ -58,13 +77,13 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// No referer.
unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-filtered referer.
// Non-blacklisted referer.
$_SERVER['HTTP_REFERER'] = 'http://example.org';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Filtered referer.
// Blacklisted referer.
$_SERVER['HTTP_REFERER'] = 'http://example.com';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Filtered referer with path.
// Blacklisted referer with path.
$_SERVER['HTTP_REFERER'] = 'http://example.net/foo/bar.html';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
@ -111,11 +130,6 @@ 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,
);
@ -125,13 +139,13 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// No referer.
unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-filtered referer.
// Non-blacklisted referer.
$_SERVER['HTTP_REFERER'] = 'http://not.evil';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Filtered referer.
// Blacklisted referer.
$_SERVER['HTTP_REFERER'] = 'http://example.com';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Filtered referer with path.
// Blacklisted referer with path.
$_SERVER['HTTP_REFERER'] = 'http://foobar.net/test/me';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Matching both.
@ -173,11 +187,6 @@ 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,
);
@ -187,13 +196,13 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// No referer.
unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-filtered referer.
// Non-blacklisted referer.
$_SERVER['HTTP_REFERER'] = 'http://not.evil';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Filtered referer.
// Blacklisted referer.
$_SERVER['HTTP_REFERER'] = 'http://example.com';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Filtered referer with path.
// Blacklisted referer with path.
$_SERVER['HTTP_REFERER'] = 'http://foobar.net/test/me';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Matching both.
@ -204,6 +213,57 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
}
/**
* Test the upgrade methodology for configuration options.
*
* @return void
*/
public function test_upgrade() {
// Create configuration of version 1.3.
$options13 = array(
'active_referer' => 1,
'cron_referer' => 0,
'referer' => array(
'example.net' => 0,
'example.com' => 1,
),
'referer_regexp' => 0,
'version' => 1.3,
);
// Set options in mock.
update_option( 'statify-blacklist', $options13 );
// Execute upgrade.
StatifyBlacklist_System::upgrade();
// Retrieve updated options.
$options_updated = get_option( 'statify-blacklist' );
// Verify size against default options (no junk left).
$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'], $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, $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, $options_updated['version'] );
}
/**
* Test CIDR address matching for IP filter (#7).
*
@ -283,20 +343,6 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
array( '2001:db8:a0b:12f0::123:456', '2001:db8:a0b:12f0::1/96 ' )
)
);
$this->assertTrue(
invoke_static(
StatifyBlacklist::class,
'cidr_match',
array( '2001:DB8:A0B:12F0::123:456', '2001:db8:a0b:12f0::1/96 ' )
)
);
$this->assertTrue(
invoke_static(
StatifyBlacklist::class,
'cidr_match',
array( '2001:db8:a0b:12f0::123:456', '2001:DB8:A0B:12F0::1/96 ' )
)
);
$this->assertFalse(
invoke_static(
StatifyBlacklist::class,
@ -306,13 +352,60 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
);
}
/**
* Test sanitization of IP addresses.
*
* @return void
*/
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 = invoke_static( StatifyBlacklist_Admin::class, 'sanitize_ips', array( array_merge( $valid, $invalid ) ) );
$this->assertNotFalse( $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.
$valid = array(
'2001:db8:a0b:12f0::',
'2001:db8:a0b:12f0::1',
'2001:db8:a0b:12f0::1/128',
'2001:db8:a0b:12f0::/64',
);
$invalid = array(
'2001:db8:a0b:12f0::x',
'2001:db8:a0b:12f0:::',
'2001:fffff:a0b:12f0::1',
'2001:db8:a0b:12f0::/129',
'1:2:3:4:5:6:7:8:9',
);
$result = invoke_static( StatifyBlacklist_Admin::class, 'sanitize_ips', array( array_merge( $valid, $invalid ) ) );
$this->assertNotFalse( $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 test_ip_filter() {
// Prepare Options: 2 filtered IPs, disabled.
// Prepare Options: 2 blacklisted IPs, disabled.
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
@ -333,11 +426,6 @@ 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,
);
@ -389,7 +477,7 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
* @return void
*/
public function test_target_filter() {
// Prepare Options: 2 filtered domains, disabled.
// Prepare Options: 2 blacklisted domains, disabled.
StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
@ -410,11 +498,6 @@ 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,
);
@ -424,14 +507,14 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
// Empty target.
unset( $_SERVER['REQUEST_URI'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Non-filtered targets.
// Non-blacklisted 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() );
// Filtered referer.
// Blacklisted referer.
$_SERVER['REQUEST_URI'] = '/excluded/page/';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['REQUEST_URI'] = '/?page_id=3';
@ -461,69 +544,6 @@ 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.
*
@ -556,11 +576,6 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
'192.0.2.123',
),
),
'ua' => array(
'active' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'version' => StatifyBlacklist::VERSION_MAIN,
);
@ -613,3 +628,69 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
}
}
/** @ignore */
function invoke_static( $class, $method_name, $parameters = array() ) {
$reflection = new \ReflectionClass( $class );
$method = $reflection->getMethod( $method_name );
$method->setAccessible( true );
return $method->invokeArgs( null, $parameters );
}
// Some mocked WP functions.
$mock_options = array();
$mock_multisite = false;
/** @ignore */
function is_multisite() {
global $mock_multisite;
return $mock_multisite;
}
/** @ignore */
function wp_parse_args( $args, $defaults = '' ) {
if ( is_object( $args ) ) {
$r = get_object_vars( $args );
} elseif ( is_array( $args ) ) {
$r =& $args;
} else {
parse_str( $args, $r );
}
if ( is_array( $defaults ) ) {
return array_merge( $defaults, $r );
}
return $r;
}
/** @ignore */
function get_option( $option, $default = false ) {
global $mock_options;
return isset( $mock_options[ $option ] ) ? $mock_options[ $option ] : $default;
}
/** @ignore */
function update_option( $option, $value, $autoload = null ) {
global $mock_options;
$mock_options[ $option ] = $value;
}
/** @ignore */
function wp_get_raw_referer() {
return isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '';
}
function wp_parse_url( $value ) {
return parse_url( $value );
}
/** @ignore */
function wp_unslash( $value ) {
return is_string( $value ) ? stripslashes( $value ) : $value;
}

390
views/settings-page.php Executable file
View File

@ -0,0 +1,390 @@
<?php
/**
* Statify Blacklist: Settings View
*
* This file contains the dynamic HTML skeleton for the plugin's settings page.
*
* @package Statify_Blacklist
* @subpackage Admin
* @since 1.0.0
*/
// phpcs:disable WordPress.WhiteSpace.PrecisionAlignment.Found
// Quit.
defined( 'ABSPATH' ) || exit;
// Update plugin options.
if ( ! empty( $_POST['statifyblacklist'] ) ) {
// Verify nonce.
check_admin_referer( 'statify-blacklist-settings' );
// Check user capabilities.
if ( ! current_user_can( 'manage_options' ) ) {
die( esc_html__( 'Are you sure you want to do this?' ) );
}
if ( ! empty( $_POST['cleanUp'] ) ) {
// CleanUp DB.
StatifyBlacklist_Admin::cleanup_database();
} else {
// Extract referer array.
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 = array_filter(
array_map(
function ( $a ) {
return trim( $a );
},
explode( "\r\n", $referer_str )
),
function ( $a ) {
return ! empty( $a );
}
);
}
// Extract target array.
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 = 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 ( 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 = array_filter(
array_map(
function ( $a ) {
return trim( $a );
},
explode( "\r\n", $ip_str )
),
function ( $a ) {
return ! empty( $a );
}
);
}
// Update options (data will be sanitized).
$statifyblacklist_update_result = StatifyBlacklist_Admin::update_options(
array(
'referer' => array(
'active' => isset( $_POST['statifyblacklist']['referer']['active'] )
? (int) $_POST['statifyblacklist']['referer']['active'] : 0,
'cron' => isset( $_POST['statifyblacklist']['referer']['cron'] )
? (int) $_POST['statifyblacklist']['referer']['cron'] : 0,
'regexp' => isset( $_POST['statifyblacklist']['referer']['regexp'] )
? (int) $_POST['statifyblacklist']['referer']['regexp'] : 0,
'blacklist' => array_flip( $referer ),
),
'target' => array(
'active' => isset( $_POST['statifyblacklist']['target']['active'] )
? (int) $_POST['statifyblacklist']['target']['active'] : 0,
'cron' => isset( $_POST['statifyblacklist']['target']['cron'] )
? (int) $_POST['statifyblacklist']['target']['cron'] : 0,
'regexp' => isset( $_POST['statifyblacklist']['target']['regexp'] )
? (int) $_POST['statifyblacklist']['target']['regexp'] : 0,
'blacklist' => array_flip( $target ),
),
'ip' => array(
'active' => isset( $_POST['statifyblacklist']['ip']['active'] )
? (int) $_POST['statifyblacklist']['ip']['active'] : 0,
'blacklist' => $ip,
),
'version' => StatifyBlacklist::VERSION_MAIN,
)
);
// Generate messages.
if ( false !== $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']['diff'] ) );
}
} else {
$statifyblacklist_post_success = __( 'Settings updated successfully.', 'statify-blacklist' );
}
}
}
/*
* 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>
<?php
if ( is_plugin_inactive( 'statify/statify.php' ) ) {
print '<div class="notice notice-warning"><p>';
esc_html_e( 'Statify plugin is not active.', 'statify-blacklist' );
print '</p></div>';
}
if ( isset( $statifyblacklist_post_warning ) ) {
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>' .
esc_html( $statifyblacklist_post_success ) .
'</p></div>';
}
?>
<form action="" method="post" id="statify-blacklist-settings">
<?php wp_nonce_field( 'statify-blacklist-settings' ); ?>
<h2><?php esc_html_e( 'Referer blacklist', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="statify-blacklist_active_referer">
<?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[referer][active]"
id="statify-blacklist_active_referer"
value="1" <?php checked( StatifyBlacklist::$options['referer']['active'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_cron_referer">
<?php esc_html_e( 'CronJob execution', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[referer][cron]" id="statify-blacklist_cron_referer"
value="1" <?php checked( StatifyBlacklist::$options['referer']['cron'], 1 ); ?>>
<p class="description"><?php esc_html_e( 'Periodically clean up database in background', 'statify-blacklist' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_referer_regexp"><?php esc_html_e( 'Matching method', 'statify-blacklist' ); ?></label>
</th>
<td>
<select name="statifyblacklist[referer][regexp]" id="statify-blacklist_referer_regexp">
<option value="<?php print esc_attr( StatifyBlacklist::MODE_NORMAL ); ?>" <?php selected( StatifyBlacklist::$options['referer']['regexp'], StatifyBlacklist::MODE_NORMAL ); ?>>
<?php esc_html_e( 'Domain', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_KEYWORD ); ?>" <?php selected( StatifyBlacklist::$options['referer']['regexp'], StatifyBlacklist::MODE_KEYWORD ); ?>>
<?php esc_html_e( 'Keyword', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX ); ?>" <?php selected( StatifyBlacklist::$options['referer']['regexp'], StatifyBlacklist::MODE_REGEX ); ?>>
<?php esc_html_e( 'RegEx case-sensitive', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX_CI ); ?>" <?php selected( StatifyBlacklist::$options['referer']['regexp'], StatifyBlacklist::MODE_REGEX_CI ); ?>>
<?php esc_html_e( 'RegEx case-insensitive', 'statify-blacklist' ); ?>
</option>
</select>
<p class="description">
<?php esc_html_e( 'Domain', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match given domain including subdomains', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'Keyword', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match every referer that contains one of the keywords', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'RegEx', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match referer by regular expression', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_referer"><?php esc_html_e( 'Referer blacklist', 'statify-blacklist' ); ?></label>
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[referer][blacklist]" id="statify-blacklist_referer"><?php
if ( empty( $statifyblacklist_update_result['referer'] ) ) {
print esc_html( implode( "\r\n", array_keys( StatifyBlacklist::$options['referer']['blacklist'] ) ) );
} else {
print esc_html( implode( "\r\n", array_keys( $statifyblacklist_update_result['referer']['sanitized'] ) ) );
}
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one domain (without subdomains) each line, e.g. example.com', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
</tbody>
</table>
<h2><?php esc_html_e( 'Target blacklist', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="statify-blacklist_active_target">
<?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[target][active]"
id="statify-blacklist_active_target"
value="1" <?php checked( StatifyBlacklist::$options['target']['active'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_cron_target">
<?php esc_html_e( 'CronJob execution', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[target][cron]" id="statify-blacklist_cron_target"
value="1" <?php checked( StatifyBlacklist::$options['target']['cron'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Clean database periodically in background', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_target_regexp">
<?php esc_html_e( 'Matching method', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<select name="statifyblacklist[target][regexp]" id="statify-blacklist_referer_regexp">
<option value="<?php print esc_attr( StatifyBlacklist::MODE_NORMAL ); ?>" <?php selected( StatifyBlacklist::$options['target']['regexp'], StatifyBlacklist::MODE_NORMAL ); ?>>
<?php esc_html_e( 'Exact', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX ); ?>" <?php selected( StatifyBlacklist::$options['target']['regexp'], StatifyBlacklist::MODE_REGEX ); ?>>
<?php esc_html_e( 'RegEx case-sensitive', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX_CI ); ?>" <?php selected( StatifyBlacklist::$options['target']['regexp'], StatifyBlacklist::MODE_REGEX_CI ); ?>>
<?php esc_html_e( 'RegEx case-insensitive', 'statify-blacklist' ); ?>
</option>
</select>
<p class="description">
<?php esc_html_e( 'Exact', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match only given targets', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'RegEx', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match target by regular expression', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_target">
<?php esc_html_e( 'Target blacklist', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[target][blacklist]" id="statify-blacklist_target"><?php
if ( empty( $statifyblacklist_update_result['target'] ) ) {
print esc_html( implode( "\r\n", array_keys( StatifyBlacklist::$options['target']['blacklist'] ) ) );
} else {
print esc_html( implode( "\r\n", array_keys( $statifyblacklist_update_result['target']['sanitized'] ) ) );
}
?></textarea>
<p class="description">
(<?php esc_html_e( 'Add one target URL each line, e.g.', 'statify-blacklist' ); ?> /, /test/page/, /?page_id=123)
</p>
</td>
</tr>
</tbody>
</table>
<h2><?php esc_html_e( 'IP blacklist', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="statify-blacklist_active_ip">
<?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[ip][active]" id="statify-blacklist_active_ip"
value="1" <?php checked( StatifyBlacklist::$options['ip']['active'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'Cron execution is not possible for IP filter, because IP addresses are not stored.', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_ip"><?php esc_html_e( 'IP blacklist', 'statify-blacklist' ); ?></label>:
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[ip][blacklist]" id="statify-blacklist_ip"><?php
if ( empty( $statifyblacklist_update_result['ip'] ) ) {
print esc_html( implode( "\r\n", StatifyBlacklist::$options['ip']['blacklist'] ) );
} else {
print esc_html( implode( "\r\n", $statifyblacklist_update_result['ip']['sanitized'] ) );
}
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one IP address or range per line, e.g.', 'statify-blacklist' ); ?>
127.0.0.1, 192.168.123.0/24, 2001:db8:a0b:12f0::1/64
</p>
</td>
</tr>
</tbody>
</table>
<p class="submit">
<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>
<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>