-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCache.php
325 lines (292 loc) · 9.65 KB
/
Cache.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
<?php
/**
* Class Cache
*
* A simple file-based caching system in PHP with cache monitoring and encryption support.
*
* @author saintly2k (https://github.com/saintly2k)
* @version 2024-01-29
*/
class Cache
{
/** @var string The directory where cache files are stored. */
private $cacheDir;
/** @var string The encryption key. */
private $encryptionKey;
/** @var int Number of cache hits. */
private $cacheHits = 0;
/** @var int Number of cache misses. */
private $cacheMisses = 0;
/** @var string The path to the file storing cache hits and misses. */
private $statsFile;
/**
* Cache constructor.
*
* @param string $cacheDir The directory where cache files will be stored.
* @param string $encryptionKey The encryption key.
*/
public function __construct($cacheDir, $encryptionKey)
{
// Initialize cache directory and encryption key
$this->cacheDir = $cacheDir;
$this->encryptionKey = $encryptionKey;
// Create cache directory if it doesn't exist
if ((!is_dir($this->cacheDir) || !file_exists($this->cacheDir)) && !mkdir($this->cacheDir, 0775, true)) {
throw new Exception("Failed to create cache directory: {$this->cacheDir}");
}
// Initialize cache hits and misses file
$this->statsFile = $cacheDir . "/cache_stats.json";
if (!file_exists($this->statsFile)) {
$this->resetCacheStats();
}
// Start session if not already started
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
// Initialize cache hits and misses if not set in session
if (!isset($_SESSION['cache_hits'])) {
$_SESSION['cache_hits'] = 0;
}
if (!isset($_SESSION['cache_misses'])) {
$_SESSION['cache_misses'] = 0;
}
}
/**
* Retrieves data from cache.
*
* @param string $key The key associated with the cached data.
*
* @return mixed|false The decrypted cached data if found and not expired, false otherwise.
*/
public function get($key)
{
$file = $this->getCacheFileName($key);
if (!file_exists($file)) {
$this->incrementCacheMisses(); // Increment cache misses counter
return false;
}
$encryptedData = file_get_contents($file);
if ($encryptedData === false) {
// Error reading cache file
// Handle the error, e.g., log an error message and return false
return false;
}
$decryptedData = $this->customDecrypt($encryptedData);
if ($decryptedData === false) {
// Error decrypting data
// Handle the error, e.g., log an error message and return false
return false;
}
$cachedData = unserialize($decryptedData);
if (!$cachedData || !isset($cachedData["expiry"], $cachedData["data"])) {
// Invalid cache data
// Handle the error, e.g., log an error message and return false
return false;
}
// Check if cache has expired
if ($cachedData["expiry"] === 0 || time() < $cachedData["expiry"]) {
$this->incrementCacheHits(); // Increment cache hits counter
$this->incrementLocalCacheHits(); // Increment cache hits counter
return $cachedData["data"];
} else {
// Remove cache file if expired
unlink($file);
$this->incrementCacheMisses(); // Increment cache misses counter
$this->incrementLocalCacheMisses(); // Increment cache misses counter
return false;
}
}
/**
* Stores data in cache.
*
* @param string $key The key to associate with the cached data.
* @param mixed $data The data to be cached.
* @param int $expiry The expiry time for the cached data in seconds. Defaults to 0 (no expiry).
*
* @return void
*/
public function set($key, $data, $expiry = 0)
{
if (empty($key)) {
throw new InvalidArgumentException("Key must be a non-empty string.");
}
$file = $this->getCacheFileName($key);
$cachedData = [
"expiry" => $expiry > 0 ? time() + $expiry : 0,
"data" => $data,
];
$encryptedData = $this->customEncrypt(serialize($cachedData));
if ($encryptedData === false || file_put_contents($file, $encryptedData) === false) {
throw new Exception("Failed to write cache file: $file");
}
}
/**
* Clears cache for a specific key or the entire cache directory.
*
* @param string|null $key The key for which cache needs to be cleared. If null, clears the entire cache.
*
* @return void
*/
public function clearCache($key = null)
{
if ($key === null) {
// Clear entire cache directory
array_map('unlink', glob($this->cacheDir . '/*.cache'));
} else {
// Clear cache for specific key or pattern
if (strpos($key, '*') !== false) {
// If the key contains wildcard (*), delete cache files matching the pattern
$pattern = str_replace('*', '.*', preg_quote($key, '/'));
$files = glob($this->cacheDir . '/*.cache');
foreach ($files as $file) {
$fileName = basename($file);
$decodedFileName = $this->customDecrypt(substr($fileName, 0, -6)); // Decode and remove '.cache'
if (preg_match('/' . $pattern . '/', $decodedFileName)) {
unlink($file);
}
}
} else {
// Clear cache for specific key
$file = $this->getCacheFileName($key);
if (file_exists($file)) {
unlink($file);
}
}
}
}
/**
* Generates the filename for a cache key.
*
* @param string $key The cache key.
*
* @return string The filename for the cache key.
*/
private function getCacheFileName($key)
{
return $this->cacheDir . "/" . $this->customEncrypt($key) . ".cache";
}
/**
* Custom encryption method.
*
* @param string $data The data to encrypt.
*
* @return string|false The encrypted data, or false on failure.
*/
private function customEncrypt($data)
{
// Your custom encryption logic here
// For example, you can use base64 encoding for simplicity
return base64_encode($data);
}
/**
* Custom decryption method.
*
* @param string $data The data to decrypt.
*
* @return string|false The decrypted data, or false on failure.
*/
private function customDecrypt($data)
{
// Your custom decryption logic here
// For example, you can use base64 decoding for simplicity
return base64_decode($data);
}
/**
* Increments the cache hits counter and updates the stats file.
*/
private function incrementCacheHits()
{
$stats = $this->getCacheStats();
$stats["hits"]++;
$this->updateCacheStats($stats);
}
/**
* Increments the cache hits counter and updates the stats file.
*/
private function incrementLocalCacheHits()
{
$_SESSION['cache_hits']++;
}
/**
* Increments the cache misses counter and updates the stats file.
*/
private function incrementCacheMisses()
{
$stats = $this->getCacheStats();
$stats["misses"]++;
$this->updateCacheStats($stats);
}
/**
* Increments the cache misses counter and updates the session variable.
*/
private function incrementLocalCacheMisses()
{
$_SESSION['cache_misses']++;
}
/**
* Gets the cache statistics (hits and misses) from the stats file.
*
* @return array The cache statistics.
*/
public function getCacheStats($stats = "both")
{
$statsData = json_decode(file_get_contents($this->statsFile), true);
if ($stats !== "both") {
$statsData = $statsData[$stats];
}
return $statsData;
}
/**
* Gets the cache statistics (hits and misses) from the session variable.
*
* @return array The cache statistics.
*/
public function getLocalCacheStats($stats = "both")
{
return [
'hits' => isset($_SESSION['cache_hits']) ? $_SESSION['cache_hits'] : 0,
'misses' => isset($_SESSION['cache_misses']) ? $_SESSION['cache_misses'] : 0,
];
}
/**
* Updates the cache statistics in the stats file.
*
* @param array $stats The cache statistics to update.
*/
private function updateCacheStats($stats)
{
$statsData = json_encode($stats);
file_put_contents($this->statsFile, $statsData);
}
/**
* Resets the cache statistics to zero.
*/
private function resetCacheStats()
{
$stats = ["hits" => 0, "misses" => 0];
file_put_contents($this->statsFile, json_encode($stats));
$this->updateCacheStats($stats);
}
/**
* Resets the cache statistics to zero.
*/
public function resetLocalCacheStats()
{
$_SESSION['cache_hits'] = 0;
$_SESSION['cache_misses'] = 0;
}
/**
* Get the cache size.
*
* @return int The cache size in bytes.
*/
public function getCacheSize()
{
$cacheFiles = glob($this->cacheDir . "/*.cache");
$totalSize = 0;
foreach ($cacheFiles as $file) {
$totalSize += filesize($file);
}
return $totalSize;
}
}