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 / includes / class-wp-optimize-browser-cache.php

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

315 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('WPO_VERSION')) die('No direct access allowed');
4
5 require_once 'class-wp-optimize-htaccess.php';
6
7 /**
8 * Class WP_Optimize_Browser_Cache
9 */
10 class WP_Optimize_Browser_Cache {
11
12 use WP_Optimize_HTTP_Error_Codes_Trait;
13
14 private $_htaccess = null;
15
16 private $_options = null;
17
18 private $_wp_optimize = null;
19
20 /**
21 * Browser cache section in htaccess will wrapped with this comment
22 *
23 * @var string
24 */
25 private $_htaccess_section_comment = 'WP-Optimize Browser Cache';
26
27 /**
28 * WP_Optimize_Browser_Cache constructor.
29 */
30 public function __construct() {
31 $this->_wp_optimize = WP_Optimize();
32
33 $this->_htaccess = new WP_Optimize_Htaccess();
34
35 $this->_options = $this->_wp_optimize->get_options();
36 }
37
38 /**
39 * Returns singleton instance object
40 *
41 * @return WP_Optimize_Browser_Cache Returns `WP_Optimize_Browser_Cache` object
42 */
43 public static function instance() {
44 static $_instance = null;
45 if (null === $_instance) {
46 $_instance = new self();
47 }
48 return $_instance;
49 }
50
51 /**
52 * Check headers for Cache-Control and Etag. And if they are exist return true.
53 *
54 * @return bool|WP_Error
55 **/
56 public function is_enabled() {
57
58 static $is_enabled;
59 if (isset($is_enabled)) return $is_enabled;
60
61 $headers = $this->get_stylesheet_headers();
62
63 if (is_wp_error($headers)) return $headers;
64
65 if (array_key_exists('cache-control', $headers) && array_key_exists('expires', $headers)) {
66 $is_enabled = true;
67 } else {
68 $is_enabled = false;
69 }
70
71 if ($this->is_browser_cache_section_exists() && false === $this->_wp_optimize->is_apache_module_loaded(array('mod_expires', 'mod_headers'))) {
72 $is_enabled = new WP_Error('Browser cache', __('We successfully updated your .htaccess file.', 'wp-optimize') . ' ' . __('But it seems one of Apache modules - mod_expires or mod_headers is not active.', 'wp-optimize'));
73 }
74
75 return $is_enabled;
76 }
77
78 /**
79 * Enable browser cache - add settings into .htaccess.
80 *
81 * @param string $expiry_time
82 */
83 public function enable($expiry_time = '1 month') {
84 $this->_htaccess->update_commented_section($this->prepare_browser_cache_section($expiry_time), $this->_htaccess_section_comment);
85 $this->_htaccess->write_file();
86 $this->_options->update_option('enable_browser_cache', true);
87 }
88
89 /**
90 * Disable cache - remove settings from .htaccess added in enable() function.
91 */
92 public function disable() {
93 $this->_htaccess->remove_commented_section($this->_htaccess_section_comment);
94 $this->_htaccess->write_file();
95 $this->_options->update_option('enable_browser_cache', false);
96 }
97
98 /**
99 * Check if browser cache option is set to true then add section with gzip settings into .htaccess (used when plugin being activated).
100 */
101 public function restore() {
102 $expire_days = $this->_options->get_option('browser_cache_expire_days', '');
103 $expire_hours = $this->_options->get_option('browser_cache_expire_hours', '');
104
105 $expiry_time = $this->prepare_interval($expire_days, $expire_hours);
106
107 $enabled = ('' == $expiry_time) ? false : true;
108
109 if ($enabled && $this->_htaccess->is_writable()) $this->enable($expiry_time);
110 }
111
112 /**
113 * Check if section with browser cache settings already exists.
114 */
115 public function is_browser_cache_section_exists() {
116 return $this->_htaccess->is_commented_section_exists($this->_htaccess_section_comment);
117 }
118
119 /**
120 * Handle for enable_browser_cache command used in WP_Optimize_Commands.
121 *
122 * @param array $params - ['browser_cache_expire' => '1 month 15 days 2 hours' || '' - for disable cache]
123 * @return array
124 */
125 public function enable_browser_cache_command_handler($params) {
126 $expire_days = isset($params['browser_cache_expire_days']) ? $params['browser_cache_expire_days'] : '';
127 $expire_hours = isset($params['browser_cache_expire_hours']) ? $params['browser_cache_expire_hours'] : '';
128
129 $current_expire_days = $this->_options->get_option('browser_cache_expire_days', '');
130 $current_expire_hours = $this->_options->get_option('browser_cache_expire_hours', '');
131
132 $section_updated = false;
133
134 $expiry_time = $this->prepare_interval($expire_days, $expire_hours);
135
136 $enable = ('' == $expiry_time) ? false : true;
137
138 /**
139 * If we don't need to do anything in .htaccess then return message.
140 */
141 if ($enable == $this->_htaccess->is_commented_section_exists() && $expire_days == $current_expire_days && $expire_hours == $current_expire_hours) {
142 $message = __('Browser static caching settings already exists in the .htaccess file', 'wp-optimize');
143
144 return array(
145 'success' => true,
146 'enabled' => $enable,
147 'message' => $message,
148 );
149 }
150
151 if ($this->_htaccess->is_writable()) {
152 // update commented section
153
154 if ($enable) {
155 $this->enable($expiry_time);
156 } else {
157 $this->disable();
158 }
159
160 // read updated file.
161 $this->_htaccess->read_file();
162 // check if section added or removed successfully.
163 $section_exists = $this->_htaccess->is_commented_section_exists();
164 // set correct $section-updated flag.
165 $section_updated = $enable === $section_exists;
166 }
167
168 if ($section_updated) {
169 $enabled = $this->is_enabled();
170
171 // save $expire value to options.
172 $this->_options->update_option('browser_cache_expire_days', $expire_days);
173 $this->_options->update_option('browser_cache_expire_hours', $expire_hours);
174
175 if (is_wp_error($enabled)) {
176 return array(
177 'success' => true,
178 'enabled' => $enabled,
179 'error_message' => $enabled->get_error_message(),
180 );
181 } else {
182 return array(
183 'success' => true,
184 'enabled' => $enabled,
185 'message' => __('We successfully updated your .htaccess file.', 'wp-optimize'),
186 );
187 }
188 } else {
189 $cache_section = $this->prepare_browser_cache_section($expiry_time);
190
191 if ($enable) {
192 $message = sprintf(__("We can\'t update your %s file.", 'wp-optimize'), $this->_htaccess->get_filename()) . ' ' . __('Please try to add following lines manually:', 'wp-optimize');
193 $output = htmlentities($this->_htaccess->get_section_begin_comment() . PHP_EOL .
194 join(PHP_EOL, $this->_htaccess->get_flat_array($cache_section)).
195 PHP_EOL . $this->_htaccess->get_section_end_comment());
196 } else {
197 $message = sprintf(__("We can\'t update your %s file.", 'wp-optimize'), $this->_htaccess->get_filename()) . ' ' . __('Please try to remove following lines manually:', 'wp-optimize');
198 $output = htmlentities($this->_htaccess->get_section_begin_comment() . PHP_EOL .
199 ' ... ... ... '.
200 PHP_EOL . $this->_htaccess->get_section_end_comment());
201 }
202
203 return array(
204 'success' => false,
205 'enabled' => $this->is_enabled(),
206 'error_message' => $message,
207 'output' => $output,
208 );
209 }
210 }
211
212 /**
213 * Use $days an $hours values to build correct time interval as a string like '2 days 3 hours' or empty string if date is empty.
214 *
215 * @param int $days
216 * @param int $hours
217 * @return string
218 */
219 private function prepare_interval($days, $hours) {
220
221 $days = is_numeric($days) ? floor($days) : 0;
222 $hours = is_numeric($hours) ? floor($hours) : 0;
223
224 if (0 == $days && 0 == $hours) {
225 return '';
226 }
227
228 $parts = array();
229
230 // if hours value more than one day then fix it.
231 $days += floor($hours / 24);
232 $hours = $hours % 24;
233
234 $years = floor($days / 365);
235 $days = $days % 365;
236 $months = floor($days / 30);
237 $days = $days % 30;
238
239 if ($years > 0) {
240 $parts[] = $years . ($years > 1 ? ' years' : ' year');
241 }
242
243 if ($months > 0) {
244 $parts[] = $months . ($months > 1 ? ' months' : ' month');
245 }
246
247 if ($days > 0) {
248 $parts[] = $days . ($days > 1 ? ' days' : ' day');
249 }
250
251 if ($hours > 0) {
252 $parts[] = $hours . ($hours > 1 ? ' hours' : ' hour');
253 }
254
255 return join(' ', $parts);
256 }
257
258 /**
259 * Build browser cache section array.
260 *
261 * @param string $expire - value like - 1 day 12 hours 15 minutes
262 * @return array
263 */
264 public function prepare_browser_cache_section($expire) {
265 return array(
266 array(
267 '<IfModule mod_expires.c>',
268 'ExpiresActive On',
269 'ExpiresByType text/css "access '.$expire.'"',
270 'ExpiresByType text/html "access '.$expire.'"',
271 'ExpiresByType image/gif "access '.$expire.'"',
272 'ExpiresByType image/png "access '.$expire.'"',
273 'ExpiresByType image/jpg "access '.$expire.'"',
274 'ExpiresByType image/jpeg "access '.$expire.'"',
275 'ExpiresByType image/webp "access '.$expire.'"',
276 'ExpiresByType image/x-icon "access '.$expire.'"',
277 'ExpiresByType application/pdf "access '.$expire.'"',
278 'ExpiresByType application/javascript "access '.$expire.'"',
279 'ExpiresByType text/x-javascript "access '.$expire.'"',
280 'ExpiresByType application/x-shockwave-flash "access '.$expire.'"',
281 'ExpiresDefault "access '.$expire.'"',
282 '</IfModule>',
283 ),
284 '',
285 array(
286 '<IfModule mod_headers.c>',
287 array(
288 '<filesMatch "\.(ico|jpe?g|png|gif|webp|swf)$">',
289 'Header set Cache-Control "public"',
290 '</filesMatch>',
291 ),
292 array(
293 '<filesMatch "\.(css)$">',
294 'Header set Cache-Control "public"',
295 '</filesMatch>',
296 ),
297 array(
298 '<filesMatch "\.(js)$">',
299 'Header set Cache-Control "private"',
300 '</filesMatch>',
301 ),
302 array(
303 '<filesMatch "\.(x?html?|php)$">',
304 'Header set Cache-Control "private, must-revalidate"',
305 '</filesMatch>',
306 ),
307 '</IfModule>',
308 ),
309 '',
310 '#Disable ETag',
311 'FileETag None',
312 );
313 }
314 }
315