Issues (4)

src/FileCache.php (1 issue)

Severity
1
<?php
2
/**
3
 * Class FileCache
4
 *
5
 * @filesource   FileCache.php
6
 * @created      25.05.2017
7
 * @package      chillerlan\SimpleCache
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2017 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\SimpleCache;
14
15
use chillerlan\Settings\SettingsContainerInterface;
16
use FilesystemIterator, RecursiveDirectoryIterator, RecursiveIteratorIterator, stdClass;
17
use Psr\Log\LoggerInterface;
18
19
use function dirname, file_get_contents, file_put_contents, hash, is_dir, is_file, is_writable,
20
	mkdir, rtrim, serialize, strpos, str_replace, time, unlink, unserialize;
21
22
use const DIRECTORY_SEPARATOR;
23
24
class FileCache extends CacheDriverAbstract{
25
26
	protected string $cachedir;
27
28
	/**
29
	 * FileCache constructor.
30
	 *
31
	 * @param \chillerlan\Settings\SettingsContainerInterface|null $options
32
	 * @param \Psr\Log\LoggerInterface|null                        $logger
33
	 *
34
	 * @throws \chillerlan\SimpleCache\CacheException
35
	 */
36
	public function __construct(SettingsContainerInterface $options = null, LoggerInterface $logger = null){
37
		parent::__construct($options, $logger);
38
39
		$this->cachedir = rtrim($this->options->cacheFilestorage, '/\\').DIRECTORY_SEPARATOR;
40
41
		if(!is_dir($this->cachedir)){
42
			throw new CacheException('invalid cachedir "'.$this->cachedir.'"');
43
		}
44
45
		if(!is_writable($this->cachedir)){
46
			throw new CacheException('cachedir is read-only. permissions?');
47
		}
48
49
	}
50
51
	/** @inheritdoc */
52
	public function get($key, $default = null){
53
		$filename = $this->getFilepath($this->checkKey($key));
54
55
		if(is_file($filename)){
56
			$content = file_get_contents($filename);
57
58
			if(!empty($content)){
59
				$data = unserialize($content);
60
61
				if($data->ttl === null || $data->ttl > time()){
62
					return $data->content;
63
				}
64
65
				unlink($filename);
66
			}
67
68
		}
69
70
		return $default;
71
	}
72
73
	/** @inheritdoc */
74
	public function set($key, $value, $ttl = null):bool{
75
		$ttl = $this->getTTL($ttl);
76
77
		$file = $this->getFilepath($this->checkKey($key));
78
		$dir  = dirname($file);
79
80
		if(!is_dir($dir)){
81
			mkdir($dir, 0755, true);
82
		}
83
84
		$data          = new stdClass;
85
		$data->ttl     = null;
86
		$data->content = $value;
87
88
		if($ttl !== null){
0 ignored issues
show
The condition $ttl !== null is always true.
Loading history...
89
			$data->ttl = time() + $ttl;
90
		}
91
92
		file_put_contents($file, serialize($data));
93
94
		if(is_file($file)){
95
			return true;
96
		}
97
98
		return false; // @codeCoverageIgnore
99
	}
100
101
	/** @inheritdoc */
102
	public function delete($key):bool{
103
		$filename = $this->getFilepath($this->checkKey($key));
104
105
		if(is_file($filename)){
106
			return unlink($filename);
107
		}
108
109
		return false;
110
	}
111
112
	/** @inheritdoc */
113
	public function clear():bool{
114
		$iterator = new RecursiveDirectoryIterator($this->cachedir, FilesystemIterator::CURRENT_AS_PATHNAME|FilesystemIterator::SKIP_DOTS);
115
		$return   = [];
116
117
		foreach(new RecursiveIteratorIterator($iterator) as $path){
118
119
			// skip files in the parent directory - cache files are only under /a/ab/[hash]
120
			if(strpos(str_replace($this->cachedir, '', $path), DIRECTORY_SEPARATOR) === false){
121
				continue;
122
			}
123
124
			$return[] = unlink($path);
125
		}
126
127
		return $this->checkReturn($return); // @codeCoverageIgnore
128
	}
129
130
	/**
131
	 * @param string $key
132
	 *
133
	 * @return string
134
	 */
135
	protected function getFilepath(string $key):string{
136
		$h = hash('sha256', $key);
137
138
		return $this->cachedir.$h[0].DIRECTORY_SEPARATOR.$h[0].$h[1].DIRECTORY_SEPARATOR.$h;
139
	}
140
141
}
142