Compare commits

...

40 Commits

Author SHA1 Message Date
ea9366a9ce
ci: add PHP 8.4 to test matrix
All checks were successful
CI / unit-test (7.4) (push) Successful in 54s
CI / unit-test (8.0) (push) Successful in 53s
CI / quality (push) Successful in 44s
CI / unit-test (5.6) (push) Successful in 1m26s
CI / unit-test (8.2) (push) Successful in 52s
CI / unit-test (8.4) (push) Successful in 41s
2025-04-19 17:39:02 +02:00
0432861e95
declare compatibility with WordPress 6.8 2025-04-19 17:38:16 +02:00
1243eef2d2
deps: update dev-dependencies
All checks were successful
CI / unit-test (7.4) (push) Successful in 59s
CI / unit-test (5.6) (push) Successful in 1m39s
CI / unit-test (8.0) (push) Successful in 55s
CI / unit-test (8.1) (push) Successful in 53s
CI / unit-test (8.2) (push) Successful in 53s
CI / unit-test (8.3) (push) Successful in 42s
CI / quality (push) Successful in 47s
2025-04-19 17:36:42 +02:00
b4898abd5b
docs: add missing quote in plugin description 2025-03-02 17:29:50 +01:00
c02263f373
declare compatibility with WordPress 6.7
All checks were successful
CI / unit-test (5.6) (push) Successful in 1m16s
CI / unit-test (7.4) (push) Successful in 1m13s
CI / unit-test (8.0) (push) Successful in 1m13s
CI / unit-test (8.3) (push) Successful in 1m3s
CI / unit-test (8.1) (push) Successful in 1m13s
CI / unit-test (8.2) (push) Successful in 1m14s
CI / quality (push) Successful in 1m7s
2024-11-14 11:36:07 +01:00
b34a79068c
ci: fix branches in plugin check workflow
All checks were successful
CI / unit-test (7.4) (push) Successful in 1m8s
CI / unit-test (8.0) (push) Successful in 1m6s
CI / unit-test (8.1) (push) Successful in 1m8s
CI / unit-test (8.3) (push) Successful in 1m1s
CI / unit-test (8.2) (push) Successful in 1m6s
CI / quality (push) Successful in 1m2s
CI / unit-test (5.6) (push) Successful in 1m13s
2024-11-12 16:16:02 +01:00
00aa79cb1e
fix: typo and deprecated options in blueprint.json 2024-11-12 16:13:22 +01:00
96cd17c3e2
ci: add workflow to run wp plugin checks
All checks were successful
CI / unit-test (5.6) (push) Successful in 1m4s
CI / unit-test (8.1) (push) Successful in 1m0s
CI / unit-test (7.4) (push) Successful in 1m3s
CI / unit-test (8.0) (push) Successful in 1m2s
CI / unit-test (8.2) (push) Successful in 1m3s
CI / unit-test (8.3) (push) Successful in 51s
CI / quality (push) Successful in 54s
2024-10-03 15:03:05 +02:00
96214d55a0
docs: update badges in README.md 2024-10-03 15:00:55 +02:00
fbb8229c3e
ci: explicitly enable xdebug coverage and add condition for analysis
All checks were successful
CI / unit-test (5.6) (push) Successful in 1m6s
CI / unit-test (7.4) (push) Successful in 1m9s
CI / unit-test (8.0) (push) Successful in 1m9s
CI / unit-test (8.1) (push) Successful in 1m4s
CI / unit-test (8.3) (push) Successful in 41s
CI / unit-test (8.2) (push) Successful in 1m2s
CI / quality (push) Successful in 56s
2024-08-08 17:37:36 +02:00
a693e0b9c0
declare compatibility with WordPress 6.6
Some checks failed
CI / unit-test (7.4) (push) Failing after 44s
CI / unit-test (5.6) (push) Failing after 47s
CI / unit-test (8.0) (push) Failing after 44s
CI / unit-test (8.1) (push) Failing after 44s
CI / unit-test (8.3) (push) Successful in 36s
CI / unit-test (8.2) (push) Failing after 45s
CI / quality (push) Successful in 50s
2024-08-08 16:41:57 +02:00
0636367e79
docs: add missing short description to README.md 2024-08-08 16:41:22 +02:00
7537261387
deps: update dev-dependencies
Some checks failed
CI / unit-test (7.4) (push) Failing after 38s
CI / unit-test (8.0) (push) Failing after 39s
CI / unit-test (8.1) (push) Failing after 39s
CI / unit-test (8.2) (push) Failing after 38s
CI / unit-test (8.3) (push) Successful in 59s
CI / unit-test (5.6) (push) Failing after 41s
CI / quality (push) Successful in 38s
2024-08-03 17:28:20 +02:00
38c1e569e6
prepare release 1.7.2 2024-06-06 20:29:05 +02:00
4290aed9ce
fix: restore database cleanup functionality (#37) (#38)
The cleanup request was no longer precessed since we refactored the
settings page in v1.7.0 to use the WP settings API. Process the request
including nonce verification during page creation restores it.
2024-06-06 20:17:19 +02:00
13809aeaa3
prepare release 1.7.1 2024-03-24 17:44:57 +01:00
9903a6163d
simplify control structures
* extract common parts from if-else branches
* convert redundante elseif to else
2024-03-24 17:39:25 +01:00
c88d716dfc
introduce blueprint.json for WP playground preview 2024-03-24 16:37:56 +01:00
714512ca15
fix HTML syntax for checkboxes in settings 2024-03-24 14:42:23 +01:00
081a6abbb0
add "Requires Plugins" to plugin headers
The headers will be supported with WordPress 6.5. The dependency on
"statify" was present from the start, so this just adds another layer
of convenience for users on WP 6.5 or later.
2024-03-17 10:32:26 +01:00
6003a0d397
remove deprecated wp_get_sites() call from uninstall routine
We only support WP 4.7 and later since 1.5. Remove the 4.6 call.
2024-03-16 12:23:32 +01:00
6f4b1722bf
fix contributor tag in README.md 2024-03-12 16:57:21 +01:00
1e81dd650f
prepare release 1.7.0 2024-03-11 18:02:04 +01:00
2437352160
deps: update dev-dependency updates 2024-03-02 10:52:19 +01:00
03c8f0126d
ci: build and test with PHP 8.3 2023-11-25 15:44:44 +01:00
cf0c0a3652
deps: update WPCS definitions to v3 2023-11-09 18:05:13 +01:00
1f4749d49a
rename $class parameter of autoload function to $class_name 2023-11-09 18:05:12 +01:00
fcf251967f
fix routine to update options without custom changes (#31)
array_merge_recursive() results in a misbehavior making arrays from
scalar options when current and default values differ. Replcae it by
array_replace_recursive() should resolve the issue for now.
2023-09-17 15:27:23 +02:00
3b169b28a7
update settings version to 1.7 2023-09-17 15:19:10 +02:00
7fd7be6c19
ci: update actions/checkout to v4 2023-09-17 15:03:58 +02:00
633da4086d
unique IP filter list 2023-09-17 14:58:33 +02:00
da6cde00cf
migrate settings to WP settings API 2023-09-17 14:58:25 +02:00
ae232eceb5
prepare release 1.6.3 2023-08-14 18:53:20 +02:00
93b4dd744d
remove useless parenthesis around DOING_AUTOSAVE check 2023-08-14 18:47:55 +02:00
268e3933c8
declare compatibility with WordPress 6.3 2023-08-14 18:42:51 +02:00
5d7a75ed31
allow compoesr/installers v2 dependency 2023-04-01 15:15:03 +02:00
aaf054fb5b
minor code style tweaks 2023-04-01 15:14:40 +02:00
17c27a7b7c
add .editorconfig 2023-04-01 14:26:48 +02:00
7757142237
declare compatibility with WordPress 6.2 2023-03-27 20:46:49 +02:00
40347b0f50
ci: analyze pull requests 2023-02-25 14:34:18 +01:00
22 changed files with 1301 additions and 779 deletions

View File

@ -1,8 +1,11 @@
/.git
/.github
/assets
/dist
/test
/vendor
/.distignore
/.editorconfig
/.gitattributes
/.gitignore
/.travis.yml

21
.editorconfig Normal file
View File

@ -0,0 +1,21 @@
# 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

1
.gitattributes vendored
View File

@ -1,5 +1,6 @@
/.github export-ignore
/assets export-ignore
/dist export-ignore
/test export-ignore
.distignore export-ignore
.gitattributes export-ignore

View File

@ -5,16 +5,17 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php: [ '5.6', '7.4', '8.0', '8.1', '8.2' ]
php: [ '5.6', '7.4', '8.0', '8.2', '8.4' ]
steps:
- name: Checkout
uses: actions/checkout@v3
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
@ -23,7 +24,7 @@ jobs:
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.0' && github.event_name != 'pull_request'
if: matrix.php == '8.2' && env.SONAR_TOKEN != ''
uses: sonarsource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -32,7 +33,7 @@ jobs:
args: >
-Dsonar.organization=stklcode-github
-Dsonar.projectKey=stklcode:statify-blacklist
-Dsonar.sources=inc,views,statify-blacklist.php
-Dsonar.sources=inc,statify-blacklist.php
-Dsonar.tests=test
-Dsonar.php.tests.reportPath=tests-junit.xml
-Dsonar.php.coverage.reportPaths=tests-clover.xml
@ -42,11 +43,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.0'
php-version: '8.2'
tools: composer
- name: Install
run: composer install --no-interaction

View File

@ -8,7 +8,7 @@ jobs:
name: Push to stable
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- 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

View File

@ -0,0 +1,23 @@
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

@ -9,7 +9,7 @@ jobs:
name: New tag
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- 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

View File

@ -1,23 +1,25 @@
[![Build Status](https://github.com/stklcode/statify-blacklist/actions/workflows/test.yml/badge.svg?branch=stable)](https://github.com/stklcode/statify-blacklist/actions/workflows/test.yml?query=branch%3Astable)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=stklcode%3Astatify-blacklist&metric=alert_status)](https://sonarcloud.io/dashboard?id=stklcode%3Astatify-blacklist)
[![Packagist Version](https://img.shields.io/packagist/v/stklcode/statify-blacklist.svg)](https://packagist.org/packages/stklcode/statify-blacklist)
[![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)
# Statify Filter #
* Contributors: Stefan Kalscheuer
* Contributors: stklcode
* Requires at least: 4.7
* Tested up to: 6.1
* Tested up to: 6.8
* Requires PHP: 5.5
* Stable tag: 1.6.2
* Stable tag: 1.7.2
* 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.
This plugin adds customizable filters to Statify to allow blocking of referer spam or internal interactions.
### Features ##
### Features ###
#### Referer Filter ####
Add a list of domains (for simplicity only second-level, e.g. _example.com_ which blocks _everything.example.com_).
@ -62,7 +64,7 @@ The plugin is capable of handling multisite installations.
### 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.
A default filter is not provided, as the plugin itself is totally neutral. If you want to filter out referer spam,
A default filter is not provided, as the plugin itself is totally neutral. If you want to filter out referer spam,
visitors from search engines, just "false" referrers from 301 redirects or you own IP address used for testing only depends on you.
### Does the filter effect user experience? ###
@ -71,7 +73,7 @@ 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.
@ -93,21 +95,36 @@ Same for IPv6 prefixes like _2001:db8:a0b:12f0::/64_.
## Upgrade Notice ##
### 1.6.2 ###
This is a service release with minor internal corrections and PHP 8.2 compatibility.
### 1.7.2 ###
This is a bugfix release to restore the manual cleanup function that was broken since 1.7.0.
### 1.6.1 ###
This is a bugfix release that corrects storage and evaluation of the user agent filter list.
### 1.7.1 ###
This is a service release with minor corrections. Recommended for all users. Tested up to 6.5.
### 1.6.0 ###
The plugin has been renamed from _Statify Blacklist_ to _Statify Filter_.
This does not imply any changes in functionality, rather than using a better wording.
In addition, there is a new filter by User Agent along with some minor corrections.
This version should be compatible with latest WordPress 5.6.
### 1.7.0 ###
This is a service release with primarily internal rework. Tested up to 6.4 and PHP 8.3.
## Changelog ##
## 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

View File

@ -0,0 +1,36 @@
{
"$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,6 +1,6 @@
{
"name": "stklcode/statify-blacklist",
"version": "1.6.2",
"version": "1.7.2",
"description": "A filter extension for the famous Statify WordPress plugin",
"keywords": [
"wordpress",
@ -19,16 +19,16 @@
"type": "wordpress-plugin",
"require": {
"php": ">=5.5",
"composer/installers": "~1.12"
"composer/installers": "~v1.12|~v2.3"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7",
"dealerdirect/phpcodesniffer-composer-installer": "^v1.0",
"phpunit/phpunit": "^5|^6|^7|^8|^9",
"phpunit/php-code-coverage": "*",
"slowprog/composer-copy-file": "~0.3",
"squizlabs/php_codesniffer": "^3.7",
"squizlabs/php_codesniffer": "^3.12",
"phpcompatibility/phpcompatibility-wp": "^2.1",
"wp-coding-standards/wpcs": "^2.3"
"wp-coding-standards/wpcs": "^3.1"
},
"scripts": {
"test-all": [

View File

@ -16,17 +16,15 @@ if ( ! defined( 'ABSPATH' ) ) {
/**
* Statify Filter admin configuration.
*
* @since 1.0.0
*/
class StatifyBlacklist_Admin extends StatifyBlacklist {
/**
* Initialize admin-only components of the plugin.
*
* @since 1.5.0
*
* @return void
*
* @since 1.5.0
*/
public static function init() {
// Add actions.
@ -46,91 +44,12 @@ 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.
*
@ -139,51 +58,33 @@ class StatifyBlacklist_Admin extends StatifyBlacklist {
public static function add_menu_page() {
$title = __( 'Statify Filter', 'statify-blacklist' );
if ( self::$multisite ) {
add_submenu_page(
'settings.php',
add_options_page(
$title,
$title,
'manage_network_plugins',
'statify-blacklist-settings',
array(
'StatifyBlacklist_Admin',
'settings_page',
)
'statify-blacklist',
array( 'StatifyBlacklist_Settings', 'create_settings_page' )
);
} else {
add_submenu_page(
'options-general.php',
add_options_page(
$title,
$title,
'manage_options',
'statify-blacklist',
array(
'StatifyBlacklist_Admin',
'settings_page',
)
array( 'StatifyBlacklist_Settings', 'create_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 ) {
@ -196,12 +97,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' );
@ -299,11 +200,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(
@ -317,56 +218,4 @@ 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(
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]))?$/i',
$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

@ -0,0 +1,752 @@
<?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

@ -89,9 +89,6 @@ 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;
}
@ -189,7 +186,7 @@ class StatifyBlacklist_System extends StatifyBlacklist {
);
} elseif ( ! isset( $options['ua']['blacklist'] ) ) {
$options['ua']['blacklist'] = array();
} elseif ( isset( $options['ua'] ) ) {
} 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'] );
}
@ -205,7 +202,7 @@ class StatifyBlacklist_System extends StatifyBlacklist {
// 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_merge_recursive( self::default_options(), self::$options );
$options = array_replace_recursive( self::default_options(), self::$options );
$options['version'] = self::VERSION_MAIN;
if ( self::$multisite ) {
update_site_option( 'statify-blacklist', $options );

View File

@ -22,9 +22,9 @@ class StatifyBlacklist {
* Plugin major version.
*
* @since 1.4.0
* @var int VERSION_MAIN
* @var float VERSION_MAIN
*/
const VERSION_MAIN = 1.6;
const VERSION_MAIN = 1.7;
/**
* Operation mode "normal".
@ -80,7 +80,7 @@ class StatifyBlacklist {
*/
public static function init() {
// Skip on autosave.
if ( ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
@ -436,7 +436,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,6 +1,6 @@
{
"name": "statify-blacklist",
"version": "1.6.2",
"version": "1.7.2",
"description": "A filter extension for the famous Statify WordPress plugin",
"author": "Stefan Kalscheuer",
"license": "GPL-2.0+"

View File

@ -8,7 +8,6 @@
<!-- 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"/>

View File

@ -7,14 +7,17 @@
* @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.6.2
* Author: Stefan Kalscheuer (@stklcode)
* Author URI: https://www.stklcode.de
* Text Domain: statify-blacklist
* License: GPLv2 or later
* 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
*
* Statify Filter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -37,7 +40,7 @@ if ( ! defined( 'ABSPATH' ) ) {
// Constants.
define( 'STATIFYBLACKLIST_FILE', __FILE__ );
define( 'STATIFYBLACKLIST_DIR', dirname( __FILE__ ) );
define( 'STATIFYBLACKLIST_DIR', __DIR__ );
define( 'STATIFYBLACKLIST_BASE', plugin_basename( __FILE__ ) );
// Check for compatibility.
@ -62,22 +65,23 @@ if ( statify_blacklist_compatibility_check() ) {
/**
* Autoloader for StatifyBlacklist classes.
*
* @param string $class Name of the class to load.
* @param string $class_name Name of the class to load.
*
* @since 1.0.0
*/
function statify_blacklist_autoload( $class ) {
function statify_blacklist_autoload( $class_name ) {
$plugin_classes = array(
'StatifyBlacklist',
'StatifyBlacklist_Admin',
'StatifyBlacklist_Settings',
'StatifyBlacklist_System',
);
if ( in_array( $class, $plugin_classes, true ) ) {
if ( in_array( $class_name, $plugin_classes, true ) ) {
require_once sprintf(
'%s/inc/class-%s.php',
STATIFYBLACKLIST_DIR,
strtolower( str_replace( '_', '-', $class ) )
strtolower( str_replace( '_', '-', $class_name ) )
);
}
}

View File

@ -1,67 +0,0 @@
<?php
/**
* Statify Filter: Unit Test
*
* This is a PHPunit test class for the plugin's functionality
*
* @package Statify_Blacklist
*/
/**
* Class StatifyBlacklist_Admin_Test.
*
* PHPUnit test class for StatifyBlacklist_Admin.
*/
class StatifyBlacklist_Admin_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',
'fe80::7645:6de2:ff:1',
'::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_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( array_map( 'strtolower', $valid ), $result );
}
}

View File

@ -0,0 +1,330 @@
<?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

@ -47,7 +47,7 @@ class StatifyBlacklist_System_Test extends PHPUnit\Framework\TestCase {
$this->assertEquals( 4, count( $options_updated['target'] ) );
$this->assertEquals( 2, count( $options_updated['ip'] ) );
$this->assertEquals( 3, count( $options_updated['ua'] ) );
$this->assertEquals( 1.6, $options_updated['version'] );
$this->assertEquals( StatifyBlacklist::VERSION_MAIN, $options_updated['version'] );
// Verify that original attributes are unchanged.
$this->assertEquals( $options13['active_referer'], $options_updated['referer']['active'] );
@ -86,7 +86,6 @@ class StatifyBlacklist_System_Test extends PHPUnit\Framework\TestCase {
),
$options_updated['ua']['blacklist']
);
$this->assertEquals( 1.6, $options_updated['version'] );
$this->assertEquals( StatifyBlacklist::VERSION_MAIN, $options_updated['version'] );
}
}

View File

@ -17,6 +17,7 @@ const ABSPATH = false;
*/
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.
@ -36,6 +37,8 @@ function invoke_static( $class, $method_name, $parameters = array() ) {
// Some mocked WP functions.
$mock_options = array();
$mock_multisite = false;
$settings_error = array();
$settings = array();
/** @ignore */
function is_multisite() {
@ -87,3 +90,45 @@ function wp_parse_url( $value ) {
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,488 +0,0 @@
<?php
/**
* Statify Filter: 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?', 'statify-blacklist' ) );
}
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 );
}
);
}
// Extract user agent array.
if ( isset( $_POST['statifyblacklist']['ua']['blacklist'] ) ) {
$ua_string = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['ua']['blacklist'] ) );
}
if ( empty( trim( $ua_string ) ) ) {
$ua = array();
} else {
$ua = array_filter(
array_map(
function ( $a ) {
return trim( $a );
},
explode( "\r\n", str_replace( '\\\\', '\\', $ua_string ) )
),
function ( $a ) {
return ! empty( $a );
}
);
}
// Update options (data will be sanitized).
$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,
),
'ua' => array(
'active' => isset( $_POST['statifyblacklist']['ua']['active'] )
? (int) $_POST['statifyblacklist']['ua']['active'] : 0,
'regexp' => isset( $_POST['statifyblacklist']['ua']['regexp'] )
? (int) $_POST['statifyblacklist']['ua']['regexp'] : 0,
'blacklist' => array_flip( $ua ),
),
'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 Filter', '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 filter', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="statify-blacklist_active_referer">
<?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[referer][active]"
id="statify-blacklist_active_referer"
value="1" <?php checked( StatifyBlacklist::$options['referer']['active'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_cron_referer">
<?php esc_html_e( 'CronJob execution', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[referer][cron]" id="statify-blacklist_cron_referer"
value="1" <?php checked( StatifyBlacklist::$options['referer']['cron'], 1 ); ?>>
<p class="description"><?php esc_html_e( 'Periodically clean up database in background', 'statify-blacklist' ); ?></p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_referer_regexp"><?php esc_html_e( 'Matching method', 'statify-blacklist' ); ?></label>
</th>
<td>
<select name="statifyblacklist[referer][regexp]" id="statify-blacklist_referer_regexp">
<option value="<?php print esc_attr( StatifyBlacklist::MODE_NORMAL ); ?>" <?php selected( StatifyBlacklist::$options['referer']['regexp'], StatifyBlacklist::MODE_NORMAL ); ?>>
<?php esc_html_e( 'Domain', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_KEYWORD ); ?>" <?php selected( StatifyBlacklist::$options['referer']['regexp'], StatifyBlacklist::MODE_KEYWORD ); ?>>
<?php esc_html_e( 'Keyword', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX ); ?>" <?php selected( StatifyBlacklist::$options['referer']['regexp'], StatifyBlacklist::MODE_REGEX ); ?>>
<?php esc_html_e( 'RegEx case-sensitive', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX_CI ); ?>" <?php selected( StatifyBlacklist::$options['referer']['regexp'], StatifyBlacklist::MODE_REGEX_CI ); ?>>
<?php esc_html_e( 'RegEx case-insensitive', 'statify-blacklist' ); ?>
</option>
</select>
<p class="description">
<?php esc_html_e( 'Domain', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match given domain including subdomains', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'Keyword', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match every referer that contains one of the keywords', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'RegEx', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match referer by regular expression', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_referer"><?php esc_html_e( 'Referer filter', 'statify-blacklist' ); ?></label>
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[referer][blacklist]" id="statify-blacklist_referer"><?php
if ( empty( $statifyblacklist_update_result['referer'] ) ) {
print esc_html( implode( "\r\n", array_keys( StatifyBlacklist::$options['referer']['blacklist'] ) ) );
} else {
print esc_html( implode( "\r\n", array_keys( $statifyblacklist_update_result['referer']['sanitized'] ) ) );
}
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one domain (without subdomains) each line, e.g. example.com', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
</tbody>
</table>
<h2><?php esc_html_e( 'Target filter', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="statify-blacklist_active_target">
<?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[target][active]"
id="statify-blacklist_active_target"
value="1" <?php checked( StatifyBlacklist::$options['target']['active'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_cron_target">
<?php esc_html_e( 'CronJob execution', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[target][cron]" id="statify-blacklist_cron_target"
value="1" <?php checked( StatifyBlacklist::$options['target']['cron'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Clean database periodically in background', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_target_regexp">
<?php esc_html_e( 'Matching method', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<select name="statifyblacklist[target][regexp]" id="statify-blacklist_target_regexp">
<option value="<?php print esc_attr( StatifyBlacklist::MODE_NORMAL ); ?>" <?php selected( StatifyBlacklist::$options['target']['regexp'], StatifyBlacklist::MODE_NORMAL ); ?>>
<?php esc_html_e( 'Exact', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX ); ?>" <?php selected( StatifyBlacklist::$options['target']['regexp'], StatifyBlacklist::MODE_REGEX ); ?>>
<?php esc_html_e( 'RegEx case-sensitive', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX_CI ); ?>" <?php selected( StatifyBlacklist::$options['target']['regexp'], StatifyBlacklist::MODE_REGEX_CI ); ?>>
<?php esc_html_e( 'RegEx case-insensitive', 'statify-blacklist' ); ?>
</option>
</select>
<p class="description">
<?php esc_html_e( 'Exact', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match only given targets', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'RegEx', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match target by regular expression', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_target">
<?php esc_html_e( 'Target filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[target][blacklist]" id="statify-blacklist_target"><?php
if ( empty( $statifyblacklist_update_result['target'] ) ) {
print esc_html( implode( "\r\n", array_keys( StatifyBlacklist::$options['target']['blacklist'] ) ) );
} else {
print esc_html( implode( "\r\n", array_keys( $statifyblacklist_update_result['target']['sanitized'] ) ) );
}
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one target URL each line, e.g.', 'statify-blacklist' ); ?> /, /test/page/, /?page_id=123
</p>
</td>
</tr>
</tbody>
</table>
<h2><?php esc_html_e( 'IP filter', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="statify-blacklist_active_ip">
<?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[ip][active]" id="statify-blacklist_active_ip"
value="1" <?php checked( StatifyBlacklist::$options['ip']['active'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'Cron execution is not possible for IP filter, because IP addresses are not stored.', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_ip"><?php esc_html_e( 'IP filter', 'statify-blacklist' ); ?></label>:
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[ip][blacklist]" id="statify-blacklist_ip"><?php
if ( empty( $statifyblacklist_update_result['ip'] ) ) {
print esc_html( implode( "\r\n", StatifyBlacklist::$options['ip']['blacklist'] ) );
} else {
print esc_html( implode( "\r\n", $statifyblacklist_update_result['ip']['sanitized'] ) );
}
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one IP address or range per line, e.g.', 'statify-blacklist' ); ?>
127.0.0.1, 192.168.123.0/24, 2001:db8:a0b:12f0::1/64
</p>
</td>
</tr>
</tbody>
</table>
<h2><?php esc_html_e( 'User agent filter', 'statify-blacklist' ); ?></h2>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="statify-blacklist_active_ua">
<?php esc_html_e( 'Activate live filter', 'statify-blacklist' ); ?>
</label>
</th>
<td>
<input type="checkbox" name="statifyblacklist[ua][active]" id="statify-blacklist_active_ua"
value="1" <?php checked( StatifyBlacklist::$options['ua']['active'], 1 ); ?>>
<p class="description">
<?php esc_html_e( 'Filter at time of tracking, before anything is stored', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'Cron execution is not possible for user agent filter, because the user agent is stored.', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_ua_regexp"><?php esc_html_e( 'Matching method', 'statify-blacklist' ); ?></label>
</th>
<td>
<select name="statifyblacklist[ua][regexp]" id="statify-blacklist_ua_regexp">
<option value="<?php print esc_attr( StatifyBlacklist::MODE_NORMAL ); ?>" <?php selected( StatifyBlacklist::$options['ua']['regexp'], StatifyBlacklist::MODE_NORMAL ); ?>>
<?php esc_html_e( 'Exact', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_KEYWORD ); ?>" <?php selected( StatifyBlacklist::$options['ua']['regexp'], StatifyBlacklist::MODE_KEYWORD ); ?>>
<?php esc_html_e( 'Keyword', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX ); ?>" <?php selected( StatifyBlacklist::$options['ua']['regexp'], StatifyBlacklist::MODE_REGEX ); ?>>
<?php esc_html_e( 'RegEx case-sensitive', 'statify-blacklist' ); ?>
</option>
<option value="<?php print esc_attr( StatifyBlacklist::MODE_REGEX_CI ); ?>" <?php selected( StatifyBlacklist::$options['ua']['regexp'], StatifyBlacklist::MODE_REGEX_CI ); ?>>
<?php esc_html_e( 'RegEx case-insensitive', 'statify-blacklist' ); ?>
</option>
</select>
<p class="description">
<?php esc_html_e( 'Exact', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match only given user agents', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'Keyword', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match every referer that contains one of the keywords', 'statify-blacklist' ); ?>
<br>
<?php esc_html_e( 'RegEx', 'statify-blacklist' ); ?> - <?php esc_html_e( 'Match user agent by regular expression', 'statify-blacklist' ); ?>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="statify-blacklist_ua"><?php esc_html_e( 'User agent filter', 'statify-blacklist' ); ?></label>:
</th>
<td>
<textarea cols="40" rows="5" name="statifyblacklist[ua][blacklist]" id="statify-blacklist_ua"><?php
if ( empty( $statifyblacklist_update_result['ua'] ) ) {
print esc_html( implode( "\r\n", array_keys( StatifyBlacklist::$options['ua']['blacklist'] ) ) );
} else {
print esc_html( implode( "\r\n", array_keys( $statifyblacklist_update_result['ua']['sanitized'] ) ) );
}
?></textarea>
<p class="description">
<?php esc_html_e( 'Add one user agent string per line, e.g.', 'statify-blacklist' ); ?>
MyBot/1.23
</p>
</td>
</tr>
</tbody>
</table>
<p class="submit">
<input class="button-primary" type="submit" name="submit" value="<?php esc_html_e( 'Save Changes', 'statify-blacklist' ); ?>">
<hr>
<input class="button-secondary" type="submit" name="cleanUp"
value="<?php esc_html_e( 'CleanUp Database', 'statify-blacklist' ); ?>"
onclick="return confirm('Do you really want to apply filters to database? This cannot be undone.');">
<br>
<p class="description">
<?php esc_html_e( 'Applies referer and target filter (even if disabled) to data stored in database.', 'statify-blacklist' ); ?>
<em><?php esc_html_e( 'This cannot be undone!', 'statify-blacklist' ); ?></em>
</p>
</p>
</form>
</div>