diff options
Diffstat (limited to 'classes/cache/local.php')
-rw-r--r-- | classes/cache/local.php | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/classes/cache/local.php b/classes/cache/local.php new file mode 100644 index 000000000..20d97d9c0 --- /dev/null +++ b/classes/cache/local.php @@ -0,0 +1,143 @@ +<?php +class Cache_Local implements Cache_Adapter { + private string $dir; + + public function set_dir(string $dir) : void { + $this->dir = Config::get(Config::CACHE_DIR) . "/" . basename(clean($dir)); + } + + public function get_dir(): string { + return $this->dir; + } + + public function make_dir(): bool { + if (!is_dir($this->dir)) { + return mkdir($this->dir); + } + return false; + } + + public function is_writable(?string $filename = null): bool { + if ($filename) { + if (file_exists($this->get_full_path($filename))) + return is_writable($this->get_full_path($filename)); + else + return is_writable($this->dir); + } else { + return is_writable($this->dir); + } + } + + public function exists(string $filename): bool { + return file_exists($this->get_full_path($filename)); + } + + /** + * @return int|false -1 if the file doesn't exist, false if an error occurred, size in bytes otherwise + */ + public function get_size(string $filename) { + if ($this->exists($filename)) + return filesize($this->get_full_path($filename)); + else + return -1; + } + + public function get_full_path(string $filename): string { + return $this->dir . "/" . basename(clean($filename)); + } + + public function get(string $filename): ?string { + if ($this->exists($filename)) + return file_get_contents($this->get_full_path($filename)); + else + return null; + } + + /** + * @param mixed $data + * + * @return int|false Bytes written or false if an error occurred. + */ + public function put(string $filename, $data) { + return file_put_contents($this->get_full_path($filename), $data); + } + + public function touch(string $filename): bool { + return touch($this->get_full_path($filename)); + } + + /** + * @return false|null|string false if detection failed, null if the file doesn't exist, string mime content type otherwise + */ + public function get_mime_type(string $filename) { + if ($this->exists($filename)) + return mime_content_type($this->get_full_path($filename)); + else + return null; + } + + /** + * @return bool|int false if the file doesn't exist (or unreadable) or isn't audio/video, true if a plugin handled, otherwise int of bytes sent + */ + public function send(string $filename) { + return $this->send_local_file($this->get_full_path($filename)); + } + + public function expire_all(): void { + $dirs = array_filter(glob(Config::get(Config::CACHE_DIR) . "/*"), "is_dir"); + + foreach ($dirs as $cache_dir) { + $num_deleted = 0; + + if (is_writable($cache_dir) && !file_exists("$cache_dir/.no-auto-expiry")) { + $files = glob("$cache_dir/*"); + + if ($files) { + foreach ($files as $file) { + if (time() - filemtime($file) > 86400*Config::get(Config::CACHE_MAX_DAYS)) { + unlink($file); + + ++$num_deleted; + } + } + } + + Debug::log("Expired $cache_dir: removed $num_deleted files."); + } + } + } + + /** + * this is essentially a wrapper for readfile() which allows plugins to hook + * output with httpd-specific "fast" implementation i.e. X-Sendfile or whatever else + * + * hook function should return true if request was handled (or at least attempted to) + * + * note that this can be called without user context so the plugin to handle this + * should be loaded systemwide in config.php + * + * @return bool|int false if the file doesn't exist (or unreadable) or isn't audio/video, true if a plugin handled, otherwise int of bytes sent + */ + function send_local_file(string $filename) { + if (file_exists($filename)) { + + if (is_writable($filename)) touch($filename); + + $tmppluginhost = new PluginHost(); + + $tmppluginhost->load(Config::get(Config::PLUGINS), PluginHost::KIND_SYSTEM); + //$tmppluginhost->load_data(); + + if ($tmppluginhost->run_hooks_until(PluginHost::HOOK_SEND_LOCAL_FILE, true, $filename)) + return true; + + $stamp = gmdate("D, d M Y H:i:s", (int)filemtime($filename)) . " GMT"; + header("Last-Modified: $stamp", true); + + return readfile($filename); + } else { + return false; + } + } + +} |