aboutsummaryrefslogtreecommitdiff
path: root/engine/lib/cache.php
diff options
context:
space:
mode:
Diffstat (limited to 'engine/lib/cache.php')
-rw-r--r--engine/lib/cache.php877
1 files changed, 436 insertions, 441 deletions
diff --git a/engine/lib/cache.php b/engine/lib/cache.php
index 694930432..3116c1a9b 100644
--- a/engine/lib/cache.php
+++ b/engine/lib/cache.php
@@ -1,458 +1,453 @@
<?php
- /**
- * Elgg cache
- * Cache file interface for caching data.
- *
- * @package Elgg
- * @subpackage API
- * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
- * @author Curverider Ltd <info@elgg.com>
- * @copyright Curverider Ltd 2008
- * @link http://elgg.org/
- */
+/**
+ * Elgg cache
+ * Cache file interface for caching data.
+ *
+ * @package Elgg.Core
+ * @subpackage Cache
+ */
+
+/* Filepath Cache */
+
+/**
+ * Returns an ElggCache object suitable for caching system information
+ *
+ * @todo Can this be done in a cleaner way?
+ * @todo Swap to memcache etc?
+ *
+ * @return ElggFileCache
+ */
+function elgg_get_system_cache() {
+ global $CONFIG;
/**
- * ElggCache The elgg cache superclass.
- * This defines the interface for a cache (wherever that cache is stored).
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage API
+ * A default filestore cache using the dataroot.
*/
- abstract class ElggCache implements
- ArrayAccess // Override for array access
- {
- /**
- * Variables for the cache object.
- *
- * @var array
- */
- private $variables;
-
- /**
- * Set the constructor.
- */
- function __construct() { $this->variables = array(); }
-
- /**
- * Set a cache variable.
- *
- * @param string $variable
- * @param string $value
- */
- public function set_variable($variable, $value)
- {
- if (!is_array($this->variables))
- $this->variables = array();
-
- $this->variables[$variable] = $value;
- }
-
- /**
- * Get variables for this cache.
- *
- * @param string $variable
- * @return mixed The variable or null;
- */
- public function get_variable($variable)
- {
- if (isset($this->variables[$variable]))
- return $this->variables[$variable];
-
- return null;
- }
-
- /**
- * Class member get overloading, returning key using $this->load defaults.
- *
- * @param string $key
- * @return mixed
- */
- function __get($key) { return $this->load($key); }
-
- /**
- * Class member set overloading, setting a key using $this->save defaults.
- *
- * @param string $key
- * @param mixed $value
- * @return mixed
- */
- function __set($key, $value) { return $this->save($key, $value); }
-
- /**
- * Supporting isset, using $this->load() with default values.
- *
- * @param string $key The name of the attribute or metadata.
- * @return bool
- */
- function __isset($key) { return (bool)$this->load($key); }
-
- /**
- * Supporting unsetting of magic attributes.
- *
- * @param string $key The name of the attribute or metadata.
- */
- function __unset($key) { return $this->delete($key); }
-
- /**
- * Save data in a cache.
- *
- * @param string $key
- * @param string $data
- * @return bool
- */
- abstract public function save($key, $data);
-
- /**
- * Load data from the cache using a given key.
- *
- * @param string $key
- * @param int $offset
- * @param int $limit
- * @return mixed The stored data or false.
- */
- abstract public function load($key, $offset = 0, $limit = null);
-
- /**
- * Invalidate a key
- *
- * @param string $key
- * @return bool
- */
- abstract public function delete($key);
-
- /**
- * Clear out all the contents of the cache.
- *
- */
- abstract public function clear();
-
- /**
- * Add a key only if it doesn't already exist.
- * Implemented simply here, if you extend this class and your caching engine provides a better way then
- * override this accordingly.
- *
- * @param string $key
- * @param string $data
- * @return bool
- */
- public function add($key, $data)
- {
- if (!isset($this[$key]))
- return $this->save($key, $data);
-
- return false;
- }
-
- // ARRAY ACCESS INTERFACE //////////////////////////////////////////////////////////
- function offsetSet($key, $value)
- {
- $this->save($key, $value);
- }
-
- function offsetGet($key)
- {
- return $this->load($key);
- }
-
- function offsetUnset($key)
- {
- if ( isset($this->key) ) {
- unset($this->key);
- }
- }
-
- function offsetExists($offset)
- {
- return isset($this->$offset);
- }
+ static $FILE_PATH_CACHE;
+
+ if (!$FILE_PATH_CACHE) {
+ $FILE_PATH_CACHE = new ElggFileCache($CONFIG->dataroot . 'system_cache/');
}
-
- /**
- * Shared memory cache description.
- * Extends ElggCache with functions useful to shared memory style caches (static variables, memcache etc)
- */
- abstract class ElggSharedMemoryCache extends ElggCache
- {
- /**
- * Namespace variable used to keep various bits of the cache
- * separate.
- *
- * @var string
- */
- private $namespace;
-
- /**
- * Set the namespace of this cache.
- * This is useful for cache types (like memcache or static variables) where there is one large
- * flat area of memory shared across all instances of the cache.
- *
- * @param string $namespace
- */
- public function setNamespace($namespace = "default") { $this->namespace = $namespace; }
- /**
- * Get the namespace currently defined.
- *
- * @return string
- */
- public function getNamespace() { return $this->namespace; }
+
+ return $FILE_PATH_CACHE;
+}
+
+/**
+ * Reset the system cache by deleting the caches
+ *
+ * @return void
+ */
+function elgg_reset_system_cache() {
+ $cache = elgg_get_system_cache();
+ $cache->clear();
+}
+
+/**
+ * Saves a system cache.
+ *
+ * @param string $type The type or identifier of the cache
+ * @param string $data The data to be saved
+ * @return bool
+ */
+function elgg_save_system_cache($type, $data) {
+ global $CONFIG;
+
+ if ($CONFIG->system_cache_enabled) {
+ $cache = elgg_get_system_cache();
+ return $cache->save($type, $data);
}
-
- /**
- * ElggStaticVariableCache
- * Dummy cache which stores values in a static array. Using this makes future replacements to other caching back
- * ends (eg memcache) much easier.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage API
- */
- class ElggStaticVariableCache extends ElggSharedMemoryCache
- {
- /**
- * The cache.
- *
- * @var unknown_type
- */
- private static $__cache;
-
- /**
- * Create the variable cache.
- *
- * This function creates a variable cache in a static variable in memory, optionally with a given namespace (to avoid overlap).
- *
- * @param string $namespace The namespace for this cache to write to - note, namespaces of the same name are shared!
- */
- function __construct($namespace = 'default')
- {
- $this->setNamespace($namespace);
- $this->clear();
- }
-
- public function save($key, $data)
- {
- $namespace = $this->getNamespace();
-
- ElggStaticVariableCache::$__cache[$namespace][$key] = $data;
-
- return true;
- }
-
- public function load($key, $offset = 0, $limit = null)
- {
- $namespace = $this->getNamespace();
-
- if (isset(ElggStaticVariableCache::$__cache[$namespace][$key]))
- return ElggStaticVariableCache::$__cache[$namespace][$key];
-
- return false;
- }
-
- public function delete($key)
- {
- $namespace = $this->getNamespace();
-
- unset(ElggStaticVariableCache::$__cache[$namespace][$key]);
-
- return true;
- }
-
- public function clear()
- {
- $namespace = $this->getNamespace();
-
- if (!isset(ElggStaticVariableCache::$__cache))
- ElggStaticVariableCache::$__cache = array();
-
- //if (!isset(ElggStaticVariableCache::$__cache[$namespace]))
- ElggStaticVariableCache::$__cache[$namespace] = array();
+
+ return false;
+}
+
+/**
+ * Retrieve the contents of a system cache.
+ *
+ * @param string $type The type of cache to load
+ * @return string
+ */
+function elgg_load_system_cache($type) {
+ global $CONFIG;
+
+ if ($CONFIG->system_cache_enabled) {
+ $cache = elgg_get_system_cache();
+ $cached_data = $cache->load($type);
+
+ if ($cached_data) {
+ return $cached_data;
}
}
+
+ return NULL;
+}
+
+/**
+ * Enables the system disk cache.
+ *
+ * Uses the 'system_cache_enabled' datalist with a boolean value.
+ * Resets the system cache.
+ *
+ * @return void
+ */
+function elgg_enable_system_cache() {
+ global $CONFIG;
+
+ datalist_set('system_cache_enabled', 1);
+ $CONFIG->system_cache_enabled = 1;
+ elgg_reset_system_cache();
+}
+
+/**
+ * Disables the system disk cache.
+ *
+ * Uses the 'system_cache_enabled' datalist with a boolean value.
+ * Resets the system cache.
+ *
+ * @return void
+ */
+function elgg_disable_system_cache() {
+ global $CONFIG;
+
+ datalist_set('system_cache_enabled', 0);
+ $CONFIG->system_cache_enabled = 0;
+ elgg_reset_system_cache();
+}
+
+/** @todo deprecate in Elgg 1.9 **/
+
+/**
+ * @access private
+ */
+function elgg_get_filepath_cache() {
+ return elgg_get_system_cache();
+}
+/**
+ * @access private
+ */
+function elgg_filepath_cache_reset() {
+ elgg_reset_system_cache();
+}
+/**
+ * @access private
+ */
+function elgg_filepath_cache_save($type, $data) {
+ return elgg_save_system_cache($type, $data);
+}
+/**
+ * @access private
+ */
+function elgg_filepath_cache_load($type) {
+ return elgg_load_system_cache($type);
+}
+/**
+ * @access private
+ */
+function elgg_enable_filepath_cache() {
+ elgg_enable_system_cache();
+}
+/**
+ * @access private
+ */
+function elgg_disable_filepath_cache() {
+ elgg_disable_system_cache();
+}
+
+/* Simplecache */
+
+/**
+ * Registers a view to simple cache.
+ *
+ * Simple cache is a caching mechanism that saves the output of
+ * views and its extensions into a file. If the view is called
+ * by the {@link simplecache/view.php} file, the Elgg framework will
+ * not be loaded and the contents of the view will returned
+ * from file.
+ *
+ * @warning Simple cached views must take no parameters and return
+ * the same content no matter who is logged in.
+ *
+ * @example
+ * $blog_js = elgg_get_simplecache_url('js', 'blog/save_draft');
+ * elgg_register_simplecache_view('js/blog/save_draft');
+ * elgg_register_js('elgg.blog', $blog_js);
+ * elgg_load_js('elgg.blog');
+ *
+ * @param string $viewname View name
+ *
+ * @return void
+ * @link http://docs.elgg.org/Views/Simplecache
+ * @see elgg_regenerate_simplecache()
+ * @since 1.8.0
+ */
+function elgg_register_simplecache_view($viewname) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->views)) {
+ $CONFIG->views = new stdClass;
+ }
+
+ if (!isset($CONFIG->views->simplecache)) {
+ $CONFIG->views->simplecache = array();
+ }
+
+ $CONFIG->views->simplecache[] = $viewname;
+}
+
+/**
+ * Get the URL for the cached file
+ *
+ * @warning You must register the view with elgg_register_simplecache_view()
+ * for caching to work. See elgg_register_simplecache_view() for a full example.
+ *
+ * @param string $type The file type: css or js
+ * @param string $view The view name
+ * @return string
+ * @since 1.8.0
+ */
+function elgg_get_simplecache_url($type, $view) {
+ global $CONFIG;
+ $lastcache = (int)$CONFIG->lastcache;
+ $viewtype = elgg_get_viewtype();
+ elgg_register_simplecache_view("$type/$view");// see #5302
+ if (elgg_is_simplecache_enabled()) {
+ $url = elgg_get_site_url() . "cache/$type/$viewtype/$view.$lastcache.$type";
+ } else {
+ $url = elgg_get_site_url() . "$type/$view.$lastcache.$type";
+ $elements = array("view" => $viewtype);
+ $url = elgg_http_add_url_query_elements($url, $elements);
+ }
- /**
- * ElggFileCache
- * Store cached data in a file store.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage API
- */
- class ElggFileCache extends ElggCache
- {
- /**
- * Set the Elgg cache.
- *
- * @param string $cache_path The cache path.
- * @param int $max_age Maximum age in seconds, 0 if no limit.
- * @param int $max_size Maximum size of cache in seconds, 0 if no limit.
- */
- function __construct($cache_path, $max_age = 0, $max_size = 0)
- {
- $this->set_variable("cache_path", $cache_path);
- $this->set_variable("max_age", $max_age);
- $this->set_variable("max_size", $max_size);
-
- if ($cache_path=="") throw new ConfigurationException(elgg_echo('ConfigurationException:NoCachePath'));
- }
-
- /**
- * Create and return a handle to a file.
- *
- * @param string $filename
- * @param string $rw
- */
- protected function create_file($filename, $rw = "rb")
- {
- // Create a filename matrix
- $matrix = "";
- $depth = strlen($filename);
- if ($depth > 5) $depth = 5;
-
- // for ($n = 0; $n < $depth; $n++)
- // $matrix .= $filename[$n] . "/";
-
- // Create full path
- $path = $this->get_variable("cache_path") . $matrix;
-
- // if (!mkdir($path, 0700, true)) throw new IOException("Could not make $path");
-
- // Open the file
- if ((!file_exists($path . $filename)) && ($rw=="rb")) return false;
-
- return fopen($path . $filename, $rw);
- }
-
- /**
- * Create a sanitised filename for the file.
- *
- * @param string $filename
- */
- protected function sanitise_filename($filename)
- {
- // TODO : Writeme
-
- return $filename;
- }
-
- /**
- * Save a key
- *
- * @param string $key
- * @param string $data
- * @return boolean
- */
- public function save($key, $data)
- {
- $f = $this->create_file($this->sanitise_filename($key), "wb");
- if ($f)
- {
- $result = fwrite($f, $data);
- fclose($f);
-
- return $result;
- }
-
- return false;
- }
-
- /**
- * Load a key
- *
- * @param string $key
- * @param int $offset
- * @param int $limit
- * @return string
- */
- public function load($key, $offset = 0, $limit = null)
- {
- $f = $this->create_file($this->sanitise_filename($key));
- if ($f)
- {
- fseek($f, $offset);
- $data = stream_get_contents($f, $limit, $offset);
- fclose($f);
-
- return $data;
+ return $url;
+}
+
+/**
+ * Regenerates the simple cache.
+ *
+ * @warning This does not invalidate the cache, but actively rebuilds it.
+ *
+ * @param string $viewtype Optional viewtype to regenerate. Defaults to all valid viewtypes.
+ *
+ * @return void
+ * @see elgg_register_simplecache_view()
+ * @since 1.8.0
+ */
+function elgg_regenerate_simplecache($viewtype = NULL) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->views->simplecache) || !is_array($CONFIG->views->simplecache)) {
+ return;
+ }
+
+ $lastcached = time();
+
+ // @todo elgg_view() checks if the page set is done (isset($CONFIG->pagesetupdone)) and
+ // triggers an event if it's not. Calling elgg_view() here breaks submenus
+ // (at least) because the page setup hook is called before any
+ // contexts can be correctly set (since this is called before page_handler()).
+ // To avoid this, lie about $CONFIG->pagehandlerdone to force
+ // the trigger correctly when the first view is actually being output.
+ $CONFIG->pagesetupdone = TRUE;
+
+ if (!file_exists($CONFIG->dataroot . 'views_simplecache')) {
+ mkdir($CONFIG->dataroot . 'views_simplecache');
+ }
+
+ if (isset($viewtype)) {
+ $viewtypes = array($viewtype);
+ } else {
+ $viewtypes = $CONFIG->view_types;
+ }
+
+ $original_viewtype = elgg_get_viewtype();
+
+ // disable error reporting so we don't cache problems
+ $old_debug = elgg_get_config('debug');
+ elgg_set_config('debug', null);
+
+ foreach ($viewtypes as $viewtype) {
+ elgg_set_viewtype($viewtype);
+ foreach ($CONFIG->views->simplecache as $view) {
+ $viewcontents = elgg_view($view);
+ $viewname = md5(elgg_get_viewtype() . $view);
+ if ($handle = fopen($CONFIG->dataroot . 'views_simplecache/' . $viewname, 'w')) {
+ fwrite($handle, $viewcontents);
+ fclose($handle);
}
-
- return false;
- }
-
- /**
- * Invalidate a given key.
- *
- * @param string $key
- * @return bool
- */
- public function delete($key)
- {
- $dir = $this->get_variable("cache_path");
-
- return unlink($dir.$f);
}
-
- public function clear()
- {
- // TODO : writeme
- }
-
- public function __destruct()
- {
- // TODO: Check size and age, clean up accordingly
- $size = 0;
- $dir = $this->get_variable("cache_path");
-
- // Short circuit if both size and age are unlimited
- if (($this->get_variable("max_age")==0) && ($this->get_variable("max_size")==0))
- return;
-
- $exclude = array(".","..");
-
- $files = scandir($dir);
- if (!$files) throw new IOException(sprintf(elgg_echo('IOException:NotDirectory'), $dir));
-
- // Perform cleanup
- foreach ($files as $f)
- {
- if (!in_array($f, $exclude))
- {
- $stat = stat($dir.$f);
-
- // Add size
- $size .= $stat['size'];
-
- // Is this older than my maximum date?
- if (($this->get_variable("max_age")>0) && (time() - $stat['mtime'] > $this->get_variable("max_age")))
- unlink($dir.$f);
-
-
-
- // TODO: Size
-
+
+ datalist_set("simplecache_lastupdate_$viewtype", $lastcached);
+ datalist_set("simplecache_lastcached_$viewtype", $lastcached);
+ }
+
+ elgg_set_config('debug', $old_debug);
+ elgg_set_viewtype($original_viewtype);
+
+ // needs to be set for links in html head
+ $CONFIG->lastcache = $lastcached;
+
+ unset($CONFIG->pagesetupdone);
+}
+
+/**
+ * Is simple cache enabled
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_is_simplecache_enabled() {
+ if (elgg_get_config('simplecache_enabled')) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Enables the simple cache.
+ *
+ * @access private
+ * @see elgg_register_simplecache_view()
+ * @return void
+ * @since 1.8.0
+ */
+function elgg_enable_simplecache() {
+ global $CONFIG;
+
+ datalist_set('simplecache_enabled', 1);
+ $CONFIG->simplecache_enabled = 1;
+ elgg_regenerate_simplecache();
+}
+
+/**
+ * Disables the simple cache.
+ *
+ * @warning Simplecache is also purged when disabled.
+ *
+ * @access private
+ * @see elgg_register_simplecache_view()
+ * @return void
+ * @since 1.8.0
+ */
+function elgg_disable_simplecache() {
+ global $CONFIG;
+ if ($CONFIG->simplecache_enabled) {
+ datalist_set('simplecache_enabled', 0);
+ $CONFIG->simplecache_enabled = 0;
+
+ // purge simple cache
+ if ($handle = opendir($CONFIG->dataroot . 'views_simplecache')) {
+ while (false !== ($file = readdir($handle))) {
+ if ($file != "." && $file != "..") {
+ unlink($CONFIG->dataroot . 'views_simplecache/' . $file);
}
}
+ closedir($handle);
}
}
+}
+
+/**
+ * Deletes all cached views in the simplecache and sets the lastcache and
+ * lastupdate time to 0 for every valid viewtype.
+ *
+ * @return bool
+ * @since 1.7.4
+ */
+function elgg_invalidate_simplecache() {
+ global $CONFIG;
+
+ if (!isset($CONFIG->views->simplecache) || !is_array($CONFIG->views->simplecache)) {
+ return false;
+ }
+
+ $handle = opendir($CONFIG->dataroot . 'views_simplecache');
+
+ if (!$handle) {
+ return false;
+ }
+
+ // remove files.
+ $return = true;
+ while (false !== ($file = readdir($handle))) {
+ if ($file != "." && $file != "..") {
+ $return &= unlink($CONFIG->dataroot . 'views_simplecache/' . $file);
+ }
+ }
+ closedir($handle);
+
+ // reset cache times
+ $viewtypes = $CONFIG->view_types;
+
+ if (!is_array($viewtypes)) {
+ return false;
+ }
+
+ foreach ($viewtypes as $viewtype) {
+ $return &= datalist_set("simplecache_lastupdate_$viewtype", 0);
+ $return &= datalist_set("simplecache_lastcached_$viewtype", 0);
+ }
+
+ return $return;
+}
+
+/**
+ * @see elgg_reset_system_cache()
+ * @access private
+ */
+function _elgg_load_cache() {
+ global $CONFIG;
+
+ $CONFIG->system_cache_loaded = false;
+
+ $CONFIG->views = new stdClass();
+ $data = elgg_load_system_cache('view_locations');
+ if (!is_string($data)) {
+ return;
+ }
+ $CONFIG->views->locations = unserialize($data);
-
- /**
- * A simple function that selects the default memory caching engine.
- *
- * This function provides a central way to get a cache for storing local variables.
- *
- * TODO: Do this better & allow plugin overrides.
- *
- * @param string $namespace Define which memory space to use.
- */
- function select_default_memcache($namespace = "default")
- {
- global $CONFIG;
- // TODO : hook out to the world ? (can't if using as object cache)
-
- // Try and see if memcache is present & enabled
- if (is_memcache_available())
- return new ElggMemcache($namespace);
-
- return new ElggStaticVariableCache($namespace);
+ $data = elgg_load_system_cache('view_types');
+ if (!is_string($data)) {
+ return;
+ }
+ $CONFIG->view_types = unserialize($data);
+
+ $CONFIG->system_cache_loaded = true;
+}
+
+/**
+ * @access private
+ */
+function _elgg_cache_init() {
+ global $CONFIG;
+
+ $viewtype = elgg_get_viewtype();
+
+ // Regenerate the simple cache if expired.
+ // Don't do it on upgrade because upgrade does it itself.
+ // @todo - move into function and perhaps run off init system event
+ if (!defined('UPGRADING')) {
+ $lastupdate = datalist_get("simplecache_lastupdate_$viewtype");
+ $lastcached = datalist_get("simplecache_lastcached_$viewtype");
+ if ($lastupdate == 0 || $lastcached < $lastupdate) {
+ elgg_regenerate_simplecache($viewtype);
+ $lastcached = datalist_get("simplecache_lastcached_$viewtype");
+ }
+ $CONFIG->lastcache = $lastcached;
}
-?> \ No newline at end of file
+
+ // cache system data if enabled and not loaded
+ if ($CONFIG->system_cache_enabled && !$CONFIG->system_cache_loaded) {
+ elgg_save_system_cache('view_locations', serialize($CONFIG->views->locations));
+ elgg_save_system_cache('view_types', serialize($CONFIG->view_types));
+ }
+
+ if ($CONFIG->system_cache_enabled && !$CONFIG->i18n_loaded_from_cache) {
+ reload_all_translations();
+ foreach ($CONFIG->translations as $lang => $map) {
+ elgg_save_system_cache("$lang.lang", serialize($map));
+ }
+ }
+}
+
+elgg_register_event_handler('ready', 'system', '_elgg_cache_init');