1: <?php
2:
3: namespace Genetsis\core;
4:
5: use Exception;
6:
7: 8: 9: 10: 11: 12: 13: 14: 15:
16: class FileCache
17: {
18:
19: protected static $cache_dir = '';
20:
21: protected static $error = null;
22:
23: protected static $prefix = '';
24:
25: 26: 27: 28: 29:
30: public static function init($path, $pref = '')
31: {
32:
33: if (!function_exists('json_decode') || !function_exists('json_encode')) {
34: throw new Exception('Cache needs the JSON PHP extensions.');
35: }
36:
37: self::$cache_dir = dirname(__FILE__) . '/' . $path;
38: self::$prefix = $pref;
39:
40: if (!is_dir(self::$cache_dir) || !is_writable(self::$cache_dir)) {
41: $auto_create = mkdir(self::$cache_dir, 0777, true);
42: if ($auto_create === false) {
43: throw new Exception("Failed creating cache directory [".self::$cache_dir."].");
44: }
45: }
46:
47: }
48:
49: 50: 51: 52: 53: 54: 55: 56: 57:
58: public static function set($key, $data = false, $ttl = 3600)
59: {
60: if (!$key) {
61: self::$error = "Invalid key";
62: return false;
63: }
64: if (!$data) {
65: self::$error = "Invalid data";
66: return false;
67: }
68: $key = self::makeFileKey($key);
69: if (!is_integer($ttl)) {
70: $ttl = (int)$ttl;
71: }
72: $store = array(
73: 'data' => $data,
74: 'ttl' => time() + $ttl,
75: );
76:
77: $status = false;
78: try {
79: $fh = fopen($key, "c");
80: if (flock($fh, LOCK_EX)) {
81: ftruncate($fh, 0);
82: fwrite($fh, json_encode($store));
83: flock($fh, LOCK_UN);
84: $status = true;
85: }
86: fclose($fh);
87: } catch (Exception $e) {
88: self::$error = "Exception caught: " . $e->getMessage();
89: return false;
90: }
91: return $status;
92: }
93:
94: 95: 96: 97: 98: 99:
100: private static function makeFileKey($key)
101: {
102: $safe_key = md5($key . '-' . self::$prefix);
103: return self::$cache_dir . $safe_key;
104: }
105:
106: 107: 108: 109: 110: 111:
112: public static function get($key)
113: {
114: if (!$key) {
115: self::$error = "Invalid key";
116: return false;
117: }
118: $key = self::makeFileKey($key);
119: if (!file_exists($key)) {
120: return false;
121: }
122: $file_content = null;
123:
124:
125: try {
126: $fh = fopen($key, "r");
127:
128: if ($fh) {
129:
130: while (!flock($fh, LOCK_EX)) {;}
131:
132: if (flock($fh, LOCK_SH)) {
133: $file_content = fread($fh, filesize($key));
134: }
135:
136:
137: flock($fh, LOCK_UN);
138:
139: fclose($fh);
140: }
141: } catch (Exception $e) {
142: self::$error = "Exception caught: " . $e->getMessage();
143: return false;
144: }
145:
146:
147: if ($file_content) {
148: $store = json_decode($file_content, true);
149: if ($store['ttl'] < time()) {
150: unlink($key);
151: self::$error = "Data expired";
152: return false;
153: }
154: }
155: return $store['data'];
156: }
157:
158: 159: 160: 161: 162: 163:
164: public static function delete($key)
165: {
166: if (!$key) {
167: self::$error = "Invalid key";
168: return false;
169: }
170: $key = self::makeFileKey($key);
171: if (!file_exists($key)) {
172: return false;
173: }
174:
175: try {
176: unlink($key);
177: } catch (Exception $e) {
178: self::$error = "Exception caught: " . $e->getMessage();
179: return false;
180: }
181:
182: return true;
183: }
184:
185: 186: 187: 188: 189:
190: public static function deleteCache()
191: {
192: return self::deleteFiles(self::$cache_dir);
193: }
194:
195: 196: 197: 198: 199: 200: 201: 202: 203: 204:
205: private static function deleteFiles($path, $del_dir = false, $level = 0)
206: {
207:
208: $path = rtrim($path, DIRECTORY_SEPARATOR);
209:
210: if (!$current_dir = @opendir($path)) {
211: return false;
212: }
213:
214: while (false !== ($filename = @readdir($current_dir))) {
215: if ($filename != "." and $filename != "..") {
216: if (is_dir($path . DIRECTORY_SEPARATOR . $filename)) {
217:
218: if (substr($filename, 0, 1) != '.') {
219: self::deleteFiles($path . DIRECTORY_SEPARATOR . $filename, $del_dir, $level + 1);
220: }
221: } else {
222: unlink($path . DIRECTORY_SEPARATOR . $filename);
223: }
224: }
225: }
226: @closedir($current_dir);
227:
228: if ($del_dir == true AND $level > 0) {
229: return @rmdir($path);
230: }
231:
232: return true;
233: }
234:
235: 236: 237: 238: 239:
240: public function getError()
241: {
242: $message = self::$error;
243: self::$error = null;
244: return $message;
245: }
246:
247: 248: 249: 250: 251:
252: public function haveError()
253: {
254: return ((self::$error !== null)
255: ? true
256: : false);
257: }
258: }