MDL-38303 cache: fixed purging of session cache when switching users

This commit is contained in:
Sam Hemelryk
2013-03-10 11:31:26 +13:00
parent 8673a98d1d
commit 35b2d0db5e
2 changed files with 113 additions and 0 deletions
+54
View File
@@ -1410,6 +1410,17 @@ class cache_application extends cache implements cache_loader_with_locking {
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cache_session extends cache {
/**
* The user the session has been established for.
* @var int
*/
protected static $loadeduserid = null;
/**
* The userid this cache is currently using.
* @var int
*/
protected $currentuserid = null;
/**
* Override the cache::construct method.
*
@@ -1426,6 +1437,8 @@ class cache_session extends cache {
* @return void
*/
public function __construct(cache_definition $definition, cache_store $store, $loader = null) {
// First up copy the loadeduserid to the current user id.
$this->currentuserid = self::$loadeduserid;
parent::__construct($definition, $store, $loader);
if ($definition->has_invalidation_events()) {
$lastinvalidation = $this->get('lastsessioninvalidation');
@@ -1474,6 +1487,47 @@ class cache_session extends cache {
$this->set('lastsessioninvalidation', cache::now());
}
}
/**
* Parses the key turning it into a string (or array is required) suitable to be passed to the cache store.
*
* This function is called for every operation that uses keys. For this reason we use this function to also check
* that the current user is the same as the user who last used this cache.
*
* @param string|int $key As passed to get|set|delete etc.
* @return string|array String unless the store supports multi-identifiers in which case an array if returned.
*/
protected function parse_key($key) {
$this->check_tracked_user();
return parent::parse_key($key);
}
/**
* Check that this cache instance is tracking the current user.
*/
protected function check_tracked_user() {
if (isset($_SESSION['USER']->id)) {
// Get the id of the current user.
$new = $_SESSION['USER']->id;
} else {
// No user set up yet.
$new = 0;
}
if ($new !== self::$loadeduserid) {
// The current user doesn't match the tracker userid for this request.
if (!is_null(self::$loadeduserid)) {
// Purge the data we have for the old user.
// This way we don't bloat the session.
$this->purge();
}
self::$loadeduserid = $new;
$this->currentuserid = $new;
} else if ($new !== $this->currentuserid) {
// The current user matches the loaded user but not the user last used by this cache.
$this->purge();
$this->currentuserid = $new;
}
}
}
/**
+59
View File
@@ -866,4 +866,63 @@ class cache_phpunit_tests extends advanced_testcase {
$this->assertTrue($cache->set('test', 'test'));
$this->assertEquals('test', $cache->get('test'));
}
/**
* Test switching users with session caches.
*/
public function test_session_cache_switch_user() {
$this->resetAfterTest(true);
$cache = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'sessioncache');
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
// Log in as the first user.
$this->setUser($user1);
$sesskey1 = sesskey();
// Set a basic value in the cache.
$cache->set('var', 1);
$this->assertTrue($cache->has('var'));
$this->assertEquals(1, $cache->get('var'));
// Change to the second user.
$this->setUser($user2);
$sesskey2 = sesskey();
// Make sure the cache doesn't give us the data for the last user.
$this->assertNotEquals($sesskey1, $sesskey2);
$this->assertFalse($cache->has('var'));
$this->assertEquals(false, $cache->get('var'));
}
/**
* Test multiple session caches when switching user.
*/
public function test_session_cache_switch_user_multiple() {
$this->resetAfterTest(true);
$cache1 = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'sessioncache1');
$cache2 = cache::make_from_params(cache_store::MODE_SESSION, 'phpunit', 'sessioncache2');
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
// Log in as the first user.
$this->setUser($user1);
$sesskey1 = sesskey();
// Set a basic value in the caches.
$cache1->set('var', 1);
$cache2->set('var', 2);
$this->assertEquals(1, $cache1->get('var'));
$this->assertEquals(2, $cache2->get('var'));
// Change to the second user.
$this->setUser($user2);
$sesskey2 = sesskey();
// Make sure the cache doesn't give us the data for the last user.
// Also make sure that switching the user has lead to both caches being purged.
$this->assertNotEquals($sesskey1, $sesskey2);
$this->assertEquals(false, $cache1->get('var'));
$this->assertEquals(false, $cache2->get('var'));
}
}