X-Git-Url: https://git.mxchange.org/?p=mailer.git;a=blobdiff_plain;f=inc%2Flibs%2Fcache_functions.php;h=a34313d1eb37053b5b06f6e32856b185d86909ad;hp=711dc5955401120849bdca078293477bcb5edcff;hb=f928ad2bed60fa256d0641eaf6d2c027a2944688;hpb=df8cb42d2d579310d1ccfb562b8f30eafdb2618e diff --git a/inc/libs/cache_functions.php b/inc/libs/cache_functions.php index 711dc59554..a34313d1eb 100644 --- a/inc/libs/cache_functions.php +++ b/inc/libs/cache_functions.php @@ -10,7 +10,12 @@ * -------------------------------------------------------------------- * * Kurzbeschreibung : Funktionen fuer die admins-Erweiterung * * -------------------------------------------------------------------- * - * * + * $Revision:: $ * + * $Date:: $ * + * $Tag:: 0.2.1-FINAL $ * + * $Author:: $ * + * Needs to be in all Files and every File needs "svn propset * + * svn:keywords Date Revision" (autoprobset!) at least!!!!!! * * -------------------------------------------------------------------- * * Copyright (c) 2003 - 2008 by Roland Haeder * * For more information visit: http://www.mxchange.org * @@ -32,337 +37,477 @@ ************************************************************************/ // Some security stuff... -if (ereg(basename(__FILE__), $_SERVER['PHP_SELF'])) -{ - $INC = substr(dirname(__FILE__), 0, strpos(dirname(__FILE__), "/inc") + 4) . "/security.php"; +if (!defined('__SECURITY')) { + $INC = substr(dirname(__FILE__), 0, strpos(dirname(__FILE__), '/inc') + 4) . '/security.php'; require($INC); } + // Caching class -class mxchange_cache -{ +class CacheSystem { // Define variables - var $update_interval = 0; - var $ret = "init"; - var $cache_path = ""; - var $cache_inc = ""; - var $cache_ctime = 0; - var $cache_pointer = false; + var $ret = 'init'; + var $path = ''; + var $inc = ''; + var $fqfn = ''; + var $pointer = false; + var $data = array(); + var $version = array(); + var $name = ''; + var $rebuilt = array(); + var $extension = '.cache'; + var $statusDone = 'done'; // Constructor - function mxchange_cache($interval, $path, $tested) { - // Remember interval in class - $this->update_interval=$interval; + function CacheSystem ($interval, $path, $tested) { + // Failed is the default + $this->ret = 'failed'; // Remeber path - $this->cache_path=$path; + $this->path = $path; // Check if path exists - if ((file_exists($path)) && (is_dir($path)) && (!$tested)) - { + if ((isDirectory($path)) && ($tested === false)) { + // Make FQFN for dummy file + $fqfn = $path . 'dummy.tmp'; + // Check if we can create a file inside the path - @touch($path."dummy.tmp", 'w'); - if (file_exists($path."dummy.tmp")) { + touch($fqfn, 'w'); + + // Is the file there? + if (isFileReadable($fqfn)) { // Yes, we can do. So let's remove it - @unlink($path."dummy.tmp"); + removeFile($fqfn); // Is there a .htaccess file? - if (file_exists($path.".htaccess")) { + if (isFileReadable($path . '.htaccess')) { // Update database that we have tested it - UPDATE_CONFIG("cache_tested", 1); + updateConfiguration('cache_tested', 1); // All done! - return "done"; + $this->ret = $this->statusDone; } else { // Stop! Set a .htaccess file first - $this->ret="htaccess"; - return "htaccess"; + $this->ret = 'htaccess'; } } } elseif ($tested) { // System already tested - $this->ret="done"; - return "done"; + $this->ret = $this->statusDone; } - - // Something goes wrong here! - $this->ret="failed"; - return "failed"; } - function cache_file($file, $ignore_ctime=false) - { - global $INC; - // Construct FQFN (full qualified file name) - $inc = $this->cache_path.$file.".cache"; + // Checks validity of cache file and if content is given + function loadCacheFile ($cacheName, $forceContent = false) { + // Remember cache file + $this->name = $cacheName; - // Rember it + filename in class - $this->cache_inc = $inc; + // Construct include filename for loadIncludeOnce() call + $this->inc = $this->path . $cacheName . $this->extension; - // Check if file exists - $status = (file_exists($inc) && (is_readable($inc)) && (is_writeable($inc))); - if ($status) - { - // Yes, it does. So let's get it's last changed date/time - $ctime = filectime($inc); - } - else - { - // No, it doesn't. Zero date/time - $ctime = "0"; - } + // Construct FQFN (full qualified file name) + $this->fqfn = constant('PATH') . $this->inc; - // Remember change date/time in class - $this->cache_ctime = $ctime; + // Check if file exists and if version matches + $status = ($this->isCacheReadable() && (is_writeable($this->fqfn)) && ($this->extensionVersionMatches('cache'))); - // Is the cache file outdated? - if (((time() - $ctime) >= $this->update_interval) && (!$ignore_ctime)) - { - // Ok, we need an update! - $status = false; - } + // Return status return $status; } - function cache_init($array) - { + // Initializes the cache file + function init () { // This will destory an existing cache file! - if ($this->ret == "done") - { + if ($this->ret == $this->statusDone) { // Create file - if (file_exists($this->cache_inc)) @chmod($this->cache_inc, 0666); - $fp = @fopen($this->cache_inc, 'w') or mxchange_die("Cannot write to cache ".$this->cache_inc." !"); + if ($this->isCacheReadable()) changeMode($this->fqfn, 0666); + $this->pointer = fopen($this->fqfn, 'w') or app_die(__METHOD__, __LINE__, "Cannot write to cache ".$this->fqfn." !"); - // Begin of cache file - fwrite($fp, "\$ARRAY = \"".$array."\";\n\n"); + // Add open PHP tag + fwrite($this->pointer, "cache_pointer = $fp; - } - else - { + // Add default depency + $this->storeExtensionVersion('cache'); + } else { // Cannot create file - ADD_FATAL(__FILE__."(".__LINE__."): ".CACHE_PROBLEMS_DETECTED); + addFatalMessage(__METHOD__, __LINE__, "(".__LINE__."): ".getMessage('CACHE_PROBLEMS_DETECTED')); } } - function add_row ($data) { - global $cacheArray; - - if (is_resource($this->cache_pointer)) { + function addRow ($data) { + // Is the pointe rvalid? + if (is_resource($this->pointer)) { // Write every array element to cache file foreach ($data as $k => $v) { // Write global cache array for immediate access - if ((substr($k, 0, 4) == "ext_") && (isset($data['ext_name'])) && (isset($data['ext_id']))) { - if ($k != "ext_name") { - $cacheArray['extensions'][$k][$data['ext_name']] = $v; + if ((substr($k, 0, 4) == 'ext_') && (isset($data['ext_name'])) && (isset($data['ext_id']))) { + if ($k != 'ext_name') { + $GLOBALS['cache_array']['extensions'][$k][$data['ext_name']] = $v; } else { - $cacheArray['extensions'][$k][$data['ext_id']] = $v; + $GLOBALS['cache_array']['extensions'][$k][$data['ext_id']] = $v; } - if (($k == "ext_keep") && ($v == "Y")) { - $cacheArray['active_extensions'][$data['ext_name']] = $v; + if (($k == 'ext_keep') && ($v == 'Y')) { + $GLOBALS['cache_array']['active_extensions'][$data['ext_name']] = $v; } // END - if - } // END - if + } elseif (is_array($v)) { + // Serialize and BASE64-encode the array + $v = base64_encode(serialize($v)); + } // Write cache line to file - @fwrite($this->cache_pointer, "\$data['".$k."'][] = \"".$v."\";\n"); + fwrite($this->pointer, $this->rewriteEntry($k, $v)); } } else { // Cannot create file - ADD_FATAL(__FILE__."(".__LINE__."): ".CACHE_PROBLEMS_DETECTED); + addFatalMessage(__METHOD__, __LINE__, "(".__LINE__."): ".getMessage('CACHE_PROBLEMS_DETECTED')); } } - function cache_close() - { + function finalize () { // Quit function when no pointer is set - if (empty($this->cache_pointer)) return; - if ($this->cache_pointer) - { + if (is_resource($this->pointer)) { + // Write footer + fwrite($this->pointer, "?>\n"); + // Close file add destroy handler - @fclose($this->cache_pointer); + fclose($this->pointer); // Set rights - if (file_exists($this->cache_inc)) @chmod($this->cache_inc, 0666); + if ($this->isCacheReadable()) changeMode($this->fqfn, 0666); // Remove pointer - unset($this->cache_pointer); - } - else - { - // Cannot create file - ADD_FATAL(__FILE__."(".__LINE__."): ".CACHE_PROBLEMS_DETECTED); - } + $this->pointer = false; + //* DEBUG: */ print __METHOD__."(".__LINE__."): {$this->name} - FINALIZED!
\n"; + } // END - if } - function cache_load() - { - if ((file_exists($this->cache_inc)) && (is_readable($this->cache_inc))) - { + function getArrayFromCache () { + // Is the cache already loaded? + if (isset($this->data[$this->name])) { + // Return it's content! + return $this->data[$this->name]; + } // END - if + + // Is the cache file there? + if ($this->isCacheReadable()) { // Prepare temporary array $data = array(); + $cache_version = null; // Load cache file - $cache = implode("", file($this->cache_inc)); + require($this->inc); - // Execute cache file - eval($cache); + // Is there an array? if (is_array($data)) { + // Cache data + $this->data[$this->name] = $data; + + // Cache version found? + if ((is_array($cache_version)) && (count($cache_version) > 0)) { + // Remember it as well... + $this->version[$this->name] = $cache_version; + } else { + // Invalid cache so destroy it + $this->destroyCacheFile(); + + // Clear cached data + $this->data[$this->name] = array(); + } + // Return cache - return $data; + return $this->data[$this->name]; } else { // Cache problem detected! - $this->cache_destroy(); + $this->destroyCacheFile(); } - } - else - { + } else { // Cache file not found or not readable - ADD_FATAL(__FILE__."(".__LINE__."): ".CACHE_CANNOT_LOAD_1.$this->cache_inc.CACHE_CANNOT_LOAD_2); + addFatalMessage(__METHOD__, __LINE__, "(".__LINE__."): ".CACHE_CANNOT_LOAD_1.$this->fqfn.CACHE_CANNOT_LOAD_2); } } - function cache_destroy() - { - if (file_exists($this->cache_inc)) - { + // Destroy an existing cache file + function destroyCacheFile ($removeArray = false, $force = false) { + // Only run in regular output mode + if ((getOutputMode() != 0) && ($force === false)) { + // Debug message if allowed + if (isDebugModeEnabled()) { + // Debug message + debug_report_bug('Not removing cache ' . $this->name . ' in output_mode=' . getOutputMode()); + } // END - if + + // Abort here + return; + } // END - if + + // Is the cache file there? + if ((!isset($this->rebuilt[$this->name])) && ($this->isCacheReadable())) { + // Close cache + $this->finalize(); + + // Debug-mode enabled? + if (isDebugModeEnabled()) { + // Log removal of cache + DEBUG_LOG(__METHOD__, __LINE__, 'removing cache: ' . $this->name); + } // END - if + // Remove cache file from system - @unlink($this->cache_inc); - if (!file_exists($this->cache_inc)) - { - // Close cache automatically (we don't need it anymore!) - $this->cache_close(); - } - else - { + removeFile($this->fqfn); + + // Shall we remove the array from memory? + if ($removeArray === true) { + // Debug message if allowed + if (isDebugModeEnabled()) { + // Debug message + DEBUG_LOG(__METHOD__, __LINE__, 'removing array!'); + } // END - if + + // Remove it from memory + unset($GLOBALS['cache_array'][$this->name]); + } // END - if + + // Is the file there? + if (!$this->isCacheReadable()) { + // The cache does no longer exist so kill the content + unset($this->data[$this->name]); + unset($this->version[$this->name]); + $this->rebuilt[$this->name] = true; + } else { // Not removed! - ADD_FATAL(__FILE__."(".__LINE__."): ".CACHE_CANNOT_UNLINK_1.$this->cache_inc.CACHE_CANNOT_UNLINK_2); + addFatalMessage(__METHOD__, __LINE__, "(".__LINE__."): ".CACHE_CANNOT_UNLINK_1.$this->fqfn.CACHE_CANNOT_UNLINK_2); } - } - else - { - // Does not exist! - ADD_FATAL(__FILE__."(".__LINE__."): ".CACHE_CANNOT_UNLINK_1.$this->cache_inc.CACHE_CANNOT_UNLINK_2); - } + } // END - if } - function cache_remove($search, $data, $array) - { - global $ARRAY; - if ((file_exists($this->cache_inc)) && (is_writeable($this->cache_inc))) - { + // Unused method: + function removeEntry ($search, $data, $array) { + if (($this->isCacheReadable()) && (is_writeable($this->fqfn))) { // Load cache into dummy array - $dummy = $this->cache_load(); + $dummy = $this->getArrayFromCache(); // Search for key in array $key = array_search($data, $dummy[$search]); - if (!empty($key)) - { + if (!empty($key)) { // Key (hopefully) found? - foreach ($array as $a) - { + foreach ($array as $a) { // So we can remove all elements as requested unset($dummy[$a][$key]); - } + } // END - foreach // Flush array to cache file - $fp = fopen($this->cache_inc, 'w'); - fwrite($fp, "\$ARRAY = \"".$ARRAY."\";\n"); - foreach ($dummy as $k=>$v) - { - if (is_array($v)) - { - // Multi line(s) found - $LINE = ""; - foreach($v as $k2=>$v2) - { - // Put every array element in a row... - $LINE .= "\$data['".$k."'][] = \"".$v2."\";\n"; - } - } - else - { - // Single line found - $LINE = "\$data['".$k."'] = \"".$v."\";\n"; - } + $this->init(); - // Write line(s) - fwrite($fp, $LINE); - } + // Write array out + $this->writeArray($dummy); // Close cache file - fclose($fp); + $this->finalize(); } - } - else - { + } else { // Cannot write to cache! - ADD_FATAL(__FILE__."(".__LINE__."): ".CACHE_PROBLEMS_DETECTED); + addFatalMessage(__METHOD__, __LINE__, "(".__LINE__."): ".getMessage('CACHE_PROBLEMS_DETECTED')); + } + } + + function writeArray ($array) { + if (is_resource($this->pointer)) { + foreach ($array as $k => $v) { + if (is_array($v)) { + // Multi line(s) found + $LINE = ''; + foreach($v as $k2 => $v2) { + // Put every array element in a row... + $LINE .= $this->rewriteEntry($k, $v2); + } + } else { + // Single line found + $LINE = $this->rewriteEntry($k, $v); + } + + // Write line(s) + fwrite($this->pointer, $LINE); + } // END - foreach + } else { + // Cannot write array! + addFatalMessage(__METHOD__, __LINE__, "(".__LINE__."): ".getMessage('CACHE_PROBLEMS_DETECTED')); } } - function cache_replace($search, $replace, $search_key, $array) - { - global $ARRAY; - if ((file_exists($this->cache_inc)) && (is_writeable($this->cache_inc))) - { + // Unused method + function replaceEntry ($search, $replace, $search_key, $array) { + if (($this->isCacheReadable()) && (is_writeable($this->fqfn))) { // Load cache into dummy array - $dummy = $this->cache_load(); + $dummy = $this->getArrayFromCache(); // Check if $dummy is valid (prevents some errors) - if ((is_array($dummy)) && (isset($dummy[$search])) && (is_array($dummy[$search]))) - { + if ((is_array($dummy)) && (isset($dummy[$search])) && (is_array($dummy[$search]))) { // Search for key in array $key_found = array_key_exists($search_key, $dummy[$search]); - if ($key_found == true) - { + if ($key_found == true) { $key = $search_key; // Key (hopefully) found? - foreach ($dummy as $a=>$v) - { + foreach ($dummy as $a => $v) { // So we can update all entries - if ($a == $search) - { + if ($a == $search) { // Update now... $dummy[$a][$search_key] = $replace; - } - } + } // END - if + } // END - foreach // Flush array to cache file - $fp = fopen($this->cache_inc, 'w'); - fwrite($fp, "\$dummy = \"".$ARRAY."\";\n"); - foreach ($dummy as $k=>$v) - { - if (is_array($v)) - { - // Multi line(s) found - $LINE = ""; - foreach($v as $k2=>$v2) - { - // Put every array element in a row... - $LINE .= "\$data['".$k."'][] = \"".$v2."\";\n"; - } - } - else - { - // Single line found - $LINE = "\$data['".$k."'] = \"".$v."\";\n"; - } - - // Write line(s) - fwrite($fp, $LINE); - } + $this->init(); + + // Write array out + $this->writeArray($dummy); // Close cache file - fclose($fp); - } - } - } - else - { + $this->finalize(); + } // END - if + } // END - if + } else { // Cannot write to cache! - ADD_FATAL(__FILE__."(".__LINE__."): ".CACHE_PROBLEMS_DETECTED); + addFatalMessage(__METHOD__, __LINE__, "(".__LINE__."): ".getMessage('CACHE_PROBLEMS_DETECTED')); + } + } + + // Writes the version of given extension to the cache file + function storeExtensionVersion ($ext_name) { + // Valid cache pointer? + if (is_resource($this->pointer)) { + // Get extension version + $ext_ver = GET_EXT_VERSION($ext_name); + + // Write cache line to file + fwrite($this->pointer, "\$cache_version['".$ext_name."'] = \"".$ext_ver."\";\n"); + + // Add the extension version to object (DO NOT REMOVE IT! Endless loop...) + $this->version[$this->name][$ext_name] = $ext_ver; + //* DEBUG: */ print __METHOD__."(".__LINE__."): {$this->name} - {$ext_name}={$ext_ver}
\n"; + } else { + // Cannot create file + addFatalMessage(__METHOD__, __LINE__, "(".__LINE__."): ".getMessage('CACHE_PROBLEMS_DETECTED')); + } + } + + // Checks wether versions from cache and extension matches + function extensionVersionMatches ($ext_name) { + // Load cache (dummy) + $this->getArrayFromCache(); + + // Get extension version + $ext_ver = GET_EXT_VERSION($ext_name); + + // Debug messages + if (isset($this->version[$this->name][$ext_name])) { + //* DEBUG: */ print __METHOD__."(".__LINE__."): cache={$this->name},ext_name={$ext_name} - {$ext_ver}/{$this->version[$this->name][$ext_name]}
\n"; + } else { + // No cache version found! + DEBUG_LOG(__METHOD__, __LINE__, "Cache {$this->name} has missing version entry for extension {$ext_name}!"); + } + + // Compare both + return ((isset($this->version[$this->name][$ext_name])) && ($this->version[$this->name][$ext_name] == $ext_ver)); + } + + // Rewrit the entry so it can be stored in cache file + // @TODO Add support for more types which break in last else-block + function rewriteEntry ($key, $value) { + // Init line + $line = ''; + + // String or non-string? ;-) + if (is_string($value)) { + // String... + $line = "\$data['".$key."'][] = \"".$value."\";\n"; + } elseif (is_null($value)) { + // Null + $line = "\$data['".$key."'][] = null;\n"; + } elseif (is_bool($value)) { + // Boolean value + if ($value === true) { + // True + $line = "\$data['".$key."'][] = true;\n"; + } else { + // False + $line = "\$data['".$key."'][] = false;\n"; + } + } else { + // Non-string + $line = "\$data['".$key."'][] = ".$value.";\n"; } + + // Return line + return $line; + } + + // Getter for cache status + function getStatus () { + return $this->ret; + } + + // Checks wether the current cache file is readable + function isCacheReadable () { + return isIncludeReadable($this->inc); } + +} // END - class + +// Destroy the cache on extension changes +function FILTER_CACHE_DESTROY_ON_EXT_CHANGE ($data) { + // Return the data anyway if there is no cache extension + if (!isCacheInstanceValid()) return $data; + + // Remove cache + if ($GLOBALS['cache_instance']->loadCacheFile('config')) $GLOBALS['cache_instance']->destroyCacheFile(false); + if ($GLOBALS['cache_instance']->loadCacheFile('extensions')) $GLOBALS['cache_instance']->destroyCacheFile(false); + if ($GLOBALS['cache_instance']->loadCacheFile('modreg')) $GLOBALS['cache_instance']->destroyCacheFile(false); + + // Return it + return $data; +} + +// Destroy the cache on changing admin +function FILTER_CACHE_DESTROY_ON_ADMIN_CHANGE () { + // Skip this step if the cache instance is not there + if (!isCacheInstanceValid()) return false; + + // Remove cache + if ($GLOBALS['cache_instance']->loadCacheFile('admins')) $GLOBALS['cache_instance']->destroyCacheFile(false); +} + +// Destroy all cache files +function FILTER_CACHE_DESTROY_ALL () { + // Skip this step if the cache instance is not there + //* DEBUG: */ DEBUG_LOG(__FUNCTION__, __LINE__, 'Called!'); + if (!isCacheInstanceValid()) return false; + + // Remove cache files + if ($GLOBALS['cache_instance']->loadCacheFile('admins')) $GLOBALS['cache_instance']->destroyCacheFile(false); + if ($GLOBALS['cache_instance']->loadCacheFile('admins_acls')) $GLOBALS['cache_instance']->destroyCacheFile(false); + if ($GLOBALS['cache_instance']->loadCacheFile('config')) $GLOBALS['cache_instance']->destroyCacheFile(false); + if ($GLOBALS['cache_instance']->loadCacheFile('extensions')) $GLOBALS['cache_instance']->destroyCacheFile(false); + if ($GLOBALS['cache_instance']->loadCacheFile('modreg')) $GLOBALS['cache_instance']->destroyCacheFile(false); + if ($GLOBALS['cache_instance']->loadCacheFile('refdepths')) $GLOBALS['cache_instance']->destroyCacheFile(false); + if ($GLOBALS['cache_instance']->loadCacheFile('refsystem')) $GLOBALS['cache_instance']->destroyCacheFile(false); + if ($GLOBALS['cache_instance']->loadCacheFile('themes')) $GLOBALS['cache_instance']->destroyCacheFile(false); + if ($GLOBALS['cache_instance']->loadCacheFile('revision')) $GLOBALS['cache_instance']->destroyCacheFile(false); + if ($GLOBALS['cache_instance']->loadCacheFile('filter')) $GLOBALS['cache_instance']->destroyCacheFile(false); + //* DEBUG: */ DEBUG_LOG(__FUNCTION__, __LINE__, 'Done!'); } + +// Filter for purging 'filter' cache +function FILTER_CACHE_DESTROY_FILTER () { + // Skip this step if the cache instance is not there + if ((!isCacheInstanceValid()) || (getConfig('update_filter_usage') == 'N')) return false; + + // Remove cache files + if ($GLOBALS['cache_instance']->loadCacheFile('filter')) $GLOBALS['cache_instance']->destroyCacheFile(false); +} + +// Filter for purging entire admin menu cache +function FILTER_CACHE_PURGE_ADMIN_MENU () { + // Just call the function + cachePurgeAdminMenu(); +} + // ?>