Passed
Push — master ( fd0d63...16794a )
by smiley
01:53
created

FileCache::get()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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