# HG changeset patch # User Dan # Date 1215468750 14400 # Node ID 935f3799b654105a194e8d12ec4e78e143ee9180 # Parent d2d4e40ecd29e663bea9ba62ded6affbbb79329a First stab at cache management backend. Everything seems to have been tested and working so far, but a number of things require a more specialized cache and can't go through the framework (e.g. user ranks which use references to map usernames to user IDs) diff -r d2d4e40ecd29 -r 935f3799b654 includes/cache.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/cache.php Mon Jul 07 18:12:30 2008 -0400 @@ -0,0 +1,131 @@ + + * @license GNU General Public License + */ + +class CacheManager +{ + /** + * Fetch a cached piece of data. + * @param string Cache ID. The timestamp is checked automatically. + */ + + public function fetch($cache_id) + { + if ( !preg_match('/^[a-z0-9_]+$/', $cache_id) ) + { + throw new Exception('Cache ID must be letters, numbers, and underscores.'); + } + $cache_file = ENANO_ROOT . "/cache/cache_$cache_id.php"; + if ( file_exists($cache_file) ) + { + require($cache_file); + if ( isset($_cache_data) && isset($_cache_ttl) && isset($_cache_timestamp) ) + { + $cache_expire = $_cache_timestamp + ( 60 * $_cache_ttl); + if ( $cache_expire >= time() || $_cache_ttl === -1 ) + { + return $_cache_data; + } + } + } + return false; + } + + /** + * Stores an array by var_export()ing it and saving it to disk. + * @param string Cache ID - human readable name for this store (letters, numbers, underscores) + * @param array Data to store + * @param int TTL for the cached array, in minutes. Defaults to 20. If set to -1, caches indefinitely. + * @return bool True on success, false on failure + */ + + public function store($cache_id, $data, $ttl = 20) + { + if ( getConfig('cache_thumbs') != '1' ) + { + // caching disabled + return false; + } + if ( !preg_match('/^[a-z0-9_]+$/', $cache_id) ) + { + throw new Exception('Cache ID must be letters, numbers, and underscores.'); + } + if ( !is_int($ttl) ) + { + throw new Exception('TTL must be an integer'); + } + + $cache_file = ENANO_ROOT . "/cache/cache_$cache_id.php"; + if ( file_exists($cache_file) ) + { + @unlink($cache_file); + } + $fh = @fopen($cache_file, 'w'); + if ( !$fh ) + { + throw new Exception('Failed to open file for writing.'); + } + $exported = Language::var_export_string($data); + $now = time(); + $content = <<lang_id}.php"; // Attempt to load the strings from a cache file - if ( file_exists($lang_file) && $allow_cache ) + $loaded = false; + + if ( $allow_cache ) { - // Yay! found it - $this->load_cache_file($lang_file); + // Load the cache manager + global $cache; + + if ( $cached = $cache->fetch("lang_{$this->lang_id}") ) + { + $this->merge($cached); + $loaded = true; + } } - else + if ( !$loaded ) { // No cache file - select and retrieve from the database $q = $db->sql_unbuffered_query("SELECT string_category, string_name, string_content FROM " . table_prefix . "language_strings WHERE lang_id = {$this->lang_id};"); @@ -150,6 +157,7 @@ while ( $row = $db->fetchrow() ); // all done fetching $this->merge($strings); + $this->regen_caches(false); } else { @@ -528,41 +536,24 @@ * Refetches the strings and writes out the cache file. */ - function regen_caches() + function regen_caches($refetch = true) { global $db, $session, $paths, $template, $plugins; // Common objects - $lang_file = ENANO_ROOT . "/cache/lang_{$this->lang_id}.php"; - // Refresh the strings in RAM to the latest copies in the DB - $this->fetch(false); + if ( $refetch ) + $this->fetch(false); - $handle = @fopen($lang_file, 'w'); - if ( !$handle ) - // Couldn't open the file. Silently fail and let the strings come from the database. - return false; - - // The file's open, that means we should be good. - fwrite($handle, 'var_export_string($this->strings); - if ( empty($exported) ) - // Ehh, that's not good - $db->_die('lang.php - var_export_string() failed'); - - fwrite($handle, $exported . '; ?>'); + // Store it + $cache->store("lang_{$this->lang_id}", $this->strings, -1); // Update timestamp in database $q = $db->sql_query('UPDATE ' . table_prefix . 'language SET last_changed = ' . time() . ' WHERE lang_id = ' . $this->lang_id . ';'); if ( !$q ) $db->_die('lang.php - updating timestamp on language'); - - // Done =) - fclose($handle); } /** diff -r d2d4e40ecd29 -r 935f3799b654 includes/paths.php --- a/includes/paths.php Mon Jul 07 02:50:17 2008 -0400 +++ b/includes/paths.php Mon Jul 07 18:12:30 2008 -0400 @@ -157,6 +157,7 @@ { global $db, $session, $paths, $template, $plugins; // Common objects global $lang; + global $cache; $code = $plugins->setHook('paths_init_before'); foreach ( $code as $cmd ) @@ -164,16 +165,9 @@ eval($cmd); } - $cache_enable = ( getConfig('cache_thumbs') == '1' ); - $cache_file = ENANO_ROOT . '/cache/cache_page_meta.php'; - $cache_fresh = ( file_exists($cache_file) ) ? filemtime($cache_file) + 1800 >= time() : false; - if ( $cache_enable && $cache_fresh ) + if ( $page_cache = $cache->fetch('page_meta') ) { - require($cache_file); - if ( isset($page_cache) && is_array($page_cache) ) - { - $this->pages = array_merge($this->pages, $page_cache); - } + $this->pages = array_merge($this->pages, $page_cache); } else { @@ -192,10 +186,7 @@ $this->pages[] =& $this->pages[$r['urlname']]; } - if ( $cache_enable ) - { - $this->update_metadata_cache(); - } + $this->update_metadata_cache(); } $db->free_result(); if ( defined('ENANO_INTERFACE_INDEX') || defined('ENANO_INTERFACE_AJAX') || defined('IN_ENANO_UPGRADE') ) @@ -585,36 +576,27 @@ { global $db, $session, $paths, $template, $plugins; // Common objects - $cache_output = <<sql_unbuffered_query('SELECT name,urlname,namespace,special,visible,comments_on,protected,delvotes,' . "\n" . ' delvote_ips,wiki_mode,password FROM '.table_prefix.'pages ORDER BY name;'); if ( !$e ) $db->_die(); + $md_array = array(); + while ( $row = $db->fetchrow() ) { $row = $this->calculate_metadata_from_row($row); - $key = addslashes($row['urlname']); - $row = substr(preg_replace('/^/m', ' ', Language::var_export_string($row)), 2); - $cache_output .= "\n '$key' => $row,"; + $md_array[$row['urlname']] = $row; } - $cache_output .= "\n);\n"; - $cache_file = ENANO_ROOT . '/cache/cache_page_meta.php'; + // import cache functions + global $cache; - $fh = @fopen($cache_file, 'w'); - if ( !$fh ) - return false; - fwrite($fh, $cache_output); - fclose($fh); + // store data (TTL 20 minutes) + $cache->store('page_meta', $md_array, 20); return true; } diff -r d2d4e40ecd29 -r 935f3799b654 includes/plugins.php --- a/includes/plugins.php Mon Jul 07 02:50:17 2008 -0400 +++ b/includes/plugins.php Mon Jul 07 18:12:30 2008 -0400 @@ -446,7 +446,6 @@ $this->update_plugins_cache($plugin_info); $GLOBALS['plugins_cache'] = $plugin_info; - @define('ENANO_PLUGINS_CACHE_LOADED', true); } /** @@ -457,26 +456,8 @@ function update_plugins_cache($plugin_info) { - $plugin_info = Language::var_export_string($plugin_info); - - $file = ENANO_ROOT . '/cache/cache_plugins.php'; - $fh = @fopen($file, 'w'); - if ( !$fh ) - // can't open for writing - return false; - - $contents = <<store('plugins', $plugin_info, -1); } /** @@ -485,9 +466,10 @@ function load_plugins_cache() { - if ( file_exists(ENANO_ROOT . '/cache/cache_plugins.php') && !defined('ENANO_PLUGINS_CACHE_LOADED') ) + global $cache; + if ( $data = $cache->fetch('plugins') ) { - require(ENANO_ROOT . '/cache/cache_plugins.php'); + $GLOBALS['plugins_cache'] = $data; } } diff -r d2d4e40ecd29 -r 935f3799b654 includes/template.php --- a/includes/template.php Mon Jul 07 02:50:17 2008 -0400 +++ b/includes/template.php Mon Jul 07 18:12:30 2008 -0400 @@ -2014,26 +2014,18 @@ function fetch_sidebar() { global $db, $session, $paths, $template, $plugins; // Common objects + global $cache; $left = ''; $right = ''; // check the cache - $cache_enable = getConfig('cache_thumbs') == '1' && !$session->user_logged_in; - $cache_file = ENANO_ROOT . "/cache/cache_anon_sidebar.php"; - $cache_fresh = intval(getConfig('sidebar_anon_cache_time') + 600) >= time(); - if ( $cache_enable && $cache_fresh ) + if ( !$session->user_logged_in && $data = $cache->fetch('anon_sidebar') ) { - @include($cache_file); - if ( isset($sidebar_cache) ) + if ( @$data['_theme_'] === $this->theme ) { - // we loaded the cache! - foreach ( $sidebar_cache as $i => $_ ) - { - $block =& $sidebar_cache[$i]; - $block = str_replace('$USERNAME$', $session->username, $block); - } - return $sidebar_cache; + unset($data['_theme_']); + return $data; } } @@ -2079,7 +2071,7 @@ break; case BLOCK_PLUGIN: $parser = $this->makeParserText('{CONTENT}'); - $c = (gettype($this->fetch_block($row['block_content'])) == 'string') ? $this->fetch_block($row['block_content']) : /* This used to say "can't find plugin block" but I think it's more friendly to just silently hide it. */ ''; + $c = '' . (gettype($this->fetch_block($row['block_content'])) == 'string') ? $this->fetch_block($row['block_content']) : /* This used to say "can't find plugin block" but I think it's more friendly to just silently hide it. */ ''; break; } // is there a {restrict} or {hideif} block? @@ -2125,26 +2117,14 @@ $min .= $bottom; } $return = Array($left, $right, $min); - if ( $cache_enable ) + if ( getConfig('cache_thumbs') == '1' && !$session->user_logged_in ) { - $cachestore = Language::var_export_string($return); + $cachestore = enano_json_encode($return); $cachestore = str_replace($session->username, '$USERNAME$', $cachestore); - $cachestore = <<page, '$PAGEID$', $cachestore); + $cachestore = enano_json_decode($cachestore); + $cachestore['_theme_'] = $this->theme; + $cache->store('anon_sidebar', $cachestore, 10); } return $return; } diff -r d2d4e40ecd29 -r 935f3799b654 plugins/SpecialAdmin.php --- a/plugins/SpecialAdmin.php Mon Jul 07 02:50:17 2008 -0400 +++ b/plugins/SpecialAdmin.php Mon Jul 07 18:12:30 2008 -0400 @@ -2166,6 +2166,7 @@ { global $db, $session, $paths, $template, $plugins; // Common objects global $lang; + global $cache; if($session->auth_level < USER_LEVEL_ADMIN) { @@ -2227,6 +2228,7 @@ exit; } } + $cache->purge('anon_sidebar'); echo '
' . $lang->get('sbedit_msg_order_update_success') . '
'; } elseif(isset($_POST['create'])) @@ -2279,7 +2281,8 @@ $template->footer(); exit; } - + + $cache->purge('anon_sidebar'); echo '
' . $lang->get('sbedit_msg_item_added') . '
'; } @@ -2385,7 +2388,7 @@ plugin_blocks as $k => $c) { - echo ''; + echo ''; } ?> @@ -2414,6 +2417,7 @@ return; break; case 'move': + $cache->purge('anon_sidebar'); if( !isset($_GET['side']) || ( isset($_GET['side']) && !preg_match('#^([0-9]+)$#', $_GET['side']) ) ) { echo '
$_GET[\'side\'] contained an SQL injection attempt
'; @@ -2436,6 +2440,7 @@ $template->footer(); exit; } + $cache->purge('anon_sidebar'); if(isset($_GET['ajax'])) { ob_end_clean(); @@ -2493,6 +2498,8 @@ ob_end_clean(); $r = $db->fetchrow(); $db->free_result(); + $cache->purge('anon_sidebar'); + if($r['block_type'] == BLOCK_PLUGIN) die('HOUSTON_WE_HAVE_A_PLUGIN'); die($r['block_content']); break; @@ -2555,6 +2562,7 @@ break; } $c = preg_replace('/\{(restrict|hideif) ([a-z0-9_\(\)\|&! ]+)\}/', '', $c); + $cache->purge('anon_sidebar'); die('var status = \'GOOD\'; var content = unescape(\''.hexencode($c).'\');'); break; } diff -r d2d4e40ecd29 -r 935f3799b654 plugins/SpecialPageFuncs.php --- a/plugins/SpecialPageFuncs.php Mon Jul 07 02:50:17 2008 -0400 +++ b/plugins/SpecialPageFuncs.php Mon Jul 07 18:12:30 2008 -0400 @@ -836,7 +836,7 @@ } $sb_html = $cloud->make_html('small', 'justify') . '
' . $lang->get('pagetools_tagcloud_sidebar_btn_larger') . ''; } - $template->sidebar_widget($lang->get('pagetools_tagcloud_sidebar_title'), "
$sb_html
"); + $template->sidebar_widget('pagetools_tagcloud_sidebar_title', "
$sb_html
"); } $plugins->attachHook('compile_template', 'sidebar_add_tag_cloud();');