Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.74% covered (warning)
89.74%
35 / 39
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Boost_Cache_Utils
89.74% covered (warning)
89.74%
35 / 39
80.00% covered (warning)
80.00%
4 / 5
18.35
0.00% covered (danger)
0.00%
0 / 1
 deep_replace
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 trailingslashit
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 sanitize_file_path
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
 normalize_request_uri
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
10
 is_visible_post_type
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2/*
3 * This file may be called before WordPress is fully initialized. See the README file for info.
4 */
5
6namespace Automattic\Jetpack_Boost\Modules\Optimizations\Page_Cache\Pre_WordPress;
7
8use WP_Post;
9
10class Boost_Cache_Utils {
11
12    /**
13     * Performs a deep string replace operation to ensure the values in $search are no longer present.
14     * Copied from wp-includes/formatting.php
15     *
16     * Repeats the replacement operation until it no longer replaces anything to remove "nested" values
17     * e.g. $subject = '%0%0%0DDD', $search ='%0D', $result ='' rather than the '%0%0DD' that
18     * str_replace would return
19     *
20     * @param string|array $search  The value being searched for, otherwise known as the needle.
21     *                              An array may be used to designate multiple needles.
22     * @param string       $subject The string being searched and replaced on, otherwise known as the haystack.
23     * @return string The string with the replaced values.
24     */
25    public static function deep_replace( $search, $subject ) {
26        $subject = (string) $subject;
27
28        $count = 1;
29        while ( $count ) {
30                $subject = str_replace( $search, '', $subject, $count );
31        }
32
33        return $subject;
34    }
35
36    public static function trailingslashit( $string ) {
37        return rtrim( $string, '/' ) . '/';
38    }
39
40    /**
41     * Returns a sanitized directory path.
42     *
43     * @param string $path - The path to sanitize.
44     * @return string
45     */
46    public static function sanitize_file_path( $path ) {
47        $path = self::trailingslashit( $path );
48        $path = self::deep_replace(
49            array( '..', '\\' ),
50            preg_replace(
51                '/[ <>\'\"\r\n\t\(\)]/',
52                '',
53                preg_replace(
54                    '/(\?.*)?(#.*)?$/',
55                    '',
56                    $path
57                )
58            )
59        );
60
61        return $path;
62    }
63
64    /**
65     * Normalize a request path, removing its query and adding a trailing slash except for existing files.
66     * This does not sanitize filesystem paths; use it only for comparisons or cache keys.
67     *
68     * @param string $request_uri - The request uri to normalize.
69     * @return string|false The normalized request uri, or false if it is not a valid cacheable path.
70     */
71    public static function normalize_request_uri( $request_uri ) {
72        if ( ! is_string( $request_uri ) ) {
73            return false;
74        }
75        if ( 0 === strpos( $request_uri, '/' ) ) {
76            $request_uri = '/' . ltrim( $request_uri, '/' );
77        }
78        if ( false !== strpos( $request_uri, '#' ) ) {
79            return false;
80        }
81        $raw_path    = explode( '?', $request_uri, 2 )[0];
82        $request_uri = parse_url( $raw_path, PHP_URL_PATH ); // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url
83        if ( false === $request_uri || (string) $request_uri !== $raw_path ) {
84            return false;
85        }
86        if ( '' === $request_uri || null === $request_uri ) {
87            $request_uri = '/';
88        } elseif ( substr( $request_uri, -1 ) !== '/' && ! is_file( ABSPATH . $request_uri ) ) {
89            $request_uri .= '/';
90        }
91
92        return $request_uri;
93    }
94
95    /**
96     * Checks if the post type is public.
97     *
98     * @param WP_Post $post - The post to check.
99     * @return bool - True if the post type is public.
100     */
101    public static function is_visible_post_type( $post ) {
102        $post_type = is_a( $post, 'WP_Post' ) ? get_post_type_object( $post->post_type ) : null;
103        if ( empty( $post_type ) || ! $post_type->public ) {
104            return false;
105        }
106        return true;
107    }
108}