mirror of
https://tt-rss.org/git/tt-rss.git
synced 2024-06-28 12:10:52 +02:00
8b129626cd
With d373b7b452
feed icon modification times get used for cache-busting, but 'Cache_Local' updates that
value on each send. This change makes it so the modification time only gets updated on files in expirable caches, keeping the value
consistent between sends for files in non-expiring caches.
Also, marking 'Cache_Local::send_local_file()' private since it's unique to that adapter.
149 lines
3.9 KiB
PHP
149 lines
3.9 KiB
PHP
<?php
|
|
class Cache_Local implements Cache_Adapter {
|
|
private string $dir;
|
|
|
|
public function remove(string $filename): bool {
|
|
return unlink($this->get_full_path($filename));
|
|
}
|
|
|
|
public function get_mtime(string $filename) {
|
|
return filemtime($this->get_full_path($filename));
|
|
}
|
|
|
|
public function set_dir(string $dir) : void {
|
|
$this->dir = Config::get(Config::CACHE_DIR) . "/" . basename(clean($dir));
|
|
|
|
$this->make_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);
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
private function send_local_file(string $filename) {
|
|
if (file_exists($filename)) {
|
|
|
|
if (is_writable($filename) && !$this->exists('.no-auto-expiry')) {
|
|
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;
|
|
|
|
return readfile($filename);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|