PluginProbe
Autoptimize / 2.4.2
Autoptimize v2.4.2
2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 All 107 releases
autoptimize / classes / autoptimizeUtils.php

autoptimizeUtils.php in Autoptimize 2.4.2, at classes/autoptimizeUtils.php

340 lines 11.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * General helpers.
4 */
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit;
8 }
9
10 class autoptimizeUtils
11 {
12 /**
13 * Returns true when mbstring is available.
14 *
15 * @param bool|null $override Allows overriding the decision.
16 *
17 * @return bool
18 */
19 public static function mbstring_available( $override = null )
20 {
21 static $available = null;
22
23 if ( null === $available ) {
24 $available = \extension_loaded( 'mbstring' );
25 }
26
27 if ( null !== $override ) {
28 $available = $override;
29 }
30
31 return $available;
32 }
33
34 /**
35 * Multibyte-capable strpos() if support is available on the server.
36 * If not, it falls back to using \strpos().
37 *
38 * @param string $haystack Haystack.
39 * @param string $needle Needle.
40 * @param int $offset Offset.
41 * @param string|null $encoding Encoding. Default null.
42 *
43 * @return int|false
44 */
45 public static function strpos( $haystack, $needle, $offset = 0, $encoding = null )
46 {
47 if ( self::mbstring_available() ) {
48 return ( null === $encoding ) ? \mb_strpos( $haystack, $needle, $offset ) : \mb_strlen( $haystack, $needle, $offset, $encoding );
49 } else {
50 return \strpos( $haystack, $needle, $offset );
51 }
52 }
53
54 /**
55 * Attempts to return the number of characters in the given $string if
56 * mbstring is available. Returns the number of bytes
57 * (instead of characters) as fallback.
58 *
59 * @param string $string String.
60 * @param string|null $encoding Encoding.
61 *
62 * @return int Number of charcters or bytes in given $string
63 * (characters if/when supported, bytes otherwise).
64 */
65 public static function strlen( $string, $encoding = null )
66 {
67 if ( self::mbstring_available() ) {
68 return ( null === $encoding ) ? \mb_strlen( $string ) : \mb_strlen( $string, $encoding );
69 } else {
70 return \strlen( $string );
71 }
72 }
73
74 /**
75 * Our wrapper around implementations of \substr_replace()
76 * that attempts to not break things horribly if at all possible.
77 * Uses mbstring if available, before falling back to regular
78 * substr_replace() (which works just fine in the majority of cases).
79 *
80 * @param string $string String.
81 * @param string $replacement Replacement.
82 * @param int $start Start offset.
83 * @param int|null $length Length.
84 * @param string|null $encoding Encoding.
85 *
86 * @return string
87 */
88 public static function substr_replace( $string, $replacement, $start, $length = null, $encoding = null )
89 {
90 if ( self::mbstring_available() ) {
91 $strlen = self::strlen( $string, $encoding );
92
93 if ( $start < 0 ) {
94 if ( -$start < $strlen ) {
95 $start = $strlen + $start;
96 } else {
97 $start = 0;
98 }
99 } elseif ( $start > $strlen ) {
100 $start = $strlen;
101 }
102
103 if ( null === $length || '' === $length ) {
104 $start2 = $strlen;
105 } elseif ( $length < 0 ) {
106 $start2 = $strlen + $length;
107 if ( $start2 < $start ) {
108 $start2 = $start;
109 }
110 } else {
111 $start2 = $start + $length;
112 }
113
114 if ( null === $encoding ) {
115 $leader = $start ? \mb_substr( $string, 0, $start ) : '';
116 $trailer = ( $start2 < $strlen ) ? \mb_substr( $string, $start2, null ) : '';
117 } else {
118 $leader = $start ? \mb_substr( $string, 0, $start, $encoding ) : '';
119 $trailer = ( $start2 < $strlen ) ? \mb_substr( $string, $start2, null, $encoding ) : '';
120 }
121
122 return "{$leader}{$replacement}{$trailer}";
123 }
124
125 return ( null === $length ) ? \substr_replace( $string, $replacement, $start ) : \substr_replace( $string, $replacement, $start, $length );
126 }
127
128 /**
129 * Decides whether this is a "subdirectory site" or not.
130 *
131 * @param bool $override Allows overriding the decision when needed.
132 *
133 * @return bool
134 */
135 public static function siteurl_not_root( $override = null )
136 {
137 static $subdir = null;
138
139 if ( null === $subdir ) {
140 $parts = self::get_ao_wp_site_url_parts();
141 $subdir = ( isset( $parts['path'] ) && ( '/' !== $parts['path'] ) );
142 }
143
144 if ( null !== $override ) {
145 $subdir = $override;
146 }
147
148 return $subdir;
149 }
150
151 /**
152 * Parse AUTOPTIMIZE_WP_SITE_URL into components using \parse_url(), but do
153 * so only once per request/lifecycle.
154 *
155 * @return array
156 */
157 public static function get_ao_wp_site_url_parts()
158 {
159 static $parts = array();
160
161 if ( empty( $parts ) ) {
162 $parts = \parse_url( AUTOPTIMIZE_WP_SITE_URL );
163 }
164
165 return $parts;
166 }
167
168 /**
169 * Modify given $cdn_url to include the site path when needed.
170 *
171 * @param string $cdn_url CDN URL to tweak.
172 * @param bool $force_cache_miss Force a cache miss in order to be able
173 * to re-run the filter.
174 *
175 * @return string
176 */
177 public static function tweak_cdn_url_if_needed( $cdn_url, $force_cache_miss = false )
178 {
179 static $results = array();
180
181 if ( ! isset( $results[ $cdn_url ] ) || $force_cache_miss ) {
182
183 // In order to return unmodified input when there's no need to tweak.
184 $results[ $cdn_url ] = $cdn_url;
185
186 // Behind a default true filter for backcompat, and only for sites
187 // in a subfolder/subdirectory, but still easily turned off if
188 // not wanted/needed...
189 if ( autoptimizeUtils::siteurl_not_root() ) {
190 $check = apply_filters( 'autoptimize_filter_cdn_magic_path_check', true, $cdn_url );
191 if ( $check ) {
192 $site_url_parts = autoptimizeUtils::get_ao_wp_site_url_parts();
193 $cdn_url_parts = \parse_url( $cdn_url );
194 $schemeless = self::is_protocol_relative( $cdn_url );
195 $cdn_url_parts = self::maybe_replace_cdn_path( $site_url_parts, $cdn_url_parts );
196 if ( false !== $cdn_url_parts ) {
197 $results[ $cdn_url ] = self::assemble_parsed_url( $cdn_url_parts, $schemeless );
198 }
199 }
200 }
201 }
202
203 return $results[ $cdn_url ];
204 }
205
206 /**
207 * When siteurl contans a path other than '/' and the CDN URL does not have
208 * a path or it's path is '/', this will modify the CDN URL's path component
209 * to match that of the siteurl.
210 * This is to support "magic" CDN urls that worked that way before v2.4...
211 *
212 * @param array $site_url_parts Site URL components array.
213 * @param array $cdn_url_parts CDN URL components array.
214 *
215 * @return array|false
216 */
217 public static function maybe_replace_cdn_path( array $site_url_parts, array $cdn_url_parts )
218 {
219 if ( isset( $site_url_parts['path'] ) && '/' !== $site_url_parts['path'] ) {
220 if ( ! isset( $cdn_url_parts['path'] ) || '/' === $cdn_url_parts['path'] ) {
221 $cdn_url_parts['path'] = $site_url_parts['path'];
222 return $cdn_url_parts;
223 }
224 }
225
226 return false;
227 }
228
229 /**
230 * Given an array or components returned from \parse_url(), assembles back
231 * the complete URL.
232 * If optional
233 *
234 * @param array $parsed_url URL components array.
235 * @param bool $schemeless Whether the assembled URL should be
236 * protocol-relative (schemeless) or not.
237 *
238 * @return string
239 */
240 public static function assemble_parsed_url( array $parsed_url, $schemeless = false )
241 {
242 $scheme = isset( $parsed_url['scheme'] ) ? $parsed_url['scheme'] . '://' : '';
243 if ( $schemeless ) {
244 $scheme = '//';
245 }
246 $host = isset( $parsed_url['host'] ) ? $parsed_url['host'] : '';
247 $port = isset( $parsed_url['port'] ) ? ':' . $parsed_url['port'] : '';
248 $user = isset( $parsed_url['user'] ) ? $parsed_url['user'] : '';
249 $pass = isset( $parsed_url['pass'] ) ? ':' . $parsed_url['pass'] : '';
250 $pass = ( $user || $pass ) ? "$pass@" : '';
251 $path = isset( $parsed_url['path'] ) ? $parsed_url['path'] : '';
252 $query = isset( $parsed_url['query'] ) ? '?' . $parsed_url['query'] : '';
253 $fragment = isset( $parsed_url['fragment'] ) ? '#' . $parsed_url['fragment'] : '';
254
255 return "$scheme$user$pass$host$port$path$query$fragment";
256 }
257
258 /**
259 * Returns true if given $url is protocol-relative.
260 *
261 * @param string $url URL to check.
262 *
263 * @return bool
264 */
265 public static function is_protocol_relative( $url )
266 {
267 $result = false;
268
269 if ( ! empty( $url ) ) {
270 $result = ( '/' === $url{1} ); // second char is `/`.
271 }
272
273 return $result;
274 }
275
276 /**
277 * Canonicalizes the given path regardless of it existing or not.
278 *
279 * @param string $path Path to normalize.
280 *
281 * @return string
282 */
283 public static function path_canonicalize( $path )
284 {
285 $patterns = array(
286 '~/{2,}~',
287 '~/(\./)+~',
288 '~([^/\.]+/(?R)*\.{2,}/)~',
289 '~\.\./~',
290 );
291 $replacements = array(
292 '/',
293 '/',
294 '',
295 '',
296 );
297
298 return preg_replace( $patterns, $replacements, $path );
299 }
300
301 /**
302 * Checks to see if 3rd party services are available and stores result in option
303 *
304 * @param string $return_result should we return resulting service status array (default no).
305 *
306 * @return none if $return_result is false (default), array if $return_result is true.
307 */
308 public static function check_service_availability( $return_result = false )
309 {
310 $service_availability_resp = wp_remote_get( 'https://misc.optimizingmatters.com/api/autoptimize_service_availablity.json?from=aomain&ver=' . AUTOPTIMIZE_PLUGIN_VERSION );
311 if ( ! is_wp_error( $service_availability_resp ) ) {
312 if ( '200' == wp_remote_retrieve_response_code( $service_availability_resp ) ) {
313 $availabilities = json_decode( wp_remote_retrieve_body( $service_availability_resp ), true );
314 if ( is_array( $availabilities ) ) {
315 update_option( 'autoptimize_service_availablity', $availabilities );
316 if ( $return_result ) {
317 return $availabilities;
318 }
319 }
320 }
321 }
322 }
323
324 /**
325 * Returns true if the string is a valid regex.
326 *
327 * @param string $string String, duh.
328 *
329 * @return bool
330 */
331 public static function str_is_valid_regex( $string )
332 {
333 set_error_handler( function() {}, E_WARNING );
334 $is_regex = ( false !== preg_match( $string, '' ) );
335 restore_error_handler();
336
337 return $is_regex;
338 }
339 }
340