PluginProbe
Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score / 1.1
Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score v1.1
trunk 1.0 1.0.1 1.1 1.1.1 1.1.2 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.1 2.1.1 2.1.2 2.2 2.2.1 All 69 releases
powered-cache / includes / dropins / page-cache.php

page-cache.php in Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score 1.1, at includes/dropins/page-cache.php

387 lines 11.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * File based caching drop-in based on Taylor Lovett's Simple Cache
4 * @link https://github.com/tlovett1/simple-cache/blob/master/inc/dropins/file-based-page-cache.php
5 */
6 defined( 'ABSPATH' ) || exit;
7
8 // Don't cache robots.txt or htacesss
9 if ( strpos( $_SERVER['REQUEST_URI'], 'robots.txt' ) !== false || strpos( $_SERVER['REQUEST_URI'], '.htaccess' ) !== false ) {
10 return;
11 }
12
13 // Don't cache non-GET requests
14 if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || $_SERVER['REQUEST_METHOD'] !== 'GET' ) {
15 return;
16 }
17
18 // Don't cache wp-admin
19 if ( is_admin() ) {
20 return;
21 }
22
23
24
25 $file_extension = $_SERVER['REQUEST_URI'];
26 $file_extension = preg_replace( '#^(.*?)\?.*$#', '$1', $file_extension );
27 $file_extension = trim( preg_replace( '#^.*\.(.*)$#', '$1', $file_extension ) );
28
29 // Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc.
30 if ( ! preg_match( '#index\.php$#i', $_SERVER['REQUEST_URI'] ) && in_array( $file_extension, array( 'php', 'xml', 'xsl' ) ) ) {
31 return;
32 }
33
34 if ( ! $GLOBALS['powered_cache_options']['enable_page_caching'] ) {
35 return;
36 }
37
38 // Don't cache page with these user agents
39 if ( ! empty( $GLOBALS['powered_cache_options']['rejected_user_agents'] ) ) {
40 $rejected_user_agents = preg_split( '#(\r\n|\n|\r)#', $GLOBALS['powered_cache_options']['rejected_user_agents'] );
41 $rejected_user_agents = implode('|',$rejected_user_agents);
42 if ( ! empty( $rejected_user_agents ) && isset( $_SERVER['HTTP_USER_AGENT'] ) && preg_match( '#(' . $rejected_user_agents . ')#', $_SERVER['HTTP_USER_AGENT'] ) ) {
43 return;
44 }
45 }
46
47
48 // Don't cache SSL
49 if ( powered_cache_is_ssl() && ( ! isset( $GLOBALS['powered_cache_options']['ssl_cache'] ) || false === $GLOBALS['powered_cache_options']['ssl_cache'] ) ) {
50 return;
51 }
52
53
54 // dont cache mobile
55 if ( ! isset( $GLOBALS['powered_cache_options']['cache_mobile'] ) || true !== $GLOBALS['powered_cache_options']['cache_mobile'] ) {
56 global $powered_cache_mobile_browsers, $powered_cache_mobile_prefixes;
57
58 $mobile_browsers = addcslashes( implode( '|', preg_split( '/[\s*,\s*]*,+[\s*,\s*]*/', $powered_cache_mobile_browsers ) ), ' ' );
59 $mobile_prefixes = addcslashes( implode( '|', preg_split( '/[\s*,\s*]*,+[\s*,\s*]*/', $powered_cache_mobile_prefixes ) ), ' ' );
60 // Don't cache if mobile detection is activated
61 if ( (preg_match('#^.*('.$mobile_browsers.').*#i', $_SERVER['HTTP_USER_AGENT']) || preg_match('#^('.$mobile_prefixes.').*#i', substr($_SERVER['HTTP_USER_AGENT'], 0, 4))) ) {
62 return '';
63 }
64
65 }
66
67
68 if ( ! empty( $_COOKIE ) ) {
69
70 //Don't cache if logged in
71 if ( ! isset( $GLOBALS['powered_cache_options']['loggedin_user_cache'] ) || false === $GLOBALS['powered_cache_options']['loggedin_user_cache'] ) {
72 $wp_cookies = array( 'wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_' );
73
74 // check logged-in cookie
75 foreach ( $_COOKIE as $key => $value ) {
76 foreach ( $wp_cookies as $cookie ) {
77 if ( strpos( $key, $cookie ) !== false ) {
78 // Logged in!
79 return;
80 }
81 }
82 }
83 }
84
85
86 if ( ! empty( $_COOKIE['powered_cache_commented_posts'] ) ) {
87 foreach ( $_COOKIE['powered_cache_commented_posts'] as $path ) {
88 if ( rtrim( $path, '/') === rtrim( $_SERVER['REQUEST_URI'], '/' ) ) {
89 // User commented on this post
90 return;
91 }
92 }
93 }
94
95 // don't cache specific cookie
96 if ( ! empty( $GLOBALS['powered_cache_options']['rejected_cookies'] ) ) {
97 $rejected_cookies = preg_split( '#(\r\n|\n|\r)#', $GLOBALS['powered_cache_options']['rejected_cookies'] );
98 $rejected_cookies = implode( '|', $rejected_cookies );
99 if ( preg_match( '#(' . $rejected_cookies . ')#', var_export( $_COOKIE, true ) ) ) {
100 return;
101 }
102 }
103
104 }
105
106
107 // Deal with optional cache exceptions
108 if ( ! empty( $GLOBALS['powered_cache_options']['rejected_uri'] ) ) {
109 $exceptions = preg_split( '#(\n|\r)#', $GLOBALS['powered_cache_options']['rejected_uri'] );
110
111 foreach ( $exceptions as $exception ) {
112 if ( preg_match( '#^[\s]*$#', $exception ) ) {
113 continue;
114 }
115
116 // full url exception
117 if ( preg_match( '#^https?://#', $exception ) ) {
118 $exception = parse_url( $exception, PHP_URL_PATH );
119 }
120
121 if ( preg_match( '#^(' . $exception . ')$#', $_SERVER['REQUEST_URI'] ) ) {
122 return;
123 }
124
125 }
126 }
127
128
129 $accepted_query_strings = array();
130 // cache url with allowed query string
131 if ( ! empty( $GLOBALS['powered_cache_options']['accepted_query_strings'] ) ) {
132 $accepted_query_strings = preg_split( '#(\r\n|\n|\r)#', $GLOBALS['powered_cache_options']['accepted_query_strings'] );
133 }
134
135 if ( ! empty( $_GET ) && isset( $accepted_query_strings ) && is_array( $accepted_query_strings ) && ! array_intersect( array_keys( $_GET ), $accepted_query_strings ) ) {
136 return;
137 }
138
139
140
141 powered_cache_serve_cache();
142
143 ob_start( 'powered_cache_page_buffer' );
144
145 /**
146 * Cache output before it goes to the browser
147 *
148 * @param string $buffer
149 * @param int $flags
150 * @since 1.0
151 * @return string
152 */
153 function powered_cache_page_buffer( $buffer, $flags ) {
154 if ( strlen( $buffer ) < 255 ) {
155 return $buffer;
156 }
157
158 // Don't cache search, 404, or password protected
159 if ( is_404() || is_search() || post_password_required() ) {
160 return $buffer;
161 }
162
163
164 // maybe we shouldn't cache template file has this constant
165 if ( defined( 'DONOTCACHEPAGE' ) && true === DONOTCACHEPAGE ) {
166 return $buffer;
167 }
168
169 // plugins might want to use filter
170 if ( true !== apply_filters( 'powered_cache_page_cache_enable', true ) ) {
171 return $buffer;
172 }
173
174
175
176 include_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
177 include_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
178
179 $filesystem = new WP_Filesystem_Direct( new StdClass() );
180
181 // Make sure we can read/write files and that proper folders exist
182 if ( ! $filesystem->exists( untrailingslashit( powered_cache_get_cache_dir() ) ) ) {
183 if ( ! $filesystem->mkdir( untrailingslashit( powered_cache_get_cache_dir() ) ) ) {
184 // Can not cache!
185 return $buffer;
186 }
187 }
188
189 if ( ! $filesystem->exists( powered_cache_get_page_cache_dir() ) ) {
190 if ( ! $filesystem->mkdir( powered_cache_get_page_cache_dir() ) ) {
191 // Can not cache!
192 return $buffer;
193 }
194 }
195
196 $buffer = apply_filters( 'powered_cache_page_caching_buffer', $buffer );
197
198 $url_path = powered_cache_get_url_path();
199
200 $dirs = explode( '/', $url_path );
201
202 $path = untrailingslashit( powered_cache_get_page_cache_dir() );
203
204 foreach ( $dirs as $dir ) {
205 if ( ! empty( $dir ) ) {
206 $path .= '/' . $dir;
207
208 if ( ! $filesystem->exists( $path ) ) {
209 if ( ! $filesystem->mkdir( $path ) ) {
210 // Can not cache!
211 return $buffer;
212 }
213 }
214 }
215 }
216
217 $modified_time = time(); // Make sure modified time is consistent
218
219 if ( array_key_exists( 'show_cache_message', $GLOBALS['powered_cache_options'] ) && true === $GLOBALS['powered_cache_options']['show_cache_message'] ) {
220 if ( preg_match( '#</html>#i', $buffer ) ) {
221 $buffer .= "\n<!-- Cache served by Powered Cache - Last modified: " . gmdate( 'D, d M Y H:i:s', $modified_time ) . " GMT -->\n";
222 }
223 }
224
225 $index_name = powered_cache_index_file();
226
227 if ( $GLOBALS['powered_cache_options']['gzip_compression'] && function_exists( 'gzencode' ) ) {
228 $filesystem->put_contents( $path . '/' . $index_name, gzencode( $buffer, 3 ), FS_CHMOD_FILE );
229 $filesystem->touch( $path . '/' . $index_name, $modified_time );
230 } else {
231 $filesystem->put_contents( $path . '/' . $index_name, $buffer, FS_CHMOD_FILE );
232 $filesystem->touch( $path . '/' . $index_name, $modified_time );
233 }
234
235 header( 'Cache-Control: no-cache' ); // Check back every time to see if re-download is necessary
236
237 header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $modified_time ) . ' GMT' );
238
239
240 do_action( 'powered_cache_page_cached', $buffer );
241
242 if ( function_exists( 'ob_gzhandler' ) && $GLOBALS['powered_cache_options']['gzip_compression'] ) {
243 return ob_gzhandler( $buffer, $flags );
244 } else {
245 return $buffer;
246 }
247 }
248
249
250 /**
251 * Optionally serve cache and exit
252 *
253 * @since 1.0
254 */
255 function powered_cache_serve_cache() {
256
257 $file_name = powered_cache_index_file();
258
259 $path = rtrim( $GLOBALS['powered_cache_options']['cache_location'], '/' ) . '/powered-cache/' . rtrim( powered_cache_get_url_path(), '/' ) . '/' . $file_name;
260
261 $modified_time = (int) @filemtime( $path );
262
263 header( 'Cache-Control: no-cache' ); // Check back in an hour
264
265 if ( ! empty( $modified_time ) && ! empty( $_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ] ) && strtotime( $_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ] ) === $modified_time ) {
266 header( $_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304 );
267 exit;
268 }
269
270 if ( @file_exists( $path ) && @is_readable( $path ) ) {
271
272 header( 'X-Powered-Cache: php' );
273
274 if ( function_exists( 'gzencode' ) && $GLOBALS['powered_cache_options']['gzip_compression'] ) {
275 header( 'Content-Encoding: gzip' );
276 }
277
278 @readfile( $path );
279
280 exit;
281 }
282 }
283
284 /**
285 * Get URL path for caching
286 *
287 * @since 1.0
288 * @return string
289 */
290 function powered_cache_get_url_path() {
291
292 $host = ( isset( $_SERVER['HTTP_HOST'] ) ) ? $_SERVER['HTTP_HOST'] : '';
293
294
295 return rtrim( $host, '/' ) . $_SERVER['REQUEST_URI'];
296 }
297
298 function powered_cache_get_user_cookie() {
299 if ( empty( $_COOKIE ) ) {
300 return false;
301 }
302
303 foreach ( $_COOKIE as $c_key => $val ) {
304 if ( false !== strpos( $c_key, 'wordpress_logged_in_' ) ) {
305 return $val;
306 }
307 }
308
309 return false;
310 }
311
312
313 /**
314 * Determines cache file names
315 * @since 1.0
316 * @return string
317 */
318 function powered_cache_index_file() {
319 $file_name = 'index';
320
321 if ( powered_cache_is_ssl() ) {
322 $file_name .= '-https';
323 }
324
325 // separate file for mobile cache
326 if ( isset( $GLOBALS['powered_cache_options']['cache_mobile'], $GLOBALS['powered_cache_options']['cache_mobile_separate_file'] )
327 && true === $GLOBALS['powered_cache_options']['cache_mobile']
328 && true === $GLOBALS['powered_cache_options']['cache_mobile_separate_file']
329 ) {
330
331
332 global $powered_cache_mobile_browsers, $powered_cache_mobile_prefixes;
333
334 $mobile_browsers = addcslashes( implode( '|', preg_split( '/[\s*,\s*]*,+[\s*,\s*]*/', $powered_cache_mobile_browsers ) ), ' ' );
335 $mobile_prefixes = addcslashes( implode( '|', preg_split( '/[\s*,\s*]*,+[\s*,\s*]*/', $powered_cache_mobile_prefixes ) ), ' ' );
336
337 // Don't cache if mobile detection is activated
338 if ( (preg_match('#^.*('.$mobile_browsers.').*#i', $_SERVER['HTTP_USER_AGENT']) || preg_match('#^('.$mobile_prefixes.').*#i', substr($_SERVER['HTTP_USER_AGENT'], 0, 4))) ) {
339 $file_name .= '-mobile';
340 }
341 }
342
343
344 if ( isset( $GLOBALS['powered_cache_options']['loggedin_user_cache'] )
345 && true === $GLOBALS['powered_cache_options']['loggedin_user_cache']
346 ) {
347 $usr_cookie = powered_cache_get_user_cookie();
348 if ( false !== $usr_cookie ) {
349 $cookie_info = explode( '|', $usr_cookie );
350
351 // user specific cache dir
352 $file_name .= '_' . $cookie_info[0] . '-' . $cookie_info[1];
353 }
354 }
355
356
357 $file_name .= '.html';
358
359 if ( function_exists( 'gzencode' ) && $GLOBALS['powered_cache_options']['gzip_compression'] ) {
360 $file_name .= '_gzip';
361 }
362
363 return $file_name;
364 }
365
366
367 /**
368 * is_ssl moved load.php in WP 4.6 but we support WP 4.1+
369 *
370 * @return bool
371 */
372 function powered_cache_is_ssl() {
373 if ( isset( $_SERVER['HTTPS'] ) ) {
374 if ( 'on' == strtolower( $_SERVER['HTTPS'] ) ) {
375 return true;
376 }
377
378 if ( '1' == $_SERVER['HTTPS'] ) {
379 return true;
380 }
381 } elseif ( isset( $_SERVER['SERVER_PORT'] ) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
382 return true;
383 }
384
385 return false;
386 }
387