Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/wp-rocket/inc/functions/files.php

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + <?php
2 +
3 + use WP_Rocket\Logger\Logger;
4 + use WP_Rocket\Engine\Cache\AdvancedCache;
5 +
6 + defined( 'ABSPATH' ) || exit;
7 +
8 + /**
9 + * Creates the advanced-cache.php file.
10 + *
11 + * @since 3.6 Uses AdvancedCache::get_advanced_cache_content().
12 + * @since 2.0
13 + *
14 + * @param AdvancedCache $advanced_cache Optional. Instance of the advanced cache handler.
15 + */
16 + function rocket_generate_advanced_cache_file( $advanced_cache = null ) {
17 + /**
18 + * Filters whether to generate the advanced-cache.php file.
19 + *
20 + * @since 3.6.3
21 + *
22 + * @param bool True (default) to go ahead with advanced cache file generation; false to stop generation.
23 + */
24 + if ( ! (bool) apply_filters( 'rocket_generate_advanced_cache_file', true ) ) {
25 + return false;
26 + }
27 +
28 + static $done = false;
29 +
30 + if ( rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ) {
31 + $done = false;
32 + }
33 +
34 + if ( $done ) {
35 + return false;
36 + }
37 + $done = true;
38 +
39 + if ( is_null( $advanced_cache ) ) {
40 + $container = apply_filters( 'rocket_container', null );
41 + $advanced_cache = $container->get( 'advanced_cache' );
42 + }
43 +
44 + return rocket_put_content(
45 + rocket_get_constant( 'WP_CONTENT_DIR' ) . '/advanced-cache.php',
46 + $advanced_cache->get_advanced_cache_content()
47 + );
48 + }
49 +
50 + /**
51 + * Generates the configuration file for the current domain based on the values of options
52 + *
53 + * @since 2.0
54 + *
55 + * @return array Names of all config files & The content that will be printed
56 + */
57 + function get_rocket_config_file() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
58 + $options = get_option( WP_ROCKET_SLUG );
59 +
60 + if ( ! $options ) {
61 + return [
62 + [],
63 + '',
64 + ];
65 + }
66 +
67 + $buffer = "<?php\n";
68 + $buffer .= "defined( 'ABSPATH' ) || exit;\n\n";
69 +
70 + $buffer .= '$rocket_cookie_hash = \'' . COOKIEHASH . "';\n";
71 + $buffer .= '$rocket_logged_in_cookie = \'' . LOGGED_IN_COOKIE . "';\n";
72 +
73 + /**
74 + * Filters the activation of the common cache for logged-in users.
75 + *
76 + * @since 2.10
77 + * @author Remy Perona
78 + *
79 + * @param bool True to activate the common cache, false to ignore.
80 + */
81 + if ( apply_filters( 'rocket_common_cache_logged_users', false ) ) {
82 + $buffer .= '$rocket_common_cache_logged_users = 1;' . "\n";
83 + }
84 +
85 + if ( ! empty( $options['cache_webp'] ) ) {
86 + /** This filter is documented in inc/classes/buffer/class-cache.php */
87 + $disable_webp_cache = apply_filters( 'rocket_disable_webp_cache', false );
88 +
89 + if ( $disable_webp_cache ) {
90 + $options['cache_webp'] = 0;
91 + }
92 + }
93 +
94 + /**
95 + * Filters the use of the mobile cache version for tablets
96 + * 'desktop' will serve desktop to tablets, 'mobile' will serve mobile to tablets
97 + *
98 + * @since 3.2
99 + * @author Remy Perona
100 + *
101 + * @param string $tablet_version valid values are 'mobile' or 'desktop'
102 + */
103 + $buffer .= '$rocket_cache_mobile_files_tablet = \'' . apply_filters( 'rocket_cache_mobile_files_tablet', 'desktop' ) . "';\n";
104 +
105 + foreach ( $options as $option => $value ) {
106 + if ( 'cache_ssl' === $option ) {
107 + if ( 1 !== (int) $value ) {
108 + if ( rocket_is_ssl_website() ) {
109 + update_rocket_option( 'cache_ssl', 1 );
110 + $value = 1;
111 + }
112 + }
113 +
114 + $buffer .= '$rocket_' . $option . ' = ' . (int) $value . ";\n";
115 + }
116 +
117 + if ( 'cache_mobile' === $option || 'do_caching_mobile_files' === $option || 'cache_webp' === $option ) {
118 + $buffer .= '$rocket_' . $option . ' = ' . (int) $value . ";\n";
119 + }
120 +
121 + if ( 'secret_cache_key' === $option ) {
122 + $buffer .= '$rocket_' . $option . ' = \'' . sanitize_key( $value ) . "';\n";
123 + }
124 +
125 + if ( 'cache_reject_uri' === $option ) {
126 + $buffer .= '$rocket_' . $option . ' = \'' . get_rocket_cache_reject_uri( true ) . "';\n";
127 + }
128 +
129 + if ( 'cache_query_strings' === $option ) {
130 + $buffer .= '$rocket_' . $option . ' = ' . call_user_func( 'var_export', get_rocket_cache_query_string(), true ) . ";\n";
131 + }
132 +
133 + if ( 'cache_reject_cookies' === $option ) {
134 + $cookies = get_rocket_cache_reject_cookies();
135 +
136 + if ( $cookies && get_rocket_option( 'cache_logged_user' ) ) {
137 + // Make sure the "logged-in cookies" are not rejected.
138 + $logged_in_cookie = explode( COOKIEHASH, LOGGED_IN_COOKIE );
139 + $logged_in_cookie = array_map( 'preg_quote', $logged_in_cookie );
140 + $logged_in_cookie = implode( '[^|]*', $logged_in_cookie );
141 + $cookies = preg_replace( '/\|' . $logged_in_cookie . '\|/', '|', '|' . $cookies . '|' );
142 + $cookies = trim( $cookies, '|' );
143 + }
144 +
145 + $buffer .= '$rocket_' . $option . ' = \'' . $cookies . "';\n";
146 + }
147 +
148 + if ( 'cache_reject_ua' === $option ) {
149 + $buffer .= '$rocket_' . $option . ' = \'' . get_rocket_cache_reject_ua() . "';\n";
150 + }
151 + }
152 +
153 + $buffer .= '$rocket_cache_ignored_parameters = ' . call_user_func( 'var_export', rocket_get_ignored_parameters(), true ) . ";\n";
154 + $buffer .= '$rocket_cache_mandatory_cookies = ' . call_user_func( 'var_export', get_rocket_cache_mandatory_cookies(), true ) . ";\n";
155 +
156 + $buffer .= '$rocket_cache_dynamic_cookies = ' . call_user_func( 'var_export', get_rocket_cache_dynamic_cookies(), true ) . ";\n";
157 +
158 + $buffer .= '$rocket_permalink_structure = \'' . wp_slash( get_option( 'permalink_structure' ) ) . "';\n";
159 +
160 + /** This filter is documented in inc/front/htaccess.php */
161 + if ( apply_filters( 'rocket_url_no_dots', false ) ) {
162 + $buffer .= '$rocket_url_no_dots = 1;';
163 + }
164 +
165 + $config_files_path = [];
166 + $urls = [ rocket_get_home_url() ];
167 +
168 + // Check if a translation plugin is activated and this configuration is in subdomain.
169 + $subdomains = get_rocket_i18n_subdomains();
170 +
171 + if ( $subdomains ) {
172 + $urls = $subdomains;
173 + }
174 +
175 + foreach ( $urls as $url ) {
176 + $file = get_rocket_parse_url( untrailingslashit( $url ) );
177 + $file['path'] = ( ! empty( $file['path'] ) ) ? str_replace( '/', '.', untrailingslashit( $file['path'] ) ) : '';
178 + $config_files_path[] = WP_ROCKET_CONFIG_PATH . strtolower( $file['host'] ) . $file['path'] . '.php';
179 + }
180 +
181 + /**
182 + * Filter all config files path
183 + *
184 + * @since 2.6.5
185 + *
186 + * @param array $config_files_path Path of all config files.
187 + */
188 + $config_files_path = apply_filters( 'rocket_config_files_path', $config_files_path );
189 +
190 + /**
191 + * Filter the content of all config files
192 + *
193 + * @since 2.1
194 + *
195 + * @param string $buffer The content that will be printed.
196 + * @param array $config_files_path Names of all config files.
197 + */
198 + $buffer = apply_filters( 'rocket_config_file', $buffer, $config_files_path );
199 + $buffer = preg_replace( '@array\s+\(@i', 'array(', $buffer );
200 + $buffer = preg_replace( '@array\(\s+\)@i', 'array()', $buffer );
201 +
202 + return [ $config_files_path, $buffer ];
203 + }
204 +
205 + /**
206 + * Create the current config domain file
207 + * For example, if home_url() return example.com, the config domain file will be in /config/example.com
208 + *
209 + * @since 2.0
210 + *
211 + * @return void
212 + */
213 + function rocket_generate_config_file() {
214 + list( $config_files_path, $buffer ) = get_rocket_config_file();
215 +
216 + if ( count( $config_files_path ) ) {
217 + rocket_init_config_dir();
218 +
219 + foreach ( $config_files_path as $file ) {
220 + rocket_put_content( $file, $buffer );
221 + }
222 + }
223 + }
224 +
225 + /**
226 + * Remove the current config domain file
227 + *
228 + * @since 2.6
229 + *
230 + * @return void
231 + */
232 + function rocket_delete_config_file() {
233 + list( $config_files_path ) = get_rocket_config_file();
234 + foreach ( $config_files_path as $config_file ) {
235 + rocket_direct_filesystem()->delete( $config_file );
236 + }
237 +
238 + // Bail out if WP Rocket is multisite.
239 + if ( is_multisite() ) {
240 + return;
241 + }
242 +
243 + try {
244 + $config_dir = new FilesystemIterator( (string) rocket_get_constant( 'WP_ROCKET_CONFIG_PATH' ) );
245 + } catch ( Exception $e ) {
246 + return;
247 + }
248 +
249 + // Remove all files with php extension in the config folder.
250 + foreach ( $config_dir as $file ) {
251 + if ( ! $file->isFile() || 'php' !== strtolower( $file->getExtension() ) ) {
252 + continue;
253 + }
254 +
255 + if ( 1 === substr_count( $file->getFilename(), '.' ) ) {
256 + continue;
257 + }
258 +
259 + if ( false === strpos( rocket_direct_filesystem()->get_contents( $file->getPathname() ), '$rocket_cookie_hash' ) ) {
260 + continue;
261 + }
262 +
263 + rocket_direct_filesystem()->delete( $file->getPathname() );
264 + }
265 + }
266 +
267 + /**
268 + * Create all cache folders (wp-rocket & min)
269 + *
270 + * @since 2.6
271 + *
272 + * @return void
273 + */
274 + function rocket_init_cache_dir() {
275 + global $is_apache;
276 +
277 + $filesystem = rocket_direct_filesystem();
278 +
279 + // Create cache folder if not exist.
280 + if ( ! $filesystem->is_dir( WP_ROCKET_CACHE_PATH ) ) {
281 + rocket_mkdir_p( WP_ROCKET_CACHE_PATH );
282 + }
283 +
284 + if ( ! $filesystem->is_file( WP_ROCKET_CACHE_PATH . 'index.html' ) ) {
285 + $filesystem->touch( WP_ROCKET_CACHE_PATH . 'index.html' );
286 + }
287 +
288 + if ( $is_apache ) {
289 + $htaccess_path = WP_ROCKET_CACHE_PATH . '.htaccess';
290 +
291 + if ( ! $filesystem->is_file( $htaccess_path ) ) {
292 + $filesystem->touch( $htaccess_path );
293 + rocket_put_content( $htaccess_path, "<IfModule mod_autoindex.c>\nOptions -Indexes\n</IfModule>" );
294 + }
295 + }
296 +
297 + // Create minify cache folder if not exist.
298 + if ( ! $filesystem->is_dir( WP_ROCKET_MINIFY_CACHE_PATH ) ) {
299 + rocket_mkdir_p( WP_ROCKET_MINIFY_CACHE_PATH );
300 + }
301 +
302 + if ( ! $filesystem->is_file( WP_ROCKET_MINIFY_CACHE_PATH . 'index.html' ) ) {
303 + $filesystem->touch( WP_ROCKET_MINIFY_CACHE_PATH . 'index.html' );
304 + }
305 +
306 + // Create busting cache folder if not exist.
307 + if ( ! $filesystem->is_dir( WP_ROCKET_CACHE_BUSTING_PATH ) ) {
308 + rocket_mkdir_p( WP_ROCKET_CACHE_BUSTING_PATH );
309 + }
310 +
311 + if ( ! $filesystem->is_file( WP_ROCKET_CACHE_BUSTING_PATH . 'index.html' ) ) {
312 + $filesystem->touch( WP_ROCKET_CACHE_BUSTING_PATH . 'index.html' );
313 + }
314 +
315 + // Create critical CSS folder if not exist.
316 + if ( ! $filesystem->is_dir( WP_ROCKET_CRITICAL_CSS_PATH ) ) {
317 + rocket_mkdir_p( WP_ROCKET_CRITICAL_CSS_PATH );
318 + }
319 +
320 + if ( ! $filesystem->is_file( WP_ROCKET_CRITICAL_CSS_PATH . 'index.html' ) ) {
321 + $filesystem->touch( WP_ROCKET_CRITICAL_CSS_PATH . 'index.html' );
322 + }
323 + }
324 +
325 + /**
326 + * Create the config folder (wp-rocket-config)
327 + *
328 + * @since 2.6
329 + *
330 + * @return void
331 + */
332 + function rocket_init_config_dir() {
333 + $filesystem = rocket_direct_filesystem();
334 +
335 + // Create config domain folder if not exist.
336 + if ( ! $filesystem->is_dir( WP_ROCKET_CONFIG_PATH ) ) {
337 + rocket_mkdir_p( WP_ROCKET_CONFIG_PATH );
338 + }
339 +
340 + // Initialize the config directory with index.html to prevent indexing.
341 + if ( ! $filesystem->is_file( WP_ROCKET_CONFIG_PATH . 'index.html' ) ) {
342 + $filesystem->touch( WP_ROCKET_CONFIG_PATH . 'index.html' );
343 + }
344 + }
345 +
346 + /**
347 + * Delete all minify cache files.
348 + *
349 + * @since 3.5.3 Replaces glob.
350 + * @since 2.1
351 + *
352 + * @param string|array $extensions Optional. File extensions to minify. Default: js and css.
353 + */
354 + function rocket_clean_minify( $extensions = [ 'js', 'css' ] ) {
355 + // Bails out if there are no extensions to target.
356 + if ( empty( $extensions ) ) {
357 + return;
358 + }
359 +
360 + if ( is_string( $extensions ) ) {
361 + $extensions = (array) $extensions;
362 + }
363 +
364 + $min_cache_path = rocket_get_constant( 'WP_ROCKET_MINIFY_CACHE_PATH' );
365 + $min_path = $min_cache_path . get_current_blog_id() . '/';
366 + $iterator = _rocket_get_cache_path_iterator( $min_path );
367 +
368 + if ( false === $iterator ) {
369 + return;
370 + }
371 +
372 + $filesystem = rocket_direct_filesystem();
373 + $min_path_regex = str_replace( '/', '\/', $min_path );
374 +
375 + foreach ( $extensions as $ext ) {
376 + /**
377 + * Fires before the minify cache files are deleted.
378 + *
379 + * @since 2.1
380 + *
381 + * @param string $ext File extensions to minify.
382 + */
383 + do_action( 'before_rocket_clean_minify', $ext ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
384 +
385 + try {
386 + $entries = new RegexIterator( $iterator, "/{$min_path_regex}.*\.{$ext}/" );
387 + } catch ( Exception $e ) {
388 + return;
389 + }
390 +
391 + foreach ( $entries as $entry ) {
392 + $filesystem->delete( $entry->getPathname() );
393 + }
394 +
395 + /**
396 + * Fires after the minify cache files was deleted.
397 + *
398 + * @since 2.1
399 + *
400 + * @param string $ext File extensions to minify.
401 + */
402 + do_action( 'after_rocket_clean_minify', $ext ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
403 + }
404 +
405 + // Delete any directories.
406 + foreach ( $iterator as $item ) {
407 + if ( $filesystem->is_dir( $item ) ) {
408 + $filesystem->delete( $item );
409 + }
410 + }
411 +
412 + // Clean the cache/min/3rd-party items.
413 + try {
414 + $files = new FilesystemIterator( "{$min_cache_path}3rd-party" );
415 +
416 + foreach ( $files as $file ) {
417 + if ( $filesystem->is_file( $file ) ) {
418 + $filesystem->delete( $file );
419 + }
420 + }
421 + } catch ( UnexpectedValueException $e ) {
422 + // No logging yet.
423 + return;
424 + }
425 + }
426 +
427 + /**
428 + * Delete all cache busting files.
429 + *
430 + * @since 2.9
431 + *
432 + * @param string|array $extensions (default: array('js','css') File extensions to clean.
433 + * @return void
434 + */
435 + function rocket_clean_cache_busting( $extensions = [ 'js', 'css' ] ) {
436 + if ( empty( $extensions ) ) {
437 + return;
438 + }
439 +
440 + if ( is_string( $extensions ) ) {
441 + $extensions = (array) $extensions;
442 + }
443 +
444 + $cache_busting_path = rocket_get_constant( 'WP_ROCKET_CACHE_BUSTING_PATH' ) . get_current_blog_id() . '/';
445 + $iterator = _rocket_get_cache_path_iterator( $cache_busting_path );
446 +
447 + if ( false === $iterator ) {
448 + return;
449 + }
450 +
451 + $filesystem = rocket_direct_filesystem();
452 + $busting_path_regex = str_replace( '/', '\/', $cache_busting_path );
453 +
454 + if ( ! rocket_direct_filesystem()->is_dir( $cache_busting_path ) ) {
455 + rocket_mkdir_p( $cache_busting_path );
456 +
457 + Logger::debug(
458 + 'No Cache Busting folder found.',
459 + [
460 + 'mkdir cache busting folder',
461 + 'cache_busting_path' => $cache_busting_path,
462 + ]
463 + );
464 +
465 + return;
466 + }
467 +
468 + foreach ( $extensions as $ext ) {
469 + /**
470 + * Fires before the cache busting files are deleted
471 + *
472 + * @since 2.9
473 + *
474 + * @param string $ext File extensions to clean.
475 + */
476 + do_action( 'before_rocket_clean_busting', $ext ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
477 +
478 + try {
479 + $entries = new RegexIterator( $iterator, "/{$busting_path_regex}.*\.{$ext}/" );
480 + } catch ( Exception $e ) {
481 + return;
482 + }
483 +
484 + foreach ( $entries as $entry ) {
485 + $filesystem->delete( $entry->getPathname() );
486 + }
487 +
488 + /**
489 + * Fires after the cache busting files was deleted
490 + *
491 + * @since 2.9
492 + *
493 + * @param string $ext File extensions to clean.
494 + */
495 + do_action( 'after_rocket_clean_cache_busting', $ext ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
496 + }
497 +
498 + foreach ( $iterator as $item ) {
499 + if ( $filesystem->is_dir( $item ) ) {
500 + $filesystem->delete( $item );
501 + }
502 + }
503 + }
504 +
505 + /**
506 + * Returns the right path when the post is trashed.
507 + *
508 + * @param array $parsed_url current parsed url.
509 + * @param int $post_id ID from the post.
510 + *
511 + * @return array
512 + */
513 + function rocket_maybe_find_right_trash_url( array $parsed_url, int $post_id ) {
514 +
515 + $post = get_post( $post_id );
516 +
517 + if ( ! $post || 'trash' !== $post->post_status ) {
518 + return $parsed_url;
519 + }
520 +
521 + $post->post_status = 'publish';
522 +
523 + $permalink = get_permalink( $post );
524 +
525 + if ( ! $permalink ) {
526 + return $parsed_url;
527 + }
528 +
529 + $new_permalink = str_replace( '__trashed', '', $permalink );
530 + return get_rocket_parse_url( $new_permalink );
531 + }
532 +
533 + /**
534 + * Delete one or several cache files.
535 + *
536 + * @since 3.5.5 Optimizes by grabbing root cache dirs once, bailing out when file/dir doesn't exist, & directly
537 + * deleting files.
538 + * @since 3.5.4 Replaces glob and optimizes.
539 + * @since 2.0 Delete cache files for all users.
540 + * @since 1.1.0 Add filter rocket_clean_files.
541 + * @since 1.0
542 + *
543 + * @param string|array $urls URLs of cache files to be deleted.
544 + * @param WP_Filesystem_Direct|null $filesystem Optional. Instance of filesystem handler.
545 + * @param bool $run_actions Run actions.
546 + */
547 + function rocket_clean_files( $urls, $filesystem = null, $run_actions = true ) {
548 + $urls = (array) $urls;
549 + if ( empty( $urls ) ) {
550 + return;
551 + }
552 +
553 + $urls = array_filter( $urls );
554 + if ( empty( $urls ) ) {
555 + return;
556 + }
557 +
558 + /** This filter is documented in inc/front/htaccess.php */
559 + $url_no_dots = (bool) apply_filters( 'rocket_url_no_dots', false );
560 + $cache_path = _rocket_get_wp_rocket_cache_path();
561 +
562 + if ( empty( $filesystem ) ) {
563 + $filesystem = rocket_direct_filesystem();
564 + }
565 +
566 + if ( $run_actions ) {
567 + /**
568 + * Fires before all cache files are deleted.
569 + *
570 + * @since 3.2.2
571 + *
572 + * @param array $urls The URLs corresponding to the deleted cache files.
573 + */
574 + do_action( 'before_rocket_clean_files', $urls ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
575 + }
576 +
577 + foreach ( $urls as $url_key => $url ) {
578 + if ( $run_actions ) {
579 + /**
580 + * Fires before the cache file is deleted.
581 + *
582 + * @param string $url The URL that the cache file to be deleted.
583 + * @since 1.0
584 + */
585 + do_action( 'before_rocket_clean_file', $url ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
586 + }
587 +
588 + if ( $url_no_dots ) {
589 + $url = str_replace( '.', '_', $url );
590 + }
591 +
592 + $parsed_url = get_rocket_parse_url( $url );
593 +
594 + if ( ! empty( $parsed_url['host'] ) ) {
595 + foreach ( _rocket_get_cache_dirs( $parsed_url['host'], $cache_path ) as $dir ) {
596 + // Decode url path.
597 + $url_chunks = explode( '/', $parsed_url['path'] );
598 + $matches = preg_grep( '/%/', $url_chunks );
599 +
600 + if ( ! empty( $matches ) ) {
601 + $parsed_url['path'] = rawurldecode( $parsed_url['path'] );
602 + }
603 +
604 + // Encode Non-latin characters if found in url path.
605 + if ( false !== preg_match_all( '/(?<non_latin>[^\x00-\x7F]+)/', $parsed_url['path'], $matches ) ) {
606 + $cb_encode_non_latin = function ( $non_latin ) {
607 + return strtolower( rawurlencode( $non_latin ) );
608 + };
609 +
610 + $parsed_url['path'] = str_replace( $matches['non_latin'], array_map( $cb_encode_non_latin, $matches['non_latin'] ), $parsed_url['path'] );
611 + }
612 +
613 + $entry = $dir . $parsed_url['path'];
614 +
615 + // For regex we use it for file names only, and it should include the * character.
616 + if ( str_contains( $entry, '*' ) ) {
617 + $regex_part = basename( $entry );
618 + $search_dir = str_replace( $regex_part, '', $entry );
619 + $matched_files = _rocket_get_dir_files_by_regex( $search_dir, '#' . $regex_part . '#i' );
620 + foreach ( $matched_files as $item ) {
621 + $current_file = $item->getPath() . DIRECTORY_SEPARATOR . $item->getFilename();
622 + if ( $filesystem->exists( $current_file ) ) {
623 + $filesystem->delete( $current_file );
624 + }
625 + }
626 + // Remove the regex part from the url.
627 + $url = str_replace( $regex_part, '', $url );
628 + $urls[ $url_key ] = $url;
629 + }
630 +
631 + // Skip if the dir/file does not exist.
632 + if ( ! $filesystem->exists( $entry ) ) {
633 + continue;
634 + }
635 +
636 + if ( $filesystem->is_dir( $entry ) ) {
637 + rocket_rrmdir( $entry, [], $filesystem );
638 + } else {
639 + $filesystem->delete( $entry );
640 + }
641 + }
642 + }
643 + if ( $run_actions ) {
644 + /**
645 + * Fires after the cache file is deleted.
646 + *
647 + * @param string $url The URL that the cache file was deleted.
648 + * @since 1.0
649 + */
650 + do_action( 'after_rocket_clean_file', $url ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
651 + }
652 + }
653 +
654 + if ( ! $run_actions ) {
655 + return;
656 + }
657 +
658 + /**
659 + * Fires after all cache files are deleted.
660 + *
661 + * @since 3.2.2
662 + *
663 + * @param array $urls The URLs corresponding to the deleted cache files.
664 + */
665 + do_action( 'after_rocket_clean_files', $urls ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
666 + }
667 +
668 + /**
669 + * Remove the home cache file and pagination
670 + *
671 + * $since 2.2 Add $lang argument
672 + *
673 + * @since 2.0 Delete cache files for all users
674 + * @since 1.0
675 + *
676 + * @param string $lang (default: '') The language code.
677 + * @return void
678 + */
679 + function rocket_clean_home( $lang = '' ) {
680 + $parse_url = get_rocket_parse_url( get_rocket_i18n_home_url( $lang ) );
681 +
682 + /** This filter is documented in inc/front/htaccess.php */
683 + if ( apply_filters( 'rocket_url_no_dots', false ) ) {
684 + $parse_url['host'] = str_replace( '.', '_', $parse_url['host'] );
685 + }
686 +
687 + $root = WP_ROCKET_CACHE_PATH . $parse_url['host'] . '*' . untrailingslashit( $parse_url['path'] );
688 +
689 + /**
690 + * Filter the homepage caching folder root
691 + *
692 + * @since 2.6.5
693 + * @param array $root The root that will be returned.
694 + * @param string $host The website host.
695 + * @param string $path The website path.
696 + */
697 + $root = apply_filters( 'rocket_clean_home_root', $root, $parse_url['host'], $parse_url['path'] );
698 +
699 + /**
700 + * Fires before the home cache file is deleted
701 + *
702 + * @since 1.0
703 + *
704 + * @param string $root The path of home cache file.
705 + * @param string $lang The current lang to purge.
706 + */
707 + do_action( 'before_rocket_clean_home', $root, $lang ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
708 +
709 + // Delete homepage.
710 + $files = glob( $root . '/*', GLOB_NOSORT );
711 +
712 + if ( $files ) {
713 + foreach ( $files as $file ) {
714 + if ( preg_match( '#/index(?:-.+\.|\.)html(?:_gzip)?$#', $file ) ) {
715 + rocket_direct_filesystem()->delete( $file );
716 + }
717 + }
718 + }
719 +
720 + // Delete homepage pagination.
721 + $dirs = glob( $root . '*/' . $GLOBALS['wp_rewrite']->pagination_base, GLOB_NOSORT );
722 + if ( $dirs ) {
723 + foreach ( $dirs as $dir ) {
724 + rocket_rrmdir( $dir );
725 + }
726 + }
727 +
728 + $param_dirs = glob( $root . '/#*', GLOB_NOSORT );
729 +
730 + if ( $param_dirs ) {
731 + foreach ( $param_dirs as $dir ) {
732 + rocket_rrmdir( $dir );
733 + }
734 + }
735 +
736 + // Remove the hidden empty file for mobile detection on NGINX with the Rocket NGINX configuration.
737 + $nginx_mobile_detect_files = glob( $root . '/.mobile-active', GLOB_NOSORT );
738 + if ( $nginx_mobile_detect_files ) {
739 + foreach ( $nginx_mobile_detect_files as $nginx_mobile_detect_file ) { // no array map to use @.
740 + rocket_direct_filesystem()->delete( $nginx_mobile_detect_file );
741 + }
742 + }
743 +
744 + // Remove the hidden empty file for webp.
745 + $nowebp_detect_files = glob( $root . '/.no-webp', GLOB_NOSORT );
746 + if ( $nowebp_detect_files ) {
747 + foreach ( $nowebp_detect_files as $nowebp_detect_file ) { // no array map to use @.
748 + rocket_direct_filesystem()->delete( $nowebp_detect_file );
749 + }
750 + }
751 +
752 + /**
753 + * Fires after the home cache file was deleted
754 + *
755 + * @since 1.0
756 + *
757 + * @param string $root The path of home cache file.
758 + * @param string $lang The current lang to purge.
759 + */
760 + do_action( 'after_rocket_clean_home', $root, $lang ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
761 + }
762 +
763 + /**
764 + * Remove the home cache feed
765 + *
766 + * @since 2.7
767 + *
768 + * @return void
769 + */
770 + function rocket_clean_home_feeds() {
771 +
772 + if ( ! has_filter( 'rocket_cache_reject_uri', 'wp_rocket_cache_feed' ) ) {
773 + return;
774 + }
775 +
776 + $urls = [];
777 + $urls[] = get_feed_link();
778 + $urls[] = get_feed_link( 'comments_' );
779 +
780 + /**
781 + * Filter the home feeds urls
782 + *
783 + * @since 2.7
784 + * @param array $urls The urls of the home feeds.
785 + */
786 + $urls = apply_filters( 'rocket_clean_home_feeds', $urls );
787 +
788 + /**
789 + * Fires before the home feeds cache is deleted
790 + *
791 + * @since 2.7
792 + *
793 + * @param array $urls The urls of the home feeds.
794 + */
795 + do_action( 'before_rocket_clean_home_feeds', $urls ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
796 +
797 + rocket_clean_files( $urls );
798 +
799 + /**
800 + * Fires after the home feeds cache was deleted
801 + *
802 + * @since 2.7
803 + *
804 + * @param array $urls The urls of the home feeds.
805 + */
806 + do_action( 'after_rocket_clean_home_feeds', $urls ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
807 + }
808 +
809 + /**
810 + * Remove all cache files for the domain.
811 + *
812 + * @since 3.5.5 Optimizes by grabbing root cache dirs once, bailing out when file/dir doesn't exist, & directly
813 + * deleting files.
814 + * @since 3.5.3 Replaces glob with SPL.
815 + * @since 2.0 Delete domain cache files for all users
816 + * @since 1.0
817 + *
818 + * @param string $lang Optional. The language code. Default: empty string.
819 + * @param WP_Filesystem_Direct|null $filesystem Optional. Instance of filesystem handler.
820 + */
821 + function rocket_clean_domain( $lang = '', $filesystem = null ) {
822 + if ( did_action( 'rocket_after_clean_domain' ) ) {
823 + return;
824 + }
825 +
826 + if ( rocket_is_importing() ) {
827 + return;
828 + }
829 +
830 + $urls = ( ! $lang || is_object( $lang ) || is_array( $lang ) || is_int( $lang ) )
831 + ? (array) get_rocket_i18n_uri()
832 + : (array) get_rocket_i18n_home_url( $lang );
833 + /**
834 + * Filter URLs to delete all caching files from a domain.
835 + *
836 + * @since 2.6.4
837 + *
838 + * @param array URLs that will be returned.
839 + * @param string The language code.
840 + */
841 + $urls = (array) apply_filters( 'rocket_clean_domain_urls', $urls, $lang );
842 + $urls = array_filter( $urls );
843 + if ( empty( $urls ) ) {
844 + return false;
845 + }
846 +
847 + /** This filter is documented in inc/front/htaccess.php */
848 + $url_no_dots = (bool) apply_filters( 'rocket_url_no_dots', false );
849 + $cache_path = _rocket_get_wp_rocket_cache_path();
850 + $dirs_to_preserve = get_rocket_i18n_to_preserve( $lang, $cache_path );
851 +
852 + if ( empty( $filesystem ) ) {
853 + $filesystem = rocket_direct_filesystem();
854 + }
855 +
856 + foreach ( $urls as $url ) {
857 + $parsed_url = get_rocket_parse_url( $url );
858 +
859 + if ( $url_no_dots ) {
860 + $parsed_url['host'] = str_replace( '.', '_', $parsed_url['host'] );
861 + }
862 +
863 + $root = $cache_path . $parsed_url['host'] . $parsed_url['path'];
864 +
865 + /**
866 + * Fires before all cache files are deleted.
867 + *
868 + * @since 1.0
869 + *
870 + * @param string $root The path of home cache file.
871 + * @param string $lang The current lang to purge.
872 + * @param string $url The home url.
873 + */
874 + do_action( 'before_rocket_clean_domain', $root, $lang, $url ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
875 +
876 + foreach ( _rocket_get_cache_dirs( $parsed_url['host'], $cache_path ) as $dir ) {
877 + $entry = $dir . $parsed_url['path'];
878 + // Skip if the dir/file does not exist.
879 + if ( ! $filesystem->exists( $entry ) ) {
880 + continue;
881 + }
882 +
883 + if ( $filesystem->is_dir( $entry ) ) {
884 + rocket_rrmdir( $entry, $dirs_to_preserve, $filesystem );
885 + } else {
886 + $filesystem->delete( $entry );
887 + }
888 + }
889 +
890 + /**
891 + * Fires after all cache files was deleted.
892 + *
893 + * @since 1.0
894 + *
895 + * @param string $root The path of home cache file.
896 + * @param string $lang The current lang to purge.
897 + * @param string $url The home url.
898 + */
899 + do_action( 'after_rocket_clean_domain', $root, $lang, $url ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
900 + }
901 +
902 + /**
903 + * Fires after all cache files was deleted.
904 + *
905 + * @since 3.15.5
906 + *
907 + * @param string $lang The current lang to purge.
908 + * @param array|string[] $urls All urls to clean.
909 + */
910 + do_action( 'rocket_after_clean_domain', $lang, $urls );
911 +
912 + return true;
913 + }
914 +
915 + /**
916 + * Delete the caching files of a specific term.
917 + *
918 + * $since 2.6.8
919 + *
920 + * @param int $term_id The term ID.
921 + * @param string $taxonomy_slug The taxonomy slug.
922 + * @return void
923 + */
924 + function rocket_clean_term( $term_id, $taxonomy_slug ) {
925 + $purge_urls = [];
926 +
927 + // Get all term infos.
928 + $term = get_term_by( 'id', $term_id, $taxonomy_slug );
929 +
930 + // Get the term language.
931 + $i18n_plugin = rocket_has_i18n();
932 +
933 + if ( 'wpml' === $i18n_plugin && ! rocket_is_plugin_active( 'woocommerce-multilingual/wpml-woocommerce.php' ) ) {
934 + // WPML.
935 + $lang = $GLOBALS['sitepress']->get_language_for_element( $term_id, 'tax_' . $taxonomy_slug );
936 + } elseif ( 'polylang' === $i18n_plugin ) {
937 + // Polylang.
938 + $lang = pll_get_term_language( $term_id );
939 + } else {
940 + $lang = false;
941 + }
942 +
943 + // Get permalink.
944 + $permalink = get_term_link( $term, $taxonomy_slug );
945 +
946 + // Add permalink.
947 + if ( '/' !== rocket_extract_url_component( $permalink, PHP_URL_PATH ) ) {
948 + array_push( $purge_urls, $permalink );
949 + }
950 +
951 + /**
952 + * Fires before deleted caching files related with the term
953 + *
954 + * @since 2.6.8
955 + * @param obj $term The term object.
956 + * @param array $purge_urls URLs cache files to remove.
957 + * @param string $lang The term language.
958 + */
959 + do_action( 'before_rocket_clean_term', $term, $purge_urls, $lang ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
960 +
961 + /**
962 + * Filter URLs cache files to remove
963 + *
964 + * @since 2.6.8
965 + * @param array $purge_urls List of URLs cache files to remove.
966 + * @param obj $term The term object.
967 + */
968 + $purge_urls = apply_filters( 'rocket_term_purge_urls', $purge_urls, $term );
969 +
970 + // Purge all files.
971 + rocket_clean_files( $purge_urls );
972 +
973 + // Never forget to purge homepage and their pagination.
974 + rocket_clean_home( $lang );
975 +
976 + /**
977 + * Fires before deleted caching files related with the term
978 + *
979 + * @since 2.6.8
980 + * @param obj $term The term object.
981 + * @param array $purge_urls URLs cache files to remove.
982 + * @param string $lang The term language.
983 + */
984 + do_action( 'after_rocket_clean_term', $term, $purge_urls, $lang ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
985 + }
986 +
987 + /**
988 + * Delete the caching files of a specific user
989 + *
990 + * $since 2.6.12
991 + *
992 + * @param int $user_id The user ID.
993 + * @param string $lang The language code.
994 + * @return void
995 + */
996 + function rocket_clean_user( $user_id, $lang = '' ) {
997 + $urls = ( ! $lang || is_object( $lang ) ) ? get_rocket_i18n_uri() : get_rocket_i18n_home_url( $lang );
998 + $urls = (array) $urls;
999 +
1000 + /** This filter is documented in inc/functions/files.php */
1001 + $urls = apply_filters( 'rocket_clean_domain_urls', $urls, $lang );
1002 + $urls = array_filter( $urls );
1003 + $user = get_user_by( 'id', $user_id );
1004 +
1005 + if ( ! $user ) {
1006 + return;
1007 + }
1008 +
1009 + $user_key = rawurlencode( $user->user_login ) . '-' . get_rocket_option( 'secret_cache_key' );
1010 +
1011 + foreach ( $urls as $url ) {
1012 + $parse_url = get_rocket_parse_url( $url );
1013 +
1014 + /** This filter is documented in inc/front/htaccess.php */
1015 + if ( apply_filters( 'rocket_url_no_dots', false ) ) {
1016 + $parse_url['host'] = str_replace( '.', '_', $parse_url['host'] );
1017 + }
1018 +
1019 + $cache_dir = $parse_url['host'] . '-' . strtolower( $user_key );
1020 + $cache_dir = $cache_dir . $parse_url['path'];
1021 + $root = rocket_get_constant( 'WP_ROCKET_CACHE_PATH' ) . $cache_dir;
1022 +
1023 + /**
1024 + * Fires before all caching files are deleted for a specific user
1025 + *
1026 + * @since 2.6.12
1027 + *
1028 + * @param int $user_id The path of home cache file.
1029 + * @param string $lang The language code.
1030 + */
1031 + do_action( 'before_rocket_clean_user', $user_id, $lang ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
1032 +
1033 + // Delete cache domain files.
1034 + $dirs = glob( $root . '*', GLOB_NOSORT );
1035 + if ( $dirs ) {
1036 + foreach ( $dirs as $dir ) {
1037 + rocket_rrmdir( $dir, get_rocket_i18n_to_preserve( $lang ) );
1038 + }
1039 + }
1040 +
1041 + /**
1042 + * Fires after all caching files are deleted for a specific user
1043 + *
1044 + * @since 2.6.12
1045 + *
1046 + * @param int $user_id The path of home cache file.
1047 + * @param string $lang The language code.
1048 + */
1049 + do_action( 'after_rocket_clean_user', $user_id, $lang ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
1050 + }
1051 + }
1052 +
1053 + /**
1054 + * Remove all caching files in the cache folder
1055 + *
1056 + * @since 2.6.8
1057 + *
1058 + * @return void
1059 + */
1060 + function rocket_clean_cache_dir() {
1061 + /**
1062 + * Fires before deleting all caching files in the cache folder
1063 + *
1064 + * @since 2.6.8
1065 + */
1066 + do_action( 'before_rocket_clean_cache_dir' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
1067 +
1068 + // Delete all caching files.
1069 + $dirs = glob( WP_ROCKET_CACHE_PATH . '*', GLOB_NOSORT );
1070 + if ( $dirs ) {
1071 + foreach ( $dirs as $dir ) {
1072 + rocket_rrmdir( $dir );
1073 + }
1074 + }
1075 +
1076 + /**
1077 + * Fires after deleting all caching files in the cache folder
1078 + *
1079 + * @since 2.6.8
1080 + */
1081 + do_action( 'after_rocket_clean_cache_dir' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
1082 + }
1083 +
1084 + /**
1085 + * Remove a single file or a folder recursively.
1086 + *
1087 + * @since 3.5.3 Replaces glob and optimizes.
1088 + * @since 1.0
1089 + * @since 3.5.3 Bails if given dir should be preserved; replaces glob; optimizes.
1090 + *
1091 + * @param string $dir File/Directory to delete.
1092 + * @param array $dirs_to_preserve Optional. Dirs that should not be deleted.
1093 + * @param WP_Filesystem_Direct|null $filesystem Optional. Instance of filesystem handler.
1094 + */
1095 + function rocket_rrmdir( $dir, array $dirs_to_preserve = [], $filesystem = null ) {
1096 + $dir = untrailingslashit( $dir );
1097 +
1098 + if ( empty( $filesystem ) ) {
1099 + $filesystem = rocket_direct_filesystem();
1100 + }
1101 +
1102 + /**
1103 + * Fires before a file/directory cache is deleted
1104 + *
1105 + * @since 1.1.0
1106 + *
1107 + * @param string $dir File/Directory to delete.
1108 + * @param array $dirs_to_preserve Directories that should not be deleted.
1109 + */
1110 + do_action( 'before_rocket_rrmdir', $dir, $dirs_to_preserve ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
1111 +
1112 + // Remove the hidden empty file for mobile detection on NGINX with the Rocket NGINX configuration.
1113 + $nginx_mobile_detect_file = $dir . '/.mobile-active';
1114 +
1115 + if ( $filesystem->is_dir( $dir ) && $filesystem->exists( $nginx_mobile_detect_file ) ) {
1116 + $filesystem->delete( $nginx_mobile_detect_file );
1117 + }
1118 +
1119 + // Remove the hidden empty file for webp.
1120 + $nowebp_detect_file = $dir . '/.no-webp';
1121 +
1122 + if ( $filesystem->is_dir( $dir ) && $filesystem->exists( $nowebp_detect_file ) ) {
1123 + $filesystem->delete( $nowebp_detect_file );
1124 + }
1125 +
1126 + if ( ! $filesystem->is_dir( $dir ) ) {
1127 + $filesystem->delete( $dir );
1128 +
1129 + return;
1130 + }
1131 +
1132 + // Get the directory entries.
1133 + $entries = [];
1134 + try {
1135 + foreach ( new FilesystemIterator( $dir ) as $entry ) {
1136 + $entries[] = $entry->getPathname();
1137 + }
1138 + } catch ( Exception $e ) { // phpcs:disable Generic.CodeAnalysis.EmptyStatement.DetectedCatch
1139 + // No action required, as logging not enabled.
1140 + }
1141 +
1142 + // Exclude directories to preserve from the entries.
1143 + if ( ! empty( $dirs_to_preserve ) && ! empty( $entries ) ) {
1144 + $keys = [];
1145 + foreach ( $dirs_to_preserve as $dir_to_preserve ) {
1146 + $matches = preg_grep( "#^$dir_to_preserve$#", $entries );
1147 + $keys[] = reset( $matches );
1148 + }
1149 +
1150 + if ( ! empty( $keys ) ) {
1151 + $keys = array_filter( $keys );
1152 + if ( ! empty( $keys ) ) {
1153 + $entries = array_diff( $entries, $keys );
1154 + }
1155 + }
1156 + }
1157 +
1158 + foreach ( $entries as $entry ) {
1159 + // If not a directory, delete it.
1160 + if ( ! $filesystem->is_dir( $entry ) ) {
1161 + $filesystem->delete( $entry );
1162 + } else {
1163 + rocket_rrmdir( $entry, $dirs_to_preserve, $filesystem );
1164 + }
1165 + }
1166 +
1167 + $filesystem->delete( $dir );
1168 +
1169 + /**
1170 + * Fires after a file/directory cache was deleted
1171 + *
1172 + * @since 1.1.0
1173 + *
1174 + * @param string $dir File/Directory to delete.
1175 + * @param array $dirs_to_preserve Dirs that should not be deleted.
1176 + */
1177 + do_action( 'after_rocket_rrmdir', $dir, $dirs_to_preserve ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
1178 + }
1179 +
1180 + /**
1181 + * Instantiate the filesystem class
1182 + *
1183 + * @since 2.10
1184 + *
1185 + * @return WP_Filesystem_Direct WP_Filesystem_Direct instance
1186 + */
1187 + function rocket_direct_filesystem() {
1188 + require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
1189 + require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
1190 + return new WP_Filesystem_Direct( new StdClass() );
1191 + }
1192 +
1193 + /**
1194 + * Directory creation based on WordPress Filesystem
1195 + *
1196 + * @since 1.3.4
1197 + *
1198 + * @param string $dir The path of directory will be created.
1199 + * @return bool
1200 + */
1201 + function rocket_mkdir( $dir ) {
1202 + $chmod = rocket_get_filesystem_perms( 'dir' );
1203 + return rocket_direct_filesystem()->mkdir( $dir, $chmod );
1204 + }
1205 +
1206 + /**
1207 + * Recursive directory creation based on full path.
1208 + *
1209 + * @param string $target path to the directory we want to create.
1210 + * @param WP_Filesystem_Direct|null $filesystem WordPress filesystem.
1211 + * @return bool True if directory is created/exists, false otherwise
1212 + * @since 1.3.4
1213 + *
1214 + * @source wp_mkdir_p() in /wp-includes/functions.php
1215 + */
1216 + function rocket_mkdir_p( $target, $filesystem = null ) {
1217 + $wrapper = null;
1218 +
1219 + $filesystem = $filesystem ?: rocket_direct_filesystem();
1220 +
1221 + if ( rocket_is_stream( $target ) ) {
1222 + list( $wrapper, $target ) = explode( '://', $target, 2 );
1223 + }
1224 +
1225 + // from php.net/mkdir user contributed notes.
1226 + $target = str_replace( '//', '/', $target );
1227 +
1228 + // Put the wrapper back on the target.
1229 + if ( null !== $wrapper ) {
1230 + $target = $wrapper . '://' . $target;
1231 + }
1232 +
1233 + // safe mode fails with a trailing slash under certain PHP versions.
1234 + $target = rtrim( $target, '/\\' );
1235 + if ( empty( $target ) ) {
1236 + $target = '/';
1237 + }
1238 +
1239 + if ( $filesystem->exists( $target ) ) {
1240 + return $filesystem->is_dir( $target );
1241 + }
1242 +
1243 + // Attempting to create the directory may clutter up our display.
1244 + if ( rocket_mkdir( $target ) ) {
1245 + return true;
1246 + } elseif ( $filesystem->is_dir( dirname( $target ) ) ) {
1247 + return false;
1248 + }
1249 +
1250 + // If the above failed, attempt to create the parent node, then try again.
1251 + if ( ( '/' !== $target ) && ( rocket_mkdir_p( dirname( $target ), $filesystem ) ) ) {
1252 + return rocket_mkdir_p( $target, $filesystem );
1253 + }
1254 +
1255 + return false;
1256 + }
1257 +
1258 + /**
1259 + * Test if a given path is a stream URL.
1260 + *
1261 + * @since 3.5.3
1262 + *
1263 + * @source wp_is_stream() in /wp-includes/functions.php
1264 + *
1265 + * @param string $path The resource path or URL.
1266 + *
1267 + * @return bool true if the path is a stream URL; else false.
1268 + */
1269 + function rocket_is_stream( $path ) {
1270 + $scheme_separator = strpos( $path, '://' );
1271 +
1272 + if ( false === $scheme_separator ) {
1273 + // $path isn't a stream.
1274 + return false;
1275 + }
1276 +
1277 + $stream = substr( $path, 0, $scheme_separator );
1278 +
1279 + return in_array( $stream, stream_get_wrappers(), true );
1280 + }
1281 +
1282 + /**
1283 + * File creation based on WordPress Filesystem.
1284 + *
1285 + * @since 1.3.5
1286 + *
1287 + * @param string $file The path of file will be created.
1288 + * @param string $content The content that will be printed in advanced-cache.php.
1289 + *
1290 + * @return bool true on success; else, false on failure.
1291 + */
1292 + function rocket_put_content( $file, $content ) {
1293 + $chmod = rocket_get_filesystem_perms( 'file' );
1294 + return rocket_direct_filesystem()->put_contents( $file, $content, $chmod );
1295 + }
1296 +
1297 + /**
1298 + * Get the permissions to apply to files and folders.
1299 + *
1300 + * Reminder:
1301 + * `$perm = fileperms( $file );`
1302 + *
1303 + * WHAT | TYPE | FILE | FOLDER |
1304 + * ----------------------------------------------+--------+--------+--------|
1305 + * `$perm` | int | 33188 | 16877 |
1306 + * `substr( decoct( $perm ), -4 )` | string | '0644' | '0755' |
1307 + * `substr( sprintf( '%o', $perm ), -4 )` | string | '0644' | '0755' |
1308 + * `$perm & 0777` | int | 420 | 493 |
1309 + * `decoct( $perm & 0777 )` | string | '644' | '755' |
1310 + * `substr( sprintf( '%o', $perm & 0777 ), -4 )` | string | '644' | '755' |
1311 + *
1312 + * @since 3.2.4
1313 + *
1314 + * @param string $type The type: 'dir' or 'file'.
1315 + *
1316 + * @return int Octal integer.
1317 + */
1318 + function rocket_get_filesystem_perms( $type ) {
1319 + static $perms = [];
1320 +
1321 + if ( rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ) {
1322 + $perms = [];
1323 + }
1324 +
1325 + // Allow variants.
1326 + switch ( $type ) {
1327 + case 'dir':
1328 + case 'dirs':
1329 + case 'folder':
1330 + case 'folders':
1331 + $type = 'dir';
1332 + break;
1333 +
1334 + case 'file':
1335 + case 'files':
1336 + $type = 'file';
1337 + break;
1338 +
1339 + default:
1340 + return 0755;
1341 + }
1342 +
1343 + if ( isset( $perms[ $type ] ) ) {
1344 + return $perms[ $type ];
1345 + }
1346 +
1347 + // If the constants are not defined, use fileperms() like WordPress does.
1348 + if ( 'dir' === $type ) {
1349 + $fs_chmod_dir = (int) rocket_get_constant( 'FS_CHMOD_DIR', 0 );
1350 + $perms[ $type ] = $fs_chmod_dir > 0
1351 + ? $fs_chmod_dir
1352 + : fileperms( rocket_get_constant( 'ABSPATH' ) ) & 0777 | 0755;
1353 + } else {
1354 + $fs_chmod_file = (int) rocket_get_constant( 'FS_CHMOD_FILE', 0 );
1355 + $perms[ $type ] = $fs_chmod_file > 0
1356 + ? $fs_chmod_file
1357 + : fileperms( rocket_get_constant( 'ABSPATH' ) . 'index.php' ) & 0777 | 0644;
1358 + }
1359 +
1360 + return $perms[ $type ];
1361 + }
1362 +
1363 + /**
1364 + * Gets Directory files matches regex.
1365 + *
1366 + * @since 3.6.3
1367 + * @access private
1368 + *
1369 + * @param string $dir Directory to search for files inside it.
1370 + * @param string $regex Regular expression for files need to be searched for.
1371 + *
1372 + * @return array|RegexIterator List of files matches this regular expression.
1373 + */
1374 + function _rocket_get_dir_files_by_regex( $dir, $regex ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
1375 + try {
1376 + $iterator = new IteratorIterator(
1377 + new FilesystemIterator( $dir )
1378 + );
1379 +
1380 + return new RegexIterator( $iterator, $regex );
1381 + } catch ( Exception $e ) {
1382 + return [];
1383 + }
1384 + }
1385 +
1386 + /**
1387 + * Get the recursive iterator for the cache path.
1388 + *
1389 + * @since 3.5.4
1390 + * @access private
1391 + *
1392 + * @param string $cache_path Path to the cache directory.
1393 + *
1394 + * @return bool|RecursiveIteratorIterator Iterator on success; else false;
1395 + */
1396 + function _rocket_get_cache_path_iterator( $cache_path ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
1397 + try {
1398 + return new RecursiveIteratorIterator(
1399 + new RecursiveDirectoryIterator( $cache_path ),
1400 + RecursiveIteratorIterator::SELF_FIRST,
1401 + RecursiveIteratorIterator::CATCH_GET_CHILD
1402 + );
1403 + } catch ( Exception $e ) {
1404 + // No logging yet.
1405 + return false;
1406 + }
1407 + }
1408 +
1409 + /**
1410 + * Gets the directories for the given URL host from the cache/wp-rocket/ directory or stored memory.
1411 + *
1412 + * @since 3.5.5
1413 + * @access private
1414 + *
1415 + * @param string $url_host The URL's host.
1416 + * @param string $cache_path Cache's path, e.g. cache/wp-rocket/.
1417 + * @param bool $hard_reset Optional. When true, resets the static domain directories array and bails out.
1418 + *
1419 + * @return array
1420 + */
1421 + function _rocket_get_cache_dirs( $url_host, $cache_path = '', $hard_reset = false ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
1422 + static $domain_dirs = [];
1423 +
1424 + if ( true === $hard_reset ) {
1425 + $domain_dirs = [];
1426 +
1427 + return;
1428 + }
1429 +
1430 + if ( isset( $domain_dirs[ $url_host ] ) ) {
1431 + return $domain_dirs[ $url_host ];
1432 + }
1433 +
1434 + if ( empty( $cache_path ) ) {
1435 + $cache_path = _rocket_get_wp_rocket_cache_path();
1436 + }
1437 +
1438 + try {
1439 + $iterator = new IteratorIterator(
1440 + new FilesystemIterator( $cache_path )
1441 + );
1442 + } catch ( Exception $e ) {
1443 + return [];
1444 + }
1445 +
1446 + $regex = sprintf(
1447 + '/%1$s%2$s(.*)/i',
1448 + _rocket_normalize_path( $cache_path, true ),
1449 + $url_host
1450 + );
1451 +
1452 + try {
1453 + $entries = new RegexIterator( $iterator, $regex );
1454 + } catch ( Exception $e ) {
1455 + return [];
1456 + }
1457 +
1458 + $domain_dirs[ $url_host ] = [];
1459 + foreach ( $entries as $entry ) {
1460 + $domain_dirs[ $url_host ][] = $entry->getPathname();
1461 + }
1462 +
1463 + return $domain_dirs[ $url_host ];
1464 + }
1465 +
1466 + /**
1467 + * Normalizes the given filesystem path:
1468 + * - Windows/IIS-based servers: converts all directory separators to "\\" or, when escaping, to "\\\\".
1469 + * - Linux-based servers: if $forced is true, uses wp_normalize_path(); else, returns the original path.
1470 + *
1471 + * @since 3.5.5
1472 + * @access private
1473 + *
1474 + * @param string $path Filesystem path (file or directory) to normalize.
1475 + * @param bool $escape Optional. When true, escapes the directory separator(s).
1476 + * @param bool $force Optional. When true, forces normalizing off non-Windows' paths.
1477 + *
1478 + * @return string
1479 + */
1480 + function _rocket_normalize_path( $path, $escape = false, $force = false ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
1481 + if ( _rocket_is_windows_fs( $path ) ) {
1482 + $path = str_replace( '/', '\\', $path );
1483 +
1484 + return $escape
1485 + ? str_replace( '\\', '\\\\', $path )
1486 + : $path;
1487 + }
1488 +
1489 + if ( $escape ) {
1490 + return str_replace( '/', '\/', $path );
1491 + }
1492 +
1493 + if ( ! $force ) {
1494 + return $path;
1495 + }
1496 +
1497 + return wp_normalize_path( $path );
1498 + }
1499 +
1500 + /**
1501 + * Checks if the filesystem (fs) is for Windows/IIS server.
1502 + *
1503 + * @since 3.5.5
1504 + * @access private
1505 + *
1506 + * @param bool $hard_reset Optional. When true, resets the memoization.
1507 + *
1508 + * @return bool
1509 + */
1510 + function _rocket_is_windows_fs( $hard_reset = false ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
1511 + static $is_windows = null;
1512 +
1513 + if ( $hard_reset ) {
1514 + $is_windows = null;
1515 + }
1516 +
1517 + if ( is_null( $is_windows ) ) {
1518 + $is_windows = (
1519 + DIRECTORY_SEPARATOR === '\\'
1520 + &&
1521 + ! rocket_get_constant( 'WP_ROCKET_RUNNING_VFS', false )
1522 + );
1523 + }
1524 +
1525 + return $is_windows;
1526 + }
1527 +
1528 + /**
1529 + * Gets the normalized cache path, i.e. normalizes constant "WP_ROCKET_CACHE_PATH".
1530 + *
1531 + * @since 3.5.5
1532 + * @access private
1533 + *
1534 + * @return string
1535 + */
1536 + function _rocket_get_wp_rocket_cache_path() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
1537 + return _rocket_normalize_path( rocket_get_constant( 'WP_ROCKET_CACHE_PATH' ) );
1538 + }
1539 +
1540 + /**
1541 + * Gets .php files in a directory as an array of SplFileInfo objects.
1542 + *
1543 + * @since 3.6.3
1544 + *
1545 + * @param string $dir_path Directory to check.
1546 + *
1547 + * @return array .php files in the directory. [...SplFileInfo]
1548 + */
1549 + function _rocket_get_php_files_in_dir( $dir_path ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
1550 + try {
1551 + $config_dir = new FilesystemIterator( (string) $dir_path );
1552 + } catch ( Exception $e ) {
1553 + return [];
1554 + }
1555 + $files = [];
1556 +
1557 + foreach ( $config_dir as $file ) {
1558 + if ( $file->isFile() && 'php' === $file->getExtension() ) {
1559 + $files[] = $file;
1560 + }
1561 + }
1562 +
1563 + return $files;
1564 + }
1565 +
1566 + /**
1567 + * Get recursive files matched by regex.
1568 + *
1569 + * @since 3.6.3
1570 + *
1571 + * @param string $regex Regular Expression to be applied.
1572 + *
1573 + * @return array|RegexIterator List of files which match the regular expression (SplFileInfo).
1574 + */
1575 + function _rocket_get_recursive_dir_files_by_regex( $regex ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
1576 + try {
1577 + $cache_path = _rocket_get_wp_rocket_cache_path();
1578 + $iterator = new RecursiveIteratorIterator(
1579 + new RecursiveDirectoryIterator( $cache_path, FilesystemIterator::SKIP_DOTS )
1580 + );
1581 + return new RegexIterator( $iterator, $regex, RecursiveRegexIterator::MATCH );
1582 + } catch ( Exception $e ) {
1583 + return [];
1584 + }
1585 + }
1586 +