182 lines
4.4 KiB
PHP
182 lines
4.4 KiB
PHP
<?php
|
|
|
|
namespace NoccyLabs\LocalCache;
|
|
|
|
use Psr\SimpleCache\InvalidArgumentException;
|
|
use Psr\SimpleCache\CacheInterface;
|
|
use Psr\SimpleCache\CacheException;
|
|
|
|
class LocalCache implements CacheInterface
|
|
{
|
|
|
|
private $cacheDir;
|
|
|
|
private $poolName;
|
|
|
|
private $defaultTtl = 3600;
|
|
|
|
public function __construct(string $poolName)
|
|
{
|
|
$this->poolName = preg_replace("/[^a-zA-Z0-9_\\-]/", "_", $poolName);
|
|
$this->cacheDir = $this->findCachePath();
|
|
}
|
|
|
|
protected function findCachePath(): string
|
|
{
|
|
$candidates = [
|
|
'/var/cache',
|
|
getenv("HOME").'/.cache',
|
|
];
|
|
while ($candidate = array_shift($candidates)) {
|
|
if (!is_writable($candidate)) {
|
|
continue;
|
|
}
|
|
$path = $candidate . DIRECTORY_SEPARATOR . 'php-localcache';
|
|
/*
|
|
if (!is_dir($path)) {
|
|
@mkdir($path);
|
|
if (!is_dir($path)) {
|
|
continue;
|
|
}
|
|
}
|
|
*/
|
|
return $path;
|
|
}
|
|
throw new CacheException("Couldn't find a usable cache directory");
|
|
}
|
|
|
|
protected function hashKey(string $key)
|
|
{
|
|
$hash = hash("sha256", $key);
|
|
return $hash;
|
|
}
|
|
|
|
protected function getKeyPath(string $key)
|
|
{
|
|
$hash = $this->hashKey($key);
|
|
$path = substr($hash, 0, 2) . DIRECTORY_SEPARATOR . substr($hash, 2, 2) . DIRECTORY_SEPARATOR . $hash;
|
|
$full = $this->cacheDir . DIRECTORY_SEPARATOR . $this->poolName . DIRECTORY_SEPARATOR . $path;
|
|
return $full;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function get($key, $default = null)
|
|
{
|
|
if (!$this->has($key)) {
|
|
return $default;
|
|
}
|
|
$path = $this->getKeyPath($key);
|
|
return file_get_contents($path);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function set($key, $value, $ttl = null)
|
|
{
|
|
$info = [
|
|
'key' => $key,
|
|
'ttl' => $ttl ?? $this->defaultTtl
|
|
];
|
|
$info['expires'] = time() + $info['ttl'];
|
|
$path = $this->getKeyPath($key);
|
|
if (!is_dir(dirname($path))) {
|
|
mkdir(dirname($path), 0777, true);
|
|
}
|
|
file_put_contents($path, $value);
|
|
file_put_contents($path.".info", serialize($info));
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function delete($key)
|
|
{
|
|
if (!$this->has($key)) {
|
|
return;
|
|
}
|
|
$path = $this->getKeyPath($key);
|
|
@unlink($path);
|
|
@unlink($path.".info");
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function has($key)
|
|
{
|
|
$path = $this->getKeyPath($key);
|
|
if (!file_exists($path)) {
|
|
return false;
|
|
}
|
|
|
|
$info = unserialize(file_get_contents($path.".info"));
|
|
if ($info['expires'] < time()) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function clear()
|
|
{
|
|
/*
|
|
$items = glob($this->cacheDir.DIRECTORY_SEPARATOR.$this->poolName.DIRECTORY_SEPARATOR."*.info");
|
|
foreach ($items as $item) {
|
|
unlink(substr($item, 0, -5));
|
|
unlink($item);
|
|
}
|
|
@rmdir($this->cacheDir . DIRECTORY_SEPARATOR . $this->poolName);
|
|
*/
|
|
|
|
$path = $this->cacheDir . DIRECTORY_SEPARATOR . $this->poolName;
|
|
exec("rm -rf ".escapeshellarg($path));
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function getMultiple($keys, $default = null)
|
|
{
|
|
if (!is_iterable($keys)) {
|
|
throw new InvalidArgumentException("Argument not iterable");
|
|
}
|
|
$ret = [];
|
|
foreach ($keys as $key) {
|
|
$ret[$key] = $this->get($key, $default);
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function setMultiple($values, $ttl = null)
|
|
{
|
|
if (!is_iterable($values)) {
|
|
throw new InvalidArgumentException("Argument not iterable");
|
|
}
|
|
foreach ($values as $key=>$value) {
|
|
$this->set($key, $value, $ttl);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function deleteMultiple($keys)
|
|
{
|
|
if (!is_iterable($keys)) {
|
|
throw new InvalidArgumentException("Argument not iterable");
|
|
}
|
|
foreach ($keys as $key) {
|
|
$this->delete($key);
|
|
}
|
|
}
|
|
}
|