From 8c556ca5093acc0750ed685380ebebc26b1b428b Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Wed, 21 Mar 2018 18:16:25 +0100
Subject: [PATCH 01/42] Removed legacy code for WP prior to 4.6
Statify itself requires WP 4.7, so no reason to stick to legacy code
anymore.
---
README.md | 7 +++++--
composer.json | 2 +-
inc/class-statifyblacklist-system.php | 3 ---
phpcs.xml | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index bceb1bb..f069d7d 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Statify Blacklist #
* Contributors: Stefan Kalscheuer
-* Requires at least: 4.4
+* Requires at least: 4.7
* Tested up to: 4.9
* Requires PHP: 5.5
* Stable tag: 1.4.3
@@ -46,7 +46,7 @@ The plugin is capable of handling multisite installations.
### Requirements ###
* PHP 5.5 or above
-* WordPress 4.4 or above
+* WordPress 4.7 or above
* Statify plugin installed and activated (1.5.0 or above)
## Frequently Asked Questions ##
@@ -82,6 +82,9 @@ Because of this, an IP blacklist can only be applied while processing the reques
## Changelog ##
+### 1.5.0 / unreleased ###
+* Minimum required WordPress version is 4.7
+
### 1.4.3 / 09.01.2018 ###
* Fix issues with multisite installation (#11)
diff --git a/composer.json b/composer.json
index be3a5d0..dc35535 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,6 @@
{
"name": "stklcode/statify-blacklist",
- "version": "1.4.3",
+ "version": "1.5.0-alpha",
"description": "A blacklist extension for the famous Statify WordPress plugin",
"keywords": [
"wordpress",
diff --git a/inc/class-statifyblacklist-system.php b/inc/class-statifyblacklist-system.php
index a9160b1..66b822f 100644
--- a/inc/class-statifyblacklist-system.php
+++ b/inc/class-statifyblacklist-system.php
@@ -31,9 +31,6 @@ public static function install( $network_wide = false ) {
if ( $network_wide && is_multisite() ) {
if ( function_exists( 'get_sites' ) ) {
$sites = get_sites();
- } elseif ( function_exists( 'wp_get_sites' ) ) {
- // @codingStandardsIgnoreLine Legacy support for WP < 4.6.
- $sites = wp_get_sites();
} else {
return;
}
diff --git a/phpcs.xml b/phpcs.xml
index a40b6c5..ff901cc 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -10,7 +10,7 @@
statify-blacklist.php
-
+
From 5e2dd4b6e19c084e593567b9290bb33889fdcc4e Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Wed, 21 Mar 2018 18:27:42 +0100
Subject: [PATCH 02/42] Removed Gulp build script
Build process is now handled by Composer and Robo, so clean up old stuff
---
Gulpfile.js | 65 ----------------------------------------------------
package.json | 14 ++---------
2 files changed, 2 insertions(+), 77 deletions(-)
delete mode 100644 Gulpfile.js
diff --git a/Gulpfile.js b/Gulpfile.js
deleted file mode 100644
index 2fe2690..0000000
--- a/Gulpfile.js
+++ /dev/null
@@ -1,65 +0,0 @@
-var gulp = require('gulp');
-var clean = require('gulp-clean');
-var copy = require('gulp-copy');
-var zip = require('gulp-zip');
-var composer = require('gulp-composer');
-var phpunit = require('gulp-phpunit');
-var exec = require('child_process').exec;
-var phpcs = require('gulp-phpcs');
-var config = require('./package.json');
-
-// Clean the target directory.
-gulp.task('clean', function () {
- console.log('Cleaning up target directory ...');
- return gulp.src('dist', {read: false})
- .pipe(clean());
-});
-
-// Prepare composer.
-gulp.task('compose', function () {
- console.log('Preparing Composer ...');
- return composer('install');
-});
-
-// Execute unit tests.
-gulp.task('test', ['compose'], function () {
- console.log('Running PHPUnit tests ...');
- return gulp.src('phpunit.xml')
- .pipe(phpunit('./vendor/bin/phpunit', {debug: false}));
-});
-
-// Execute PHP Code Sniffer.
-gulp.task('test-cs', function (cb) {
- return exec('./vendor/bin/phpcs --config-set installed_paths vendor/wimg/php-compatibility,vendor/wp-coding-standards/wpcs', function (err, stdout, stderr) {
- console.log(stdout);
- console.log(stderr);
- if (null === err) {
- console.log('Running PHP Code Sniffer tests ...');
- // exec('./vendor/bin/phpcs --standard=phpcs.xml', function(err, stdout, stderr) {
- // console.log(stdout);
- // console.log(stderr);
- // });
- gulp.src(['statify-blacklist.php', 'inc/**/*.php'])
- .pipe(phpcs({bin: './vendor/bin/phpcs', standard: 'phpcs.xml'}))
- .pipe(phpcs.reporter('log'));
- }
- cb(err);
- });
-});
-
-// Bundle files as required for plugin distribution..
-gulp.task('bundle', ['clean'], function () {
- console.log('Collecting files for package dist/' + config.name + config.version + ' ...');
- return gulp.src(['**/*.php', '!RoboFile.php', '!test/**', '!vendor/**', 'README.md', 'LICENSE.md'], {base: './'})
- .pipe(copy('./dist/' + config.name + '.' + config.version + '/' + config.name));
-});
-
-// Create a ZIP package of the relevant files for plugin distribution.
-gulp.task('package', ['bundle'], function () {
- console.log('Building package dist/' + config.name + config.version + '.zip ...');
- return gulp.src('./dist/' + config.name + '.' + config.version + '/**')
- .pipe(zip(config.name + '.' + config.version + '.zip'))
- .pipe(gulp.dest('./dist'));
-});
-
-gulp.task('default', ['clean', 'compose', 'test', 'test-cs', 'bundle', 'package']);
diff --git a/package.json b/package.json
index ebda245..cf9bc2f 100644
--- a/package.json
+++ b/package.json
@@ -1,17 +1,7 @@
{
"name": "statify-blacklist",
- "version": "1.4.3",
+ "version": "1.5.0-alpha",
"description": "A blacklist extension for the famous Statify WordPress plugin",
"author": "Stefan Kalscheuer",
- "license": "GPL-2.0+",
- "devDependencies": {
- "gulp": "^3.9.1",
- "gulp-clean": "^0.3.2",
- "gulp-copy": "^1.0.1",
- "gulp-zip": "^4.0.0",
- "gulp-composer": "^0.4.4",
- "gulp-phpunit": "^0.24.1",
- "gulp-phpcs": "^2.1.0",
- "child_process": "^1.0.2"
- }
+ "license": "GPL-2.0+"
}
From c77e1ee01235c4bef4a9f933f3a8ba5fe6cb5751 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sat, 19 May 2018 13:44:39 +0200
Subject: [PATCH 03/42] Apply coding standards to unit test (except some mocks)
---
test/statifyblacklist-test.php | 110 +++++++++++++++++++--------------
1 file changed, 62 insertions(+), 48 deletions(-)
diff --git a/test/statifyblacklist-test.php b/test/statifyblacklist-test.php
index aa31aa9..523feb5 100644
--- a/test/statifyblacklist-test.php
+++ b/test/statifyblacklist-test.php
@@ -20,17 +20,17 @@
/**
* The StatifyBlacklist base class.
*/
-require_once( 'inc/class-statifyblacklist.php' );
+require_once __DIR__ . '/../inc/class-statifyblacklist.php';
/**
* The StatifyBlacklist system class.
*/
-require_once( 'inc/class-statifyblacklist-system.php' );
+require_once __DIR__ . '/../inc/class-statifyblacklist-system.php';
/**
* The StatifyBlacklist admin class.
*/
-require_once( 'inc/class-statifyblacklist-admin.php' );
+require_once __DIR__ . '/../inc/class-statifyblacklist-admin.php';
/**
* Class StatifyBlacklistTest.
@@ -43,6 +43,8 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
/**
* Test simple referer filter.
+ *
+ * @return void
*/
public function test_referer_filter() {
// Prepare Options: 2 blacklisted domains, disabled.
@@ -103,8 +105,10 @@ public function test_referer_filter() {
/**
* Test referer filter using regular expressions.
+ *
+ * @return void
*/
- public function testRefererRegexFilter() {
+ public function test_referer_regex_filter() {
// Prepare Options: 2 regular expressions.
StatifyBlacklist::$_options = array(
'referer' => array(
@@ -158,8 +162,10 @@ public function testRefererRegexFilter() {
/**
* Test the upgrade methodology for configuration options.
+ *
+ * @return void
*/
- public function testUpgrade() {
+ public function test_upgrade() {
// Create configuration of version 1.3.
$options13 = array(
'active_referer' => 1,
@@ -179,41 +185,43 @@ public function testUpgrade() {
StatifyBlacklist_System::upgrade();
// Retrieve updated options.
- $optionsUpdated = get_option( 'statify-blacklist' );
+ $options_updated = get_option( 'statify-blacklist' );
// Verify size against default options (no junk left).
- $this->assertEquals( 4, count( $optionsUpdated ) );
- $this->assertEquals( 4, count( $optionsUpdated['referer'] ) );
- $this->assertEquals( 4, count( $optionsUpdated['target'] ) );
- $this->assertEquals( 2, count( $optionsUpdated['ip'] ) );
+ $this->assertEquals( 4, count( $options_updated ) );
+ $this->assertEquals( 4, count( $options_updated['referer'] ) );
+ $this->assertEquals( 4, count( $options_updated['target'] ) );
+ $this->assertEquals( 2, count( $options_updated['ip'] ) );
// Verify that original attributes are unchanged.
- $this->assertEquals( $options13['active_referer'], $optionsUpdated['referer']['active'] );
- $this->assertEquals( $options13['cron_referer'], $optionsUpdated['referer']['cron'] );
- $this->assertEquals( $options13['referer'], $optionsUpdated['referer']['blacklist'] );
- $this->assertEquals( $options13['referer_regexp'], $optionsUpdated['referer']['regexp'] );
+ $this->assertEquals( $options13['active_referer'], $options_updated['referer']['active'] );
+ $this->assertEquals( $options13['cron_referer'], $options_updated['referer']['cron'] );
+ $this->assertEquals( $options13['referer'], $options_updated['referer']['blacklist'] );
+ $this->assertEquals( $options13['referer_regexp'], $options_updated['referer']['regexp'] );
// Verify that new attributes are present in config and filled with default values (disabled, empty).
- $this->assertEquals( 0, $optionsUpdated['target']['active'] );
- $this->assertEquals( 0, $optionsUpdated['target']['cron'] );
- $this->assertEquals( 0, $optionsUpdated['target']['regexp'] );
- $this->assertEquals( array(), $optionsUpdated['target']['blacklist'] );
- $this->assertEquals( 0, $optionsUpdated['ip']['active'] );
- $this->assertEquals( array(), $optionsUpdated['ip']['blacklist'] );
+ $this->assertEquals( 0, $options_updated['target']['active'] );
+ $this->assertEquals( 0, $options_updated['target']['cron'] );
+ $this->assertEquals( 0, $options_updated['target']['regexp'] );
+ $this->assertEquals( array(), $options_updated['target']['blacklist'] );
+ $this->assertEquals( 0, $options_updated['ip']['active'] );
+ $this->assertEquals( array(), $options_updated['ip']['blacklist'] );
// Verify that version number has changed to current release.
- $this->assertEquals( StatifyBlacklist::VERSION_MAIN, $optionsUpdated['version'] );
+ $this->assertEquals( StatifyBlacklist::VERSION_MAIN, $options_updated['version'] );
}
/**
- * Test CIDR address matching for IP filter (#7)
+ * Test CIDR address matching for IP filter (#7).
+ *
+ * @return void
*/
- public function testCidrMatch() {
+ public function test_cidr_match() {
// IPv4 tests.
- $this->assertTrue( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '127.0.0.1', '127.0.0.1' ) ) );
- $this->assertTrue( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '127.0.0.1', '127.0.0.1/32' ) ) );
+ $this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '127.0.0.1', '127.0.0.1' ) ) );
+ $this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '127.0.0.1', '127.0.0.1/32' ) ) );
$this->assertFalse(
- invokeStatic(
+ invoke_static(
StatifyBlacklist::class, 'cidr_match', array(
'127.0.0.1',
'127.0.0.1/33',
@@ -221,7 +229,7 @@ public function testCidrMatch() {
)
);
$this->assertFalse(
- invokeStatic(
+ invoke_static(
StatifyBlacklist::class, 'cidr_match', array(
'127.0.0.1',
'127.0.0.1/-1',
@@ -229,7 +237,7 @@ public function testCidrMatch() {
)
);
$this->assertTrue(
- invokeStatic(
+ invoke_static(
StatifyBlacklist::class, 'cidr_match', array(
'192.0.2.123',
'192.0.2.0/24',
@@ -237,7 +245,7 @@ public function testCidrMatch() {
)
);
$this->assertFalse(
- invokeStatic(
+ invoke_static(
StatifyBlacklist::class, 'cidr_match', array(
'192.0.3.123',
'192.0.2.0/24',
@@ -245,7 +253,7 @@ public function testCidrMatch() {
)
);
$this->assertTrue(
- invokeStatic(
+ invoke_static(
StatifyBlacklist::class, 'cidr_match', array(
'192.0.2.123',
'192.0.2.120/29',
@@ -253,16 +261,16 @@ public function testCidrMatch() {
)
);
$this->assertFalse(
- invokeStatic(
+ invoke_static(
StatifyBlacklist::class, 'cidr_match', array(
'192.0.2.128',
'192.0.2.120/29',
)
)
);
- $this->assertTrue( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '10.11.12.13', '10.0.0.0/8' ) ) );
+ $this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '10.11.12.13', '10.0.0.0/8' ) ) );
$this->assertFalse(
- invokeStatic(
+ invoke_static(
StatifyBlacklist::class, 'cidr_match', array(
'10.11.12.345',
'10.0.0.0/8',
@@ -271,12 +279,12 @@ public function testCidrMatch() {
);
// IPv6 tests.
- $this->assertTrue( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1' ) ) );
- $this->assertTrue( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/128' ) ) );
- $this->assertFalse( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/129' ) ) );
- $this->assertFalse( invokeStatic( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/-1' ) ) );
+ $this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1' ) ) );
+ $this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/128' ) ) );
+ $this->assertFalse( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/129' ) ) );
+ $this->assertFalse( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/-1' ) ) );
$this->assertTrue(
- invokeStatic(
+ invoke_static(
StatifyBlacklist::class, 'cidr_match', array(
'2001:db8:a0b:12f0:1:2:3:4',
'2001:db8:a0b:12f0::1/64 ',
@@ -284,7 +292,7 @@ public function testCidrMatch() {
)
);
$this->assertTrue(
- invokeStatic(
+ invoke_static(
StatifyBlacklist::class, 'cidr_match', array(
'2001:db8:a0b:12f0::123:456',
'2001:db8:a0b:12f0::1/96 ',
@@ -292,7 +300,7 @@ public function testCidrMatch() {
)
);
$this->assertFalse(
- invokeStatic(
+ invoke_static(
StatifyBlacklist::class, 'cidr_match', array(
'2001:db8:a0b:12f0::1:132:465',
'2001:db8:a0b:12f0::1/96 ',
@@ -302,13 +310,15 @@ public function testCidrMatch() {
}
/**
- * Test sanitization of IP addresses
+ * Test sanitization of IP addresses.
+ *
+ * @return void
*/
- public function testSanitizeIPs() {
+ public function test_sanitize_ips() {
// IPv4 tests.
$valid = array( '192.0.2.123', '192.0.2.123/32', '192.0.2.0/24', '192.0.2.128/25' );
$invalid = array( '12.34.56.789', '192.0.2.123/33', '192.0.2.123/-1' );
- $result = invokeStatic( StatifyBlacklist_Admin::class, 'sanitizeIPs', array( array_merge( $valid, $invalid ) ) );
+ $result = invoke_static( StatifyBlacklist_Admin::class, 'sanitizeIPs', array( array_merge( $valid, $invalid ) ) );
$this->assertNotFalse( $result );
$this->assertInternalType( 'array', $result );
$this->assertEquals( $valid, $result );
@@ -327,7 +337,7 @@ public function testSanitizeIPs() {
'2001:db8:a0b:12f0::/129',
'1:2:3:4:5:6:7:8:9',
);
- $result = invokeStatic( StatifyBlacklist_Admin::class, 'sanitizeIPs', array( array_merge( $valid, $invalid ) ) );
+ $result = invoke_static( StatifyBlacklist_Admin::class, 'sanitizeIPs', array( array_merge( $valid, $invalid ) ) );
$this->assertNotFalse( $result );
$this->assertInternalType( 'array', $result );
$this->assertEquals( $valid, $result );
@@ -335,8 +345,10 @@ public function testSanitizeIPs() {
/**
* Test IP filter (#7).
+ *
+ * @return void
*/
- public function testIPFilter() {
+ public function test_ip_filter() {
// Prepare Options: 2 blacklisted IPs, disabled.
StatifyBlacklist::$_options = array(
'referer' => array(
@@ -405,8 +417,10 @@ public function testIPFilter() {
/**
* Test simple target filter.
+ *
+ * @return void
*/
- public function testTargetFilter() {
+ public function test_target_filter() {
// Prepare Options: 2 blacklisted domains, disabled.
StatifyBlacklist::$_options = array(
'referer' => array(
@@ -476,9 +490,9 @@ public function testTargetFilter() {
/** @ignore */
-function invokeStatic( $class, $methodName, $parameters = array() ) {
+function invoke_static( $class, $method_name, $parameters = array() ) {
$reflection = new \ReflectionClass( $class );
- $method = $reflection->getMethod( $methodName );
+ $method = $reflection->getMethod( $method_name );
$method->setAccessible( true );
return $method->invokeArgs( null, $parameters );
From f34b76194232e81ec90b7004efd24c9b77b65e1a Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sat, 19 May 2018 15:09:57 +0200
Subject: [PATCH 04/42] Removed load_plugin_textdomain and domain path header
Translation is handled via translate.wordpress.org and minimum required
version is greater than 4.6, so the local translation artifacts are
dropped.
---
README.md | 1 +
inc/class-statifyblacklist.php | 3 ---
statify-blacklist.php | 1 -
3 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/README.md b/README.md
index fe7eece..c22f181 100644
--- a/README.md
+++ b/README.md
@@ -84,6 +84,7 @@ Because of this, an IP blacklist can only be applied while processing the reques
### 1.5.0 / unreleased ###
* Minimum required WordPress version is 4.7
+* Removed `load_plugin_textdomain()` and `Domain Path` header
### 1.4.4 / 19.05.2018 ###
* Fix live filter chain when regular expressions are active (#12)
diff --git a/inc/class-statifyblacklist.php b/inc/class-statifyblacklist.php
index 3ebea16..b56b1a1 100644
--- a/inc/class-statifyblacklist.php
+++ b/inc/class-statifyblacklist.php
@@ -86,9 +86,6 @@ public static function init() {
// Admin only filters.
if ( is_admin() ) {
- // Load Textdomain (only needed for backend.
- load_plugin_textdomain( 'statifyblacklist', false, STATIFYBLACKLIST_DIR . '/lang/' );
-
// Add actions.
add_action( 'wpmu_new_blog', array( 'StatifyBlacklist_System', 'install_site' ) );
add_action( 'delete_blog', array( 'StatifyBlacklist_System', 'uninstall_site' ) );
diff --git a/statify-blacklist.php b/statify-blacklist.php
index 7588846..af33b65 100644
--- a/statify-blacklist.php
+++ b/statify-blacklist.php
@@ -14,7 +14,6 @@
* Author: Stefan Kalscheuer (@stklcode)
* Author URI: https://www.stklcode.de
* Text Domain: statify-blacklist
- * Domain Path: /lang
* License: GPLv2 or later
*
* Statify Blacklist is free software: you can redistribute it and/or modify
From bcd42bde2a34f1ba548579a532bc297f1d3e471c Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sat, 20 Oct 2018 10:12:38 +0200
Subject: [PATCH 05/42] Minor code style fixes
---
composer.json | 8 ++++----
inc/class-statifyblacklist-admin.php | 23 ++++++++++++++++++-----
inc/class-statifyblacklist-system.php | 2 +-
inc/class-statifyblacklist.php | 3 ++-
4 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/composer.json b/composer.json
index dc35535..36727f2 100644
--- a/composer.json
+++ b/composer.json
@@ -23,13 +23,13 @@
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.4",
- "consolidation/robo": "^1.0.0",
+ "consolidation/robo": "^1.3",
"phpunit/phpunit": "*",
"phpunit/php-code-coverage": "*",
"slowprog/composer-copy-file": "~0.2",
- "squizlabs/php_codesniffer": "^3.1",
- "wimg/php-compatibility": "^8.0",
- "wp-coding-standards/wpcs": "~0.14"
+ "squizlabs/php_codesniffer": "^3.3",
+ "wimg/php-compatibility": "^9.0",
+ "wp-coding-standards/wpcs": "^1.1"
},
"scripts": {
"build": [
diff --git a/inc/class-statifyblacklist-admin.php b/inc/class-statifyblacklist-admin.php
index e807ef9..b391de3 100644
--- a/inc/class-statifyblacklist-admin.php
+++ b/inc/class-statifyblacklist-admin.php
@@ -74,14 +74,24 @@ public static function add_menu_page() {
$title = __( 'Statify Blacklist', 'statify-blacklist' );
if ( self::$multisite ) {
add_submenu_page(
- 'settings.php', $title, $title, 'manage_network_plugins', 'statify-blacklist-settings', array(
+ 'settings.php',
+ $title,
+ $title,
+ 'manage_network_plugins',
+ 'statify-blacklist-settings',
+ array(
'StatifyBlacklist_Admin',
'settings_page',
)
);
} else {
add_submenu_page(
- 'options-general.php', $title, $title, 'manage_options', 'statify-blacklist', array(
+ 'options-general.php',
+ $title,
+ $title,
+ 'manage_options',
+ 'statify-blacklist',
+ array(
'StatifyBlacklist_Admin',
'settings_page',
)
@@ -251,12 +261,15 @@ function ( $r ) {
*/
private static function sanitizeIPs( $ips ) {
return array_filter(
- $ips, function ( $ip ) {
+ $ips,
+ function ( $ip ) {
return preg_match(
- '/^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])(\/([0-9]|[1-2][0-9]|3[0-2]))?$/', $ip
+ '/^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])(\/([0-9]|[1-2][0-9]|3[0-2]))?$/',
+ $ip
) ||
preg_match(
- '/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$/', $ip
+ '/^(([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
);
}
);
diff --git a/inc/class-statifyblacklist-system.php b/inc/class-statifyblacklist-system.php
index 66b822f..8d65df5 100644
--- a/inc/class-statifyblacklist-system.php
+++ b/inc/class-statifyblacklist-system.php
@@ -1,6 +1,6 @@
Date: Sat, 27 Oct 2018 17:44:13 +0200
Subject: [PATCH 06/42] Merge if-clauses for cron job detection
---
inc/class-statifyblacklist.php | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/inc/class-statifyblacklist.php b/inc/class-statifyblacklist.php
index 0d7efbc..428991d 100644
--- a/inc/class-statifyblacklist.php
+++ b/inc/class-statifyblacklist.php
@@ -109,10 +109,9 @@ public static function init() {
}
// CronJob to clean up database.
- if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
- if ( 1 === self::$_options['referer']['cron'] || 1 === self::$_options['target']['cron'] ) {
- add_action( 'statify_cleanup', array( 'StatifyBlacklist_Admin', 'cleanup_database' ) );
- }
+ if ( defined( 'DOING_CRON' ) && DOING_CRON &&
+ ( 1 === self::$_options['referer']['cron'] || 1 === self::$_options['target']['cron'] ) ) {
+ add_action( 'statify_cleanup', array( 'StatifyBlacklist_Admin', 'cleanup_database' ) );
}
}
From 8e6cb5c553017a97eec23895960fe50d055072a7 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sat, 27 Oct 2018 18:33:00 +0200
Subject: [PATCH 07/42] Added compatibility check for WP and PHP version
(closes #17)
---
README.md | 1 +
statify-blacklist.php | 72 ++++++++++++++++++++++++++++++++++++++-----
2 files changed, 65 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index 37a82fa..3479cab 100644
--- a/README.md
+++ b/README.md
@@ -85,6 +85,7 @@ Because of this, an IP blacklist can only be applied while processing the reques
### 1.5.0 / unreleased ###
* Minimum required WordPress version is 4.7
* Removed `load_plugin_textdomain()` and `Domain Path` header
+* Added automatic compatibility check for WP and PHP version (#17)
### 1.4.4 / 19.05.2018 ###
* Fix live filter chain when regular expressions are active (#12)
diff --git a/statify-blacklist.php b/statify-blacklist.php
index 3420de1..892a44b 100644
--- a/statify-blacklist.php
+++ b/statify-blacklist.php
@@ -38,18 +38,24 @@
define( 'STATIFYBLACKLIST_DIR', dirname( __FILE__ ) );
define( 'STATIFYBLACKLIST_BASE', plugin_basename( __FILE__ ) );
-// System Hooks.
-add_action( 'plugins_loaded', array( 'StatifyBlacklist', 'init' ) );
+// Check for compatibility.
+if ( statify_blacklist_compatibility_check() ) {
+ // System Hooks.
+ add_action( 'plugins_loaded', array( 'StatifyBlacklist', 'init' ) );
-register_activation_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'install' ) );
+ register_activation_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'install' ) );
-register_uninstall_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'uninstall' ) );
+ register_uninstall_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'uninstall' ) );
-// Upgrade hook.
-register_activation_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'upgrade' ) );
+ // Upgrade hook.
+ register_activation_hook( STATIFYBLACKLIST_FILE, array( 'StatifyBlacklist_System', 'upgrade' ) );
-// Autoload.
-spl_autoload_register( 'statify_blacklist_autoload' );
+ // Autoload.
+ spl_autoload_register( 'statify_blacklist_autoload' );
+} else {
+ // Disbale plugin, if active.
+ add_action( 'admin_init', 'statify_blacklist_disable' );
+}
/**
* Autoloader for StatifyBlacklist classes.
@@ -73,3 +79,53 @@ function statify_blacklist_autoload( $class ) {
);
}
}
+
+/**
+ * Check for compatibility with PHP and WP version.
+ *
+ * @since 1.5.0
+ *
+ * @return boolean Whether minimum WP and PHP versions are met.
+ */
+function statify_blacklist_compatibility_check() {
+ return version_compare( $GLOBALS['wp_version'], '4.7', '>=' ) &&
+ version_compare( phpversion(), '5.5', '>=' );
+}
+
+/**
+ * Disable plugin if active and incompatible.
+ *
+ * @return void
+ */
+function statify_blacklist_disable() {
+ if ( is_plugin_active( STATIFYBLACKLIST_BASE ) ) {
+ deactivate_plugins( STATIFYBLACKLIST_BASE );
+ add_action( 'admin_notices', 'statify_blacklist_disabled_notice' );
+ if ( isset( $_GET['activate'] ) ) {
+ unset( $_GET['activate'] );
+ }
+ }
+}
+
+/**
+ * Admin notification for unmet requirements.
+ *
+ * @return void
+ */
+function statify_blacklist_disabled_notice() {
+ echo '';
+ printf(
+ /* translators: minimum version numbers for WordPress and PHP inserted at placeholders */
+ esc_html__( 'Statify Blacklist requires at least WordPress %1$s and PHP %2$s.', 'my-plugin' ),
+ '4.7',
+ '5.5'
+ );
+ echo ' ';
+ printf(
+ /* translators: current version numbers for WordPress and PHP inserted at placeholders */
+ esc_html__( 'Your site is running WordPress %1$s on PHP %2$s, thus the plugin has been disabled.', 'my-plugin' ),
+ esc_html( $GLOBALS['wp_version'] ),
+ esc_html( phpversion() )
+ );
+ echo '
';
+}
From 74826384a8fd69fd8122cb07c6c88734548d23a2 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sat, 27 Oct 2018 18:34:23 +0200
Subject: [PATCH 08/42] Moved admin initialization to admin class
---
inc/class-statifyblacklist-admin.php | 31 ++++++++++++++++++++++++++++
inc/class-statifyblacklist.php | 21 +------------------
2 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/inc/class-statifyblacklist-admin.php b/inc/class-statifyblacklist-admin.php
index b391de3..319a462 100644
--- a/inc/class-statifyblacklist-admin.php
+++ b/inc/class-statifyblacklist-admin.php
@@ -18,6 +18,37 @@
* @since 1.0.0
*/
class StatifyBlacklist_Admin extends StatifyBlacklist {
+
+ /**
+ * Initialize admin-only components of the plugin.
+ *
+ * @since 1.5.0
+ *
+ * @return void
+ */
+ public static function init() {
+ // Add actions.
+ add_action( 'wpmu_new_blog', array( 'StatifyBlacklist_System', 'install_site' ) );
+ add_action( 'delete_blog', array( 'StatifyBlacklist_System', 'uninstall_site' ) );
+ add_filter( 'plugin_row_meta', array( 'StatifyBlacklist_Admin', 'plugin_meta_link' ), 10, 2 );
+
+ if ( self::$multisite ) {
+ add_action( 'network_admin_menu', array( 'StatifyBlacklist_Admin', 'add_menu_page' ) );
+ add_filter(
+ 'network_admin_plugin_action_links',
+ array(
+ 'StatifyBlacklist_Admin',
+ 'plugin_actions_links',
+ ),
+ 10,
+ 2
+ );
+ } else {
+ add_action( 'admin_menu', array( 'StatifyBlacklist_Admin', 'add_menu_page' ) );
+ add_filter( 'plugin_action_links', array( 'StatifyBlacklist_Admin', 'plugin_actions_links' ), 10, 2 );
+ }
+ }
+
/**
* Update options.
*
diff --git a/inc/class-statifyblacklist.php b/inc/class-statifyblacklist.php
index 428991d..d630e25 100644
--- a/inc/class-statifyblacklist.php
+++ b/inc/class-statifyblacklist.php
@@ -86,26 +86,7 @@ public static function init() {
// Admin only filters.
if ( is_admin() ) {
- // Add actions.
- add_action( 'wpmu_new_blog', array( 'StatifyBlacklist_System', 'install_site' ) );
- add_action( 'delete_blog', array( 'StatifyBlacklist_System', 'uninstall_site' ) );
- add_filter( 'plugin_row_meta', array( 'StatifyBlacklist_Admin', 'plugin_meta_link' ), 10, 2 );
-
- if ( self::$multisite ) {
- add_action( 'network_admin_menu', array( 'StatifyBlacklist_Admin', 'add_menu_page' ) );
- add_filter(
- 'network_admin_plugin_action_links',
- array(
- 'StatifyBlacklist_Admin',
- 'plugin_actions_links',
- ),
- 10,
- 2
- );
- } else {
- add_action( 'admin_menu', array( 'StatifyBlacklist_Admin', 'add_menu_page' ) );
- add_filter( 'plugin_action_links', array( 'StatifyBlacklist_Admin', 'plugin_actions_links' ), 10, 2 );
- }
+ StatifyBlacklist_Admin::init();
}
// CronJob to clean up database.
From 74f2e0f9a71ad68ac718070bb4dbcddc59af368c Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sat, 27 Oct 2018 18:41:09 +0200
Subject: [PATCH 09/42] Removed deprecated instance() and __construct() methods
from base class
---
inc/class-statifyblacklist-admin.php | 6 ++++--
inc/class-statifyblacklist-system.php | 13 ++++++++++--
inc/class-statifyblacklist.php | 29 +++++++--------------------
statify-blacklist.php | 12 ++++++++---
4 files changed, 31 insertions(+), 29 deletions(-)
diff --git a/inc/class-statifyblacklist-admin.php b/inc/class-statifyblacklist-admin.php
index 319a462..a148228 100644
--- a/inc/class-statifyblacklist-admin.php
+++ b/inc/class-statifyblacklist-admin.php
@@ -9,8 +9,10 @@
* @since 1.0.0
*/
-// Quit.
-defined( 'ABSPATH' ) || exit;
+// Quit if accessed directly.
+if ( ! defined( 'ABSPATH' ) ) {
+ exit;
+}
/**
* Statify Blacklist admin configuration.
diff --git a/inc/class-statifyblacklist-system.php b/inc/class-statifyblacklist-system.php
index 8d65df5..c136d29 100644
--- a/inc/class-statifyblacklist-system.php
+++ b/inc/class-statifyblacklist-system.php
@@ -9,8 +9,10 @@
* @since 1.0.0
*/
-// Quit.
-defined( 'ABSPATH' ) || exit;
+// Quit if accessed directly.
+if ( ! defined( 'ABSPATH' ) ) {
+ exit;
+}
/**
* Statify Blacklist system configuration.
@@ -25,6 +27,7 @@ class StatifyBlacklist_System extends StatifyBlacklist {
* @since 1.0.0
*
* @param bool $network_wide Whether the plugin was activated network-wide or not.
+ * @return void
*/
public static function install( $network_wide = false ) {
// Create tables for each site in a network.
@@ -59,6 +62,7 @@ public static function install( $network_wide = false ) {
* @since 1.4.3
*
* @param integer $site_id Site ID.
+ * @return void
*/
public static function install_site( $site_id ) {
switch_to_blog( (int) $site_id );
@@ -74,6 +78,8 @@ public static function install_site( $site_id ) {
* Plugin uninstall handler.
*
* @since 1.0.0
+ *
+ * @return void
*/
public static function uninstall() {
if ( is_multisite() ) {
@@ -109,6 +115,7 @@ public static function uninstall() {
* @since 1.4.3
*
* @param integer $site_id Site ID.
+ * @return void
*/
public static function uninstall_site( $site_id ) {
$old = get_current_blog_id();
@@ -121,6 +128,8 @@ public static function uninstall_site( $site_id ) {
* Upgrade plugin options.
*
* @since 1.2.0
+ *
+ * @return void
*/
public static function upgrade() {
self::update_options();
diff --git a/inc/class-statifyblacklist.php b/inc/class-statifyblacklist.php
index d630e25..faf8df3 100644
--- a/inc/class-statifyblacklist.php
+++ b/inc/class-statifyblacklist.php
@@ -8,8 +8,10 @@
* @since 1.0.0
*/
-// Quit.
-defined( 'ABSPATH' ) || exit;
+// Quit if accessed directly.
+if ( ! defined( 'ABSPATH' ) ) {
+ exit;
+}
/**
* Statify Blacklist.
@@ -42,30 +44,12 @@ class StatifyBlacklist {
*/
public static $multisite;
- /**
- * Class self initialize.
- *
- * @since 1.0.0
- * @deprecated 1.4.2 Replaced by init().
- */
- public static function instance() {
- self::init();
- }
-
- /**
- * Class constructor.
- *
- * @since 1.0.0
- * @deprecated 1.4.2 Replaced by init().
- */
- public function __construct() {
- self::init();
- }
-
/**
* Plugin initialization.
*
* @since 1.4.2
+ *
+ * @return void
*/
public static function init() {
// Skip on autosave or AJAX.
@@ -103,6 +87,7 @@ public static function init() {
* @since 1.2.1 update_options($options = null) Parameter with default value introduced.
*
* @param array $options Optional. New options to save.
+ * @return void
*/
public static function update_options( $options = null ) {
if ( self::$multisite ) {
diff --git a/statify-blacklist.php b/statify-blacklist.php
index 892a44b..429754a 100644
--- a/statify-blacklist.php
+++ b/statify-blacklist.php
@@ -10,7 +10,7 @@
* 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.4.4
+ * Version: 1.5.0-alpha
* Author: Stefan Kalscheuer (@stklcode)
* Author URI: https://www.stklcode.de
* Text Domain: statify-blacklist
@@ -30,8 +30,10 @@
* along with Statify Blacklist. If not, see http://www.gnu.org/licenses/gpl-2.0.html.
*/
-// Quit.
-defined( 'ABSPATH' ) || exit;
+// Quit if accessed directly.
+if ( ! defined( 'ABSPATH' ) ) {
+ exit;
+}
// Constants.
define( 'STATIFYBLACKLIST_FILE', __FILE__ );
@@ -95,6 +97,8 @@ function statify_blacklist_compatibility_check() {
/**
* Disable plugin if active and incompatible.
*
+ * @since 1.5.0
+ *
* @return void
*/
function statify_blacklist_disable() {
@@ -110,6 +114,8 @@ function statify_blacklist_disable() {
/**
* Admin notification for unmet requirements.
*
+ * @since 1.5.0
+ *
* @return void
*/
function statify_blacklist_disabled_notice() {
From 35b6d5592b75f4a8f16292ee6a88dbf81ce0efcb Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sat, 27 Oct 2018 19:05:09 +0200
Subject: [PATCH 10/42] Cleaned up labels and added PHPCS rule for settings
view
---
phpcs.xml | 3 +-
views/settings-page.php | 140 ++++++++++++++++++++--------------------
2 files changed, 73 insertions(+), 70 deletions(-)
diff --git a/phpcs.xml b/phpcs.xml
index ff901cc..b317a5b 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -6,8 +6,9 @@
- inc
statify-blacklist.php
+ inc
+ views
diff --git a/views/settings-page.php b/views/settings-page.php
index 2213995..e2a210b 100755
--- a/views/settings-page.php
+++ b/views/settings-page.php
@@ -19,7 +19,7 @@
// Check user capabilities.
if ( ! current_user_can( 'manage_options' ) ) {
- die( __( 'Are you sure you want to do this?' ) );
+ die( esc_html__( 'Are you sure you want to do this?' ) );
}
if ( ! empty( $_POST['cleanUp'] ) ) {
@@ -27,24 +27,27 @@
StatifyBlacklist_Admin::cleanup_database();
} else {
// Extract referer array.
- if ( empty( trim( $_POST['statifyblacklist']['referer']['blacklist'] ) ) ) {
+ $referer_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['referer']['blacklist'] ) );
+ if ( empty( trim( $referer_str ) ) ) {
$referer = array();
} else {
- $referer = explode( "\r\n", $_POST['statifyblacklist']['referer']['blacklist'] );
+ $referer = explode( "\r\n", $referer_str );
}
// Extract target array.
- if ( empty( trim( $_POST['statifyblacklist']['target']['blacklist'] ) ) ) {
+ $target_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['target']['blacklist'] ) );
+ if ( empty( trim( $target_str ) ) ) {
$target = array();
} else {
- $target = explode( "\r\n", str_replace( '\\\\', '\\', $_POST['statifyblacklist']['target']['blacklist'] ) );
+ $target = explode( "\r\n", str_replace( '\\\\', '\\', $target_str ) );
}
// Extract IP array.
- if ( empty( trim( $_POST['statifyblacklist']['ip']['blacklist'] ) ) ) {
+ $ip_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['ip']['blacklist'] ) );
+ if ( empty( trim( $ip_str ) ) ) {
$ip = array();
} else {
- $ip = explode( "\r\n", $_POST['statifyblacklist']['ip']['blacklist'] );
+ $ip = explode( "\r\n", $ip_str );
}
// Update options (data will be sanitized).
@@ -90,10 +93,17 @@
}
} // End if().
} // End if().
+
+/*
+ * Disable some code style rules that are impractical for textarea content:
+ *
+ * phpcs:disable Squiz.PHP.EmbeddedPhp.ContentBeforeOpen
+ * phpcs:disable Squiz.PHP.EmbeddedPhp.ContentAfterEnd
+ */
?>
-
+
';
@@ -103,7 +113,7 @@
if ( isset( $statifyblacklist_post_warning ) ) {
print '
' .
esc_html( $statifyblacklist_post_warning );
- print ' ';
+ print ' ';
esc_html_e( 'Settings have not been saved yet.', 'statify-blacklist' );
print '
';
}
@@ -120,26 +130,24 @@
/>
+ id="statify-blacklist_active_referer"
+ value="1" >
- />
+ >
- (
- )
-
+ ()
:
-
-
+
+
>
@@ -150,28 +158,22 @@
-
- (
- )
-
+ ()
- :
+ :
-
-
- (
- )
-
+ ?>
+
+ ()
@@ -182,26 +184,24 @@
/>
+ id="statify-blacklist_active_target"
+ value="1" >
- />
+ >
- (
- )
-
+ ()
:
-
-
+
+
>
@@ -212,29 +212,29 @@
-
- (
- )
-
+ ()
- :
+ :
-
-
- (
- )
-
+ ?>
+
+
+ (
+
+ )
+
@@ -244,8 +244,8 @@
@@ -279,14 +279,16 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
From 7e51c7d63eebfc901e6dc2dd1384457a14242c83 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sat, 27 Oct 2018 19:09:34 +0200
Subject: [PATCH 11/42] Add PHP 7.3 to CI matrix
---
.travis.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.travis.yml b/.travis.yml
index a1f594f..169a412 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,6 +6,7 @@ php:
- '7.0'
- '7.1'
- '7.2'
+ - '7.3'
before_script:
- composer install
script:
From f60c6ec2fffe0501c2c4da6e01eb33b8b9544a26 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Tue, 30 Oct 2018 19:32:52 +0100
Subject: [PATCH 12/42] Fixed textdomain for compatibility notice
---
statify-blacklist.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/statify-blacklist.php b/statify-blacklist.php
index 429754a..02a5c39 100644
--- a/statify-blacklist.php
+++ b/statify-blacklist.php
@@ -122,14 +122,14 @@ function statify_blacklist_disabled_notice() {
echo '';
printf(
/* translators: minimum version numbers for WordPress and PHP inserted at placeholders */
- esc_html__( 'Statify Blacklist requires at least WordPress %1$s and PHP %2$s.', 'my-plugin' ),
+ esc_html__( 'Statify Blacklist requires at least WordPress %1$s and PHP %2$s.', 'statify-blacklist' ),
'4.7',
'5.5'
);
echo ' ';
printf(
/* translators: current version numbers for WordPress and PHP inserted at placeholders */
- esc_html__( 'Your site is running WordPress %1$s on PHP %2$s, thus the plugin has been disabled.', 'my-plugin' ),
+ esc_html__( 'Your site is running WordPress %1$s on PHP %2$s, thus the plugin has been disabled.', 'statify-blacklist' ),
esc_html( $GLOBALS['wp_version'] ),
esc_html( phpversion() )
);
From 36a65482e26c4c24d9565f271fef33fc15454103 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Thu, 1 Nov 2018 20:28:55 +0100
Subject: [PATCH 13/42] Add badges to ReadMe [skip ci]
---
README.md | 5 +++++
RoboFile.php | 8 +++++++-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 3479cab..4b72d1b 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,8 @@
+[![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/pluginkollektiv/statify)
+[![License](https://img.shields.io/badge/license-GPL%20v2-blue.svg)](https://github.com/stklcode/statify-blacklist/blob/master/LICENSE.txt)
+
# Statify Blacklist #
* Contributors: Stefan Kalscheuer
* Requires at least: 4.7
diff --git a/RoboFile.php b/RoboFile.php
index e991634..b08f75b 100644
--- a/RoboFile.php
+++ b/RoboFile.php
@@ -139,8 +139,14 @@ private function bundle() {
'views' => $this->target_dir . '/' . $this->final_name . '/views',
] )->run();
$this->_copy( 'statify-blacklist.php', $this->target_dir . '/' . $this->final_name . '/statify-blacklist.php' );
- $this->_copy( 'README.md', $this->target_dir . '/' . $this->final_name . '/README.md' );
$this->_copy( 'LICENSE.md', $this->target_dir . '/' . $this->final_name . '/LICENSE.md' );
+ $this->_copy( 'README.md', $this->target_dir . '/' . $this->final_name . '/README.md' );
+
+ // Remove content before title (e.g. badges) from README file.
+ $this->taskReplaceInFile( $this->target_dir . '/' . $this->final_name . '/README.md' )
+ ->regex( '/^[^\\#]*/' )
+ ->to( '' )
+ ->run();
}
/**
From abcaab7a33f89bf15d53f0bb0eb89830105b06a9 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Thu, 1 Nov 2018 21:58:06 +0100
Subject: [PATCH 14/42] Fixed ReadMe badge links [skip ci]
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 4b72d1b..c591dd1 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
[![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/pluginkollektiv/statify)
-[![License](https://img.shields.io/badge/license-GPL%20v2-blue.svg)](https://github.com/stklcode/statify-blacklist/blob/master/LICENSE.txt)
+[![Packagist Version](https://img.shields.io/packagist/v/stklcode/statify-blacklist.svg)](https://packagist.org/packages/stklcode/statify-blacklist)
+[![License](https://img.shields.io/badge/license-GPL%20v2-blue.svg)](https://github.com/stklcode/statify-blacklist/blob/master/LICENSE.md)
# Statify Blacklist #
* Contributors: Stefan Kalscheuer
From 4ce3a8f336780fd9d10b08c6797f7496a8ff5547 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Fri, 2 Nov 2018 16:05:15 +0100
Subject: [PATCH 15/42] Add Slack notification to Travis
---
.travis.yml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.travis.yml b/.travis.yml
index 169a412..b6c3e11 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,3 +11,6 @@ before_script:
- composer install
script:
- composer test-all
+notifications:
+ slack:
+ secure: "ScXTSMO65veI1jA6TBHGDUtvDqEMkqJykaNf7vLLbb7YIxPIHHNBiX/wcjOHVFfQXZCV3qxQrflB7Lbm9qVUsAv861jTO9x/ZkECl5QhRoc0DIznejwZoypx0HJ9tBZFYT6qNUkViXRKZ/ILAiBLU9Yw52WACtQB9hu3FNFZwmKsjipvV8Sne1qEyTkLYLaMphsbC5mtXYdKMHvdt39jsYsk91UWGeYbXQ37LkMbsaG/8YHXF724d5JO7BRGoThw6p5knKAO5fk29V7GfNqg2h+hnGyNIUOcmxujgMDMFLyFCGMZpPoBa+3jyWWgq4PgpQt0F5VZtJFGoXCGcoMQm5IbVfqkSKJ4jYhqiSIrqSebLmzoPHepWX3yn8tpfOiBWjC6K9w9esp6vcZf26rnAJcjcGkA01rMrHRwR+UEMCLvj7q0DR0qzi/AFeED6gtpODzUf93Rp42Tz1iGvWIbgeCtkCWjfPO6XLuNiqGVPEVaT5BDKqlqbijdKxxp7yh1fdt8s0fInWdIsgoWTbU9DC1W4ZiqtQW7oYO+QtFZMaD6kZWpSqJUwB3kW5JL3odAUEm8bLbRWBvK5ZjGdaGqSbOs6f9gAKcf86iQQhwzCJSOgFlLlKFv9smicjPC+BGOxgx32pgseHNPWn6tmEo/ihmmr/NbbqoOusUKX9gQbA4="
From c511dcb517aa61399e5868949d90c593f4641432 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Wed, 6 Mar 2019 15:06:47 +0100
Subject: [PATCH 16/42] rework settings page
The settings page now features the 2 column layout like generated by WP
settings API. The regular expression selects are slightly rewritten in
preparation of additional mathing methods.
---
views/settings-page.php | 313 +++++++++++++++++++++++-----------------
1 file changed, 181 insertions(+), 132 deletions(-)
diff --git a/views/settings-page.php b/views/settings-page.php
index e2a210b..27c0d93 100755
--- a/views/settings-page.php
+++ b/views/settings-page.php
@@ -124,159 +124,208 @@
}
?>
From b691f2c618ed86993c071918691b07e0f2879e14 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Wed, 6 Mar 2019 17:23:06 +0100
Subject: [PATCH 17/42] adjust sanitization of settings and warning messages
---
inc/class-statifyblacklist-admin.php | 57 ++++++++++++-----
views/settings-page.php | 95 ++++++++++++++++++----------
2 files changed, 105 insertions(+), 47 deletions(-)
diff --git a/inc/class-statifyblacklist-admin.php b/inc/class-statifyblacklist-admin.php
index a148228..5fe6832 100644
--- a/inc/class-statifyblacklist-admin.php
+++ b/inc/class-statifyblacklist-admin.php
@@ -20,6 +20,9 @@
* @since 1.0.0
*/
class StatifyBlacklist_Admin extends StatifyBlacklist {
+ const MODE_NORMAL = 0;
+ const MODE_REGEX = 1;
+ const MODE_REGEX_CI = 2;
/**
* Initialize admin-only components of the plugin.
@@ -61,27 +64,51 @@ public static function init() {
*/
public static function update_options( $options = null ) {
if ( isset( $options ) && current_user_can( 'manage_options' ) ) {
- // Sanitize URLs and remove empty inputs.
+
+ // Sanitize referer list.
$given_referer = $options['referer']['blacklist'];
- if ( 0 === $options['referer']['regexp'] ) {
+ if ( self::MODE_NORMAL === $options['referer']['regexp'] ) {
+ // Sanitize URLs and remove empty inputs.
$sanitized_referer = self::sanitizeURLs( $given_referer );
+ } elseif ( self::MODE_REGEX === $options['referer']['regexp'] || self::MODE_REGEX_CI === $options['referer']['regexp'] ) {
+ // TODO Check regular expressions.
+ $sanitized_referer = $given_referer;
} else {
$sanitized_referer = $given_referer;
}
- // Sanitize IPs and Subnets and remove empty inputs.
+ // Sanitize target list.
+ $given_target = $options['target']['blacklist'];
+ if ( self::MODE_REGEX === $options['target']['regexp'] || self::MODE_REGEX_CI === $options['target']['regexp'] ) {
+ // TODO Check regular expressions.
+ $sanitized_target = $given_target;
+ } else {
+ $sanitized_target = $given_target;
+ }
+
+ // Sanitize IPs and subnets and remove empty inputs.
$given_ip = $options['ip']['blacklist'];
$sanitized_ip = self::sanitizeIPs( $given_ip );
// Abort on errors.
- if ( ! empty( array_diff( array_keys( $given_referer ), array_keys( $sanitized_referer ) ) ) ) {
- return array(
- 'referer' => $sanitized_referer,
- );
- } elseif ( ! empty( array_diff( $given_ip, $sanitized_ip ) ) ) {
- return array(
- 'ip' => array_diff( $given_ip, $sanitized_ip ),
- );
+ $errors = [
+ 'referer' => [
+ 'sanitized' => $sanitized_referer,
+ 'diff' => array_diff( $given_referer, $sanitized_referer ),
+ ],
+ 'target' => [
+ 'sanitized' => $sanitized_target,
+ 'diff' => array_diff( $given_target, $sanitized_target ),
+ ],
+ 'ip' => [
+ 'sanitized' => $sanitized_ip,
+ 'diff' => array_diff( $given_ip, $sanitized_ip ),
+ ],
+ ];
+ if ( ! empty( $errors['referer']['diff'] )
+ || ! empty( $errors['target']['diff'] )
+ || ! empty( $errors['ip']['diff'] ) ) {
+ return $errors;
}
// Update database on success.
@@ -300,10 +327,10 @@ function ( $ip ) {
'/^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])(\/([0-9]|[1-2][0-9]|3[0-2]))?$/',
$ip
) ||
- preg_match(
- '/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$/',
- $ip
- );
+ preg_match(
+ '/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$/',
+ $ip
+ );
}
);
}
diff --git a/views/settings-page.php b/views/settings-page.php
index 27c0d93..42dcdb4 100755
--- a/views/settings-page.php
+++ b/views/settings-page.php
@@ -29,31 +29,61 @@
// Extract referer array.
$referer_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['referer']['blacklist'] ) );
if ( empty( trim( $referer_str ) ) ) {
- $referer = array();
+ $referer = [];
} else {
- $referer = explode( "\r\n", $referer_str );
+ $referer = array_filter(
+ array_map(
+ function ( $a ) {
+ return trim( $a );
+ },
+ explode( "\r\n", $referer_str )
+ ),
+ function ( $a ) {
+ return ! empty( $a );
+ }
+ );
}
// Extract target array.
$target_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['target']['blacklist'] ) );
if ( empty( trim( $target_str ) ) ) {
- $target = array();
+ $target = [];
} else {
- $target = explode( "\r\n", str_replace( '\\\\', '\\', $target_str ) );
+ $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.
$ip_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['ip']['blacklist'] ) );
if ( empty( trim( $ip_str ) ) ) {
- $ip = array();
+ $ip = [];
} else {
- $ip = explode( "\r\n", $ip_str );
+ $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(
+ [
+ 'referer' => [
'active' => isset( $_POST['statifyblacklist']['referer']['active'] )
? (int) $_POST['statifyblacklist']['referer']['active'] : 0,
'cron' => isset( $_POST['statifyblacklist']['referer']['cron'] )
@@ -61,8 +91,8 @@
'regexp' => isset( $_POST['statifyblacklist']['referer']['regexp'] )
? (int) $_POST['statifyblacklist']['referer']['regexp'] : 0,
'blacklist' => array_flip( $referer ),
- ),
- 'target' => array(
+ ],
+ 'target' => [
'active' => isset( $_POST['statifyblacklist']['target']['active'] )
? (int) $_POST['statifyblacklist']['target']['active'] : 0,
'cron' => isset( $_POST['statifyblacklist']['target']['cron'] )
@@ -70,23 +100,25 @@
'regexp' => isset( $_POST['statifyblacklist']['target']['regexp'] )
? (int) $_POST['statifyblacklist']['target']['regexp'] : 0,
'blacklist' => array_flip( $target ),
- ),
- 'ip' => array(
+ ],
+ 'ip' => [
'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 ) {
- if ( array_key_exists( 'referer', $statifyblacklist_update_result ) ) {
- $statifyblacklist_post_warning = __( 'Some URLs are invalid and have been sanitized.', 'statify-blacklist' );
- } elseif ( array_key_exists( 'ip', $statifyblacklist_update_result ) ) {
+ $statifyblacklist_post_warning = [];
+ 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['ip']['diff'] ) ) {
// translators: List of invalid IP addresses (comma separated).
- $statifyblacklist_post_warning = sprintf( __( 'Some IPs are invalid : %s', 'statify-blacklist' ), implode( ', ', $statifyblacklist_update_result['ip'] ) );
+ $statifyblacklist_post_warning[] = sprintf( __( 'Some IPs are invalid: %s', 'statify-blacklist' ), implode( ', ', $statifyblacklist_update_result['ip']['diff'] ) );
}
} else {
$statifyblacklist_post_success = __( 'Settings updated successfully.', 'statify-blacklist' );
@@ -111,11 +143,10 @@
print '
';
}
if ( isset( $statifyblacklist_post_warning ) ) {
- print '' .
- esc_html( $statifyblacklist_post_warning );
- print ' ';
- esc_html_e( 'Settings have not been saved yet.', 'statify-blacklist' );
- print '
';
+ foreach ( $statifyblacklist_post_warning as $w ) {
+ print '';
+ }
+ print '' . esc_html( 'Settings have not been saved yet.', 'statify-blacklist' ) . '
';
}
if ( isset( $statifyblacklist_post_success ) ) {
print '' .
@@ -187,10 +218,10 @@
@@ -270,10 +301,10 @@
@@ -311,10 +342,10 @@
From 2eb08ce673590d4154cb61a8557d6c0915f28d2d Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Tue, 12 Mar 2019 17:32:32 +0100
Subject: [PATCH 18/42] update dev dependencies
---
composer.json | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/composer.json b/composer.json
index 36727f2..6477aec 100644
--- a/composer.json
+++ b/composer.json
@@ -23,13 +23,13 @@
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.4",
- "consolidation/robo": "^1.3",
+ "consolidation/robo": "^1.4",
"phpunit/phpunit": "*",
"phpunit/php-code-coverage": "*",
- "slowprog/composer-copy-file": "~0.2",
- "squizlabs/php_codesniffer": "^3.3",
- "wimg/php-compatibility": "^9.0",
- "wp-coding-standards/wpcs": "^1.1"
+ "slowprog/composer-copy-file": "~0.3",
+ "squizlabs/php_codesniffer": "^3.4",
+ "phpcompatibility/php-compatibility": "^9.1",
+ "wp-coding-standards/wpcs": "^2.0"
},
"scripts": {
"build": [
From 0822537f0ed4adb17e8747b6b5a9fce979be8e46 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Tue, 12 Mar 2019 17:57:26 +0100
Subject: [PATCH 19/42] adjustments for PHPUnit 8
Added result cache to .gitignore and replaced assertInternalType() by
assertIsArray() with backwords compatibility for PHP 5 builds.
---
.gitignore | 3 ++-
phpunit.xml | 2 +-
test/statifyblacklist-test.php | 16 ++++++++++++++--
3 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/.gitignore b/.gitignore
index 29ba421..283f98c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,5 @@ composer.lock
/dist/
.idea
tests-clover.xml
-tests-junit.xml
\ No newline at end of file
+tests-junit.xml
+.phpunit.result.cache
diff --git a/phpunit.xml b/phpunit.xml
index 4ea43f9..f6cdc73 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -12,6 +12,6 @@
-
+
diff --git a/test/statifyblacklist-test.php b/test/statifyblacklist-test.php
index bd4d062..29a7b43 100644
--- a/test/statifyblacklist-test.php
+++ b/test/statifyblacklist-test.php
@@ -320,7 +320,15 @@ public function test_sanitize_ips() {
$invalid = array( '12.34.56.789', '192.0.2.123/33', '192.0.2.123/-1' );
$result = invoke_static( StatifyBlacklist_Admin::class, 'sanitizeIPs', array( array_merge( $valid, $invalid ) ) );
$this->assertNotFalse( $result );
- $this->assertInternalType( 'array', $result );
+ /*
+ * Unfortunately this is nencessary 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.
@@ -339,7 +347,11 @@ public function test_sanitize_ips() {
);
$result = invoke_static( StatifyBlacklist_Admin::class, 'sanitizeIPs', array( array_merge( $valid, $invalid ) ) );
$this->assertNotFalse( $result );
- $this->assertInternalType( 'array', $result );
+ if ( method_exists( $this, 'assertIsArray' ) ) {
+ $this->assertIsArray( $result );
+ } else {
+ $this->assertInternalType( 'array', $result );
+ }
$this->assertEquals( $valid, $result );
}
From b7c3b5187326b70292081d6411b275c28406d47c Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Tue, 12 Mar 2019 19:37:22 +0100
Subject: [PATCH 20/42] implement keyword filter for referer blacklist (closes
#15)
In addition to the pre-existing normal and regular expression filters a
keyword mode is added. This filter matches if the referer string
contains a given keyword (case insensitive).
---
README.md | 2 +
inc/class-statifyblacklist-admin.php | 24 +++++-
inc/class-statifyblacklist.php | 105 ++++++++++++++++++++-------
test/statifyblacklist-test.php | 71 +++++++++++++++---
views/settings-page.php | 19 +++--
5 files changed, 174 insertions(+), 47 deletions(-)
diff --git a/README.md b/README.md
index b913aee..3dc84e4 100644
--- a/README.md
+++ b/README.md
@@ -91,6 +91,8 @@ Because of this, an IP blacklist can only be applied while processing the reques
* Minimum required WordPress version is 4.7
* Removed `load_plugin_textdomain()` and `Domain Path` header
* Added automatic compatibility check for WP and PHP version (#17)
+* Added keyword filter mode for referer blacklist (#15)
+* Layout adjustments on settings page
### 1.4.4 / 19.05.2018 ###
* Fix live filter chain when regular expressions are active (#12)
diff --git a/inc/class-statifyblacklist-admin.php b/inc/class-statifyblacklist-admin.php
index 5fe6832..35f78d8 100644
--- a/inc/class-statifyblacklist-admin.php
+++ b/inc/class-statifyblacklist-admin.php
@@ -20,9 +20,6 @@
* @since 1.0.0
*/
class StatifyBlacklist_Admin extends StatifyBlacklist {
- const MODE_NORMAL = 0;
- const MODE_REGEX = 1;
- const MODE_REGEX_CI = 2;
/**
* Initialize admin-only components of the plugin.
@@ -96,7 +93,7 @@ public static function update_options( $options = null ) {
'sanitized' => $sanitized_referer,
'diff' => array_diff( $given_referer, $sanitized_referer ),
],
- 'target' => [
+ 'target' => [
'sanitized' => $sanitized_target,
'diff' => array_diff( $given_target, $sanitized_target ),
],
@@ -334,4 +331,23 @@ function ( $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(
+ $expressions,
+ function ( $re ) {
+ // Check of preg_match() fails (warnings suppressed).
+ return false === @preg_match( $re, null );
+ }
+ );
+ }
}
diff --git a/inc/class-statifyblacklist.php b/inc/class-statifyblacklist.php
index faf8df3..59b071e 100644
--- a/inc/class-statifyblacklist.php
+++ b/inc/class-statifyblacklist.php
@@ -28,6 +28,35 @@ class StatifyBlacklist {
*/
const VERSION_MAIN = 1.4;
+ /**
+ * Operation mode "normal".
+ *
+ * @var integer MODE_NORMAL
+ */
+ const MODE_NORMAL = 0;
+
+ /**
+ * Operation mode "regular expression".
+ *
+ * @var integer MODE_REGEX
+ */
+ const MODE_REGEX = 1;
+
+ /**
+ * Operation mode "regular expression case insensitive".
+ *
+ * @var integer MODE_REGEX_CI
+ */
+ const MODE_REGEX_CI = 2;
+
+ /**
+ * Operation mode "keyword".
+ *
+ * @since 1.5.0
+ * @var integer MODE_KEYWORD
+ */
+ const MODE_KEYWORD = 3;
+
/**
* Plugin options.
*
@@ -137,35 +166,57 @@ protected static function default_options() {
public static function apply_blacklist_filter() {
// Referer blacklist.
if ( isset( self::$_options['referer']['active'] ) && 0 !== self::$_options['referer']['active'] ) {
- // Regular Expression filtering since 1.3.0.
- if ( isset( self::$_options['referer']['regexp'] ) && self::$_options['referer']['regexp'] > 0 ) {
- // Get full referer string.
- $referer = wp_get_raw_referer();
- if ( ! $referer ) {
- $referer = '';
- }
- // Merge given regular expressions into one.
- $regexp = '/' . implode( '|', array_keys( self::$_options['referer']['blacklist'] ) ) . '/';
- if ( 2 === self::$_options['referer']['regexp'] ) {
- $regexp .= 'i';
- }
+ // Determine filter mode.
+ $mode = isset( self::$_options['referer']['regexp'] ) ? intval( self::$_options['referer']['regexp'] ) : 0;
- // Check blacklist (no return to continue filtering #12).
- if ( 1 === preg_match( $regexp, $referer ) ) {
- return true;
- }
- } else {
- // Extract relevant domain parts.
- $referer = wp_parse_url( wp_get_raw_referer() );
- $referer = strtolower( ( isset( $referer['host'] ) ? $referer['host'] : '' ) );
+ // Get full referer string.
+ $referer = wp_get_raw_referer();
+ if ( ! $referer ) {
+ $referer = '';
+ }
- // Get blacklist.
- $blacklist = self::$_options['referer']['blacklist'];
+ switch ( $mode ) {
- // Check blacklist.
- if ( isset( $blacklist[ $referer ] ) ) {
- return true;
- }
+ // Regular Expression filtering since 1.3.0.
+ case self::MODE_REGEX:
+ case self::MODE_REGEX_CI:
+ // Merge given regular expressions into one.
+ $regexp = '/' . implode( '|', array_keys( self::$_options['referer']['blacklist'] ) ) . '/';
+ if ( self::MODE_REGEX_CI === self::$_options['referer']['regexp'] ) {
+ $regexp .= 'i';
+ }
+
+ // 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;
+ }
}
}
@@ -324,6 +375,6 @@ private static function cidr_match( $ip, $net ) {
}
return ( 0 === substr_compare( sprintf( '%032b', ip2long( $ip ) ), sprintf( '%032b', ip2long( $base ) ), 0, $mask ) );
- } // End if().
+ }
}
}
diff --git a/test/statifyblacklist-test.php b/test/statifyblacklist-test.php
index 29a7b43..e91d378 100644
--- a/test/statifyblacklist-test.php
+++ b/test/statifyblacklist-test.php
@@ -151,7 +151,7 @@ public function test_referer_regex_filter() {
// Matching both.
$_SERVER['HTTP_REFERER'] = 'http://example.net/test/me';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
- // Mathinc with wrong case.
+ // Matching with wrong case.
$_SERVER['HTTP_REFERER'] = 'http://eXaMpLe.NeT/tEsT/mE';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
@@ -160,6 +160,59 @@ public function test_referer_regex_filter() {
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
}
+ /**
+ * Test referer filter using keywords.
+ *
+ * @return void
+ */
+ public function test_referer_keyword_filter() {
+ // Prepare Options: 2 regular expressions.
+ StatifyBlacklist::$_options = array(
+ 'referer' => array(
+ 'active' => 1,
+ 'cron' => 0,
+ 'regexp' => StatifyBlacklist::MODE_KEYWORD,
+ 'blacklist' => array(
+ 'example' => 0,
+ 'test' => 1,
+ ),
+ ),
+ 'target' => array(
+ 'active' => 0,
+ 'cron' => 0,
+ 'regexp' => StatifyBlacklist::MODE_NORMAL,
+ 'blacklist' => array(),
+ ),
+ 'ip' => array(
+ 'active' => 0,
+ 'blacklist' => array(),
+ ),
+ 'version' => StatifyBlacklist::VERSION_MAIN,
+ );
+
+ // No multisite.
+ StatifyBlacklist::$multisite = false;
+
+ // No referer.
+ unset( $_SERVER['HTTP_REFERER'] );
+ $this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
+ // Non-blacklisted referer.
+ $_SERVER['HTTP_REFERER'] = 'http://not.evil';
+ $this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
+ // Blacklisted referer.
+ $_SERVER['HTTP_REFERER'] = 'http://example.com';
+ $this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
+ // Blacklisted referer with path.
+ $_SERVER['HTTP_REFERER'] = 'http://foobar.net/test/me';
+ $this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
+ // Matching both.
+ $_SERVER['HTTP_REFERER'] = 'http://example.net/test/me';
+ $this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
+ // Matching with wrong case.
+ $_SERVER['HTTP_REFERER'] = 'http://eXaMpLe.NeT/tEsT/mE';
+ $this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
+ }
+
/**
* Test the upgrade methodology for configuration options.
*
@@ -366,13 +419,13 @@ public function test_ip_filter() {
'referer' => array(
'active' => 0,
'cron' => 0,
- 'regexp' => 0,
+ 'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'target' => array(
'active' => 0,
'cron' => 0,
- 'regexp' => 0,
+ 'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'ip' => array(
@@ -438,13 +491,13 @@ public function test_target_filter() {
'referer' => array(
'active' => 0,
'cron' => 0,
- 'regexp' => 0,
+ 'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(),
),
'target' => array(
'active' => 0,
'cron' => 0,
- 'regexp' => 0,
+ 'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(
'/excluded/page/' => 0,
'/?page_id=3' => 1,
@@ -513,7 +566,7 @@ public function test_combined_filters() {
'referer' => array(
'active' => 1,
'cron' => 0,
- 'regexp' => 0,
+ 'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(
'example.com' => 0,
),
@@ -521,7 +574,7 @@ public function test_combined_filters() {
'target' => array(
'active' => 1,
'cron' => 0,
- 'regexp' => 0,
+ 'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(
'/excluded/page/' => 0
),
@@ -561,9 +614,9 @@ public function test_combined_filters() {
$_SERVER['REMOTE_ADDR'] = '192.0.2.234';
// Same for RegExp filters.
- StatifyBlacklist::$_options['referer']['regexp'] = 1;
+ StatifyBlacklist::$_options['referer']['regexp'] = StatifyBlacklist::MODE_REGEX;
StatifyBlacklist::$_options['referer']['blacklist'] = array( 'example\.com' => 0 );
- StatifyBlacklist::$_options['target']['regexp'] = 1;
+ StatifyBlacklist::$_options['target']['regexp'] = StatifyBlacklist::MODE_REGEX;
StatifyBlacklist::$_options['target']['blacklist'] = array( '\/excluded\/.*' => 0 );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
diff --git a/views/settings-page.php b/views/settings-page.php
index 42dcdb4..b4a69bb 100755
--- a/views/settings-page.php
+++ b/views/settings-page.php
@@ -194,13 +194,16 @@ function ( $a ) {
- >
+ >
- >
+ >
+
+
+ >
- >
+ >
@@ -208,6 +211,8 @@ function ( $a ) {
-
+ -
+
-
@@ -272,14 +277,14 @@ function ( $a ) {
-
- >
+
+ >
- >
+ >
- >
+ >
From 124b4ecb752c18fc1333c07e57a930332efb1454 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Tue, 12 Mar 2019 19:39:40 +0100
Subject: [PATCH 21/42] dependency corrections for PHP 5.5
composer-copy-file 0.3 requires PHP 5.6, so reverted back to ~0.2
---
composer.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/composer.json b/composer.json
index 6477aec..8b32fc6 100644
--- a/composer.json
+++ b/composer.json
@@ -26,7 +26,7 @@
"consolidation/robo": "^1.4",
"phpunit/phpunit": "*",
"phpunit/php-code-coverage": "*",
- "slowprog/composer-copy-file": "~0.3",
+ "slowprog/composer-copy-file": "~0.2",
"squizlabs/php_codesniffer": "^3.4",
"phpcompatibility/php-compatibility": "^9.1",
"wp-coding-standards/wpcs": "^2.0"
From 84ce89b1278c0f153e3a5d61df8ffc172b9a32b9 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sun, 17 Mar 2019 16:46:59 +0100
Subject: [PATCH 22/42] Add .gitattributes
Set development files, tests and assets to export ignore list to clean
up the package distributed via Composer/Packagist.
---
.gitattributes | 12 ++++++++++++
1 file changed, 12 insertions(+)
create mode 100644 .gitattributes
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..c323621
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,12 @@
+/assets export-ignore
+/test export-ignore
+.gitattributes export-ignore
+.gitignore export-ignore
+.travis.yml export-ignore
+composer.json export-ignore
+composer.lock export-ignore
+CONTRIBUTING.md export-ignore
+package.json export-ignore
+phpcs.xml export-ignore
+phpunit.xml export-ignore
+RoboFile.php export-ignore
From 39dcce3eeb0ea9ac39206bc407f5ce67fac6010a Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sun, 17 Mar 2019 16:50:50 +0100
Subject: [PATCH 23/42] Harmonize helper funcitons to snake_case
---
inc/class-statifyblacklist-admin.php | 10 +++++-----
test/statifyblacklist-test.php | 4 ++--
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/inc/class-statifyblacklist-admin.php b/inc/class-statifyblacklist-admin.php
index 35f78d8..1920157 100644
--- a/inc/class-statifyblacklist-admin.php
+++ b/inc/class-statifyblacklist-admin.php
@@ -66,7 +66,7 @@ public static function update_options( $options = null ) {
$given_referer = $options['referer']['blacklist'];
if ( self::MODE_NORMAL === $options['referer']['regexp'] ) {
// Sanitize URLs and remove empty inputs.
- $sanitized_referer = self::sanitizeURLs( $given_referer );
+ $sanitized_referer = self::sanitize_urls( $given_referer );
} elseif ( self::MODE_REGEX === $options['referer']['regexp'] || self::MODE_REGEX_CI === $options['referer']['regexp'] ) {
// TODO Check regular expressions.
$sanitized_referer = $given_referer;
@@ -85,7 +85,7 @@ public static function update_options( $options = null ) {
// Sanitize IPs and subnets and remove empty inputs.
$given_ip = $options['ip']['blacklist'];
- $sanitized_ip = self::sanitizeIPs( $given_ip );
+ $sanitized_ip = self::sanitize_ips( $given_ip );
// Abort on errors.
$errors = [
@@ -234,7 +234,7 @@ public static function cleanup_database() {
$referer_regexp = implode( '|', array_keys( self::$_options['referer']['blacklist'] ) );
} else {
// Sanitize URLs.
- $referer = self::sanitizeURLs( self::$_options['referer']['blacklist'] );
+ $referer = self::sanitize_urls( self::$_options['referer']['blacklist'] );
// Build filter regexp.
$referer_regexp = str_replace( '.', '\.', implode( '|', array_flip( $referer ) ) );
@@ -294,7 +294,7 @@ public static function cleanup_database() {
*
* @return array sanitized array.
*/
- private static function sanitizeURLs( $urls ) {
+ private static function sanitize_urls( $urls ) {
return array_flip(
array_filter(
array_map(
@@ -316,7 +316,7 @@ function ( $r ) {
*
* @return array sanitized array.
*/
- private static function sanitizeIPs( $ips ) {
+ private static function sanitize_ips( $ips ) {
return array_filter(
$ips,
function ( $ip ) {
diff --git a/test/statifyblacklist-test.php b/test/statifyblacklist-test.php
index e91d378..b741062 100644
--- a/test/statifyblacklist-test.php
+++ b/test/statifyblacklist-test.php
@@ -371,7 +371,7 @@ 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, 'sanitizeIPs', array( array_merge( $valid, $invalid ) ) );
+ $result = invoke_static( StatifyBlacklist_Admin::class, 'sanitize_ips', array( array_merge( $valid, $invalid ) ) );
$this->assertNotFalse( $result );
/*
* Unfortunately this is nencessary as long as we run PHP 5 tests, because "assertInternalType" is deprecated
@@ -398,7 +398,7 @@ public function test_sanitize_ips() {
'2001:db8:a0b:12f0::/129',
'1:2:3:4:5:6:7:8:9',
);
- $result = invoke_static( StatifyBlacklist_Admin::class, 'sanitizeIPs', array( array_merge( $valid, $invalid ) ) );
+ $result = invoke_static( StatifyBlacklist_Admin::class, 'sanitize_ips', array( array_merge( $valid, $invalid ) ) );
$this->assertNotFalse( $result );
if ( method_exists( $this, 'assertIsArray' ) ) {
$this->assertIsArray( $result );
From 1c69ba31bb43e26811934b1da83b1413cd53028e Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sun, 17 Mar 2019 17:27:33 +0100
Subject: [PATCH 24/42] Preprocessing of regular expression in separate
funciton
---
inc/class-statifyblacklist.php | 48 ++++++++++++++++++++++++++++------
test/statifyblacklist-test.php | 7 ++++-
2 files changed, 46 insertions(+), 9 deletions(-)
diff --git a/inc/class-statifyblacklist.php b/inc/class-statifyblacklist.php
index 59b071e..7bbe94c 100644
--- a/inc/class-statifyblacklist.php
+++ b/inc/class-statifyblacklist.php
@@ -116,6 +116,7 @@ public static function init() {
* @since 1.2.1 update_options($options = null) Parameter with default value introduced.
*
* @param array $options Optional. New options to save.
+ *
* @return void
*/
public static function update_options( $options = null ) {
@@ -181,10 +182,10 @@ public static function apply_blacklist_filter() {
case self::MODE_REGEX:
case self::MODE_REGEX_CI:
// Merge given regular expressions into one.
- $regexp = '/' . implode( '|', array_keys( self::$_options['referer']['blacklist'] ) ) . '/';
- if ( self::MODE_REGEX_CI === self::$_options['referer']['regexp'] ) {
- $regexp .= 'i';
- }
+ $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 ) ) {
@@ -229,10 +230,10 @@ public static function apply_blacklist_filter() {
$target = ( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '/' );
// @codingStandardsIgnoreEnd
// Merge given regular expressions into one.
- $regexp = '/' . implode( '|', array_keys( self::$_options['target']['blacklist'] ) ) . '/';
- if ( 2 === self::$_options['target']['regexp'] ) {
- $regexp .= 'i';
- }
+ $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 ) ) {
@@ -268,6 +269,37 @@ public static function apply_blacklist_filter() {
return null;
}
+ /**
+ * Preprocess regular expression provided by the user, i.e. add delimiters and optional ci flag.
+ *
+ * @param string|array $expression Original expression string or array of expressions.
+ * @param string|array $case_insensitive Make expression match case-insensitive.
+ *
+ * @return string Preprocessed expression ready for preg_match().
+ */
+ protected static function regex( $expression, $case_insensitive ) {
+ $res = '/';
+ if ( is_string( $expression ) ) {
+ $res .= str_replace( '/', '\/', $expression );
+ } elseif ( is_array( $expression ) ) {
+ $res .= implode(
+ '|',
+ array_map(
+ function ( $e ) {
+ return str_replace( '/', '\/', $e );
+ },
+ $expression
+ )
+ );
+ }
+ $res .= '/';
+ if ( $case_insensitive ) {
+ $res .= 'i';
+ }
+
+ return $res;
+ }
+
/**
* Helper method to determine the client's IP address.
*
diff --git a/test/statifyblacklist-test.php b/test/statifyblacklist-test.php
index b741062..4d9609f 100644
--- a/test/statifyblacklist-test.php
+++ b/test/statifyblacklist-test.php
@@ -617,11 +617,16 @@ public function test_combined_filters() {
StatifyBlacklist::$_options['referer']['regexp'] = StatifyBlacklist::MODE_REGEX;
StatifyBlacklist::$_options['referer']['blacklist'] = array( 'example\.com' => 0 );
StatifyBlacklist::$_options['target']['regexp'] = StatifyBlacklist::MODE_REGEX;
- StatifyBlacklist::$_options['target']['blacklist'] = array( '\/excluded\/.*' => 0 );
+ StatifyBlacklist::$_options['target']['blacklist'] = array( '/excluded/.*' => 0 );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['HTTP_REFERER'] = 'https://example.com';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
+ // Check case-insensitive match.
+ $_SERVER['HTTP_REFERER'] = 'https://eXaMpLe.com';
+ $this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
+ StatifyBlacklist::$_options['referer']['regexp'] = StatifyBlacklist::MODE_REGEX_CI;
+ $this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['HTTP_REFERER'] = 'https://example.net';
$_SERVER['REQUEST_URI'] = '/excluded/page/';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
From 44ee7ee83921e7dee74a1e0043711997a1200e5a Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sun, 17 Mar 2019 17:34:57 +0100
Subject: [PATCH 25/42] Check regular expressions and prevent saving invalid
settings (#13)
---
inc/class-statifyblacklist-admin.php | 20 ++++++++++++++------
views/settings-page.php | 7 ++++++-
2 files changed, 20 insertions(+), 7 deletions(-)
diff --git a/inc/class-statifyblacklist-admin.php b/inc/class-statifyblacklist-admin.php
index 1920157..18692f4 100644
--- a/inc/class-statifyblacklist-admin.php
+++ b/inc/class-statifyblacklist-admin.php
@@ -63,22 +63,26 @@ public static function update_options( $options = null ) {
if ( isset( $options ) && current_user_can( 'manage_options' ) ) {
// Sanitize referer list.
- $given_referer = $options['referer']['blacklist'];
+ $given_referer = $options['referer']['blacklist'];
+ $invalid_referer = [];
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'] ) {
- // TODO Check regular expressions.
$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'];
+ $given_target = $options['target']['blacklist'];
+ $invalid_target = [];
if ( self::MODE_REGEX === $options['target']['regexp'] || self::MODE_REGEX_CI === $options['target']['regexp'] ) {
- // TODO Check regular expressions.
$sanitized_target = $given_target;
+ // Check regular expressions.
+ $invalid_target = self::sanitize_regex( $given_target );
} else {
$sanitized_target = $given_target;
}
@@ -92,10 +96,12 @@ public static function update_options( $options = null ) {
'referer' => [
'sanitized' => $sanitized_referer,
'diff' => array_diff( $given_referer, $sanitized_referer ),
+ 'invalid' => $invalid_referer,
],
'target' => [
'sanitized' => $sanitized_target,
'diff' => array_diff( $given_target, $sanitized_target ),
+ 'invalid' => $invalid_target,
],
'ip' => [
'sanitized' => $sanitized_ip,
@@ -103,7 +109,9 @@ public static function update_options( $options = null ) {
],
];
if ( ! empty( $errors['referer']['diff'] )
+ || ! empty( $errors['referer']['invalid'] )
|| ! empty( $errors['target']['diff'] )
+ || ! empty( $errors['target']['invalid'] )
|| ! empty( $errors['ip']['diff'] ) ) {
return $errors;
}
@@ -343,10 +351,10 @@ function ( $ip ) {
*/
private static function sanitize_regex( $expressions ) {
return array_filter(
- $expressions,
+ array_flip( $expressions ),
function ( $re ) {
// Check of preg_match() fails (warnings suppressed).
- return false === @preg_match( $re, null );
+ return false === @preg_match( StatifyBlacklist::regex( $re, false ), null );
}
);
}
diff --git a/views/settings-page.php b/views/settings-page.php
index b4a69bb..cd073cf 100755
--- a/views/settings-page.php
+++ b/views/settings-page.php
@@ -116,6 +116,9 @@ function ( $a ) {
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' ) . ' ' . implode( ' ', $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'] ) );
@@ -144,7 +147,9 @@ function ( $a ) {
}
if ( isset( $statifyblacklist_post_warning ) ) {
foreach ( $statifyblacklist_post_warning as $w ) {
- print '';
+ print '' .
+ wp_kses( $w, [ 'br' => [] ] ) .
+ '
';
}
print '' . esc_html( 'Settings have not been saved yet.', 'statify-blacklist' ) . '
';
}
From 22373d2308b8ee99aa7c4a5d5f9d3b99aa0f5867 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sun, 17 Mar 2019 17:43:29 +0100
Subject: [PATCH 26/42] CONTRIBUTING++ [skip ci]
Adapt branch names to git flow and add a sentence on pull requests.
---
CONTRIBUTING.md | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b70affd..8e24a86 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -33,17 +33,19 @@ If the changes introduce new functionality or affect major parts of existing cod
For adding new functionality a new test case the corresponding PHPUnit test would be nice (no hard criterion though).
+The `master` branch should also be target for most pull requests.
+However it it features new functionality you might want to target the `develop` branch instead (see next section for details on branches).
+
### Branches
The `master` branch represents the current state of development.
Please ensure your initial code is up to date with it at the time you start development.
-The `master` should also be target for most pull requests.
In addition, this project features a `develop` branch, which holds bleeding edge developments, not necessarily considered stable or even compatible.
Do not expect this code to run smoothly, but you might have a look into the history to see if some work on an issue has already been started there.
-For fixes and features, there might be additional branches, likely prefixed by `ft-` (feature) or `hf-` (hotfix) followed by an issue number (if applicable) and/or a title.
-Feel free to adapt these naming scheme to your forks.
+For fixes and features, there might be additional branches, likely prefixed by `hotfix/` or `feature/` followed by an issue number (if applicable) and/or a title.
+Feel free to adapt this naming scheme to your forks.
### Merge Requirements
From 0b07697db8640d07ee86f9c719c9342764b8c5e3 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sun, 18 Aug 2019 18:21:57 +0200
Subject: [PATCH 27/42] check if POST values are actually set before
sanitization
---
views/settings-page.php | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/views/settings-page.php b/views/settings-page.php
index cd073cf..dd1a75a 100755
--- a/views/settings-page.php
+++ b/views/settings-page.php
@@ -27,7 +27,9 @@
StatifyBlacklist_Admin::cleanup_database();
} else {
// Extract referer array.
- $referer_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['referer']['blacklist'] ) );
+ if ( isset( $_POST['statifyblacklist']['referer']['blacklist'] ) ) {
+ $referer_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['referer']['blacklist'] ) );
+ }
if ( empty( trim( $referer_str ) ) ) {
$referer = [];
} else {
@@ -45,7 +47,9 @@ function ( $a ) {
}
// Extract target array.
- $target_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['target']['blacklist'] ) );
+ if ( isset( $_POST['statifyblacklist']['target']['blacklist'] ) ) {
+ $target_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['target']['blacklist'] ) );
+ }
if ( empty( trim( $target_str ) ) ) {
$target = [];
} else {
@@ -63,7 +67,9 @@ function ( $a ) {
}
// Extract IP array.
- $ip_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['ip']['blacklist'] ) );
+ if ( isset( $_POST['statifyblacklist']['ip']['blacklist'] ) ) {
+ $ip_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['ip']['blacklist'] ) );
+ }
if ( empty( trim( $ip_str ) ) ) {
$ip = [];
} else {
From 82667dcf93d165207f0dabc3c3d5493f013fe020 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sun, 18 Aug 2019 18:23:33 +0200
Subject: [PATCH 28/42] update Composer dependencies
---
composer.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/composer.json b/composer.json
index 8b32fc6..8dc9df3 100644
--- a/composer.json
+++ b/composer.json
@@ -22,14 +22,14 @@
"composer/installers": "~1.0"
},
"require-dev": {
- "dealerdirect/phpcodesniffer-composer-installer": "^0.4",
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5",
"consolidation/robo": "^1.4",
"phpunit/phpunit": "*",
"phpunit/php-code-coverage": "*",
"slowprog/composer-copy-file": "~0.2",
"squizlabs/php_codesniffer": "^3.4",
- "phpcompatibility/php-compatibility": "^9.1",
- "wp-coding-standards/wpcs": "^2.0"
+ "phpcompatibility/php-compatibility": "^9.2",
+ "wp-coding-standards/wpcs": "^2.1"
},
"scripts": {
"build": [
From a88a89c4423c2f679f028add4e98d9d811173bee Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sun, 6 Oct 2019 17:32:22 +0200
Subject: [PATCH 29/42] update WP Codex and license links [skip ci]
---
LICENSE.md | 2 +-
README.md | 4 ++--
statify-blacklist.php | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/LICENSE.md b/LICENSE.md
index 5544f2d..28fbeca 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -357,5 +357,5 @@ into proprietary programs. If your program is a subroutine library,
you may consider it more useful to permit linking proprietary
applications with the library. If this is what you want to do, use the
[GNU Lesser General Public
-License](http://www.gnu.org/licenses/lgpl.html) instead of this
+License](https://www.gnu.org/licenses/lgpl.html) instead of this
License.
diff --git a/README.md b/README.md
index 3dc84e4..db3affb 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
* Requires PHP: 5.5
* Stable tag: 1.4.4
* License: GPLv2 or later
-* License URI: http://www.gnu.org/licenses/gpl-2.0.html
+* License URI: https://www.gnu.org/licenses/gpl-2.0.html
## Description ##
A blacklist extension for the famous [Statify](https://wordpress.org/plugins/statify/) Wordpress plugin.
@@ -45,7 +45,7 @@ The plugin is capable of handling multisite installations.
* Special Thanks to [pluginkollektiv](https://github.com/pluginkollektiv) for maintaining _Statify_
## Installation ##
-* If you don’t know how to install a plugin for WordPress, [here’s how](http://codex.wordpress.org/Managing_Plugins#Installing_Plugins).
+* If you don’t know how to install a plugin for WordPress, [here’s how](https://wordpress.org/support/article/managing-plugins/#installing-plugins).
* Make sure _Statify_ plugin is installed and active
* Goto _Settings_ -> _Statify Blacklist_ to configure the plugin
diff --git a/statify-blacklist.php b/statify-blacklist.php
index 02a5c39..f7d5111 100644
--- a/statify-blacklist.php
+++ b/statify-blacklist.php
@@ -27,7 +27,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with Statify Blacklist. If not, see http://www.gnu.org/licenses/gpl-2.0.html.
+ * along with Statify Blacklist. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
*/
// Quit if accessed directly.
From 84cf79fd041b7ff1c5f1b02d1832a6437fe98a0a Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sun, 6 Oct 2019 17:52:08 +0200
Subject: [PATCH 30/42] remove underscore prefix from options field
---
inc/class-statifyblacklist-admin.php | 20 +++++++--------
inc/class-statifyblacklist-system.php | 20 +++++++--------
inc/class-statifyblacklist.php | 36 +++++++++++++--------------
test/statifyblacklist-test.php | 34 ++++++++++++-------------
4 files changed, 55 insertions(+), 55 deletions(-)
diff --git a/inc/class-statifyblacklist-admin.php b/inc/class-statifyblacklist-admin.php
index 18692f4..9a77a26 100644
--- a/inc/class-statifyblacklist-admin.php
+++ b/inc/class-statifyblacklist-admin.php
@@ -229,20 +229,20 @@ public static function cleanup_database() {
}
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
- $clean_ref = ( 1 === self::$_options['referer']['cron'] );
- $clean_trg = ( 1 === self::$_options['target']['cron'] );
+ $clean_ref = ( 1 === self::$options['referer']['cron'] );
+ $clean_trg = ( 1 === self::$options['target']['cron'] );
} else {
$clean_ref = true;
$clean_trg = true;
}
if ( $clean_ref ) {
- if ( isset( self::$_options['referer']['regexp'] ) && self::$_options['referer']['regexp'] > 0 ) {
+ if ( isset( self::$options['referer']['regexp'] ) && self::$options['referer']['regexp'] > 0 ) {
// Merge given regular expressions into one.
- $referer_regexp = implode( '|', array_keys( self::$_options['referer']['blacklist'] ) );
+ $referer_regexp = implode( '|', array_keys( self::$options['referer']['blacklist'] ) );
} else {
// Sanitize URLs.
- $referer = self::sanitize_urls( self::$_options['referer']['blacklist'] );
+ $referer = self::sanitize_urls( self::$options['referer']['blacklist'] );
// Build filter regexp.
$referer_regexp = str_replace( '.', '\.', implode( '|', array_flip( $referer ) ) );
@@ -250,12 +250,12 @@ public static function cleanup_database() {
}
if ( $clean_trg ) {
- if ( isset( self::$_options['target']['regexp'] ) && self::$_options['target']['regexp'] > 0 ) {
+ if ( isset( self::$options['target']['regexp'] ) && self::$options['target']['regexp'] > 0 ) {
// Merge given regular expressions into one.
- $target_regexp = implode( '|', array_keys( self::$_options['target']['blacklist'] ) );
+ $target_regexp = implode( '|', array_keys( self::$options['target']['blacklist'] ) );
} else {
// Build filter regexp.
- $target_regexp = str_replace( '.', '\.', implode( '|', array_flip( self::$_options['target']['blacklist'] ) ) );
+ $target_regexp = str_replace( '.', '\.', implode( '|', array_flip( self::$options['target']['blacklist'] ) ) );
}
}
@@ -268,7 +268,7 @@ public static function cleanup_database() {
$wpdb->query(
$wpdb->prepare(
"DELETE FROM `$wpdb->statify` WHERE "
- . ( ( 1 === self::$_options['referer']['regexp'] ) ? ' BINARY ' : '' )
+ . ( ( 1 === self::$options['referer']['regexp'] ) ? ' BINARY ' : '' )
. 'referrer REGEXP %s', $referer_regexp
)
);
@@ -277,7 +277,7 @@ public static function cleanup_database() {
$wpdb->query(
$wpdb->prepare(
"DELETE FROM `$wpdb->statify` WHERE "
- . ( ( 1 === self::$_options['target']['regexp'] ) ? ' BINARY ' : '' )
+ . ( ( 1 === self::$options['target']['regexp'] ) ? ' BINARY ' : '' )
. 'target REGEXP %s', $target_regexp
)
);
diff --git a/inc/class-statifyblacklist-system.php b/inc/class-statifyblacklist-system.php
index c136d29..a0312c3 100644
--- a/inc/class-statifyblacklist-system.php
+++ b/inc/class-statifyblacklist-system.php
@@ -134,10 +134,10 @@ public static function uninstall_site( $site_id ) {
public static function upgrade() {
self::update_options();
// Check if config array is not associative (pre 1.2.0).
- if ( array_keys( self::$_options['referer'] ) === range( 0, count( self::$_options['referer'] ) - 1 ) ) {
+ if ( array_keys( self::$options['referer'] ) === range( 0, count( self::$options['referer'] ) - 1 ) ) {
// Flip referer array to make domains keys.
- $options = self::$_options;
- $options['referer'] = array_flip( self::$_options['referer'] );
+ $options = self::$options;
+ $options['referer'] = array_flip( self::$options['referer'] );
if ( self::$multisite ) {
update_site_option( 'statify-blacklist', $options );
} else {
@@ -146,14 +146,14 @@ public static function upgrade() {
}
// Version not set (pre 1.3.0) or older than 1.4.
- if ( ! isset( self::$_options['version'] ) || self::$_options['version'] < 1.4 ) {
+ if ( ! isset( self::$options['version'] ) || self::$options['version'] < 1.4 ) {
// Upgrade options to new schema.
$options = array(
'referer' => array(
- 'active' => self::$_options['active_referer'],
- 'cron' => self::$_options['cron_referer'],
- 'regexp' => self::$_options['referer_regexp'],
- 'blacklist' => self::$_options['referer'],
+ 'active' => self::$options['active_referer'],
+ 'cron' => self::$options['cron_referer'],
+ 'regexp' => self::$options['referer_regexp'],
+ 'blacklist' => self::$options['referer'],
),
'target' => array(
'active' => 0,
@@ -176,9 +176,9 @@ public static function upgrade() {
}
// Version older than current major release.
- if ( self::VERSION_MAIN > self::$_options['version'] ) {
+ if ( self::VERSION_MAIN > self::$options['version'] ) {
// Merge default options with current config, assuming only additive changes.
- $options = array_merge_recursive( self::default_options(), self::$_options );
+ $options = array_merge_recursive( self::default_options(), self::$options );
$options['version'] = self::VERSION_MAIN;
if ( self::$multisite ) {
update_site_option( 'statify-blacklist', $options );
diff --git a/inc/class-statifyblacklist.php b/inc/class-statifyblacklist.php
index 7bbe94c..05b9b12 100644
--- a/inc/class-statifyblacklist.php
+++ b/inc/class-statifyblacklist.php
@@ -61,9 +61,9 @@ class StatifyBlacklist {
* Plugin options.
*
* @since 1.0.0
- * @var array $_options
+ * @var array $options
*/
- public static $_options;
+ public static $options;
/**
* Multisite Status.
@@ -93,7 +93,7 @@ public static function init() {
self::update_options();
// Add Filter to statify hook if enabled.
- if ( 0 !== self::$_options['referer']['active'] || 0 !== self::$_options['target']['active'] || 0 !== self::$_options['ip']['active'] ) {
+ if ( 0 !== self::$options['referer']['active'] || 0 !== self::$options['target']['active'] || 0 !== self::$options['ip']['active'] ) {
add_filter( 'statify__skip_tracking', array( 'StatifyBlacklist', 'apply_blacklist_filter' ) );
}
@@ -104,7 +104,7 @@ public static function init() {
// CronJob to clean up database.
if ( defined( 'DOING_CRON' ) && DOING_CRON &&
- ( 1 === self::$_options['referer']['cron'] || 1 === self::$_options['target']['cron'] ) ) {
+ ( 1 === self::$options['referer']['cron'] || 1 === self::$options['target']['cron'] ) ) {
add_action( 'statify_cleanup', array( 'StatifyBlacklist_Admin', 'cleanup_database' ) );
}
}
@@ -125,7 +125,7 @@ public static function update_options( $options = null ) {
} else {
$o = get_option( 'statify-blacklist' );
}
- self::$_options = wp_parse_args( $o, self::default_options() );
+ self::$options = wp_parse_args( $o, self::default_options() );
}
/**
@@ -166,9 +166,9 @@ protected static function default_options() {
*/
public static function apply_blacklist_filter() {
// Referer blacklist.
- if ( isset( self::$_options['referer']['active'] ) && 0 !== self::$_options['referer']['active'] ) {
+ 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;
+ $mode = isset( self::$options['referer']['regexp'] ) ? intval( self::$options['referer']['regexp'] ) : 0;
// Get full referer string.
$referer = wp_get_raw_referer();
@@ -183,8 +183,8 @@ public static function apply_blacklist_filter() {
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']
+ array_keys( self::$options['referer']['blacklist'] ),
+ self::MODE_REGEX_CI === self::$options['referer']['regexp']
);
// Check blacklist (no return to continue filtering #12).
@@ -196,7 +196,7 @@ public static function apply_blacklist_filter() {
// Keyword filter since 1.5.0 (#15).
case self::MODE_KEYWORD:
// Get blacklist.
- $blacklist = self::$_options['referer']['blacklist'];
+ $blacklist = self::$options['referer']['blacklist'];
foreach ( array_keys( $blacklist ) as $keyword ) {
if ( false !== strpos( strtolower( $referer ), strtolower( $keyword ) ) ) {
@@ -212,7 +212,7 @@ public static function apply_blacklist_filter() {
$referer = strtolower( ( isset( $referer['host'] ) ? $referer['host'] : '' ) );
// Get blacklist.
- $blacklist = self::$_options['referer']['blacklist'];
+ $blacklist = self::$options['referer']['blacklist'];
// Check blacklist.
if ( isset( $blacklist[ $referer ] ) ) {
@@ -222,17 +222,17 @@ public static function apply_blacklist_filter() {
}
// Target blacklist (since 1.4.0).
- if ( isset( self::$_options['target']['active'] ) && 0 !== self::$_options['target']['active'] ) {
+ if ( isset( self::$options['target']['active'] ) && 0 !== self::$options['target']['active'] ) {
// Regular Expression filtering since 1.3.0.
- if ( isset( self::$_options['target']['regexp'] ) && 0 < self::$_options['target']['regexp'] ) {
+ if ( isset( self::$options['target']['regexp'] ) && 0 < self::$options['target']['regexp'] ) {
// Get full referer string.
// @codingStandardsIgnoreStart The globals are checked.
$target = ( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '/' );
// @codingStandardsIgnoreEnd
// Merge given regular expressions into one.
$regexp = self::regex(
- array_keys( self::$_options['target']['blacklist'] ),
- self::MODE_REGEX_CI === self::$_options['target']['regexp']
+ array_keys( self::$options['target']['blacklist'] ),
+ self::MODE_REGEX_CI === self::$options['target']['regexp']
);
// Check blacklist (no return to continue filtering #12).
@@ -245,7 +245,7 @@ public static function apply_blacklist_filter() {
$target = ( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '/' );
// @codingStandardsIgnoreEnd
// Get blacklist.
- $blacklist = self::$_options['target']['blacklist'];
+ $blacklist = self::$options['target']['blacklist'];
// Check blacklist.
if ( isset( $blacklist[ $target ] ) ) {
return true;
@@ -254,10 +254,10 @@ public static function apply_blacklist_filter() {
}
// IP blacklist (since 1.4.0).
- if ( isset( self::$_options['ip']['active'] ) && 0 !== self::$_options['ip']['active'] ) {
+ if ( isset( self::$options['ip']['active'] ) && 0 !== self::$options['ip']['active'] ) {
$ip = self::get_ip();
if ( false !== ( $ip ) ) {
- foreach ( self::$_options['ip']['blacklist'] as $net ) {
+ foreach ( self::$options['ip']['blacklist'] as $net ) {
if ( self::cidr_match( $ip, $net ) ) {
return true;
}
diff --git a/test/statifyblacklist-test.php b/test/statifyblacklist-test.php
index 4d9609f..cd3aad6 100644
--- a/test/statifyblacklist-test.php
+++ b/test/statifyblacklist-test.php
@@ -48,7 +48,7 @@ class StatifyBlacklist_Test extends PHPUnit\Framework\TestCase {
*/
public function test_referer_filter() {
// Prepare Options: 2 blacklisted domains, disabled.
- StatifyBlacklist::$_options = array(
+ StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
'cron' => 0,
@@ -88,7 +88,7 @@ public function test_referer_filter() {
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Activate filter and run tests again.
- StatifyBlacklist::$_options['referer']['active'] = 1;
+ StatifyBlacklist::$options['referer']['active'] = 1;
unset( $_SERVER['HTTP_REFERER'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
@@ -110,7 +110,7 @@ public function test_referer_filter() {
*/
public function test_referer_regex_filter() {
// Prepare Options: 2 regular expressions.
- StatifyBlacklist::$_options = array(
+ StatifyBlacklist::$options = array(
'referer' => array(
'active' => 1,
'cron' => 0,
@@ -156,7 +156,7 @@ public function test_referer_regex_filter() {
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Set RegExp filter to case insensitive.
- StatifyBlacklist::$_options['referer']['regexp'] = 2;
+ StatifyBlacklist::$options['referer']['regexp'] = 2;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
}
@@ -167,7 +167,7 @@ public function test_referer_regex_filter() {
*/
public function test_referer_keyword_filter() {
// Prepare Options: 2 regular expressions.
- StatifyBlacklist::$_options = array(
+ StatifyBlacklist::$options = array(
'referer' => array(
'active' => 1,
'cron' => 0,
@@ -415,7 +415,7 @@ public function test_sanitize_ips() {
*/
public function test_ip_filter() {
// Prepare Options: 2 blacklisted IPs, disabled.
- StatifyBlacklist::$_options = array(
+ StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
'cron' => 0,
@@ -445,7 +445,7 @@ public function test_ip_filter() {
$_SERVER['REMOTE_ADDR'] = '192.0.2.123';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Activate filter.
- StatifyBlacklist::$_options['ip']['active'] = 1;
+ StatifyBlacklist::$options['ip']['active'] = 1;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Try matching v6 address.
$_SERVER['REMOTE_ADDR'] = '2001:db8:a0b:12f0::1';
@@ -456,11 +456,11 @@ public function test_ip_filter() {
$_SERVER['REMOTE_ADDR'] = '2001:db8:a0b:12f0::2';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Subnet matching.
- StatifyBlacklist::$_options['ip']['blacklist'] = array(
+ StatifyBlacklist::$options['ip']['blacklist'] = array(
'192.0.2.0/25',
'2001:db8:a0b:12f0::/96',
);
- $_SERVER['REMOTE_ADDR'] = '192.0.2.123';
+ $_SERVER['REMOTE_ADDR'] = '192.0.2.123';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['REMOTE_ADDR'] = '192.0.2.234';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
@@ -487,7 +487,7 @@ public function test_ip_filter() {
*/
public function test_target_filter() {
// Prepare Options: 2 blacklisted domains, disabled.
- StatifyBlacklist::$_options = array(
+ StatifyBlacklist::$options = array(
'referer' => array(
'active' => 0,
'cron' => 0,
@@ -530,7 +530,7 @@ public function test_target_filter() {
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
// Activate filter and run tests again.
- StatifyBlacklist::$_options['target']['active'] = 1;
+ StatifyBlacklist::$options['target']['active'] = 1;
unset( $_SERVER['REQUEST_URI'] );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
@@ -562,7 +562,7 @@ public function test_target_filter() {
*/
public function test_combined_filters() {
// Prepare Options: simple referer + simple target + ip.
- StatifyBlacklist::$_options = array(
+ StatifyBlacklist::$options = array(
'referer' => array(
'active' => 1,
'cron' => 0,
@@ -614,10 +614,10 @@ public function test_combined_filters() {
$_SERVER['REMOTE_ADDR'] = '192.0.2.234';
// Same for RegExp filters.
- StatifyBlacklist::$_options['referer']['regexp'] = StatifyBlacklist::MODE_REGEX;
- StatifyBlacklist::$_options['referer']['blacklist'] = array( 'example\.com' => 0 );
- StatifyBlacklist::$_options['target']['regexp'] = StatifyBlacklist::MODE_REGEX;
- StatifyBlacklist::$_options['target']['blacklist'] = array( '/excluded/.*' => 0 );
+ StatifyBlacklist::$options['referer']['regexp'] = StatifyBlacklist::MODE_REGEX;
+ StatifyBlacklist::$options['referer']['blacklist'] = array( 'example\.com' => 0 );
+ StatifyBlacklist::$options['target']['regexp'] = StatifyBlacklist::MODE_REGEX;
+ StatifyBlacklist::$options['target']['blacklist'] = array( '/excluded/.*' => 0 );
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['HTTP_REFERER'] = 'https://example.com';
@@ -625,7 +625,7 @@ public function test_combined_filters() {
// Check case-insensitive match.
$_SERVER['HTTP_REFERER'] = 'https://eXaMpLe.com';
$this->assertNull( StatifyBlacklist::apply_blacklist_filter() );
- StatifyBlacklist::$_options['referer']['regexp'] = StatifyBlacklist::MODE_REGEX_CI;
+ StatifyBlacklist::$options['referer']['regexp'] = StatifyBlacklist::MODE_REGEX_CI;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['HTTP_REFERER'] = 'https://example.net';
$_SERVER['REQUEST_URI'] = '/excluded/page/';
From 3f5990f1f37bb25c7c8305dbc34cb9794957a149 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sun, 6 Oct 2019 17:57:55 +0200
Subject: [PATCH 31/42] update PHPCS ruleset and re-enable warnings
---
RoboFile.php | 16 +++---
composer.json | 6 +-
inc/class-statifyblacklist-admin.php | 2 +
phpcs.xml | 10 +---
statify-blacklist.php | 2 +
test/statifyblacklist-test.php | 83 +++++++++++++---------------
views/settings-page.php | 6 +-
7 files changed, 60 insertions(+), 65 deletions(-)
diff --git a/RoboFile.php b/RoboFile.php
index b08f75b..fc7fe1e 100644
--- a/RoboFile.php
+++ b/RoboFile.php
@@ -19,10 +19,10 @@
*/
class RoboFile extends Tasks {
const PROJECT_NAME = 'statify-blacklist';
- const SVN_URL = 'https://plugins.svn.wordpress.org/statify-blacklist';
+ const SVN_URL = 'https://plugins.svn.wordpress.org/statify-blacklist';
- const OPT_TARGET = 'target';
- const OPT_SKIPTEST = 'skipTests';
+ const OPT_TARGET = 'target';
+ const OPT_SKIPTEST = 'skipTests';
const OPT_SKIPSTYLE = 'skipStyle';
/**
@@ -134,10 +134,12 @@ public function build(
*/
private function bundle() {
$this->say( 'Bundling resources...' );
- $this->taskCopyDir( [
- 'inc' => $this->target_dir . '/' . $this->final_name . '/inc',
- 'views' => $this->target_dir . '/' . $this->final_name . '/views',
- ] )->run();
+ $this->taskCopyDir(
+ [
+ 'inc' => $this->target_dir . '/' . $this->final_name . '/inc',
+ 'views' => $this->target_dir . '/' . $this->final_name . '/views',
+ ]
+ )->run();
$this->_copy( 'statify-blacklist.php', $this->target_dir . '/' . $this->final_name . '/statify-blacklist.php' );
$this->_copy( 'LICENSE.md', $this->target_dir . '/' . $this->final_name . '/LICENSE.md' );
$this->_copy( 'README.md', $this->target_dir . '/' . $this->final_name . '/README.md' );
diff --git a/composer.json b/composer.json
index 8dc9df3..a2190ec 100644
--- a/composer.json
+++ b/composer.json
@@ -19,7 +19,7 @@
"type": "wordpress-plugin",
"require": {
"php": ">=5.5",
- "composer/installers": "~1.0"
+ "composer/installers": "~1.7"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5",
@@ -27,8 +27,8 @@
"phpunit/phpunit": "*",
"phpunit/php-code-coverage": "*",
"slowprog/composer-copy-file": "~0.2",
- "squizlabs/php_codesniffer": "^3.4",
- "phpcompatibility/php-compatibility": "^9.2",
+ "squizlabs/php_codesniffer": "^3.5",
+ "phpcompatibility/php-compatibility": "^9.3",
"wp-coding-standards/wpcs": "^2.1"
},
"scripts": {
diff --git a/inc/class-statifyblacklist-admin.php b/inc/class-statifyblacklist-admin.php
index 9a77a26..2ab7e29 100644
--- a/inc/class-statifyblacklist-admin.php
+++ b/inc/class-statifyblacklist-admin.php
@@ -354,6 +354,8 @@ private static function sanitize_regex( $expressions ) {
array_flip( $expressions ),
function ( $re ) {
// Check of preg_match() fails (warnings suppressed).
+
+ // phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged
return false === @preg_match( StatifyBlacklist::regex( $re, false ), null );
}
);
diff --git a/phpcs.xml b/phpcs.xml
index b317a5b..3e2fb67 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -2,7 +2,7 @@
Derived from WordPress Coding Standard
-
+
@@ -13,13 +13,9 @@
-
-
-
-
-
-
+
+
diff --git a/statify-blacklist.php b/statify-blacklist.php
index f7d5111..2e94b7c 100644
--- a/statify-blacklist.php
+++ b/statify-blacklist.php
@@ -105,9 +105,11 @@ function statify_blacklist_disable() {
if ( is_plugin_active( STATIFYBLACKLIST_BASE ) ) {
deactivate_plugins( STATIFYBLACKLIST_BASE );
add_action( 'admin_notices', 'statify_blacklist_disabled_notice' );
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( isset( $_GET['activate'] ) ) {
unset( $_GET['activate'] );
}
+ // phpcs:enable
}
}
diff --git a/test/statifyblacklist-test.php b/test/statifyblacklist-test.php
index cd3aad6..16c6f41 100644
--- a/test/statifyblacklist-test.php
+++ b/test/statifyblacklist-test.php
@@ -275,59 +275,52 @@ public function test_cidr_match() {
$this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '127.0.0.1', '127.0.0.1/32' ) ) );
$this->assertFalse(
invoke_static(
- StatifyBlacklist::class, 'cidr_match', array(
- '127.0.0.1',
- '127.0.0.1/33',
- )
+ StatifyBlacklist::class,
+ 'cidr_match',
+ array( '127.0.0.1', '127.0.0.1/33' )
)
);
$this->assertFalse(
invoke_static(
- StatifyBlacklist::class, 'cidr_match', array(
- '127.0.0.1',
- '127.0.0.1/-1',
- )
+ StatifyBlacklist::class,
+ 'cidr_match',
+ array( '127.0.0.1', '127.0.0.1/-1' )
)
);
$this->assertTrue(
invoke_static(
- StatifyBlacklist::class, 'cidr_match', array(
- '192.0.2.123',
- '192.0.2.0/24',
- )
+ StatifyBlacklist::class,
+ 'cidr_match',
+ array( '192.0.2.123', '192.0.2.0/24' )
)
);
$this->assertFalse(
invoke_static(
- StatifyBlacklist::class, 'cidr_match', array(
- '192.0.3.123',
- '192.0.2.0/24',
- )
+ StatifyBlacklist::class,
+ 'cidr_match',
+ array( '192.0.3.123', '192.0.2.0/24' )
)
);
$this->assertTrue(
invoke_static(
- StatifyBlacklist::class, 'cidr_match', array(
- '192.0.2.123',
- '192.0.2.120/29',
- )
+ StatifyBlacklist::class,
+ 'cidr_match',
+ array( '192.0.2.123', '192.0.2.120/29' )
)
);
$this->assertFalse(
invoke_static(
- StatifyBlacklist::class, 'cidr_match', array(
- '192.0.2.128',
- '192.0.2.120/29',
- )
+ StatifyBlacklist::class,
+ 'cidr_match',
+ array( '192.0.2.128', '192.0.2.120/29' )
)
);
$this->assertTrue( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '10.11.12.13', '10.0.0.0/8' ) ) );
$this->assertFalse(
invoke_static(
- StatifyBlacklist::class, 'cidr_match', array(
- '10.11.12.345',
- '10.0.0.0/8',
- )
+ StatifyBlacklist::class,
+ 'cidr_match',
+ array( '10.11.12.345', '10.0.0.0/8' )
)
);
@@ -338,26 +331,23 @@ public function test_cidr_match() {
$this->assertFalse( invoke_static( StatifyBlacklist::class, 'cidr_match', array( '::1', '::1/-1' ) ) );
$this->assertTrue(
invoke_static(
- StatifyBlacklist::class, 'cidr_match', array(
- '2001:db8:a0b:12f0:1:2:3:4',
- '2001:db8:a0b:12f0::1/64 ',
- )
+ StatifyBlacklist::class,
+ 'cidr_match',
+ array( '2001:db8:a0b:12f0:1:2:3:4', '2001:db8:a0b:12f0::1/64 ' )
)
);
$this->assertTrue(
invoke_static(
- StatifyBlacklist::class, 'cidr_match', array(
- '2001:db8:a0b:12f0::123:456',
- '2001:db8:a0b:12f0::1/96 ',
- )
+ StatifyBlacklist::class,
+ 'cidr_match',
+ array( '2001:db8:a0b:12f0::123:456', '2001:db8:a0b:12f0::1/96 ' )
)
);
$this->assertFalse(
invoke_static(
- StatifyBlacklist::class, 'cidr_match', array(
- '2001:db8:a0b:12f0::1:132:465',
- '2001:db8:a0b:12f0::1/96 ',
- )
+ StatifyBlacklist::class,
+ 'cidr_match',
+ array( '2001:db8:a0b:12f0::1:132:465', '2001:db8:a0b:12f0::1/96 ' )
)
);
}
@@ -373,6 +363,7 @@ public function test_sanitize_ips() {
$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 nencessary 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.
@@ -576,13 +567,13 @@ public function test_combined_filters() {
'cron' => 0,
'regexp' => StatifyBlacklist::MODE_NORMAL,
'blacklist' => array(
- '/excluded/page/' => 0
+ '/excluded/page/' => 0,
),
),
'ip' => array(
'active' => 1,
'blacklist' => array(
- '192.0.2.123'
+ '192.0.2.123',
),
),
'version' => StatifyBlacklist::VERSION_MAIN,
@@ -593,8 +584,8 @@ public function test_combined_filters() {
// No match.
$_SERVER['HTTP_REFERER'] = 'https://example.net';
- $_SERVER['REQUEST_URI'] = '/normal/page/';
- $_SERVER['REMOTE_ADDR'] = '192.0.2.234';
+ $_SERVER['REQUEST_URI'] = '/normal/page/';
+ $_SERVER['REMOTE_ADDR'] = '192.0.2.234';
unset( $_SERVER['HTTP_X_FORWARDED_FOR'] );
unset( $_SERVER['HTTP_X_REAL_IP'] );
@@ -604,7 +595,7 @@ public function test_combined_filters() {
// Matching target.
$_SERVER['HTTP_REFERER'] = 'https://example.net';
- $_SERVER['REQUEST_URI'] = '/excluded/page/';
+ $_SERVER['REQUEST_URI'] = '/excluded/page/';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
// Matching IP.
@@ -628,7 +619,7 @@ public function test_combined_filters() {
StatifyBlacklist::$options['referer']['regexp'] = StatifyBlacklist::MODE_REGEX_CI;
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['HTTP_REFERER'] = 'https://example.net';
- $_SERVER['REQUEST_URI'] = '/excluded/page/';
+ $_SERVER['REQUEST_URI'] = '/excluded/page/';
$this->assertTrue( StatifyBlacklist::apply_blacklist_filter() );
$_SERVER['REQUEST_URI'] = '/normal/page/';
$_SERVER['REMOTE_ADDR'] = '192.0.2.123';
diff --git a/views/settings-page.php b/views/settings-page.php
index dd1a75a..e4c6404 100755
--- a/views/settings-page.php
+++ b/views/settings-page.php
@@ -9,6 +9,8 @@
* @since 1.0.0
*/
+// phpcs:disable WordPress.WhiteSpace.PrecisionAlignment.Found
+
// Quit.
defined( 'ABSPATH' ) || exit;
@@ -132,8 +134,8 @@ function ( $a ) {
} else {
$statifyblacklist_post_success = __( 'Settings updated successfully.', 'statify-blacklist' );
}
- } // End if().
-} // End if().
+ }
+}
/*
* Disable some code style rules that are impractical for textarea content:
From ebc44c722ecec5a074026559d3104990b0f84f1c Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Tue, 7 Jan 2020 19:24:38 +0100
Subject: [PATCH 32/42] use long array syntax
For some reason short syntax is discouraged in the latest WPCS ruleset.
To stay in line with WPCS we use long syntax now.
---
inc/class-statifyblacklist-admin.php | 20 ++++++++++----------
views/settings-page.php | 26 +++++++++++++-------------
2 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/inc/class-statifyblacklist-admin.php b/inc/class-statifyblacklist-admin.php
index 2ab7e29..2644d4c 100644
--- a/inc/class-statifyblacklist-admin.php
+++ b/inc/class-statifyblacklist-admin.php
@@ -64,7 +64,7 @@ public static function update_options( $options = null ) {
// Sanitize referer list.
$given_referer = $options['referer']['blacklist'];
- $invalid_referer = [];
+ $invalid_referer = array();
if ( self::MODE_NORMAL === $options['referer']['regexp'] ) {
// Sanitize URLs and remove empty inputs.
$sanitized_referer = self::sanitize_urls( $given_referer );
@@ -78,7 +78,7 @@ public static function update_options( $options = null ) {
// Sanitize target list.
$given_target = $options['target']['blacklist'];
- $invalid_target = [];
+ $invalid_target = array();
if ( self::MODE_REGEX === $options['target']['regexp'] || self::MODE_REGEX_CI === $options['target']['regexp'] ) {
$sanitized_target = $given_target;
// Check regular expressions.
@@ -92,22 +92,22 @@ public static function update_options( $options = null ) {
$sanitized_ip = self::sanitize_ips( $given_ip );
// Abort on errors.
- $errors = [
- 'referer' => [
+ $errors = array(
+ 'referer' => array(
'sanitized' => $sanitized_referer,
'diff' => array_diff( $given_referer, $sanitized_referer ),
'invalid' => $invalid_referer,
- ],
- 'target' => [
+ ),
+ 'target' => array(
'sanitized' => $sanitized_target,
'diff' => array_diff( $given_target, $sanitized_target ),
'invalid' => $invalid_target,
- ],
- 'ip' => [
+ ),
+ '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'] )
diff --git a/views/settings-page.php b/views/settings-page.php
index e4c6404..46ce8d0 100755
--- a/views/settings-page.php
+++ b/views/settings-page.php
@@ -33,7 +33,7 @@
$referer_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['referer']['blacklist'] ) );
}
if ( empty( trim( $referer_str ) ) ) {
- $referer = [];
+ $referer = array();
} else {
$referer = array_filter(
array_map(
@@ -53,7 +53,7 @@ function ( $a ) {
$target_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['target']['blacklist'] ) );
}
if ( empty( trim( $target_str ) ) ) {
- $target = [];
+ $target = array();
} else {
$target = array_filter(
array_map(
@@ -73,7 +73,7 @@ function ( $a ) {
$ip_str = sanitize_textarea_field( wp_unslash( $_POST['statifyblacklist']['ip']['blacklist'] ) );
}
if ( empty( trim( $ip_str ) ) ) {
- $ip = [];
+ $ip = array();
} else {
$ip = array_filter(
array_map(
@@ -90,8 +90,8 @@ function ( $a ) {
// Update options (data will be sanitized).
$statifyblacklist_update_result = StatifyBlacklist_Admin::update_options(
- [
- 'referer' => [
+ array(
+ 'referer' => array(
'active' => isset( $_POST['statifyblacklist']['referer']['active'] )
? (int) $_POST['statifyblacklist']['referer']['active'] : 0,
'cron' => isset( $_POST['statifyblacklist']['referer']['cron'] )
@@ -99,8 +99,8 @@ function ( $a ) {
'regexp' => isset( $_POST['statifyblacklist']['referer']['regexp'] )
? (int) $_POST['statifyblacklist']['referer']['regexp'] : 0,
'blacklist' => array_flip( $referer ),
- ],
- 'target' => [
+ ),
+ 'target' => array(
'active' => isset( $_POST['statifyblacklist']['target']['active'] )
? (int) $_POST['statifyblacklist']['target']['active'] : 0,
'cron' => isset( $_POST['statifyblacklist']['target']['cron'] )
@@ -108,19 +108,19 @@ function ( $a ) {
'regexp' => isset( $_POST['statifyblacklist']['target']['regexp'] )
? (int) $_POST['statifyblacklist']['target']['regexp'] : 0,
'blacklist' => array_flip( $target ),
- ],
- 'ip' => [
+ ),
+ '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 = [];
+ $statifyblacklist_post_warning = array();
if ( ! empty( $statifyblacklist_update_result['referer']['diff'] ) ) {
$statifyblacklist_post_warning[] = __( 'Some URLs are invalid and have been sanitized.', 'statify-blacklist' );
}
@@ -156,7 +156,7 @@ function ( $a ) {
if ( isset( $statifyblacklist_post_warning ) ) {
foreach ( $statifyblacklist_post_warning as $w ) {
print '' .
- wp_kses( $w, [ 'br' => [] ] ) .
+ wp_kses( $w, array( 'br' => array() ) ) .
'
';
}
print '' . esc_html( 'Settings have not been saved yet.', 'statify-blacklist' ) . '
';
From 253d2fadd2ff9ffcec6c7d63dcf4b6158a93f3d4 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Tue, 7 Jan 2020 19:26:51 +0100
Subject: [PATCH 33/42] use only supported PHP versions + 5.6 for CI builds
---
.travis.yml | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index b6c3e11..79000c5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,9 @@
language: php
-dist: trusty
php:
- - '5.5'
- '5.6'
- - '7.0'
- - '7.1'
- '7.2'
- '7.3'
+ - '7.4'
before_script:
- composer install
script:
From 736cec1d1205a797dd6436604f565e35ababd179 Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Tue, 7 Jan 2020 19:27:47 +0100
Subject: [PATCH 34/42] fix use of esc_html__() for translated escape in
settings page
---
views/settings-page.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/views/settings-page.php b/views/settings-page.php
index 46ce8d0..e69d429 100755
--- a/views/settings-page.php
+++ b/views/settings-page.php
@@ -159,7 +159,7 @@ function ( $a ) {
wp_kses( $w, array( 'br' => array() ) ) .
'';
}
- print '' . esc_html( 'Settings have not been saved yet.', 'statify-blacklist' ) . '
';
+ print '' . esc_html__( 'Settings have not been saved yet.', 'statify-blacklist' ) . '
';
}
if ( isset( $statifyblacklist_post_success ) ) {
print '' .
From ac73b2316d7dabac88f0c246c8b3d09be9f251dc Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sun, 10 May 2020 11:35:18 +0200
Subject: [PATCH 35/42] typo fixes
---
README.md | 4 ++--
inc/class-statifyblacklist-admin.php | 2 +-
statify-blacklist.php | 2 +-
test/statifyblacklist-test.php | 2 +-
views/settings-page.php | 6 +++---
5 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index 70099f3..a8c1ead 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@ visitors from search engines, just "false" referers from 301 redirects or you ow
No. It only prevent's _Statify_ from tracking, nothing more or less.
### Does live filtering impact performance? ###
-Yes, but probalby not noticeable. Checking a single referer string against a (usually small) list should be negligible compared to the total loading procedure.
+Yes, but probably not noticeable. Checking a single referer string against a (usually small) list should be negligible compared to the total loading procedure.
If this still is an issue for you, consider deactivating the filter and only run the one-time-cleanup or activate the cron job.
### Is any personal data collected? ###
@@ -127,7 +127,7 @@ Because of this, an IP blacklist can only be applied while processing the reques
### 1.2.0 / 29.08.2016 ###
* Switched from `in_array()` to faster `isset()` for referer checking
-* Optional cron execiton implemented
+* Optional cron execution implemented
### 1.1.2 / 17.08.2016 ###
* Prepared for localization
diff --git a/inc/class-statifyblacklist-admin.php b/inc/class-statifyblacklist-admin.php
index 2644d4c..78a43fb 100644
--- a/inc/class-statifyblacklist-admin.php
+++ b/inc/class-statifyblacklist-admin.php
@@ -263,7 +263,7 @@ public static function cleanup_database() {
global $wpdb;
// Execute filter on database.
- // @codingStandardsIgnoreStart These statements prouce warnings, rework in future release (TODO).
+ // @codingStandardsIgnoreStart These statements produce warnings, rework in future release (TODO).
if ( ! empty( $referer_regexp ) ) {
$wpdb->query(
$wpdb->prepare(
diff --git a/statify-blacklist.php b/statify-blacklist.php
index 2e94b7c..e9488c5 100644
--- a/statify-blacklist.php
+++ b/statify-blacklist.php
@@ -55,7 +55,7 @@
// Autoload.
spl_autoload_register( 'statify_blacklist_autoload' );
} else {
- // Disbale plugin, if active.
+ // Disable plugin, if active.
add_action( 'admin_init', 'statify_blacklist_disable' );
}
diff --git a/test/statifyblacklist-test.php b/test/statifyblacklist-test.php
index 16c6f41..a7a18e4 100644
--- a/test/statifyblacklist-test.php
+++ b/test/statifyblacklist-test.php
@@ -365,7 +365,7 @@ public function test_sanitize_ips() {
$this->assertNotFalse( $result );
/*
- * Unfortunately this is nencessary as long as we run PHP 5 tests, because "assertInternalType" is deprecated
+ * 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' ) ) {
diff --git a/views/settings-page.php b/views/settings-page.php
index e69d429..fed2ed4 100755
--- a/views/settings-page.php
+++ b/views/settings-page.php
@@ -177,7 +177,7 @@ function ( $a ) {
-
+
@@ -257,7 +257,7 @@ function ( $a ) {
-
+
@@ -341,7 +341,7 @@ function ( $a ) {
-
+
From 4a6cc49fcecb9a1e9ed42f59d66a3a71cbe8a62a Mon Sep 17 00:00:00 2001
From: Stefan Kalscheuer
Date: Sun, 10 May 2020 11:37:17 +0200
Subject: [PATCH 36/42] fix use of $options variable in settings view
Underscore prefix has been removed from this field, but the change
did not reach the settings page yet.
---
views/settings-page.php | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/views/settings-page.php b/views/settings-page.php
index fed2ed4..ec41d70 100755
--- a/views/settings-page.php
+++ b/views/settings-page.php
@@ -183,7 +183,7 @@ function ( $a ) {
>
+ value="1" >
@@ -197,7 +197,7 @@ function ( $a ) {
>
+ value="1" >
@@ -207,16 +207,16 @@ function ( $a ) {
- >
+ >
- >
+ >
- >
+ >
- >
+ >
@@ -237,7 +237,7 @@ function ( $a ) {
>
+ value="1" >
@@ -277,7 +277,7 @@ function ( $a ) {
>
+ value="1" >
@@ -291,13 +291,13 @@ function ( $a ) {
- >
+ >
- >
+ >
- >
+ >
@@ -320,7 +320,7 @@ function ( $a ) {
>
+ value="1" >
@@ -361,7 +361,7 @@ function ( $a ) {
Date: Sun, 10 May 2020 11:46:25 +0200
Subject: [PATCH 37/42] update settings page screenshot
---
assets/screenshot-1.png | Bin 67508 -> 95425 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/assets/screenshot-1.png b/assets/screenshot-1.png
index 6147f4c995d2e875c92fea26dc8a03358813f055..b03eb2ca5a75e5e8aec74adb062ea1c1ff11fce1 100644
GIT binary patch
literal 95425
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