PluginProbe ʕ •ᴥ•ʔ
10Web Booster – Website speed optimization, Cache & Page Speed optimizer / trunk
10Web Booster – Website speed optimization, Cache & Page Speed optimizer vtrunk
2.33.0 2.30.5 2.30.7 2.30.9 2.31.10 2.31.8 2.32.11 2.32.21 2.32.3 2.32.4 2.32.7 2.6.31 2.6.40 2.6.42 2.6.7 2.7.37 2.7.44 2.7.47 2.8.18 2.8.19 2.8.32 2.8.34 2.8.35 2.9.23 2.9.24 2.9.25 2.9.27 v2.27.4 trunk 2.0.10 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.17 2.0.18 2.0.21 2.0.22 2.0.25 2.0.26 2.0.27 2.0.3 2.0.7 2.0.9 2.10.46 2.10.65 2.10.66 2.10.68 2.11.41 2.11.42 2.11.43 2.12.15 2.12.21 2.12.22 2.12.23 2.12.26 2.13.37 2.13.40 2.13.41 2.13.42 2.13.44 2.13.45 2.13.47 2.14.49 2.14.50 2.15.18 2.17.21 2.17.23 2.18.17 2.19.44 2.19.45 2.19.46 2.19.49 2.2.12 2.2.15 2.2.16 2.2.18 2.2.8 2.20.31 2.20.32 2.20.33 2.21.11 2.21.12 2.21.16 2.21.25 2.22.32 2.23.13 2.23.15 2.23.16 2.23.18 2.24.12 2.24.14 2.24.18 2.25.14 2.26.6 2.28.10 2.28.13 2.28.14 2.28.7 2.29.1 2.29.2 2.29.3 2.3.0 2.3.1 2.3.2 2.3.3 2.30.18
tenweb-speed-optimizer / includes / OptimizerCache.php
tenweb-speed-optimizer / includes Last commit date
WebPageCache 8 months ago external 2 months ago ExcludeJsFromDelay.php 2 years ago OptimizerBanner.php 11 months ago OptimizerBase.php 2 years ago OptimizerCSSMin.php 2 years ago OptimizerCache.php 1 year ago OptimizerCacheStructure.php 2 years ago OptimizerCriticalCss.php 1 year ago OptimizerElementor.php 2 years ago OptimizerFonts.php 2 years ago OptimizerImages.php 1 year ago OptimizerLogger.php 1 year ago OptimizerMain.php 2 months ago OptimizerOnInit.php 11 months ago OptimizerScripts.php 2 years ago OptimizerSettings.php 2 months ago OptimizerStyles.php 2 years ago OptimizerUrl.php 1 year ago OptimizerUtils.php 2 months ago OptimizerWhiteLabel.php 2 years ago
OptimizerCache.php
506 lines
1 <?php
2
3 namespace TenWebOptimizer;
4
5 /*
6 * Handles disk-cache-related operations.
7 */
8 if (!defined('ABSPATH')) {
9 exit;
10 }
11
12 class OptimizerCache
13 {
14 /**
15 * Cache filename.
16 *
17 * @var string
18 */
19 private $filename;
20
21 /**
22 * Cache directory path (with a trailing slash).
23 *
24 * @var string
25 */
26 private $cachedir;
27
28 /**
29 * Whether gzipping is done by the web server or us.
30 * True => we don't gzip, the web server does it.
31 * False => we do it ourselves.
32 *
33 * @var bool
34 */
35 private $nogzip;
36
37 private $hashes;
38
39 private $ext;
40
41 private $media;
42
43 /**
44 * Ctor.
45 *
46 * @param string $md5 hash
47 * @param string $ext extension
48 */
49 public function __construct($post_id = null, $ext = 'php', $media = 'all', $name_prefix = '')
50 {
51 if (!isset($post_id)) {
52 $post_id = OptimizerUtils::get_current_post_info();
53 }
54
55 if (empty($name_prefix)) {
56 $name_prefix = 'aggregated';
57 }
58 $this->media = $media;
59 $this->cachedir = TWO_CACHE_DIR;
60 $this->nogzip = TWO_CACHE_NOGZIP;
61 $this->ext = $ext;
62
63 if (!$this->nogzip) {
64 $this->filename = TWO_CACHEFILE_PREFIX . $post_id . 'gzip.php';
65 } else {
66 if (in_array($ext, ['js', 'css'])) {
67 if ($media !== 'all') {
68 if (!empty($media)) {
69 $name_prefix .= '_' . md5($media) . '_delay';
70 } else {
71 $name_prefix .= '_delay';
72 }
73 }
74 $this->filename = $ext . '/' . TWO_CACHEFILE_PREFIX . $post_id . '_' . $name_prefix . '.min.' . $ext;
75 } elseif ($ext === 'critical') {
76 $this->filename = $ext . '/' . TWO_CACHEFILE_PREFIX . $post_id . '_' . $name_prefix . '.css';
77 } elseif ($ext === 'font') {
78 $this->filename = 'critical/' . TWO_CACHEFILE_PREFIX . $post_id . '_' . $name_prefix . '.json';
79 } else {
80 $this->filename = TWO_CACHEFILE_PREFIX . $post_id . '.' . $ext;
81 }
82 }
83 }
84
85 //todo remove first version cache logic
86
87 /**
88 * Check whether it is a GET REQUEST
89 */
90 public static function isGetRequest()
91 {
92 return isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
93 }
94
95 /**
96 * Returns true if the cached file exists on disk.
97 *
98 * @return bool
99 */
100 public function check()
101 {
102 static $files = [];
103 $files[] = $this->filename;
104
105 if (
106 !is_dir($this->cachedir) &&
107 !mkdir($concurrentDirectory = $this->cachedir, 0777, true) && // phpcs:ignore
108 !is_dir($concurrentDirectory) &&
109 !is_writable($concurrentDirectory) // phpcs:ignore
110 ) {
111 return false;
112 }
113 file_put_contents($this->cachedir . '_all_cache_files.txt', json_encode($files)); // phpcs:ignore
114
115 return file_exists($this->cachedir . $this->filename);
116 }
117
118 /**
119 * Returns cache contents if they exist, false otherwise.
120 *
121 * @return string|false
122 */
123 public function retrieve()
124 {
125 if ($this->check()) {
126 if (false == $this->nogzip) {
127 return file_get_contents($this->cachedir . $this->filename . '.none');
128 }
129
130 return file_get_contents($this->cachedir . $this->filename); // phpcs:ignore
131 }
132
133 return false;
134 }
135
136 /**
137 * Stores given $data in cache.
138 *
139 * @param string $data data to cache
140 * @param string $mime mimetype
141 *
142 * @return void
143 */
144 public function cache($data, $mime)
145 {
146 self::check_and_create_dirs();
147
148 if ($this->nogzip === false) {
149 // We handle gzipping ourselves.
150 $file = 'default.php';
151 $phpcode = file_get_contents(TENWEB_SO_PLUGIN_DIR . 'config/' . $file);
152 $phpcode = str_replace(['%%CONTENT%%', 'exit;'], [$mime, ''], $phpcode);
153 @file_put_contents($this->cachedir . $this->filename, $phpcode); // phpcs:ignore
154 @file_put_contents($this->cachedir . $this->filename . '.none', $data); // phpcs:ignore
155 } else {
156 // Write code to cache without doing anything else.
157 @file_put_contents($this->cachedir . $this->filename, $data); // phpcs:ignore
158 }
159
160 if (!empty($this->hashes)) {
161 $cacheFile = $this->cachedir . '_cached.json';
162 $oldData = '';
163
164 if (file_exists($cacheFile)) {
165 $oldData = json_decode(file_get_contents($cacheFile), true); // phpcs:ignore
166 }
167
168 if (empty($oldData)) {
169 $oldData = [];
170 }
171 $oldData[$this->filename] = ['media' => $this->media, 'hashes' => $this->hashes];
172 @file_put_contents($cacheFile, json_encode($oldData)); // phpcs:ignore
173 }
174 }
175
176 public static function getFileCacheSructure()
177 {
178 $cacheFile = TWO_CACHE_DIR . '_cached.json';
179
180 if (file_exists($cacheFile)) {
181 return json_decode(file_get_contents($cacheFile), true); // phpcs:ignore
182 }
183
184 return [];
185 }
186
187 public static function filterThroughCache($scripts)
188 {
189 $cachedFiles = OptimizerCache::getFileCacheSructure();
190
191 $result = [
192 'code' => [],
193 'scripts' => $scripts
194 ];
195
196 foreach ($cachedFiles as $key => $files) {
197 $scriptsToRemove = [];
198
199 if (isset($files['hashes'])) {
200 foreach ($files['hashes'] as $i => $file) {
201 if (isset($scripts[$file])) {
202 $scriptsToRemove[] = $file;
203 unset($files['hashes'][$i]);
204 }
205 }
206
207 if (empty($files['hashes'])) {
208 if (empty($result['code'][$files['media']])) {
209 $result['code'][$files['media']] = '';
210 }
211 $result['code'][$files['media']] .= file_get_contents(TWO_CACHE_DIR . $key); // phpcs:ignore
212 $result['scripts'] = array_diff_key($result['scripts'], array_flip($scriptsToRemove));
213 }
214 }
215 }
216
217 return $result;
218 }
219
220 /**
221 * Get cache filename.
222 *
223 * @return string
224 */
225 public function getname($flag = false)
226 {
227 if ($flag) {
228 return $this->filename;
229 }
230 $date = time();
231
232 return $this->filename . '?date=' . $date;
233 }
234
235 protected static function is_valid_cache_file($dir, $file)
236 {
237 //check if is valid file
238
239 return '.' !== $file && '..' !== $file && false !== strpos($file, TWO_CACHEFILE_PREFIX)
240 && is_file($dir . $file);
241 }
242
243 /**
244 * Clears contents of TWO_CACHE_DIR.
245 *
246 * @return void
247 */
248 protected static function clear_cache_classic()
249 {
250 $contents = self::get_cache_contents();
251
252 foreach ($contents as $name => $files) {
253 $dir = rtrim(TWO_CACHE_DIR . $name, '/') . '/';
254
255 foreach ($files as $file) {
256 if (self::is_valid_cache_file($dir, $file)) {
257 @unlink($dir . $file); // @codingStandardsIgnoreLine
258 }
259 }
260 }
261 @unlink(TWO_CACHE_DIR . '/.htaccess'); // @codingStandardsIgnoreLine
262 }
263
264 /**
265 * Recursively deletes the specified pathname (file/directory) if possible.
266 * Returns true on success, false otherwise.
267 *
268 * @param string $pathname pathname to remove
269 *
270 * @return bool
271 */
272 protected static function rmdir($pathname)
273 {
274 $files = self::get_dir_contents($pathname);
275
276 foreach ($files as $file) {
277 $path = $pathname . '/' . $file;
278
279 if (is_dir($path)) {
280 self::rmdir($path);
281 } else {
282 unlink($path); // phpcs:ignore
283 }
284 }
285
286 return rmdir($pathname); // phpcs:ignore
287 }
288
289 /**
290 * Clears contents of TWO_CACHE_DIR by renaming the current
291 * cache directory into a new one with a unique name and then
292 * re-creating the default (empty) cache directory.
293 *
294 * @return bool returns true when everything is done successfully, false otherwise
295 */
296 protected static function clear_cache_via_rename()
297 {
298 $ok = false;
299 $dir = self::get_pathname_base();
300 $new_name = self::get_unique_name();
301 // Makes sure the new pathname is on the same level...
302 $new_pathname = dirname($dir) . '/' . $new_name;
303 $renamed = @rename($dir, $new_pathname); // @codingStandardsIgnoreLine
304
305 return $ok;
306 }
307
308 /**
309 * Returns a (hopefully) unique new cache folder name for renaming purposes.
310 *
311 * @return string
312 */
313 protected static function get_unique_name()
314 {
315 $prefix = self::get_advanced_cache_clear_prefix();
316
317 return uniqid($prefix, true);
318 }
319
320 /**
321 * Get cache prefix name used in advanced cache clearing mode.
322 *
323 * @return string
324 */
325 protected static function get_advanced_cache_clear_prefix()
326 {
327 $pathname = self::get_pathname_base();
328 $basename = basename($pathname);
329
330 return $basename . '-';
331 }
332
333 /**
334 * Returns an array of file and directory names found within
335 * the given $pathname without '.' and '..' elements.
336 *
337 * @param string $pathname pathname
338 *
339 * @return array
340 */
341 protected static function get_dir_contents($pathname)
342 {
343 return array_slice(scandir($pathname), 2);
344 }
345
346 /**
347 * Wipes directories which were created as part of the fast cache clearing
348 * routine (which renames the current cache directory into a new one with
349 * a custom-prefixed unique name).
350 *
351 * @return bool
352 */
353 public static function delete_advanced_cache_clear_artifacts()
354 {
355 $dir = self::get_pathname_base();
356 $prefix = self::get_advanced_cache_clear_prefix();
357 $parent = dirname($dir);
358 $ok = false;
359 // Returns the list of files without '.' and '..' elements.
360 $files = self::get_dir_contents($parent);
361
362 if (is_array($files) && !empty($files)) {
363 foreach ($files as $file) {
364 $path = $parent . '/' . $file;
365 $prefixed = (false !== strpos($path, $prefix));
366
367 // Removing only our own (prefixed) directories...
368 if (is_dir($path) && $prefixed) {
369 $ok = self::rmdir($path);
370 }
371 }
372 }
373
374 return $ok;
375 }
376
377 public static function get_path($getBase = true)
378 {
379 $pathname = self::get_pathname_base();
380
381 if (is_multisite()) {
382 $blog_id = get_current_blog_id();
383 $pathname .= $blog_id . '/';
384 }
385
386 if ($getBase) {
387 return $pathname;
388 }
389
390 return $pathname;
391 }
392
393 /**
394 * Returns the base path of our cache directory.
395 *
396 * @return string
397 */
398 protected static function get_pathname_base()
399 {
400 return WP_CONTENT_DIR . TENWEB_SO_CACHE_CHILD_DIR;
401 }
402
403 protected static function get_cache_contents()
404 {
405 $contents = [];
406
407 foreach (['', 'js', 'css'] as $dir) {
408 $contents[$dir] = scandir(TWO_CACHE_DIR . $dir);
409 }
410
411 return $contents;
412 }
413
414 /**
415 * Performs a scan of cache directory contents and returns an array
416 * with 3 values: count, size, timestamp.
417 * count = total number of found files
418 * size = total filesize (in bytes) of found files
419 * timestamp = unix timestamp when the scan was last performed/finished.
420 *
421 * @return array
422 */
423 protected static function stats_scan()
424 {
425 $count = 0;
426 $size = 0;
427
428 // Scan everything in our cache directories.
429 foreach (self::get_cache_contents() as $name => $files) {
430 $dir = rtrim(TWO_CACHE_DIR . $name, '/') . '/';
431
432 foreach ($files as $file) {
433 if (self::is_valid_cache_file($dir, $file)) {
434 if (TWO_CACHE_NOGZIP && (false !== strpos($file, '.js') || false !== strpos($file, '.css') || false !== strpos($file, '.img') || false !== strpos($file, '.txt'))) {
435 // Web server is gzipping, we count .js|.css|.img|.txt files.
436 $count++;
437 } elseif (!TWO_CACHE_NOGZIP && false !== strpos($file, '.none')) {
438 // We are gzipping ourselves via php, counting only .none files.
439 $count++;
440 }
441 $size += filesize($dir . $file);
442 }
443 }
444 }
445
446 return [$count, $size, time()];
447 }
448
449 /**
450 * Checks if cache dirs exist and create if not.
451 * Returns false if not succesful.
452 *
453 * @return bool
454 */
455 public static function check_and_create_dirs()
456 {
457 if (!defined('TWO_CACHE_DIR')) {
458 // We didn't set a cache.
459 return false;
460 }
461
462 foreach (['', 'js', 'css', 'critical'] as $dir) {
463 if (!self::check_cache_dir(TWO_CACHE_DIR . $dir)) {
464 return false;
465 }
466 }
467
468 return true;
469 }
470
471 /**
472 * Ensures the specified `$dir` exists and is writeable.
473 * Returns false if that's not the case.
474 *
475 * @param string $dir directory to check/create
476 *
477 * @return bool
478 */
479 protected static function check_cache_dir($dir)
480 {
481 // Try creating the dir if it doesn't exist.
482 if (!file_exists($dir)) {
483 if (!mkdir($dir, 0777, true) && !is_dir($dir)) { // phpcs:ignore
484 return false;
485 } // @codingStandardsIgnoreLine
486
487 if (!file_exists($dir)) {
488 return false;
489 }
490 }
491
492 // If we still cannot write, bail.
493 if (!is_writable($dir)) { // phpcs:ignore
494 return false;
495 }
496 // Create an index.html in there to avoid prying eyes!
497 $idx_file = rtrim($dir, '/\\') . '/index.html';
498
499 if (!is_file($idx_file)) {
500 @file_put_contents($idx_file, '<html><head><meta name="robots" content="noindex, nofollow"></head><body></body></html>'); // phpcs:ignore
501 }
502
503 return true;
504 }
505 }
506