1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
class _FileCache { |
4
|
|
|
// Create a new FileCache instance. |
5
|
|
|
// Parameters: |
6
|
|
|
// $path: The path to the base directory which will be used for the cache. |
7
|
|
|
// $expirationTimeInSeconds: The expiration time, in seconds, for items added to the |
8
|
|
|
// cache. Any value less than 1 is automatically clamped to 1. |
9
|
|
|
// Optional. Defaults to 30. |
10
|
|
|
// $cleanInterval: How often to clean expired entries. On average, expired entries will |
11
|
|
|
// be cleaned every $cleanInterval get or set requests. Any value < 1 will be clamped |
12
|
|
|
// to 1. |
13
|
|
|
// Optional. Defaults to 1000. |
14
|
|
|
// $directoryDepth: The number of directories deep to make the cache. The directory names |
15
|
|
|
// are derived from segments of the sha1 hash of the cache key, working from left to right. |
16
|
|
|
// Each segment consists of the next two hexadecimal characters of the sha1 hash of the |
17
|
|
|
// cache key. This must be between 1 and 10, inclusive. |
18
|
|
|
// Optional. Defaults to 2. |
19
|
|
|
public function __construct( |
20
|
|
|
$path = '', |
21
|
|
|
$expirationTimeInSeconds = 30, |
22
|
|
|
$cleanInterval = 2000, |
23
|
|
|
$directoryDepth = 2) { |
24
|
|
|
|
25
|
|
|
$this->path = '/tmp/_FileCache_/'.(string)$path; |
|
|
|
|
26
|
|
|
|
27
|
|
|
if ($expirationTimeInSeconds < 1) $expirationTimeInSeconds = 1; |
28
|
|
|
$this->expirationTimeInSeconds = (int)$expirationTimeInSeconds; |
|
|
|
|
29
|
|
|
|
30
|
|
|
if ($cleanInterval < 1) $cleanInterval = 1; |
31
|
|
|
$this->cleanInterval = (int)$cleanInterval; |
|
|
|
|
32
|
|
|
|
33
|
|
|
if ($directoryDepth<1) $directoryDepth=1; else if ($directoryDepth>10) $directoryDepth=10; |
34
|
|
|
$this->directoryDepth = (int)$directoryDepth; |
|
|
|
|
35
|
|
|
} |
36
|
|
|
|
37
|
|
|
// Get an object from the cache. |
38
|
|
|
// Parameters: |
39
|
|
|
// $key: The cache key. |
40
|
|
|
// Returns: |
41
|
|
|
// The object which was previously stored, or false if a cache miss occurred. |
42
|
|
|
public function get($key) { |
43
|
|
|
//return false; |
44
|
|
View Code Duplication |
if (($this->cleanInterval == 1) || |
45
|
|
|
(rand(1, $this->cleanInterval) == $this->cleanInterval)) { |
46
|
|
|
$this->clean(); |
47
|
|
|
} |
48
|
|
|
$val = false; |
49
|
|
|
$fn = $this->getCacheFilename($key); |
50
|
|
|
$exptime = time()-$this->expirationTimeInSeconds; |
51
|
|
|
$fileData = @file_get_contents($fn); |
52
|
|
|
if ($fileData!==false && @file_exists($fn) && (@filemtime($fn) > $exptime)) { |
53
|
|
|
$val = unserialize($fileData); |
54
|
|
|
} |
55
|
|
|
return $val; |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
// Store an object into the cache. |
59
|
|
|
// Parameters: |
60
|
|
|
// $key: The cache key. |
61
|
|
|
// $value: The object to store. |
62
|
|
|
public function set($key, $value) { |
63
|
|
View Code Duplication |
if (($this->cleanInterval == 1) || |
64
|
|
|
(rand(1, $this->cleanInterval) == $this->cleanInterval)) { |
65
|
|
|
$this->clean(); |
66
|
|
|
} |
67
|
|
|
$fn = $this->getCacheFilename($key, true); |
68
|
|
|
$fileData = file_put_contents($fn,serialize($value)); |
|
|
|
|
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
// Delete an object from the cache. |
72
|
|
|
// Parameters: |
73
|
|
|
// $key: The cache key. |
74
|
|
|
public function delete($key) { |
75
|
|
|
$fn = $this->getCacheFilename($key); |
76
|
|
|
|
77
|
|
|
// Delete the cache file. |
78
|
|
|
if (@unlink($fn)) { |
79
|
|
|
// Delete empty subdirectories, all the way up to but excluding the top-level cache dir. |
80
|
|
|
$refPath = rtrim($this->path, "/\\"); |
|
|
|
|
81
|
|
|
$dir = rtrim(dirname($fn), "/\\"); |
82
|
|
|
for ($i = 0; $i < $this->directoryDepth; $i++) { |
83
|
|
|
if (!@rmdir($dir)) break; |
84
|
|
|
$dir = rtrim(dirname($dir), "/\\"); |
85
|
|
|
} |
86
|
|
|
} |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
// Clean expired entries. |
90
|
|
|
public function clean() { |
91
|
|
|
$this->cleanPath($this->path); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
// Clean expired entries from a directory. |
95
|
|
|
public function cleanPath($path) { |
96
|
|
|
$exptime = time()-$this->expirationTimeInSeconds; |
97
|
|
|
foreach (@glob($path.'/*', GLOB_NOSORT) as $fn) { |
98
|
|
|
if (@is_dir($fn)) { |
99
|
|
|
$this->cleanPath($fn); |
100
|
|
|
} else if (@filemtime($fn) <= $exptime) { |
101
|
|
|
@unlink($fn); |
|
|
|
|
102
|
|
|
} |
103
|
|
|
} |
104
|
|
|
if ($path != $this->path) { |
105
|
|
|
@rmdir($path); |
|
|
|
|
106
|
|
|
} |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
private function getCacheFilename($key, $autoCreateDirectory = false) { |
110
|
|
|
$hash = sha1($key); |
111
|
|
|
$path = $this->path; |
112
|
|
|
for ($i = 0, $idx = 0; $i < $this->directoryDepth; $i++, $idx += 2) { |
113
|
|
|
$path .= '/'.substr($hash, $idx, 2); |
114
|
|
|
} |
115
|
|
|
if ($autoCreateDirectory) @mkdir($path, 0777, true); |
|
|
|
|
116
|
|
|
$path .= '/'.$hash; |
117
|
|
|
return $path; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
public function fixPermissions($user) { |
121
|
|
|
$cmd = escapeshellcmd('chown -R '.$user.':'.$user. ' ' . $this->path); |
122
|
|
|
exec($cmd); |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
|
126
|
|
|
} |
127
|
|
|
|
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: