From 8ec005fd1ae11542d68a83085ca3cec75dbdb36a Mon Sep 17 00:00:00 2001 From: cwells-mm Date: Tue, 8 Sep 2026 15:32:41 +0100 Subject: [PATCH 1/4] WordPress 7.1 compatibility and PHP SDK 1.0.10 Verified against WordPress 7.1 on PHP 8.2 and 8.4, with the index.php override both enabled and disabled, plus WP-CLI and wp-cron. - Guard $_SERVER['SERVER_ADDR'], which is not populated by every SAPI. This warned on every front-end request; with the index override active it printed before WordPress loaded, putting output ahead of the redirect headers the waiting room depends on. - Guard a missing public key when building the diagnostics header. - Declare Requires at least and Requires PHP. The 7.4 floor matches what WordPress 7.1 itself requires, and SDK 1.0.10 needs 7.1 as a minimum. - Update the SDK to 1.0.10, clearing the PHP 8.4 implicit-nullable deprecation and the unguarded $_SERVER reads behind it. - Bump to 1.1.15; 1.1.14 is already published on wordpress.org. - Backfill the 1.1.14 changelog entry, which until now existed only in the published SVN tag. Co-Authored-By: Claude Opus 5 (1M context) --- README.txt | 16 ++++++++++++++-- composer.json | 2 +- composer.lock | 21 +++++++++------------ crowdhandler.php | 6 ++++-- includes/class-crowdhandler-diagnostics.php | 11 +++++++---- includes/class-crowdhandler-gatekeeper.php | 5 ++++- 6 files changed, 39 insertions(+), 22 deletions(-) diff --git a/README.txt b/README.txt index 92b52e3..244ef1d 100644 --- a/README.txt +++ b/README.txt @@ -1,8 +1,10 @@ === CrowdHandler virtual waiting room === Contributors: rickmutt Tags: waiting room, traffic management, queue management, ecommerce, CrowdHandler, -Tested up to: 6.7.2 -Stable tag: 1.1.13 +Requires at least: 5.6 +Tested up to: 7.1 +Requires PHP: 7.4 +Stable tag: 1.1.15 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -89,6 +91,16 @@ You can uninstall the plugin at any time to remove CrowdHandler from your site. == Changelog == += 1.1.15 = +* Tested up to WordPress 7.1 +* Fixed a PHP warning emitted on every front-end request when SERVER_ADDR is not set +* Fixed a PHP warning when no public key has been saved +* Declared Requires at least and Requires PHP in the plugin header and readme +* Updated the CrowdHandler PHP SDK to 1.0.10, clearing PHP 8.4 deprecations += 1.1.14 = +* Updated the CrowdHandler PHP SDK +* Fixed the waiting room being skipped on sites behind a reverse proxy that terminates TLS upstream +* Diagnostics header now reports index override and enabled state as separate flags = 1.1.13 = * Compatibility change for crowdhandler-php-skd release 1.0.8 = 1.1.12 = diff --git a/composer.json b/composer.json index bb63cc7..40d294d 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "type": "project", "require": { "php": ">=5.3", - "crowdhandler/sdk": "dev-master" + "crowdhandler/sdk": "^1.0.10" }, "license": "GPL-2.0-or-later", "authors": [ diff --git a/composer.lock b/composer.lock index eec4467..de1a11e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,22 +4,21 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "761bd3f834865a086ab764d8c6d16706", + "content-hash": "57436c0fffb56769f8423ab5d32c6d48", "packages": [ { "name": "crowdhandler/sdk", - "version": "dev-master", + "version": "1.0.10", "source": { "type": "git", "url": "https://github.com/crowdhandler/crowdhandler-php-sdk.git", - "reference": "3c5eec39e12641b469e0f3c062631646c9bd621a" + "reference": "c154df1043f8d51216785abc398177f1925e381b" }, "require": { "ext-curl": "*", "ext-json": "*", - "php": ">= 5.3" + "php": ">=7.1" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -45,17 +44,17 @@ ], "description": "A PHP library for interacting with CrowdHandler", "homepage": "https://www.crowdhandler.com/", - "time": "2022-12-23T10:16:00+00:00" + "time": "2026-09-08T14:13:30+00:00" } ], "packages-dev": [ { "name": "wordpress/wordpress", - "version": "5.9.5", + "version": "5.9.10", "source": { "type": "git", "url": "https://github.com/WordPress/wordpress-develop.git", - "reference": "7268fe465f2589a7dc793e3f93aceea763f1aded" + "reference": "97bbefb1253db8232b40e82e86b5b4ef49a4bb5d" }, "require": { "php": ">=5.6" @@ -99,14 +98,12 @@ "support": { "issues": "https://core.trac.wordpress.org/" }, - "time": "2022-10-17T20:16:15+00:00" + "time": "2024-06-24T17:08:47+00:00" } ], "aliases": [], "minimum-stability": "dev", - "stability-flags": { - "crowdhandler/sdk": 20 - }, + "stability-flags": [], "prefer-stable": true, "prefer-lowest": false, "platform": { diff --git a/crowdhandler.php b/crowdhandler.php index 3cde6fa..5fb2d59 100644 --- a/crowdhandler.php +++ b/crowdhandler.php @@ -16,7 +16,9 @@ * Plugin Name: CrowdHandler virtual waiting room * Plugin URI: https://signup.crowdhandler.com/?utm_source=WordPress&utm_medium=Plugin_Dir * Description: During periods of heavy traffic, our queue management solution helps safeguard your website from crashing and protects your sales. - * Version: 1.1.13 + * Version: 1.1.15 + * Requires at least: 5.6 + * Requires PHP: 7.4 * Author: CROWDHANDLER LTD * License: GPL-2.0+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt @@ -38,7 +40,7 @@ * Start at version 0.1.0 and use SemVer - https://semver.org * Rename this for your plugin and update it as you release new versions. */ -define('CROWDHANDLER_VERSION', '1.1.13'); +define('CROWDHANDLER_VERSION', '1.1.15'); /** * The code that runs during plugin activation. diff --git a/includes/class-crowdhandler-diagnostics.php b/includes/class-crowdhandler-diagnostics.php index 0a92e7b..fd57f20 100644 --- a/includes/class-crowdhandler-diagnostics.php +++ b/includes/class-crowdhandler-diagnostics.php @@ -21,11 +21,14 @@ public function __construct() public function addCHDiagnostics($headers) { if($this->options){ - $indexOverride = (isset($this->options['crowdhandler_settings_field_override_index'])) ? '1' : '0'; - $isEnabled = (isset($this->options['crowdhandler_settings_field_is_enabled'])) ? '1' : '0'; + $indexOverride = (isset($this->options['crowdhandler_settings_field_override_index'])) ? 'i' : '0'; + $isEnabled = (isset($this->options['crowdhandler_settings_field_is_enabled'])) ? 'e' : '0'; $timestamp = new DateTime(); - $formatedTime = $timestamp->format(DateTime::ISO8601); - $headers['x-crowdhandler-info'] = CROWDHANDLER_VERSION . '::' . $this->options['crowdhandler_settings_field_public_key'] . '::' . $indexOverride . '::' . $isEnabled . '::' . $formatedTime; + $formatedTime = $timestamp->format(DateTimeInterface::ATOM); + $publicKey = isset($this->options['crowdhandler_settings_field_public_key']) + ? $this->options['crowdhandler_settings_field_public_key'] + : ''; + $headers['x-crowdhandler-info'] = CROWDHANDLER_VERSION . '::' . $publicKey . '::' . $indexOverride . '::' . $isEnabled . '::' . $formatedTime; } return $headers; } diff --git a/includes/class-crowdhandler-gatekeeper.php b/includes/class-crowdhandler-gatekeeper.php index 575127c..3fdd274 100644 --- a/includes/class-crowdhandler-gatekeeper.php +++ b/includes/class-crowdhandler-gatekeeper.php @@ -50,7 +50,10 @@ public function checkRequest() "/^((?!.*\?).*(\.(avi|css|eot|gif|ico|jpg|jpeg|js|json|mov|mp4|mpeg|mpg|og[g|v]|pdf|png|svg|tiff|ttf|txt|wmv|woff|woff2|xml))$)|.*(^.*w[c|p]-.+)|^((?!.*\?.*xmlrpc\.php).*xmlrpc.php)|\?rest_route=.+/" ); - $isHostServer = $this->gateKeeper->ip === $_SERVER["SERVER_ADDR"]; + // SERVER_ADDR is not populated by every SAPI (CLI, WP-Cron loopbacks and some + // FastCGI setups omit it), so read it defensively to avoid a PHP warning. + $serverAddress = isset($_SERVER["SERVER_ADDR"]) ? $_SERVER["SERVER_ADDR"] : null; + $isHostServer = $serverAddress !== null && $this->gateKeeper->ip === $serverAddress; if (!$isHostServer) { $this->gateKeeper->setFailTrust(true); From 66af0f789f3fde6229c32e5c2aea8fd6ccd4ca4d Mon Sep 17 00:00:00 2001 From: cwells-mm Date: Tue, 8 Sep 2026 16:27:24 +0100 Subject: [PATCH 2/4] Raise the composer PHP floor to 7.4 composer.json still declared php >=5.3 while the plugin header and readme declare Requires PHP 7.4 and the locked SDK 1.0.10 needs >=7.1. Composer could therefore resolve and install the plugin on runtimes it does not support, and the declared requirements disagreed with one another. Aligns composer.json with the plugin header and syncs the lock's platform block to match. Co-Authored-By: Claude Opus 5 (1M context) --- composer.json | 2 +- composer.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 40d294d..82add4f 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "crowdhandler/crowdhandler-wordpress", "type": "project", "require": { - "php": ">=5.3", + "php": ">=7.4", "crowdhandler/sdk": "^1.0.10" }, "license": "GPL-2.0-or-later", diff --git a/composer.lock b/composer.lock index de1a11e..5d66515 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "57436c0fffb56769f8423ab5d32c6d48", + "content-hash": "81ea3b70b1e45f86517e4cb89170711c", "packages": [ { "name": "crowdhandler/sdk", @@ -107,7 +107,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": ">=5.3" + "php": ">=7.4" }, "platform-dev": [], "plugin-api-version": "2.3.0" From 6f2316ce95acfb56a440a2ffb5cf42dd9bad8531 Mon Sep 17 00:00:00 2001 From: cwells-mm Date: Tue, 8 Sep 2026 16:38:53 +0100 Subject: [PATCH 3/4] Sanitize the settings and the diagnostics header value crowdhandler_settings was registered without a sanitize_callback, so the stored public key was whatever was posted. That value is interpolated into the x-crowdhandler-info response header. PHP refuses to send any header containing CR/LF, so this was not an injection route: the forged header never materialised. What did happen is that the whole x-crowdhandler-info header was silently dropped and a PHP warning emitted -- and with the index.php override active that warning prints before WordPress loads, ahead of the redirect headers. Strips CR/LF where the header is built, and registers a sanitize_callback so the value is cleaned on the way in as well. Checkbox fields keep their existing shape ('on' or absent), which isEnabled() and the index override both depend on. Also fixes the $formatedTime misspelling. Co-Authored-By: Claude Opus 5 (1M context) --- admin/class-crowdhandler-admin.php | 40 ++++++++++++++++++++- includes/class-crowdhandler-diagnostics.php | 8 +++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/admin/class-crowdhandler-admin.php b/admin/class-crowdhandler-admin.php index 55b92f3..71c81fe 100644 --- a/admin/class-crowdhandler-admin.php +++ b/admin/class-crowdhandler-admin.php @@ -164,7 +164,11 @@ public function settings_page_html() public function settings_init() { - register_setting('crowdhandler', 'crowdhandler_settings'); + register_setting( + 'crowdhandler', + 'crowdhandler_settings', + array('sanitize_callback' => array($this, 'sanitize_settings')) + ); add_settings_section( 'crowdhandler_settings_section', @@ -212,6 +216,40 @@ public function settings_init() } + /** + * Sanitize the settings before they are stored. + * + * The public key is echoed back in the x-crowdhandler-info response header, + * so it must never carry line breaks. Checkboxes are stored as 'on' or + * omitted entirely, which is the shape the rest of the plugin expects. + */ + public function sanitize_settings($input) + { + $output = array(); + + if (!is_array($input)) { + return $output; + } + + if (isset($input['crowdhandler_settings_field_public_key'])) { + $key = sanitize_text_field($input['crowdhandler_settings_field_public_key']); + $output['crowdhandler_settings_field_public_key'] = trim(str_replace(array("\r", "\n"), '', $key)); + } + + $checkboxes = array( + 'crowdhandler_settings_field_override_index', + 'crowdhandler_settings_field_is_enabled', + ); + + foreach ($checkboxes as $checkbox) { + if (isset($input[$checkbox]) && $input[$checkbox] === 'on') { + $output[$checkbox] = 'on'; + } + } + + return $output; + } + public function settings_section_callback($args) { ?> diff --git a/includes/class-crowdhandler-diagnostics.php b/includes/class-crowdhandler-diagnostics.php index fd57f20..567afef 100644 --- a/includes/class-crowdhandler-diagnostics.php +++ b/includes/class-crowdhandler-diagnostics.php @@ -24,11 +24,15 @@ public function addCHDiagnostics($headers) $indexOverride = (isset($this->options['crowdhandler_settings_field_override_index'])) ? 'i' : '0'; $isEnabled = (isset($this->options['crowdhandler_settings_field_is_enabled'])) ? 'e' : '0'; $timestamp = new DateTime(); - $formatedTime = $timestamp->format(DateTimeInterface::ATOM); + $formattedTime = $timestamp->format(DateTimeInterface::ATOM); $publicKey = isset($this->options['crowdhandler_settings_field_public_key']) ? $this->options['crowdhandler_settings_field_public_key'] : ''; - $headers['x-crowdhandler-info'] = CROWDHANDLER_VERSION . '::' . $publicKey . '::' . $indexOverride . '::' . $isEnabled . '::' . $formatedTime; + // PHP refuses to send any header containing CR/LF, so a stored key + // with line breaks would drop this header entirely and emit a + // warning. Strip them rather than rely on that being caught later. + $publicKey = str_replace(array("\r", "\n"), '', $publicKey); + $headers['x-crowdhandler-info'] = CROWDHANDLER_VERSION . '::' . $publicKey . '::' . $indexOverride . '::' . $isEnabled . '::' . $formattedTime; } return $headers; } From 294c66e1d623a3edec12d4345b8e8a10141d11d4 Mon Sep 17 00:00:00 2001 From: Carl Wells <61698960+carl-wells-crowdhandler@users.noreply.github.com> Date: Tue, 8 Sep 2026 16:47:59 +0100 Subject: [PATCH 4/4] Add type definition to crowdhandler settings Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- admin/class-crowdhandler-admin.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/admin/class-crowdhandler-admin.php b/admin/class-crowdhandler-admin.php index 71c81fe..88ee227 100644 --- a/admin/class-crowdhandler-admin.php +++ b/admin/class-crowdhandler-admin.php @@ -167,7 +167,10 @@ public function settings_init() register_setting( 'crowdhandler', 'crowdhandler_settings', - array('sanitize_callback' => array($this, 'sanitize_settings')) + array( + 'type' => 'array', + 'sanitize_callback' => array($this, 'sanitize_settings'), + ) ); add_settings_section(