Issue #2293163 by Wim Leers, pwolanin: Fixed MemoryBackend's cache entries may be modified unintentionally thanks to object references.
parent
4ab1724827
commit
6383bb2aa6
|
@ -73,6 +73,9 @@ class MemoryBackend implements CacheBackendInterface {
|
|||
*
|
||||
* @param object $cache
|
||||
* An item loaded from cache_get() or cache_get_multiple().
|
||||
* @param bool $allow_invalid
|
||||
* (optional) If TRUE, cache items may be returned even if they have expired
|
||||
* or been invalidated.
|
||||
*
|
||||
* @return mixed
|
||||
* The item with data as appropriate or FALSE if there is no
|
||||
|
@ -82,15 +85,22 @@ class MemoryBackend implements CacheBackendInterface {
|
|||
if (!isset($cache->data)) {
|
||||
return FALSE;
|
||||
}
|
||||
// The object passed into this function is the one stored in $this->cache.
|
||||
// We must clone it as part of the preparation step so that the actual
|
||||
// cache object is not affected by the unserialize() call or other
|
||||
// manipulations of the returned object.
|
||||
|
||||
$prepared = clone $cache;
|
||||
$prepared->data = unserialize($prepared->data);
|
||||
|
||||
// Check expire time.
|
||||
$cache->valid = $cache->expire == Cache::PERMANENT || $cache->expire >= REQUEST_TIME;
|
||||
$prepared->valid = $prepared->expire == Cache::PERMANENT || $prepared->expire >= REQUEST_TIME;
|
||||
|
||||
if (!$allow_invalid && !$cache->valid) {
|
||||
if (!$allow_invalid && !$prepared->valid) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return $cache;
|
||||
return $prepared;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,7 +109,7 @@ class MemoryBackend implements CacheBackendInterface {
|
|||
public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) {
|
||||
$this->cache[$cid] = (object) array(
|
||||
'cid' => $cid,
|
||||
'data' => $data,
|
||||
'data' => serialize($data),
|
||||
'created' => REQUEST_TIME,
|
||||
'expire' => $expire,
|
||||
'tags' => $this->flattenTags($tags),
|
||||
|
|
|
@ -188,6 +188,25 @@ abstract class GenericCacheBackendUnitTestBase extends DrupalUnitTestBase {
|
|||
$cached = $backend->get('test6');
|
||||
$this->assert(is_object($cached), "Backend returned an object for cache id test6.");
|
||||
$this->assertIdentical($with_variable, $cached->data);
|
||||
|
||||
// Make sure that a cached object is not affected by changing the original.
|
||||
$data = new \stdClass();
|
||||
$data->value = 1;
|
||||
$data->obj = new \stdClass();
|
||||
$data->obj->value = 2;
|
||||
$backend->set('test7', $data);
|
||||
$expected_data = clone $data;
|
||||
// Add a property to the original. It should not appear in the cached data.
|
||||
$data->this_should_not_be_in_the_cache = TRUE;
|
||||
$cached = $backend->get('test7');
|
||||
$this->assert(is_object($cached), "Backend returned an object for cache id test7.");
|
||||
$this->assertEqual($expected_data, $cached->data);
|
||||
$this->assertFalse(isset($cached->data->this_should_not_be_in_the_cache));
|
||||
// Add a property to the cache data. It should not appear when we fetch
|
||||
// the data from cache again.
|
||||
$cached->data->this_should_not_be_in_the_cache = TRUE;
|
||||
$fresh_cached = $backend->get('test7');
|
||||
$this->assertFalse(isset($fresh_cached->data->this_should_not_be_in_the_cache));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue