Skip to content

Commit

Permalink
4.1.0 Release
Browse files Browse the repository at this point in the history
* Add some defense to ensure end users are running the correct version of PHP before loading the system. (#76)
* Eliminate a race condition where another plugin or the theme created the session first. (#75)
* Schedule a cron to auto-delete expired sessions. (#77)

Closes #75, closes #76, closes #77, resolves #78.
  • Loading branch information
ericmann committed Jan 7, 2019
1 parent ebba699 commit 80cc544
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 42 deletions.
21 changes: 20 additions & 1 deletion README.md
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 @@ -56,6 +70,11 @@ None
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.
- Fix: Schedule a cron to auto-delete expired sessions.

**4.0.0**
- New: Add an object cache based handler to leverage Redis or Memcached if available for faster queries.
- New: Adopt the Contributor Covenant (v1.4) as the project's official code of conduct.
Expand Down Expand Up @@ -161,7 +180,7 @@ Additional Information
**Requires at least:** 4.7
**Tested up to:** 5.0.2
**Requires PHP:** 7.1
**Stable tag:** 4.0.0
**Stable tag:** 4.1.0
**License:** GPLv2 or later
**License URI:** http://www.gnu.org/licenses/gpl-2.0.html

Expand Down
2 changes: 1 addition & 1 deletion composer.json
@@ -1,7 +1,7 @@
{
"name" : "ericmann/wp-session-manager",
"description" : "Prototype session management for WordPress.",
"version" : "4.0.0",
"version" : "4.1.0",
"type" : "wordpress-plugin",
"keywords" : ["session"],
"homepage" : "https://github.com/ericmann/wp-session-manager",
Expand Down
16 changes: 12 additions & 4 deletions includes/DatabaseHandler.php
Expand Up @@ -252,11 +252,21 @@ protected function directDelete(string $key)
* @param int $maxlifetime (Unused).
* @param callable $next Next clean operation in the stack.
*
* @global \wpdb $wpdb
*
* @return mixed
*/
public function clean($maxlifetime, $next)
{
self::directClean();

return $next($maxlifetime);
}

/**
* Update the database by removing any sessions that are no longer valid
*
* @global \wpdb $wpdb
*/
public static function directClean()
{
global $wpdb;

Expand All @@ -269,7 +279,5 @@ public function clean($maxlifetime, $next)
)
);
}

return $next($maxlifetime);
}
}
21 changes: 20 additions & 1 deletion readme.txt
Expand Up @@ -5,7 +5,7 @@ Tags: session
Requires at least: 4.7
Tested up to: 5.0.2
Requires PHP: 7.1
Stable tag: 4.0.0
Stable tag: 4.1.0
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html

Expand Down Expand Up @@ -54,12 +54,31 @@ 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

== 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.
* Fix: Schedule a cron to auto-delete expired sessions.

= 4.0.0 =
* New: Add an object cache based handler to leverage Redis or Memcached if available for faster queries.
* New: Adopt the Contributor Covenant (v1.4) as the project's official code of conduct.
Expand Down
27 changes: 27 additions & 0 deletions tests/DatabaseHandlerTest.php
@@ -0,0 +1,27 @@
<?php

namespace EAMann\WPSession;

use PHPUnit\Framework\TestCase;

class DatabaseHandlerTest extends TestCase
{

public function test_create()
{
$handler = new DatabaseHandler();

$called = false;
$callback = function($path, $name) use (&$called) {
$this->assertEquals('path', $path);
$this->assertEquals('name', $name);

$called = true;
};

$handler->create('path', 'name', $callback);

$this->assertTrue($called);
}

}
156 changes: 121 additions & 35 deletions wp-session-manager.php
Expand Up @@ -3,65 +3,151 @@
* Plugin Name: WP Session Manager
* Plugin URI: https://paypal.me/eam
* Description: Session management for WordPress.
* Version: 4.0.0
* Version: 4.1.0
* Author: Eric Mann
* Author URI: https://eamann.com
* License: GPLv2+
*
* @package WP Session Manager
*/

$wp_session_autoload = __DIR__ . '/vendor/autoload.php';
if (file_exists($wp_session_autoload)) {
require_once $wp_session_autoload;
if (!defined('WP_SESSION_MINIMUM_PHP_VERSION')) {
define('WP_SESSION_MINIMUM_PHP_VERSION', '7.1.0');
}

if (!class_exists('EAMann\Sessionz\Manager')) {
exit('WP Session Manager requires Composer autoloading, which is not configured');
}
$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'
)
];

// Queue up the session stack.
$wp_session_handler = EAMann\Sessionz\Manager::initialize();
/**
* Initialize the plugin, bootstrap autoloading, and register default hooks
*/
function wp_session_manager_initialize()
{
$wp_session_autoload = __DIR__ . '/vendor/autoload.php';
if (file_exists($wp_session_autoload)) {
require_once $wp_session_autoload;
}

// 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 (!class_exists('EAMann\Sessionz\Manager')) {
exit('WP Session Manager requires Composer autoloading, which is not configured');
}

// 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 (!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());

/**
* The database handler can automatically clean up sessions as it goes. By default,
* we'll run the cleanup routine every hour to catch any stale sessions that PHP's
* garbage collector happens to miss. This timeout can be filtered to increase or
* decrease the frequency of the manual purge.
*
* @param string $timeout Interval with which to purge stale sessions
*/
$timeout = apply_filters('wp_session_gc_interval', 'hourly');

if (!wp_next_scheduled('wp_session_database_gc')) {
wp_schedule_event(time(), $timeout, 'wp_session_database_gc');
}

add_action('wp_session_database_gc', ['EAMann\WPSession\DatabaseHandler', 'directClean']);
}

// 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));
}

// 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';
}

// 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));
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.
\EAMann\WPSession\DatabaseHandler::createTable();

register_deactivation_hook(__FILE__, function () {
wp_clear_scheduled_hook('wp_session_database_gc');
});
}

// 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());
/**
* 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
}

// Create the required table.
add_action('admin_init', ['EAMann\WPSession\DatabaseHandler', 'createTable']);
add_action('wp_session_init', ['EAMann\WPSession\DatabaseHandler', 'createTable']);
add_action('wp_install', ['EAMann\WPSession\DatabaseHandler', 'createTable']);
register_activation_hook(__FILE__, ['EAMann\WPSession\DatabaseHandler', 'createTable']);
/**
* Print an admin notice if we're on a bad version of PHP.
*
* @global array $wp_session_messages
*/
function wp_session_manager_deactivated_notice()
{
global $wp_session_messages;
?>
<div class="notice notice-error">
<p><?php echo esc_html($wp_session_messages['bad_php_version']); ?></p>
</div>
<?php
}

/**
* If a session hasn't already been started by some external system, start one!
*/
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();
}
}

// 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);
// WordPress won't enforce the minimum version of PHP for us, so we need to check.
if (version_compare(PHP_VERSION, WP_SESSION_MINIMUM_PHP_VERSION, '<')) {
add_action('admin_notices', 'wp_session_manager_deactivated_notice');
} else {
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);
}
}

0 comments on commit 80cc544

Please sign in to comment.