Skip to content

Commit

Permalink
Eliminate a race condition where another plugin or the theme created …
Browse files Browse the repository at this point in the history
…the session first. Fixes #75
  • Loading branch information
ericmann committed Jan 3, 2019
1 parent 902260b commit c445880
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 33 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ Absolutely! As of version 2.0, this plugin will create a new table for WordPress
define( 'WP_SESSION_USE_OPTIONS', true );
```

**I get an error saying my PHP version is out of date. Why?**

PHP 5.6 was designated end-of-life and stopped receiving security patches in December 2018. PHP 7.0 was _also_ marked end-of-life in December 2018. The minimum version of PHP supported by WP Session Manager is now PHP 7.1.

If your server is running an older version of PHP, the session system _will not work!_ To avoid triggering a PHP error, the plugin will instead output this notice to upgrade and disable itself silently. You won't see a PHP error, but you also won't get session support.

Reach out to your hosting provider or system administrator to upgrade your server.

**I get an error saying another plugin is setting up a session. What can I do?**

WP Session Manager overrides PHP's default session implementation with its own custom handler. Unfortunately, we can't swap in a new handler if a session is already active. This plugin hooks into the `plugins_loaded` hook to set things up as early as possible, but if you have code in _another_ plugin (or your theme) that attempts to invoke `session_start()` before WP Session Manager loads, then the custom handler won't work at all.

Inspect your other plugins and try to find the one that's interfering. Then, reach out to the developer to explain the conflict and see if they have a fix.

Screenshots
-----------

Expand All @@ -58,6 +72,7 @@ Changelog

**4.1.0**
- Fix: Add some defense to ensure end users are running the correct version of PHP before loading the system.
- Fix: Eliminate a race condition where another plugin or the theme created the session first.

**4.0.0**
- New: Add an object cache based handler to leverage Redis or Memcached if available for faster queries.
Expand Down
15 changes: 15 additions & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ Absolutely! As of version 2.0, this plugin will create a new table for WordPress
define( 'WP_SESSION_USE_OPTIONS', true );
`

= I get an error saying my PHP version is out of date. Why? =

PHP 5.6 was designated end-of-life and stopped receiving security patches in December 2018. PHP 7.0 was _also_ marked end-of-life in December 2018. The minimum version of PHP supported by WP Session Manager is now PHP 7.1.

If your server is running an older version of PHP, the session system _will not work!_ To avoid triggering a PHP error, the plugin will instead output this notice to upgrade and disable itself silently. You won't see a PHP error, but you also won't get session support.

Reach out to your hosting provider or system administrator to upgrade your server.

= I get an error saying another plugin is setting up a session. What can I do? =

WP Session Manager overrides PHP's default session implementation with its own custom handler. Unfortunately, we can't swap in a new handler if a session is already active. This plugin hooks into the `plugins_loaded` hook to set things up as early as possible, but if you have code in _another_ plugin (or your theme) that attempts to invoke `session_start()` before WP Session Manager loads, then the custom handler won't work at all.

Inspect your other plugins and try to find the one that's interfering. Then, reach out to the developer to explain the conflict and see if they have a fix.

== Screenshots ==

None
Expand All @@ -62,6 +76,7 @@ None

= 4.1.0 =
* Fix: Add some defense to ensure end users are running the correct version of PHP before loading the system.
* Fix: Eliminate a race condition where another plugin or the theme created the session first.

= 4.0.0 =
* New: Add an object cache based handler to leverage Redis or Memcached if available for faster queries.
Expand Down
102 changes: 69 additions & 33 deletions wp-session-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@
define('WP_SESSION_MINIMUM_PHP_VERSION', '7.1.0');
}

$wp_session_messages = [
'bad_php_version' => sprintf(
__(
'WP Session Manager requires PHP %s or newer. Please contact your system administrator to upgrade!',
'wp-session-manager'
),
WP_SESSION_MINIMUM_PHP_VERSION,
PHP_VERSION
),
'multiple_sessions' => __(
'Another plugin is attempting to start a session with WordPress. WP Session Manager will not work!',
'wp-session-manager'
)
];

/**
* Initialize the plugin, bootstrap autoloading, and register default hooks
*/
Expand All @@ -29,28 +44,37 @@ function wp_session_manager_initialize()
exit('WP Session Manager requires Composer autoloading, which is not configured');
}

// Queue up the session stack.
$wp_session_handler = EAMann\Sessionz\Manager::initialize();
if (!isset($_SESSION)) {
// Queue up the session stack.
$wp_session_handler = EAMann\Sessionz\Manager::initialize();

// Fall back to database storage where needed.
if (defined('WP_SESSION_USE_OPTIONS') && WP_SESSION_USE_OPTIONS) {
$wp_session_handler->addHandler(new \EAMann\WPSession\OptionsHandler());
} else {
$wp_session_handler->addHandler(new \EAMann\WPSession\DatabaseHandler());
}
// Fall back to database storage where needed.
if (defined('WP_SESSION_USE_OPTIONS') && WP_SESSION_USE_OPTIONS) {
$wp_session_handler->addHandler(new \EAMann\WPSession\OptionsHandler());
} else {
$wp_session_handler->addHandler(new \EAMann\WPSession\DatabaseHandler());
}

// If we have an external object cache, let's use it!
if (wp_using_ext_object_cache()) {
$wp_session_handler->addHandler(new EAMann\WPSession\CacheHandler());
}
// If we have an external object cache, let's use it!
if (wp_using_ext_object_cache()) {
$wp_session_handler->addHandler(new EAMann\WPSession\CacheHandler());
}

// Decrypt the data surfacing from external storage.
if (defined('WP_SESSION_ENC_KEY') && WP_SESSION_ENC_KEY) {
$wp_session_handler->addHandler(new \EAMann\Sessionz\Handlers\EncryptionHandler(WP_SESSION_ENC_KEY));
// Decrypt the data surfacing from external storage.
if (defined('WP_SESSION_ENC_KEY') && WP_SESSION_ENC_KEY) {
$wp_session_handler->addHandler(new \EAMann\Sessionz\Handlers\EncryptionHandler(WP_SESSION_ENC_KEY));
}

// Use an in-memory cache for the instance if we can. This will only help in rare cases.
$wp_session_handler->addHandler(new \EAMann\Sessionz\Handlers\MemoryHandler());

$_SESSION['wp_session_manager'] = 'active';
}

// Use an in-memory cache for the instance if we can. This will only help in rare cases.
$wp_session_handler->addHandler(new \EAMann\Sessionz\Handlers\MemoryHandler());
if (! isset($_SESSION['wp_session_manager']) || $_SESSION['wp_session_manager'] !== 'active') {
add_action('admin_notices', 'wp_session_manager_multiple_sessions_notice');
return;
}

// Create the required table.
add_action('admin_init', ['EAMann\WPSession\DatabaseHandler', 'createTable']);
Expand All @@ -59,22 +83,32 @@ function wp_session_manager_initialize()
register_activation_hook(__FILE__, ['EAMann\WPSession\DatabaseHandler', 'createTable']);
}

/**
* Print an admin notice if too many plugins are manipulating sessions.
*
* @global array $wp_session_messages
*/
function wp_session_manager_multiple_sessions_notice()
{
global $wp_session_messages;
?>
<div class="notice notice-error">
<p><?php echo esc_html($wp_session_messages['multiple_sessions']); ?></p>
</div>
<?php
}

/**
* Print an admin notice if we're on a bad version of PHP.
*
* @global array $wp_session_messages
*/
function wp_session_manager_deactivated_notice()
{
$message = sprintf(
__(
'WP Session Manager requires PHP %s or newer. Please contact your system administrator to upgrade!',
'wp-session-manager'
),
WP_SESSION_MINIMUM_PHP_VERSION,
PHP_VERSION
);
global $wp_session_messages;
?>
<div class="notice notice-error">
<p><?php echo esc_html($message); ?></p>
<p><?php echo esc_html($wp_session_messages['bad_php_version']); ?></p>
</div>
<?php
}
Expand All @@ -84,9 +118,7 @@ function wp_session_manager_deactivated_notice()
*/
function wp_session_manager_start_session()
{
$bootstrap = \EAMann\WPSession\DatabaseHandler::createTable();

if (!is_wp_error($bootstrap) && session_status() !== PHP_SESSION_ACTIVE) {
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
}
Expand All @@ -95,10 +127,14 @@ function wp_session_manager_start_session()
if (version_compare(PHP_VERSION, WP_SESSION_MINIMUM_PHP_VERSION, '<')) {
add_action('admin_notices', 'wp_session_manager_deactivated_notice');
} else {
wp_session_manager_initialize();
$bootstrap = \EAMann\WPSession\DatabaseHandler::createTable();

if (!is_wp_error($bootstrap)) {
add_action('plugins_loaded', 'wp_session_manager_initialize', 1, 0);

// Start up session management, if we're not in the CLI.
if (!defined('WP_CLI') || false === WP_CLI) {
add_action('plugins_loaded', 'wp_session_manager_start_session', 10, 0);
// Start up session management, if we're not in the CLI.
if (!defined('WP_CLI') || false === WP_CLI) {
add_action('plugins_loaded', 'wp_session_manager_start_session', 10, 0);
}
}
}

0 comments on commit c445880

Please sign in to comment.