PluginProbe ʕ •ᴥ•ʔ
JetBackup – Backup, Restore & Migrate / trunk
JetBackup – Backup, Restore & Migrate vtrunk
3.1.22.3 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.8.1 1.4.9 1.5.0 1.5.1 1.5.1.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.10 1.6.11 1.6.12 1.6.13 1.6.15 1.6.5.1 1.6.8.8 1.6.9 1.6.9.1 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7.5 2.0.8.7 2.0.9.11 2.0.9.14 2.0.9.15 2.0.9.6 2.0.9.7 2.0.9.9 3.1.10.7 3.1.11.1 3.1.12.3 3.1.13.4 3.1.14.17 3.1.15.4 3.1.16.1 3.1.17.5 3.1.18.10 3.1.18.8 3.1.18.9 3.1.19.8 3.1.20.3 3.1.21.3 3.1.7.9 3.1.9.2 trunk 1.1.90 1.1.91 1.2.0 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2
backup / src / JetBackup / 3rdparty / SleekDB / Cache.php
backup / src / JetBackup / 3rdparty / SleekDB Last commit date
Classes 4 months ago Exceptions 1 year ago .htaccess 1 year ago Cache.php 4 months ago Query.php 1 year ago QueryBuilder.php 1 year ago SleekDB.php 1 year ago Store.php 4 months ago autoload.php 1 year ago index.html 1 year ago web.config 1 year ago
Cache.php
309 lines
1 <?php
2
3 namespace SleekDB;
4
5 use Closure;
6 use Exception;
7 use ReflectionFunction;
8 use SleekDB\Classes\IoHelper;
9 use SleekDB\Exceptions\IOException;
10
11 /**
12 * Class Cache
13 * Caching layer of SleekDB, handles everything regarding caching.
14 */
15 class Cache
16 {
17
18 const DEFAULT_CACHE_DIR = "cache/";
19 const NO_LIFETIME_FILE_STRING = "no_lifetime";
20
21 /**
22 * Lifetime in seconds or deletion with deleteAll
23 * @var int|null
24 */
25 protected $lifetime;
26
27 protected $cachePath = "";
28
29 protected $cacheDir = "";
30
31 protected $tokenArray;
32
33 /**
34 * Cache constructor.
35 * @param string $storePath
36 * @param array $cacheTokenArray
37 * @param int|null $cacheLifetime
38 */
39 public function __construct(string $storePath, array &$cacheTokenArray, $cacheLifetime)
40 {
41 // TODO make it possible to define custom cache directory.
42 // $cacheDir = "";
43 // $this->setCacheDir($cacheDir);
44
45 $this->setCachePath($storePath);
46
47 $this->setTokenArray($cacheTokenArray);
48
49 $this->lifetime = $cacheLifetime;
50 }
51
52 /**
53 * Retrieve the cache lifetime for current query.
54 * @return int|null lifetime in seconds (int) or no lifetime with null
55 */
56 public function getLifetime()
57 {
58 return $this->lifetime;
59 }
60
61 /**
62 * Retrieve the path to cache folder of current store.
63 * @return string path to cache directory
64 */
65 public function getCachePath(): string
66 {
67 return $this->cachePath;
68 }
69
70 /**
71 * Retrieve the cache token used as filename to store cache file.
72 * @return string unique token for current query.
73 */
74 public function getToken(): string
75 {
76 $tokenArray = $this->getTokenArray();
77 $tokenArray = self::convertClosuresToString($tokenArray);
78
79 return md5(json_encode($tokenArray));
80 }
81
82 /**
83 * Delete all cache files for current store.
84 * @return bool
85 */
86 public function deleteAll(): bool
87 {
88 return IoHelper::deleteFiles(glob($this->getCachePath()."*"));
89 }
90
91 /**
92 * Delete all cache files with no lifetime (null) in current store.
93 * @return bool
94 */
95 public function deleteAllWithNoLifetime(): bool
96 {
97 $noLifetimeFileString = self::NO_LIFETIME_FILE_STRING;
98 return IoHelper::deleteFiles(glob($this->getCachePath()."*.$noLifetimeFileString.json"));
99 }
100
101 /**
102 * Save content for current query as a cache file.
103 * @param array $content
104 * @throws IOException if cache folder is not writable or saving failed.
105 */
106 public function set(array $content){
107 $lifetime = $this->getLifetime();
108 $cachePath = $this->getCachePath();
109 $token = $this->getToken();
110
111 $noLifetimeFileString = self::NO_LIFETIME_FILE_STRING;
112 $cacheFile = $cachePath . $token . ".$noLifetimeFileString.json";
113
114 if(is_int($lifetime)){
115 $cacheFile = $cachePath . $token . ".$lifetime.json";
116 }
117
118 IoHelper::writeContentToFile($cacheFile, json_encode($content, JSON_INVALID_UTF8_SUBSTITUTE));
119 }
120
121 /**
122 * Retrieve content of cache file.
123 * @return array|null array on success, else null
124 * @throws IOException if cache file is not readable or does not exist.
125 */
126 public function get(){
127 $cachePath = $this->getCachePath();
128 $token = $this->getToken();
129
130 $cacheFile = null;
131
132 IoHelper::checkRead($cachePath);
133
134 $cacheFiles = glob($cachePath.$token."*.json");
135
136 if($cacheFiles !== false && count($cacheFiles) > 0){
137 $cacheFile = $cacheFiles[0];
138 }
139
140 if(!empty($cacheFile)){
141 $cacheParts = explode(".", $cacheFile);
142 if(count($cacheParts) >= 3){
143 $lifetime = $cacheParts[count($cacheParts) - 2];
144 if(is_numeric($lifetime)){
145 if($lifetime === "0"){
146 return json_decode(IoHelper::getFileContent($cacheFile), true);
147 }
148 $fileExpiredAfter = filemtime($cacheFile) + (int) $lifetime;
149 if(time() <= $fileExpiredAfter){
150 return json_decode(IoHelper::getFileContent($cacheFile), true);
151 }
152 IoHelper::deleteFile($cacheFile);
153 } else if($lifetime === self::NO_LIFETIME_FILE_STRING){
154 return json_decode(IoHelper::getFileContent($cacheFile), true);
155 }
156 }
157 }
158 return null;
159 }
160
161 /**
162 * Delete cache file/s for current query.
163 * @return bool
164 */
165 public function delete(): bool
166 {
167 return IoHelper::deleteFiles(glob($this->getCachePath().$this->getToken()."*.json"));
168 }
169
170 /**
171 * @param string $storePath
172 * @return Cache
173 */
174 private function setCachePath(string $storePath): Cache
175 {
176 $cachePath = "";
177 $cacheDir = $this->getCacheDir();
178
179 if(!empty($storePath)){
180 IoHelper::normalizeDirectory($storePath);
181 $cachePath = $storePath . $cacheDir;
182 }
183
184 $this->cachePath = $cachePath;
185
186 return $this;
187 }
188
189 /**
190 * Set the cache token array used for cache token string generation.
191 * @param array $tokenArray
192 * @return Cache
193 */
194 private function setTokenArray(array &$tokenArray): Cache
195 {
196 $this->tokenArray = &$tokenArray;
197 return $this;
198 }
199
200 /**
201 * Retrieve the cache token array.
202 * @return array
203 */
204 private function getTokenArray(): array
205 {
206 return $this->tokenArray;
207 }
208
209 /**
210 * Convert one or multiple closures to string. If array provided, recursively.
211 * @param mixed $data
212 * @return mixed
213 */
214 private static function convertClosuresToString($data){
215 if(!is_array($data)){
216 if($data instanceof \Closure){
217 return self::getClosureAsString($data);
218 }
219 return $data;
220 }
221 foreach ($data as $key => $token){
222 if(is_array($token)){
223 $data[$key] = self::convertClosuresToString($token);
224 } else if($token instanceof \Closure){
225 $data[$key] = self::getClosureAsString($token);
226 }
227 }
228 return $data;
229 }
230
231 /**
232 * Retrieve a string representation of a closure that can be used to differentiate between closures
233 * when generating the cache token string.
234 * @param Closure $closure
235 * @return false|string string representation of closure or false on failure.
236 */
237 private static function getClosureAsString(Closure $closure)
238 {
239 try{
240 $reflectionFunction = new ReflectionFunction($closure); // get reflection object
241 } catch (Exception $exception){
242 return false;
243 }
244 $filePath = $reflectionFunction->getFileName(); // absolute path of php file containing function
245 $startLine = $reflectionFunction->getStartLine(); // start line of function
246 $endLine = $reflectionFunction->getEndLine(); // end line of function
247 $lineSeparator = PHP_EOL; // line separator "\n"
248
249 $staticVariables = $reflectionFunction->getStaticVariables();
250 $staticVariables = var_export($staticVariables, true);
251
252 if($filePath === false || $startLine === false || $endLine === false){
253 return false;
254 }
255
256 $startEndDifference = $endLine - $startLine;
257
258 $startLine--; // -1 to use it with the array representation of the file
259
260 if($startLine < 0 || $startEndDifference < 0){
261 return false;
262 }
263
264 // get content of file containing function
265 $fp = fopen($filePath, 'rb');
266 $fileContent = "";
267 if(flock($fp, LOCK_SH)){
268 $fileContent = @stream_get_contents($fp);
269 }
270 flock($fp, LOCK_UN);
271 fclose($fp);
272
273 if(empty($fileContent)){
274 return false;
275 }
276
277 // separate the file into an array containing every line as one element
278 $fileContentArray = explode($lineSeparator, $fileContent);
279 if(count($fileContentArray) < $endLine){
280 return false;
281 }
282
283 // return the part of the file containing the function as a string.
284 $functionString = implode("", array_slice($fileContentArray, $startLine, $startEndDifference + 1));
285 $functionString .= "|staticScopeVariables:".$staticVariables;
286 return $functionString;
287 }
288
289 /**
290 * Set the cache directory name.
291 * @param string $cacheDir
292 * @return Cache
293 */
294 private function setCacheDir(string $cacheDir): Cache
295 {
296 IoHelper::normalizeDirectory($cacheDir);
297 $this->cacheDir = $cacheDir;
298 return $this;
299 }
300
301 /**
302 * Retrieve the cache directory name or the default cache directory name if empty.
303 * @return string
304 */
305 private function getCacheDir(): string
306 {
307 return (!empty($this->cacheDir)) ? $this->cacheDir : self::DEFAULT_CACHE_DIR;
308 }
309 }