PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.7.1
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.7.1
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / minify / class-wp-optimize-minify-cache-functions.php

class-wp-optimize-minify-cache-functions.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 3.7.1, at minify/class-wp-optimize-minify-cache-functions.php

578 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) die('No direct access allowed');
3
4 if (!defined('WP_OPTIMIZE_MINIFY_DIR')) {
5 die('No direct access.');
6 }
7
8 if (!function_exists('wpo_delete_files')) {
9 include WPO_PLUGIN_MAIN_PATH.'cache/file-based-page-cache-functions.php';
10 }
11
12 class WP_Optimize_Minify_Cache_Functions {
13
14 /**
15 * Fix the permission bits on generated files
16 *
17 * @param String $file - full path to a file
18 */
19 public static function fix_permission_bits($file) {
20 if (function_exists('stat')) {
21 if ($stat = stat(dirname($file))) {
22 $perms = $stat['mode'] & 0007777;
23 chmod($file, $perms);
24 clearstatcache();
25 return true;
26 }
27 }
28
29 // Get permissions from parent directory
30 $perms = 0777;
31 if (function_exists('stat')) {
32 if ($stat = stat(dirname($file))) {
33 $perms = $stat['mode'] & 0007777;
34 }
35 }
36
37 if (file_exists($file)) {
38 if (($perms & ~umask() != $perms)) {
39 $folder_parts = explode('/', substr($file, strlen(dirname($file)) + 1));
40 for ($i = 1, $c = count($folder_parts); $i <= $c; $i++) {
41 chmod(dirname($file) . '/' . implode('/', array_slice($folder_parts, 0, $i)), $perms);
42 }
43 }
44 }
45 return true;
46 }
47
48 /**
49 * Get cache directories and urls
50 *
51 * @return Array
52 */
53 public static function cache_path() {
54 // get latest time stamp
55 $cache_time = wp_optimize_minify_config()->get('last-cache-update');
56
57 $cache_base_dir = WPO_CACHE_MIN_FILES_DIR . "/$cache_time";
58 $cache_dir_url = WPO_CACHE_MIN_FILES_URL . "/$cache_time/assets";
59 $tmp_dir = WPO_CACHE_MIN_FILES_DIR . "/tmp";
60 $header_dir = WPO_CACHE_MIN_FILES_DIR . "/$cache_time/header";
61 $cache_dir = WPO_CACHE_MIN_FILES_DIR . "/$cache_time/assets";
62
63 // Create directories
64 $dirs = array($cache_dir, $tmp_dir, $header_dir);
65 foreach ($dirs as $target) {
66 $enabled = wp_optimize_minify_config()->get('enabled');
67 if (false === $enabled) break;
68
69 if (!is_dir($target) && !wp_mkdir_p($target)) {
70 error_log('WP_Optimize_Minify_Cache_Functions::cache_path(): The folder "'.$target.'" could not be created.');
71 }
72 }
73 return array(
74 'tmpdir' => $tmp_dir,
75 'cachedir' => $cache_dir,
76 'cachedirurl' => $cache_dir_url,
77 'headerdir' => $header_dir,
78 'cachebasedir' => $cache_base_dir
79 );
80 }
81
82 /**
83 * Increment file names
84 */
85 public static function cache_increment() {
86 $stamp = time();
87 wp_optimize_minify_config()->update(array(
88 'last-cache-update' => $stamp
89 ));
90 return $stamp;
91 }
92
93 /**
94 * Reset the cache (Increment + purge temp files)
95 */
96 public static function reset() {
97 self::cache_increment();
98 self::purge_temp_files();
99 }
100
101 /**
102 * Will delete temporary intermediate stuff but leave final css/js alone for compatibility
103 *
104 * @return array
105 */
106 public static function purge_temp_files() {
107 // get cache directories and urls
108 $cache_path = self::cache_path();
109 $tmp_dir = $cache_path['tmpdir'];
110 $header_dir = $cache_path['headerdir'];
111
112 // delete temporary directories only
113 if (is_dir($tmp_dir)) {
114 wpo_delete_files($tmp_dir, true);
115 }
116 if (is_dir($header_dir)) {
117 wpo_delete_files($header_dir, true);
118 }
119
120 /**
121 * Action triggered after purging temporary files
122 */
123 do_action('wpo_min_after_purge_temp_files');
124 return array(
125 'tmpdir' => $tmp_dir,
126 'headerdir' => $header_dir,
127 );
128 }
129
130 /**
131 * Purge supported hosting and plugins
132 *
133 * @return array An array of caches purged message
134 */
135 public static function purge_others() {
136 /**
137 * Action triggered before purging other plugins cache
138 */
139 do_action('wpo_min_before_purge_others');
140
141 // WordPress default cache
142 if (function_exists('wp_cache_flush')) {
143 wp_cache_flush();
144 }
145
146 // Purge WP-Optimize
147 WP_Optimize()->get_page_cache()->purge();
148
149 // Store the messages of purged cache if it was successful
150 $result = array();
151
152 // When plugins have a simple method, add them to the array ('Plugin Name' => 'method_name')
153 $others = array(
154 'WP Super Cache' => 'wp_cache_clear_cache',
155 'W3 Total Cache' => 'w3tc_pgcache_flush',
156 'WP Fastest Cache' => 'wpfc_clear_all_cache',
157 'WP Rocket' => 'rocket_clean_domain',
158 'Cachify' => 'cachify_flush_cache',
159 'Comet Cache' => array('comet_cache', 'clear'),
160 'SG Optimizer' => 'sg_cachepress_purge_cache',
161 'Pantheon' => 'pantheon_wp_clear_edge_all',
162 'Zen Cache' => array('zencache', 'clear'),
163 'Breeze' => array('Breeze_PurgeCache', 'breeze_cache_flush'),
164 'Swift Performance' => array('Swift_Performance_Cache', 'clear_all_cache'),
165 );
166
167 foreach ($others as $plugin => $method) {
168 if (is_callable($method)) {
169 call_user_func($method);
170
171 $result[] = self::get_caches_purged_message($plugin);
172 }
173 }
174
175 // Purge LiteSpeed Cache
176 if (is_callable(array('LiteSpeed_Cache_Tags', 'add_purge_tag'))) {
177 LiteSpeed_Cache_Tags::add_purge_tag('*');
178
179 $result[] = self::get_caches_purged_message('LiteSpeed Cache');
180 }
181
182 // Purge Hyper Cache
183 if (class_exists('HyperCache')) {
184 do_action('autoptimize_action_cachepurged');
185
186 $result[] = self::get_caches_purged_message('Hyper Cache');
187 }
188
189 // Purge Godaddy Managed WordPress Hosting (Varnish + APC)
190 if (class_exists('WPaaS\Plugin')) {
191 self::godaddy_request('BAN');
192 $result[] = sprintf(__('A cache purge request has been sent to %s.', 'wp-optimize'), '<strong>Go Daddy Varnish</strong>') . ' ' . __('Please note that it may not work every time, due to cache rate limiting by your host.', 'wp-optimize');
193 }
194
195 // purge cache enabler
196 if (has_action('ce_clear_cache')) {
197 do_action('ce_clear_cache');
198
199 $result[] = self::get_caches_purged_message('Cache Enabler');
200 }
201
202 // Purge WP Engine
203 if (class_exists("WpeCommon")) {
204 if (method_exists('WpeCommon', 'purge_memcached')) {
205 WpeCommon::purge_memcached();
206 }
207 if (method_exists('WpeCommon', 'clear_maxcdn_cache')) {
208 WpeCommon::clear_maxcdn_cache();
209 }
210 if (method_exists('WpeCommon', 'purge_varnish_cache')) {
211 WpeCommon::purge_varnish_cache();
212 }
213
214 if (method_exists('WpeCommon', 'purge_memcached') || method_exists('WpeCommon', 'clear_maxcdn_cache') || method_exists('WpeCommon', 'purge_varnish_cache')) {
215 $result[] = sprintf(__('A cache purge request has been sent to %s.', 'wp-optimize'), '<strong>WP Engine</strong>') . ' ' . __('Please note that it may not work every time, due to cache rate limiting by your host.', 'wp-optimize');
216 }
217 }
218
219 // Purge Kinsta
220 global $kinsta_cache;
221 if (isset($kinsta_cache) && class_exists('\\Kinsta\\CDN_Enabler')) {
222 if (!empty($kinsta_cache->kinsta_cache_purge) && is_callable(array($kinsta_cache->kinsta_cache_purge, 'purge_complete_caches'))) {
223 $kinsta_cache->kinsta_cache_purge->purge_complete_caches();
224
225 $result[] = self::get_remote_caches_purged_message('Kinsta');
226 }
227 }
228
229 // Purge Pagely
230 if (class_exists('PagelyCachePurge')) {
231 $purge_pagely = new PagelyCachePurge();
232 if (is_callable(array($purge_pagely, 'purgeAll'))) {
233 $purge_pagely->purgeAll();
234
235 $result[] = self::get_remote_caches_purged_message('Pagely');
236 }
237 }
238
239 // Purge Pressidum
240 if (defined('WP_NINUKIS_WP_NAME') && class_exists('Ninukis_Plugin') && is_callable(array('Ninukis_Plugin', 'get_instance'))) {
241 $purge_pressidum = Ninukis_Plugin::get_instance();
242 if (is_callable(array($purge_pressidum, 'purgeAllCaches'))) {
243 $purge_pressidum->purgeAllCaches();
244
245 $result[] = self::get_remote_caches_purged_message('Pressidium');
246 }
247 }
248
249 // Purge Savvii
250 if (defined('\Savvii\CacheFlusherPlugin::NAME_DOMAINFLUSH_NOW')) {
251 $purge_savvii = new \Savvii\CacheFlusherPlugin();
252 if (is_callable(array($purge_savvii, 'domainflush'))) {
253 $purge_savvii->domainflush();
254
255 $result[] = self::get_remote_caches_purged_message('Savvii');
256 }
257 }
258
259 /**
260 * Action triggered when purging other plugins cache, and nothing was triggered
261 */
262 do_action('wpo_min_after_purge_others');
263
264 return $result;
265 }
266
267 /**
268 * Returns the purged cache message for the given plugin name
269 *
270 * @param string $plugin_name Name of the plugin
271 *
272 * @return string
273 */
274 public static function get_caches_purged_message($plugin_name) {
275 $message = sprintf(
276 __('All caches from %s have also been purged.', 'wp-optimize'),
277 '<strong>' . esc_html($plugin_name) . '</strong>'
278 );
279
280 return $message;
281 }
282
283 /**
284 * Returns remote purged cache message for given host name
285 *
286 * @param string $host_name
287 *
288 * @return string
289 */
290 public static function get_remote_caches_purged_message($host_name) {
291 $message = sprintf(
292 __('A cache purge request has been sent to %s.', 'wp-optimize'),
293 '<strong>' . esc_html($host_name) . '</strong>'
294 );
295
296 return $message;
297 }
298
299 /**
300 * Purge all public files on uninstallation
301 * This will break cached pages that ref minified JS/CSS
302 *
303 * @return Boolean
304 */
305 public static function purge() {
306 $log = '';
307 if (is_dir(WPO_CACHE_MIN_FILES_DIR)) {
308 if (wpo_delete_files(WPO_CACHE_MIN_FILES_DIR, true)) {
309 $log = "[Minify] files and folders are deleted recursively";
310 } else {
311 $log = "[Minify] recursive files and folders deletion unsuccessful";
312 }
313 if (wp_optimize_minify_config()->get('debug')) {
314 error_log($log);
315 }
316 }
317 return true;
318 }
319
320 /**
321 * Purge cache files older than 30 days
322 *
323 * @return array
324 */
325 public static function purge_old() {
326 if (!class_exists('WP_Optimize_Minify_Config')) {
327 include_once WPO_PLUGIN_MAIN_PATH . 'minify/class-wp-optimize-minify-config.php';
328 }
329 $cache_time = wp_optimize_minify_config()->get('last-cache-update');
330 $cache_lifespan = wp_optimize_minify_config()->get('cache_lifespan');
331
332 /**
333 * Minify cache lifespan
334 *
335 * @param int The minify cache expiry timestamp
336 */
337 $expires = apply_filters('wp_optimize_minify_cache_expiry_time', time() - 86400 * $cache_lifespan);
338 $log = array();
339
340 // get all directories that are a direct child of current directory
341 if (is_dir(WPO_CACHE_MIN_FILES_DIR) && is_writable(dirname(WPO_CACHE_MIN_FILES_DIR))) {
342 if ($handle = opendir(WPO_CACHE_MIN_FILES_DIR)) {
343 while (false !== ($d = readdir($handle))) {
344 if (strcmp($d, '.')==0 || strcmp($d, '..')==0) {
345 continue;
346 }
347 $log[] = "cache expiration time - $expires";
348 $log[] = "checking if cache has expired - $d";
349 if ($d != $cache_time && (is_numeric($d) && $d <= $expires)) {
350 $dir = WPO_CACHE_MIN_FILES_DIR.'/'.$d;
351 if (is_dir($dir)) {
352 $log[] = "deleting cache in $dir";
353 if (wpo_delete_files($dir, true)) {
354 $log[] = "files and folders are deleted recursively - $dir";
355 } else {
356 $log[] = "recursive files and folders deletion unsuccessful - $dir";
357 }
358 if (file_exists($dir)) {
359 if (rmdir($dir)) {
360 $log[] = "folder deleted successfully - $dir";
361 } else {
362 $log[] = "folder deletion unsuccessful - $dir";
363 }
364 }
365 }
366 }
367 }
368 closedir($handle);
369 }
370 }
371 if (wp_optimize_minify_config()->get('debug')) {
372 foreach ($log as $message) {
373 error_log($message);
374 }
375 }
376
377 return $log;
378 }
379
380 /**
381 * Get transients from the disk
382 *
383 * @return String|Boolean
384 */
385 public static function get_transient($key) {
386 $cache_path = self::cache_path();
387 $tmp_dir = $cache_path['tmpdir'];
388 $f = $tmp_dir.'/'.$key.'.transient';
389 clearstatcache();
390 if (file_exists($f)) {
391 return file_get_contents($f);
392 } else {
393 return false;
394 }
395 }
396
397 /**
398 * Set cache on disk
399 *
400 * @param String $key
401 * @param Mixed $code
402 *
403 * @return Boolean
404 */
405 public static function set_transient($key, $code) {
406 if (is_null($code) || empty($code)) {
407 return false;
408 }
409 $cache_path = self::cache_path();
410 $tmp_dir = $cache_path['tmpdir'];
411 $f = $tmp_dir.'/'.$key.'.transient';
412 file_put_contents($f, $code);
413 self::fix_permission_bits($f);
414 return true;
415 }
416
417 /**
418 * Get the cache size and count
419 *
420 * @param string $folder
421 * @return String
422 */
423 public static function get_cachestats($folder) {
424 clearstatcache();
425 if (is_dir($folder)) {
426 $dir = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($folder, FilesystemIterator::SKIP_DOTS));
427 $size = 0;
428 $file_count = 0;
429 foreach ($dir as $file) {
430 $size += $file->getSize();
431 $file_count++;
432 }
433 return WP_Optimize()->format_size($size) . ' ('.$file_count.' files)';
434 } else {
435 return sprintf(__('Error: %s is not a directory!', 'wp-optimize'), $folder);
436 }
437 }
438
439 /**
440 * Purge GoDaddy Managed WordPress Hosting (Varnish)
441 *
442 * Source: https://github.com/wp-media/wp-rocket/blob/master/inc/3rd-party/hosting/godaddy.php
443 *
444 * @param String $method
445 * @param String|Null $url
446 */
447 public static function godaddy_request($method, $url = null) {
448 $url = empty($url) ? home_url() : $url;
449 $host = parse_url($url, PHP_URL_HOST);
450 $url = set_url_scheme(str_replace($host, WPaas\Plugin::vip(), $url), 'http');
451 wp_cache_flush();
452 update_option('gd_system_last_cache_flush', time()); // purge apc
453 wp_remote_request(esc_url_raw($url), array('method' => $method, 'blocking' => false, 'headers' => array('Host' => $host)));
454 }
455
456 /**
457 * List all cache files
458 *
459 * @param integer $stamp A timestamp
460 * @param boolean $use_cache If true, do not use transient value
461 * @return array
462 */
463 public static function get_cached_files($stamp = 0, $use_cache = true) {
464 if ($use_cache && $files = get_transient('wpo_minify_get_cached_files')) {
465 return $files;
466 }
467 $cache_path = self::cache_path();
468 $cache_dir = $cache_path['cachedir'];
469 $size = self::get_cachestats($cache_dir);
470 $total_size = self::get_cachestats(WPO_CACHE_MIN_FILES_DIR);
471 $o = wp_optimize_minify_config()->get();
472 $cache_time = (0 == $o['last-cache-update']) ? __('Never.', 'wp-optimize') : self::format_date_time($o['last-cache-update']);
473 $return = array(
474 'js' => array(),
475 'css' => array(),
476 'stamp' => $stamp,
477 'cachesize' => esc_html($size),
478 'total_cache_size' => esc_html($total_size),
479 'cacheTime' => $cache_time,
480 'cachePath' => $cache_path['cachedir']
481 );
482
483 // Inspect directory with opendir, since glob might not be available in some systems
484 clearstatcache();
485 if (is_dir($cache_dir.'/') && $handle = opendir($cache_dir.'/')) {
486 while (false !== ($file = readdir($handle))) {
487 $file = $cache_dir.'/'.$file;
488 $ext = pathinfo($file, PATHINFO_EXTENSION);
489 if (in_array($ext, array('js', 'css'))) {
490 $log = self::generate_log($file.'.json' );
491 $min_css = substr($file, 0, -4).'.min.css';
492 $minjs = substr($file, 0, -3).'.min.js';
493 $file_name = basename($file);
494 $file_url = trailingslashit($cache_path['cachedirurl']).$file_name;
495 if ('css' == $ext && file_exists($min_css)) {
496 $file_name = basename($min_css);
497 }
498 if ('js' == $ext && file_exists($minjs)) {
499 $file_name = basename($minjs);
500 }
501 $file_size = WP_Optimize()->format_size(filesize($file));
502 $uid = hash('adler32', $file_name);
503 array_push($return[$ext], array('uid' => $uid, 'filename' => $file_name, 'file_url' => $file_url, 'log' => $log, 'fsize' => $file_size));
504 }
505 }
506 closedir($handle);
507 }
508 set_transient('wpo_minify_get_cached_files', $return, DAY_IN_SECONDS);
509 return $return;
510 }
511
512 /**
513 * Generate log information from a json file.
514 *
515 * @param string $file Full path of log file.
516 *
517 * @return object Could be either a 'json_decode' object upon successful parsing of the JSON file, or a stdClass object
518 * upon failure. In the case of stdClass object, $obj->error will contain the error message.
519 */
520 public static function generate_log($file) {
521 $error_log = new stdClass();
522
523 $cache_path = self::cache_path();
524 $file_name = basename($file);
525 $file_url = trailingslashit($cache_path['cachedirurl']) . $file_name;
526 $file_link_html = '<a href="' . esc_url($file_url) . '" target="_blank">' . $file_name . '</a>';
527
528 if (!file_exists($file)) {
529 $error_log->error = sprintf(__('Log file %s is missing', 'wp-optimize'), $file_link_html);
530 return $error_log;
531 }
532
533 $log = json_decode(file_get_contents($file));
534
535 $is_valid_json = json_last_error() === JSON_ERROR_NONE ? true : false;
536
537 if (!$is_valid_json) {
538 $error_log->error = sprintf(__('JSON error in file %s | Error details: %s', 'wp-optimize'), $file_link_html, json_last_error_msg());
539 return $error_log;
540 }
541
542 if (!isset($log->header) || !isset($log->files)) {
543 $error_log->error = sprintf(__('Some data is missing in the log file %s', 'wp-optimize'), $file_link_html);
544 return $error_log;
545 }
546
547 return $log;
548 }
549
550 /**
551 * Format a timestamp using WP's date_format and time_format
552 *
553 * @param integer $timestamp - The timestamp
554 * @return string
555 */
556 public static function format_date_time($timestamp) {
557 return WP_Optimize()->format_date_time($timestamp);
558 }
559
560 /**
561 * Format the log created when merging assets. Called via array_map
562 *
563 * @param array $files The files array, containing the 'log' object or array.
564 * @return array
565 */
566 public static function format_file_logs($files) {
567 $files['log'] = WP_Optimize()->include_template(
568 'minify/cached-file-log.php',
569 true,
570 array(
571 'log' => $files['log'],
572 'minify_config' => wp_optimize_minify_config()->get(),
573 )
574 );
575 return $files;
576 }
577 }
578