PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.22
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.22
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.2.22, at minify/class-wp-optimize-minify-cache-functions.php

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