147 lines
4.1 KiB
PHP
147 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace Tqdev\PhpCrudApi\Cache;
|
|
|
|
class TempFileCache implements Cache
|
|
{
|
|
const SUFFIX = 'cache';
|
|
|
|
private $path;
|
|
private $segments;
|
|
|
|
public function __construct(string $prefix, string $config)
|
|
{
|
|
$this->segments = [];
|
|
$s = DIRECTORY_SEPARATOR;
|
|
$ps = PATH_SEPARATOR;
|
|
if ($config == '') {
|
|
$this->path = sys_get_temp_dir() . $s . $prefix . self::SUFFIX;
|
|
} elseif (strpos($config, $ps) === false) {
|
|
$this->path = $config;
|
|
} else {
|
|
list($path, $segments) = explode($ps, $config);
|
|
$this->path = $path;
|
|
$this->segments = explode(',', $segments);
|
|
}
|
|
if (file_exists($this->path) && is_dir($this->path)) {
|
|
$this->clean($this->path, array_filter($this->segments), strlen(md5('')), false);
|
|
}
|
|
}
|
|
|
|
private function getFileName(string $key): string
|
|
{
|
|
$s = DIRECTORY_SEPARATOR;
|
|
$md5 = md5($key);
|
|
$filename = rtrim($this->path, $s) . $s;
|
|
$i = 0;
|
|
foreach ($this->segments as $segment) {
|
|
$filename .= substr($md5, $i, $segment) . $s;
|
|
$i += $segment;
|
|
}
|
|
$filename .= substr($md5, $i);
|
|
return $filename;
|
|
}
|
|
|
|
public function set(string $key, string $value, int $ttl = 0): bool
|
|
{
|
|
$filename = $this->getFileName($key);
|
|
$dirname = dirname($filename);
|
|
if (!file_exists($dirname)) {
|
|
if (!mkdir($dirname, 0755, true)) {
|
|
return false;
|
|
}
|
|
}
|
|
$string = $ttl . '|' . $value;
|
|
return $this->filePutContents($filename, $string) !== false;
|
|
}
|
|
|
|
private function filePutContents($filename, $string)
|
|
{
|
|
return file_put_contents($filename, $string, LOCK_EX);
|
|
}
|
|
|
|
private function fileGetContents($filename)
|
|
{
|
|
$file = fopen($filename, 'rb');
|
|
if ($file === false) {
|
|
return false;
|
|
}
|
|
$lock = flock($file, LOCK_SH);
|
|
if (!$lock) {
|
|
fclose($file);
|
|
return false;
|
|
}
|
|
$string = '';
|
|
while (!feof($file)) {
|
|
$string .= fread($file, 8192);
|
|
}
|
|
flock($file, LOCK_UN);
|
|
fclose($file);
|
|
return $string;
|
|
}
|
|
|
|
private function getString($filename): string
|
|
{
|
|
$data = $this->fileGetContents($filename);
|
|
if ($data === false) {
|
|
return '';
|
|
}
|
|
list($ttl, $string) = explode('|', $data, 2);
|
|
if ($ttl > 0 && time() - filemtime($filename) > $ttl) {
|
|
return '';
|
|
}
|
|
return $string;
|
|
}
|
|
|
|
public function get(string $key): string
|
|
{
|
|
$filename = $this->getFileName($key);
|
|
if (!file_exists($filename)) {
|
|
return '';
|
|
}
|
|
$string = $this->getString($filename);
|
|
if ($string == null) {
|
|
return '';
|
|
}
|
|
return $string;
|
|
}
|
|
|
|
private function clean(string $path, array $segments, int $len, bool $all) /*: void*/
|
|
{
|
|
$entries = scandir($path);
|
|
foreach ($entries as $entry) {
|
|
if ($entry === '.' || $entry === '..') {
|
|
continue;
|
|
}
|
|
$filename = $path . DIRECTORY_SEPARATOR . $entry;
|
|
if (count($segments) == 0) {
|
|
if (strlen($entry) != $len) {
|
|
continue;
|
|
}
|
|
if (is_file($filename)) {
|
|
if ($all || $this->getString($filename) == null) {
|
|
unlink($filename);
|
|
}
|
|
}
|
|
} else {
|
|
if (strlen($entry) != $segments[0]) {
|
|
continue;
|
|
}
|
|
if (is_dir($filename)) {
|
|
$this->clean($filename, array_slice($segments, 1), $len - $segments[0], $all);
|
|
rmdir($filename);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function clear(): bool
|
|
{
|
|
if (!file_exists($this->path) || !is_dir($this->path)) {
|
|
return false;
|
|
}
|
|
$this->clean($this->path, array_filter($this->segments), strlen(md5('')), true);
|
|
return true;
|
|
}
|
|
}
|