This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Mouf\Utils\Cache; |
||
3 | |||
4 | use Mouf\Utils\Log\LogInterface; |
||
5 | use Psr\Log\LoggerInterface; |
||
6 | |||
7 | /** |
||
8 | * This package contains a cache mechanism that relies on temporary files. |
||
9 | * It is very close to the "classic" FileCache, but it will create a subdirectory system in order |
||
10 | * to avoid having all files inside the same folders.<br/> |
||
11 | *<br/> |
||
12 | * One important property is $hashDept. It sets the length of the subdirectory. |
||
13 | * The higher it is, the more subfolders will be created, but the lesser cache file they will contain. |
||
14 | * Max count of subfolders is 16^$hashDepth, so you cannot set a depth higher then 4 as it could create |
||
15 | * more than 1 000 000 subfolders.<br/> |
||
16 | *<br/> |
||
17 | * As an example :<br/> |
||
18 | * <ul> |
||
19 | * <li>1 000 000 items are stored into 256 subfolders for $hashDepth == 2, witch means around 4 000 files per folder</li> |
||
20 | * <li>1 000 000 items are stored into 4096 subfolders for $hashDepth == 3, witch means around 250 files per folder</li> |
||
21 | *</ul> |
||
22 | *<br/> |
||
23 | * If you consider caching more than 1 000 000 items, you should consider another cache service |
||
24 | *<br/> |
||
25 | *<br/> |
||
26 | * <b><u>WARNING:</u> YOU CANNOT SHARE HIS FOLDER WITH OTHER CACHE SYSTEMS<b>, or even put any other file |
||
27 | * into the $cacheDirectory, as it will remove the whole folder when purged. |
||
28 | */ |
||
29 | class BigFileCache implements CacheInterface { |
||
30 | |||
31 | /** |
||
32 | * The default time to live of elements stored in the session (in seconds). |
||
33 | * Please note that if the session is flushed, all the elements of the cache will disapear anyway. |
||
34 | * If empty, the time to live will be the time of the session. |
||
35 | * |
||
36 | * @Property |
||
37 | * @var int |
||
38 | */ |
||
39 | private $defaultTimeToLive; |
||
40 | |||
41 | /** |
||
42 | * The logger used to trace the cache activity. |
||
43 | * Supports both PSR3 compatible logger and old Mouf logger for compatibility reasons. |
||
44 | * |
||
45 | * @var LoggerInterface|LogInterface |
||
46 | */ |
||
47 | private $log; |
||
48 | |||
49 | /** |
||
50 | * The directory the files are stored in. |
||
51 | * If none is specified, they are stored in the "filecache" directory. |
||
52 | * The directory must end with a trailing "/". |
||
53 | * |
||
54 | * @Property |
||
55 | * @var string |
||
56 | */ |
||
57 | private $cacheDirectory; |
||
58 | |||
59 | /** |
||
60 | * Whether the directory is relative to the system temp directory or not. |
||
61 | * |
||
62 | * @Property |
||
63 | * @var boolean |
||
64 | */ |
||
65 | private $relativeToSystemTempDirectory = true; |
||
66 | |||
67 | private $hashDepth = 2; |
||
68 | |||
69 | /** |
||
70 | * @param int $defaultTimeToLive |
||
71 | * @param LoggerInterface|LogInterface $log |
||
72 | * @param string $cacheDirectory |
||
73 | * @param boolean $relativeToSystemTempDirectory |
||
74 | * @param int $hashDepth |
||
75 | */ |
||
76 | function __construct($defaultTimeToLive, $log, $cacheDirectory, $relativeToSystemTempDirectory) |
||
77 | { |
||
78 | $this->defaultTimeToLive = $defaultTimeToLive; |
||
79 | $this->log = $log; |
||
80 | $this->cacheDirectory = $cacheDirectory; |
||
81 | $this->relativeToSystemTempDirectory = $relativeToSystemTempDirectory; |
||
82 | } |
||
83 | |||
84 | /** |
||
85 | * Sets the length of the subdirectory. |
||
86 | * See Class documentation for more details |
||
87 | * |
||
88 | * @param int $hashDepth |
||
89 | */ |
||
90 | public function setHashDepth($hashDepth) |
||
91 | { |
||
92 | if ($hashDepth > 4 || $hashDepth < 1){ |
||
93 | throw new \Exception("hashDepth property should be betwwen 1 and 4"); |
||
94 | } |
||
95 | $this->hashDepth = $hashDepth; |
||
96 | } |
||
97 | |||
98 | |||
99 | |||
100 | |||
101 | /** |
||
102 | * Returns the cached value for the key passed in parameter. |
||
103 | * |
||
104 | * @param string $key |
||
105 | * @return mixed |
||
106 | */ |
||
107 | public function get($key) { |
||
108 | $filename = $this->getFileName($key); |
||
109 | |||
110 | if (is_readable($filename)) { |
||
111 | $fp = fopen($filename, "r"); |
||
112 | if ($fp === false) {//File may have been deleted between is_readable and fopen |
||
113 | return null; |
||
114 | } |
||
115 | $timeout = fgets($fp); |
||
116 | |||
117 | if ($timeout > time() || $timeout==0) { |
||
118 | $contents = ""; |
||
119 | while (!feof($fp)) { |
||
120 | $contents .= fread($fp, 65536); |
||
121 | } |
||
122 | fclose($fp); |
||
123 | $value = unserialize($contents); |
||
124 | //$this->log->trace("Retrieving key '$key' from file cache: value returned:".var_export($value, true)); |
||
0 ignored issues
–
show
|
|||
125 | if ($this->log) { |
||
126 | if ($this->log instanceof LoggerInterface) { |
||
127 | $this->log->info("Retrieving key '{key}' from file cache.", array('key'=>$key)); |
||
128 | } else { |
||
129 | $this->log->trace("Retrieving key '$key' from file cache."); |
||
130 | } |
||
131 | } |
||
132 | return $value; |
||
133 | View Code Duplication | } else { |
|
134 | fclose($fp); |
||
135 | unlink($filename); |
||
136 | if ($this->log) { |
||
137 | if ($this->log instanceof LoggerInterface) { |
||
138 | $this->log->info("Retrieving key '{key}' from file cache: key outdated, cache miss.", array('key'=>$key)); |
||
139 | } else { |
||
140 | $this->log->trace("Retrieving key '$key' from file cache: key outdated, cache miss."); |
||
141 | } |
||
142 | } |
||
143 | return null; |
||
144 | } |
||
145 | } else { |
||
146 | if ($this->log) { |
||
147 | if ($this->log instanceof LoggerInterface) { |
||
148 | $this->log->info("Retrieving key '{key}' from file cache: cache miss.", array('key'=>$key)); |
||
149 | } else { |
||
150 | $this->log->trace("Retrieving key '$key' from file cache: cache miss."); |
||
151 | } |
||
152 | } |
||
153 | return null; |
||
154 | } |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * Sets the value in the cache. |
||
159 | * |
||
160 | * @param string $key The key of the value to store |
||
161 | * @param mixed $value The value to store |
||
162 | * @param float $timeToLive The time to live of the cache, in seconds. |
||
163 | */ |
||
164 | public function set($key, $value, $timeToLive = null) { |
||
165 | $filename = $this->getFileName($key); |
||
166 | //$this->log->trace("Storing value in cache: key '$key', value '".var_export($value, true)."'"); |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
69% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
167 | if ($this->log) { |
||
168 | if ($this->log instanceof LoggerInterface) { |
||
169 | $this->log->info("Storing value in cache: key '{key}'", array('key'=>$key)); |
||
170 | } else { |
||
171 | $this->log->trace("Storing value in cache: key '$key'"); |
||
172 | } |
||
173 | } |
||
174 | |||
175 | $oldUmask = umask(0); |
||
176 | $subfolder = $this->getDirectory($key); |
||
177 | if (!is_writable($filename)) { |
||
178 | if (!file_exists($subfolder)) { |
||
179 | mkdir($subfolder, 0777, true); |
||
180 | } |
||
181 | } |
||
182 | |||
183 | View Code Duplication | if ($timeToLive == null) { |
|
184 | if (empty($this->defaultTimeToLive)) { |
||
185 | $timeOut = 0; |
||
186 | } else { |
||
187 | $timeOut = time() + $this->defaultTimeToLive; |
||
188 | } |
||
189 | } else { |
||
190 | $timeOut = time() + $timeToLive; |
||
191 | } |
||
192 | |||
193 | $fp = fopen($filename, "w"); |
||
194 | fwrite($fp, $timeOut."\n"); |
||
195 | fwrite($fp, serialize($value)); |
||
196 | fclose($fp); |
||
197 | // Cache is shared with group, not with the rest of the world. |
||
198 | chmod($filename, 0660); |
||
199 | |||
200 | umask($oldUmask); |
||
201 | } |
||
202 | |||
203 | /** |
||
204 | * Removes the object whose key is $key from the cache. |
||
205 | * |
||
206 | * @param string $key The key of the object |
||
207 | */ |
||
208 | View Code Duplication | public function purge($key) { |
|
209 | if ($this->log) { |
||
210 | if ($this->log instanceof LoggerInterface) { |
||
211 | $this->log->info("Purging key '{key}' from file cache.", array('key'=>$key)); |
||
212 | } else { |
||
213 | $this->log->trace("Purging key '$key' from file cache."); |
||
214 | } |
||
215 | } |
||
216 | $filename = $this->getFileName($key); |
||
217 | if (file_exists($filename)) { |
||
218 | unlink($filename); |
||
219 | } |
||
220 | } |
||
221 | |||
222 | /** |
||
223 | * Removes all the objects from the cache. |
||
224 | * |
||
225 | */ |
||
226 | public function purgeAll() { |
||
227 | if ($this->log) { |
||
228 | if ($this->log instanceof LoggerInterface) { |
||
229 | $this->log->info("Purging the whole file cache."); |
||
230 | } else { |
||
231 | $this->log->trace("Purging the whole file cache."); |
||
232 | } |
||
233 | } |
||
234 | self::rrmdir($this->getDirectory()); |
||
235 | } |
||
236 | |||
237 | /** |
||
238 | * @param mixed $key : if set, this function will return the cache directory WITH subfolder |
||
239 | * @return string |
||
240 | */ |
||
241 | protected function getDirectory($key = null) { |
||
242 | |||
243 | $dir = ""; |
||
244 | if ($this->relativeToSystemTempDirectory) { |
||
245 | $dir .= sys_get_temp_dir()."/"; |
||
246 | } |
||
247 | if (!empty($this->cacheDirectory)) { |
||
248 | $dir .= $this->cacheDirectory; |
||
249 | } else { |
||
250 | $dir .= "filecache/"; |
||
251 | } |
||
252 | |||
253 | if ($key){ |
||
254 | $subFolder = substr(hash("sha256", $key), 0, $this->hashDepth) . "/"; |
||
255 | }else{ |
||
256 | $subFolder = ""; |
||
257 | } |
||
258 | |||
259 | return $dir.$subFolder; |
||
260 | } |
||
261 | |||
262 | protected function getFileName($key) { |
||
263 | $subFolder = $this->getDirectory($key); |
||
264 | // Remove any "/" and ":" from the name, and replace those with "_" ... |
||
265 | $key = str_replace(array("_", "/", "\\", ":"), array("___", "_s_", "_b_", "_d_"), $key); |
||
266 | |||
267 | // Windows full path need to be less than 260 characters. We need to limit the size of the filename |
||
268 | $fullPath = $subFolder.$key.".cache"; |
||
269 | |||
270 | // Approximative value due to NTFS short file names (e.g. PROGRA~1) that get longer when evaluated by Windows |
||
271 | if (strlen($fullPath)<160) { |
||
272 | return $fullPath; |
||
273 | } |
||
274 | |||
275 | |||
276 | // If we go above 160 characters, let's transform the key into a md5 |
||
277 | return $subFolder.md5($key).'.cache'; |
||
278 | } |
||
279 | |||
280 | private static function rrmdir($dir) { |
||
281 | if (is_dir($dir)) { |
||
282 | $objects = scandir($dir); |
||
283 | foreach ($objects as $object) { |
||
284 | if ($object != "." && $object != "..") { |
||
285 | if (filetype($dir."/".$object) == "dir") |
||
286 | self::rrmdir($dir."/".$object); |
||
287 | else unlink ($dir."/".$object); |
||
288 | } |
||
289 | } |
||
290 | reset($objects); |
||
291 | rmdir($dir); |
||
292 | } |
||
293 | } |
||
294 | } |
||
295 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.