123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- <?php
- /**
- * Pico Cache plugin
- * Name "PicoZCache" is to be loaded as last.
- *
- * Author Maximilian Beck before 2.0, Nepose since 2.0
- * @author Improvements by various authors, gathered by https://github.com/ohnonot (2022)
- * PME20240329 Cache invalidate on changed source
- * @license http://opensource.org/licenses/MIT
- * @version 2.0
- */
- class PicoZCache extends AbstractPicoPlugin
- {
- const API_VERSION=3;
- protected $dependsOn = array();
- private $doCache = true;
- private $FileName;
- private $url;
- protected $enabled = false;
- public function onConfigLoaded(array &$config)
- {
- // ensure cache_dir ends with '/'
- $this->Dir = rtrim($this->getPluginConfig('dir', 'content/zcache/','content/zcache/'),'/').'/';
- $this->Time = $this->getPluginConfig('expires', 0);
- $this->XHTML = $this->getPluginConfig('xhtml_output', false);
- $this->Exclude = $this->getPluginConfig('exclude', null);
- $this->ExcludeRegex = $this->getPluginConfig('exclude_regex', null);
- $this->IgnoreQuery = $this->getPluginConfig('ignore_query', false);
- $this->IgnoreQueryExclude = $this->getPluginConfig('ignore_query_exclude', null);
- $this->Invalidate = $this->getPluginConfig('invalidate', false);
- }
- public function onRequestUrl(&$url)
- {
- $this->url = $url;
- }
- public function onRequestFile(&$file)
- {
- $name = $this->url == "" ? "index" : $this->url;
- //~ echo 'File: '. $file . '<br/>Url: '. $name ;
- // Skip cache for url matching an excluded page
- if ($this->Exclude && in_array($name, $this->Exclude)) {
- $this->doCache = false;
- return;
- }
- // Skip cache for url matching exclude regex
- //PME20240336 Regex needs '/' delimiters.
- if ($this->ExcludeRegex && preg_match('/' . preg_quote($this->ExcludeRegex, '/') . '/', $name)) {
- $this->doCache = false;
- return;
- }
- // Add query to name if so configured
- if ($this->IgnoreQuery === false || in_array($name, $this->IgnoreQueryExclude)) {
- $query = (!empty($_GET)) ? '__'.md5(serialize($_GET)) : null;
- $name = $name . $query;
- }
- //PME20230326 replace every path delimiter with a '+' to prevent cache clashes.
- // Replace any character except numbers and digits with a '-' to form valid file names
- $seq = explode('/', $name);
- $seq = array_map(fn($x): string => preg_replace('/[^A-Za-z0-9_\-]/', '_', $x), $seq);
- $this->FileName = $this->Dir . implode('+', $seq) . '.html';
-
- // If invalidate cached file when source page has changed, delete stale
- // cached copy when source page is more recent
- if (file_exists($this->FileName) && $this->Invalidate && filemtime($file) > filemtime($this->FileName)) {
- // Delete stale cache copy
- // echo 'filemtime(source) = ' . filemtime($file) . '<br/>';
- // echo 'filemtime(cached) = ' . filemtime($this->FileName).'<br/>';
- // echo 'time = '. time().'<br/>';
- // echo 'this->Time = ' . $this->Time.'<br/>';
- unlink($this->FileName);
- }
-
- // If a cached file exists and the cacheTime is not expired, load the file and exit
- if (file_exists($this->FileName)) {
- if ($this->Time > 0) {
- //~ echo time().'<br/>' . filemtime($this->FileName).'<br/>' . $this->Time.'<br/>';
- header("Expires: " . gmdate("D, d M Y H:i:s", $this->Time + filemtime($this->FileName)) . " GMT");
- ($this->XHTML) ? header('Content-Type: application/xhtml+xml') : header('Content-Type: text/html');
- if (time() - filemtime($this->FileName) > $this->Time) return;
- }
- die(readfile($this->FileName));
- }
- }
- public function on404ContentLoaded(&$rawContent)
- {
- //don't cache error pages. This prevents filling up the cache with non existent pages
- $this->doCache = false;
- }
- public function onPageRendered(&$output)
- {
- if ($this->doCache) {
- if (!is_dir($this->Dir)) {
- mkdir($this->Dir, 0755, true);
- }
- file_put_contents($this->FileName, $output);
- }
- }
- }
|