PluginProbe
Autoptimize / 1.8.2
Autoptimize v1.8.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
← All changes | classes/autoptimizeBase.php +141 -687 2.4.21.8.2 View file →
@@ -1,703 +1,157 @@
1 1 <?php
2 -/**
3 - * Base class other (more-specific) classes inherit from.
4 - */
2 +if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
5 3
6 -if ( ! defined( 'ABSPATH' ) ) {
7 - exit;
8 -}
9 -
10 4 abstract class autoptimizeBase
11 5 {
12 - /**
13 - * Holds content being processed (html, scripts, styles)
14 - *
15 - * @var string
16 - */
17 - protected $content = '';
6 + protected $content = '';
7 +
8 + public function __construct($content)
9 + {
10 + $this->content = $content;
11 + //Best place to catch errors
12 + }
13 +
14 + //Reads the page and collects tags
15 + abstract public function read($justhead);
16 +
17 + //Joins and optimizes collected things
18 + abstract public function minify();
19 +
20 + //Caches the things
21 + abstract public function cache();
22 +
23 + //Returns the content
24 + abstract public function getcontent();
25 +
26 + //Converts an URL to a full path
27 + protected function getpath($url) {
28 + if (strpos($url,'//')===0) {
29 + $url = "http:".$url;
30 + } else if ((strpos($url,'//')===false) && (strpos($url,parse_url(AUTOPTIMIZE_WP_SITE_URL,PHP_URL_HOST))===false)) {
31 + $url = AUTOPTIMIZE_WP_SITE_URL.$url;
32 + }
33 + $path = str_replace(AUTOPTIMIZE_WP_ROOT_URL,'',$url);
34 + if(preg_match('#^((https?|ftp):)?//#i',$path)) {
35 + /** External script/css (adsense, etc) */
36 + return false;
37 + }
38 + $path = str_replace('//','/',WP_ROOT_DIR.$path);
39 + return $path;
40 + }
41 +
42 + // logger
43 + protected function ao_logger($logmsg) {
44 + $logfile=WP_CONTENT_DIR.'/ao_log.txt';
45 + $logmsg.="\n";
46 + file_put_contents($logfile,$logmsg,FILE_APPEND);
47 + }
18 48
19 - /**
20 - * Controls debug logging.
21 - *
22 - * @var bool
23 - */
24 - public $debug_log = false;
49 + // hide everything between noptimize-comment tags
50 + protected function hide_noptimize($noptimize_in) {
51 + if ( preg_match( '/<!--\s?noptimize\s?-->/', $noptimize_in ) ) {
52 + $noptimize_out = preg_replace_callback(
53 + '#<!--\s?noptimize\s?-->.*?<!--\s?/\s?noptimize\s?-->#is',
54 + create_function(
55 + '$matches',
56 + 'return "%%NOPTIMIZE%%".base64_encode($matches[0])."%%NOPTIMIZE%%";'
57 + ),
58 + $noptimize_in
59 + );
60 + } else {
61 + $noptimize_out = $noptimize_in;
62 + }
63 + return $noptimize_out;
64 + }
65 +
66 + // unhide noptimize-tags
67 + protected function restore_noptimize($noptimize_in) {
68 + if ( strpos( $noptimize_in, '%%NOPTIMIZE%%' ) !== false ) {
69 + $noptimize_out = preg_replace_callback(
70 + '#%%NOPTIMIZE%%(.*?)%%NOPTIMIZE%%#is',
71 + create_function(
72 + '$matches',
73 + 'return stripslashes(base64_decode($matches[1]));'
74 + ),
75 + $noptimize_in
76 + );
77 + } else {
78 + $noptimize_out = $noptimize_in;
79 + }
80 + return $noptimize_out;
81 + }
25 82
26 - public function __construct( $content )
27 - {
28 - $this->content = $content;
29 - }
83 + protected function hide_iehacks($iehacks_in) {
84 + if ( strpos( $iehacks_in, '<!--[if' ) !== false ) {
85 + $iehacks_out = preg_replace_callback(
86 + '#<!--\[if.*?\[endif\]-->#is',
87 + create_function(
88 + '$matches',
89 + 'return "%%IEHACK%%".base64_encode($matches[0])."%%IEHACK%%";'
90 + ),
91 + $iehacks_in
92 + );
93 + } else {
94 + $iehacks_out = $iehacks_in;
95 + }
96 + return $iehacks_out;
97 + }
30 98
31 - /**
32 - * Reads the page and collects tags.
33 - *
34 - * @param array $options Options.
35 - *
36 - * @return bool
37 - */
38 - abstract public function read( $options );
99 + protected function restore_iehacks($iehacks_in) {
100 + if ( strpos( $iehacks_in, '%%IEHACK%%' ) !== false ) {
101 + $iehacks_out = preg_replace_callback(
102 + '#%%IEHACK%%(.*?)%%IEHACK%%#is',
103 + create_function(
104 + '$matches',
105 + 'return stripslashes(base64_decode($matches[1]));'
106 + ),
107 + $iehacks_in
108 + );
109 + } else {
110 + $iehacks_out=$iehacks_in;
111 + }
112 + return $iehacks_out;
113 + }
39 114
40 - /**
41 - * Joins and optimizes collected things.
42 - *
43 - * @return bool
44 - */
45 - abstract public function minify();
46 -
47 - /**
48 - * Caches the things.
49 - *
50 - * @return void
51 - */
52 - abstract public function cache();
53 -
54 - /**
55 - * Returns the content
56 - *
57 - * @return string
58 - */
59 - abstract public function getcontent();
60 -
61 - /**
62 - * Tranfsorms a given URL to a full local filepath if possible.
63 - * Returns local filepath or false.
64 - *
65 - * @param string $url URL to transform.
66 - *
67 - * @return bool|string
68 - */
69 - public function getpath( $url )
70 - {
71 - $url = apply_filters( 'autoptimize_filter_cssjs_alter_url', $url );
72 -
73 - if ( false !== strpos( $url, '%' ) ) {
74 - $url = urldecode( $url );
75 - }
76 -
77 - $site_host = parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST );
78 - $content_host = parse_url( AUTOPTIMIZE_WP_ROOT_URL, PHP_URL_HOST );
79 -
80 - // Normalizing attempts...
81 - $double_slash_position = strpos( $url, '//' );
82 - if ( 0 === $double_slash_position ) {
83 - if ( is_ssl() ) {
84 - $url = 'https:' . $url;
85 - } else {
86 - $url = 'http:' . $url;
87 - }
88 - } elseif ( ( false === $double_slash_position ) && ( false === strpos( $url, $site_host ) ) ) {
89 - if ( AUTOPTIMIZE_WP_SITE_URL === $site_host ) {
90 - $url = AUTOPTIMIZE_WP_SITE_URL . $url;
91 - } else {
92 - $url = AUTOPTIMIZE_WP_SITE_URL . autoptimizeUtils::path_canonicalize( $url );
93 - }
94 - }
95 -
96 - if ( $site_host !== $content_host ) {
97 - $url = str_replace( AUTOPTIMIZE_WP_CONTENT_URL, AUTOPTIMIZE_WP_SITE_URL . AUTOPTIMIZE_WP_CONTENT_NAME, $url );
98 - }
99 -
100 - // First check; hostname wp site should be hostname of url!
101 - $url_host = @parse_url( $url, PHP_URL_HOST ); // @codingStandardsIgnoreLine
102 - if ( $url_host !== $site_host ) {
103 - /**
104 - * First try to get all domains from WPML (if available)
105 - * then explicitely declare $this->cdn_url as OK as well
106 - * then apply own filter autoptimize_filter_cssjs_multidomain takes an array of hostnames
107 - * each item in that array will be considered part of the same WP multisite installation
108 - */
109 - $multidomains = array();
110 -
111 - $multidomains_wpml = apply_filters( 'wpml_setting', array(), 'language_domains' );
112 - if ( ! empty( $multidomains_wpml ) ) {
113 - $multidomains = array_map( array( $this, 'get_url_hostname' ), $multidomains_wpml );
114 - }
115 -
116 - if ( ! empty( $this->cdn_url ) ) {
117 - $multidomains[] = parse_url( $this->cdn_url, PHP_URL_HOST );
118 - }
119 -
120 - $multidomains = apply_filters( 'autoptimize_filter_cssjs_multidomain', $multidomains );
121 -
122 - if ( ! empty( $multidomains ) ) {
123 - if ( in_array( $url_host, $multidomains ) ) {
124 - $url = str_replace( $url_host, $site_host, $url );
115 + protected function hide_comments($comments_in) {
116 + if ( strpos( $comments_in, '<!--' ) !== false ) {
117 + $comments_out = preg_replace_callback(
118 + '#<!--.*?-->#is',
119 + create_function(
120 + '$matches',
121 + 'return "%%COMMENTS%%".base64_encode($matches[0])."%%COMMENTS%%";'
122 + ),
123 + $comments_in
124 + );
125 125 } else {
126 - return false;
126 + $comments_out = $comments_in;
127 127 }
128 - } else {
129 - return false;
130 - }
128 + return $comments_out;
131 129 }
132 130
133 - // Try to remove "wp root url" from url while not minding http<>https.
134 - $tmp_ao_root = preg_replace( '/https?:/', '', AUTOPTIMIZE_WP_ROOT_URL );
135 -
136 - if ( $site_host !== $content_host ) {
137 - // As we replaced the content-domain with the site-domain, we should match against that.
138 - $tmp_ao_root = preg_replace( '/https?:/', '', AUTOPTIMIZE_WP_SITE_URL );
139 - }
140 -
141 - $tmp_url = preg_replace( '/https?:/', '', $url );
142 - $path = str_replace( $tmp_ao_root, '', $tmp_url );
143 -
144 - // If path starts with :// or //, this is not a URL in the WP context and
145 - // we have to assume we can't aggregate.
146 - if ( preg_match( '#^:?//#', $path ) ) {
147 - // External script/css (adsense, etc).
148 - return false;
149 - }
150 -
151 - // Prepend with WP_ROOT_DIR to have full path to file.
152 - $path = str_replace( '//', '/', WP_ROOT_DIR . $path );
153 -
154 - // Final check: does file exist and is it readable?
155 - if ( file_exists( $path ) && is_file( $path ) && is_readable( $path ) ) {
156 - return $path;
157 - } else {
158 - return false;
159 - }
160 - }
161 -
162 - /**
163 - * Returns the hostname part of a given $url if we're able to parse it.
164 - * If not, it returns the original url (prefixed with http:// scheme in case
165 - * it was missing).
166 - * Used as callback for WPML multidomains filter.
167 - *
168 - * @param string $url URL.
169 - *
170 - * @return string
171 - */
172 - protected function get_url_hostname( $url )
173 - {
174 - // Checking that the url starts with something vaguely resembling a protocol.
175 - if ( ( 0 !== strpos( $url, 'http' ) ) && ( 0 !== strpos( $url, '//' ) ) ) {
176 - $url = 'http://' . $url;
177 - }
178 -
179 - // Grab the hostname.
180 - $hostname = parse_url( $url, PHP_URL_HOST );
181 -
182 - // Fallback when parse_url() fails.
183 - if ( empty( $hostname ) ) {
184 - $hostname = $url;
185 - }
186 -
187 - return $hostname;
188 - }
189 -
190 - /**
191 - * Hides everything between noptimize-comment tags.
192 - *
193 - * @param string $markup Markup to process.
194 - *
195 - * @return string
196 - */
197 - protected function hide_noptimize( $markup )
198 - {
199 - return $this->replace_contents_with_marker_if_exists(
200 - 'NOPTIMIZE',
201 - '/<!--\s?noptimize\s?-->/',
202 - '#<!--\s?noptimize\s?-->.*?<!--\s?/\s?noptimize\s?-->#is',
203 - $markup
204 - );
205 - }
206 -
207 - /**
208 - * Unhide noptimize-tags.
209 - *
210 - * @param string $markup Markup to process.
211 - *
212 - * @return string
213 - */
214 - protected function restore_noptimize( $markup )
215 - {
216 - return $this->restore_marked_content( 'NOPTIMIZE', $markup );
217 - }
218 -
219 - /**
220 - * Hides "iehacks" content.
221 - *
222 - * @param string $markup Markup to process.
223 - *
224 - * @return string
225 - */
226 - protected function hide_iehacks( $markup )
227 - {
228 - return $this->replace_contents_with_marker_if_exists(
229 - 'IEHACK', // Marker name...
230 - '<!--[if', // Invalid regex, will fallback to search using strpos()...
231 - '#<!--\[if.*?\[endif\]-->#is', // Replacement regex...
232 - $markup
233 - );
234 - }
235 -
236 - /**
237 - * Restores "hidden" iehacks content.
238 - *
239 - * @param string $markup Markup to process.
240 - *
241 - * @return string
242 - */
243 - protected function restore_iehacks( $markup )
244 - {
245 - return $this->restore_marked_content( 'IEHACK', $markup );
246 - }
247 -
248 - /**
249 - * "Hides" content within HTML comments using a regex-based replacement
250 - * if HTML comment markers are found.
251 - * `<!--example-->` becomes `%%COMMENTS%%ZXhhbXBsZQ==%%COMMENTS%%`
252 - *
253 - * @param string $markup Markup to process.
254 - *
255 - * @return string
256 - */
257 - protected function hide_comments( $markup )
258 - {
259 - return $this->replace_contents_with_marker_if_exists(
260 - 'COMMENTS',
261 - '<!--',
262 - '#<!--.*?-->#is',
263 - $markup
264 - );
265 - }
266 -
267 - /**
268 - * Restores original HTML comment markers inside a string whose HTML
269 - * comments have been "hidden" by using `hide_comments()`.
270 - *
271 - * @param string $markup Markup to process.
272 - *
273 - * @return string
274 - */
275 - protected function restore_comments( $markup )
276 - {
277 - return $this->restore_marked_content( 'COMMENTS', $markup );
278 - }
279 -
280 - /**
281 - * Replaces the given URL with the CDN-version of it when CDN replacement
282 - * is supposed to be done.
283 - *
284 - * @param string $url URL to process.
285 - *
286 - * @return string
287 - */
288 - public function url_replace_cdn( $url )
289 - {
290 - // For 2.3 back-compat in which cdn-ing appeared to be automatically
291 - // including WP subfolder/subdirectory into account as part of cdn-ing,
292 - // even though it might've caused serious troubles in certain edge-cases.
293 - $cdn_url = autoptimizeUtils::tweak_cdn_url_if_needed( $this->cdn_url );
294 -
295 - // Allows API/filter to further tweak the cdn url...
296 - $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', $cdn_url );
297 - if ( ! empty( $cdn_url ) ) {
298 - $this->debug_log( 'before=' . $url );
299 -
300 - // Simple str_replace-based approach fails when $url is protocol-or-host-relative.
301 - $is_protocol_relative = autoptimizeUtils::is_protocol_relative( $url );
302 - $is_host_relative = ( ! $is_protocol_relative && ( '/' === $url{0} ) );
303 - $cdn_url = rtrim( $cdn_url, '/' );
304 -
305 - if ( $is_host_relative ) {
306 - // Prepending host-relative urls with the cdn url.
307 - $url = $cdn_url . $url;
308 - } else {
309 - // Either a protocol-relative or "regular" url, replacing it either way.
310 - if ( $is_protocol_relative ) {
311 - // Massage $site_url so that simple str_replace() still "works" by
312 - // searching for the protocol-relative version of AUTOPTIMIZE_WP_SITE_URL.
313 - $site_url = str_replace( array( 'http:', 'https:' ), '', AUTOPTIMIZE_WP_SITE_URL );
131 + protected function restore_comments($comments_in) {
132 + if ( strpos( $comments_in, '%%COMMENTS%%' ) !== false ) {
133 + $comments_out = preg_replace_callback(
134 + '#%%COMMENTS%%(.*?)%%COMMENTS%%#is',
135 + create_function(
136 + '$matches',
137 + 'return stripslashes(base64_decode($matches[1]));'
138 + ),
139 + $comments_in
140 + );
314 141 } else {
315 - $site_url = AUTOPTIMIZE_WP_SITE_URL;
142 + $comments_out=$comments_in;
316 143 }
317 - $this->debug_log( '`' . $site_url . '` -> `' . $cdn_url . '` in `' . $url . '`' );
318 - $url = str_replace( $site_url, $cdn_url, $url );
319 - }
144 + return $comments_out;
145 + }
146 +
147 + protected function url_replace_cdn($url) {
148 + if (!empty($this->cdn_url)) {
149 + $url=str_replace(AUTOPTIMIZE_WP_SITE_URL,rtrim($this->cdn_url,'/'),$url);
150 + }
151 + return $url;
152 + }
320 153
321 - $this->debug_log( 'after=' . $url );
322 - }
323 -
324 - // Allow API filter to take further care of CDN replacement.
325 - $url = apply_filters( 'autoptimize_filter_base_replace_cdn', $url );
326 -
327 - return $url;
328 - }
329 -
330 - /**
331 - * Injects/replaces the given payload markup into `$this->content`
332 - * at the specified location.
333 - * If the specified tag cannot be found, the payload is appended into
334 - * $this->content along with a warning wrapped inside <!--noptimize--> tags.
335 - *
336 - * @param string $payload Markup to inject.
337 - * @param array $where Array specifying the tag name and method of injection.
338 - * Index 0 is the tag name (i.e., `</body>`).
339 - * Index 1 specifies Ë›'before', 'after' or 'replace'. Defaults to 'before'.
340 - *
341 - * @return void
342 - */
343 - protected function inject_in_html( $payload, $where )
344 - {
345 - $warned = false;
346 - $position = autoptimizeUtils::strpos( $this->content, $where[0] );
347 - if ( false !== $position ) {
348 - // Found the tag, setup content/injection as specified.
349 - if ( 'after' === $where[1] ) {
350 - $content = $where[0] . $payload;
351 - } elseif ( 'replace' === $where[1] ) {
352 - $content = $payload;
353 - } else {
354 - $content = $payload . $where[0];
355 - }
356 - // Place where specified.
357 - $this->content = autoptimizeUtils::substr_replace(
358 - $this->content,
359 - $content,
360 - $position,
361 - // Using plain strlen() should be safe here for now, since
362 - // we're not searching for multibyte chars here still...
363 - strlen( $where[0] )
364 - );
365 - } else {
366 - // Couldn't find what was specified, just append and add a warning.
367 - $this->content .= $payload;
368 - if ( ! $warned ) {
369 - $tag_display = str_replace( array( '<', '>' ), '', $where[0] );
370 - $this->content .= '<!--noptimize--><!-- Autoptimize found a problem with the HTML in your Theme, tag `' . $tag_display . '` missing --><!--/noptimize-->';
371 - $warned = true;
372 - }
373 - }
374 - }
375 -
376 - /**
377 - * Returns true if given `$tag` is found in the list of `$removables`.
378 - *
379 - * @param string $tag Tag to search for.
380 - * @param array $removables List of things considered completely removable.
381 - *
382 - * @return bool
383 - */
384 - protected function isremovable( $tag, $removables )
385 - {
386 - foreach ( $removables as $match ) {
387 - if ( false !== strpos( $tag, $match ) ) {
388 - return true;
389 - }
390 - }
391 -
392 - return false;
393 - }
394 -
395 - /**
396 - * Callback used in `self::inject_minified()`.
397 - *
398 - * @param array $matches Regex matches.
399 - *
400 - * @return string
401 - */
402 - public function inject_minified_callback( $matches )
403 - {
404 - static $conf = null;
405 - if ( null === $conf ) {
406 - $conf = autoptimizeConfig::instance();
407 - }
408 -
409 - /**
410 - * $matches[1] holds the whole match caught by regex in self::inject_minified(),
411 - * so we take that and split the string on `|`.
412 - * First element is the filepath, second is the md5 hash of contents
413 - * the filepath had when it was being processed.
414 - * If we don't have those, we'll bail out early.
415 - */
416 - $filepath = null;
417 - $filehash = null;
418 -
419 - // Grab the parts we need.
420 - $parts = explode( '|', $matches[1] );
421 - if ( ! empty( $parts ) ) {
422 - $filepath = isset( $parts[0] ) ? base64_decode($parts[0]) : null;
423 - $filehash = isset( $parts[1] ) ? $parts[1] : null;
424 - }
425 -
426 - // Bail early if something's not right...
427 - if ( ! $filepath || ! $filehash ) {
428 - return "\n";
429 - }
430 -
431 - $filecontent = file_get_contents( $filepath );
432 -
433 - // Some things are differently handled for css/js...
434 - $is_js_file = ( '.js' === substr( $filepath, -3, 3 ) );
435 -
436 - $is_css_file = false;
437 - if ( ! $is_js_file ) {
438 - $is_css_file = ( '.css' === substr( $filepath, -4, 4 ) );
439 - }
440 -
441 - // BOMs being nuked here unconditionally (regardless of where they are)!
442 - $filecontent = preg_replace( "#\x{EF}\x{BB}\x{BF}#", '', $filecontent );
443 -
444 - // Remove comments and blank lines.
445 - if ( $is_js_file ) {
446 - $filecontent = preg_replace( '#^\s*\/\/.*$#Um', '', $filecontent );
447 - }
448 -
449 - // Nuke un-important comments.
450 - $filecontent = preg_replace( '#^\s*\/\*[^!].*\*\/\s?#Um', '', $filecontent );
451 -
452 - // Normalize newlines.
453 - $filecontent = preg_replace( '#(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+#', "\n", $filecontent );
454 -
455 - // JS specifics.
456 - if ( $is_js_file ) {
457 - // Append a semicolon at the end of js files if it's missing.
458 - $last_char = substr( $filecontent, -1, 1 );
459 - if ( ';' !== $last_char && '}' !== $last_char ) {
460 - $filecontent .= ';';
461 - }
462 - // Check if try/catch should be used.
463 - $opt_js_try_catch = $conf->get( 'autoptimize_js_trycatch' );
464 - if ( 'on' === $opt_js_try_catch ) {
465 - // It should, wrap in try/catch.
466 - $filecontent = 'try{' . $filecontent . '}catch(e){}';
467 - }
468 - } elseif ( $is_css_file ) {
469 - $filecontent = autoptimizeStyles::fixurls( $filepath, $filecontent );
470 - } else {
471 - $filecontent = '';
472 - }
473 -
474 - // Return modified (or empty!) code/content.
475 - return "\n" . $filecontent;
476 - }
477 -
478 - /**
479 - * Inject already minified code in optimized JS/CSS.
480 - *
481 - * @param string $in Markup.
482 - *
483 - * @return string
484 - */
485 - protected function inject_minified( $in )
486 - {
487 - $out = $in;
488 - if ( false !== strpos( $in, '%%INJECTLATER%%' ) ) {
489 - $out = preg_replace_callback(
490 - '#\/\*\!%%INJECTLATER' . AUTOPTIMIZE_HASH . '%%(.*?)%%INJECTLATER%%\*\/#is',
491 - array( $this, 'inject_minified_callback' ),
492 - $in
493 - );
494 - }
495 -
496 - return $out;
497 - }
498 -
499 - /**
500 - * Specialized method to create the INJECTLATER marker.
501 - * These are somewhat "special", in the sense that they're additionally wrapped
502 - * within an "exclamation mark style" comment, so that they're not stripped
503 - * out by minifiers.
504 - * They also currently contain the hash of the file's contents too (unlike other markers).
505 - *
506 - * @param string $filepath Filepath.
507 - * @param string $hash Hash.
508 - *
509 - * @return string
510 - */
511 - public static function build_injectlater_marker( $filepath, $hash )
512 - {
513 - $contents = '/*!' . self::build_marker( 'INJECTLATER', $filepath, $hash ) . '*/';
514 -
515 - return $contents;
516 - }
517 -
518 - /**
519 - * Creates and returns a `%%`-style named marker which holds
520 - * the base64 encoded `$data`.
521 - * If `$hash` is provided, it's appended to the base64 encoded string
522 - * using `|` as the separator (in order to support building the
523 - * somewhat special/different INJECTLATER marker).
524 - *
525 - * @param string $name Marker name.
526 - * @param string $data Marker data which will be base64-encoded.
527 - * @param string|null $hash Optional.
528 - *
529 - * @return string
530 - */
531 - public static function build_marker( $name, $data, $hash = null )
532 - {
533 - // Start the marker, add the data.
534 - $marker = '%%' . $name . AUTOPTIMIZE_HASH . '%%' . base64_encode( $data );
535 -
536 - // Add the hash if provided.
537 - if ( null !== $hash ) {
538 - $marker .= '|' . $hash;
539 - }
540 -
541 - // Close the marker.
542 - $marker .= '%%' . $name . '%%';
543 -
544 - return $marker;
545 - }
546 -
547 - /**
548 - * Searches for `$search` in `$content` (using either `preg_match()`
549 - * or `strpos()`, depending on whether `$search` is a valid regex pattern or not).
550 - * If something is found, it replaces `$content` using `$re_replace_pattern`,
551 - * effectively creating our named markers (`%%{$marker}%%`.
552 - * These are then at some point replaced back to their actual/original/modified
553 - * contents using `autoptimizeBase::restore_marked_content()`.
554 - *
555 - * @param string $marker Marker name (without percent characters).
556 - * @param string $search A string or full blown regex pattern to search for in $content. Uses `strpos()` or `preg_match()`.
557 - * @param string $re_replace_pattern Regex pattern to use when replacing contents.
558 - * @param string $content Content to work on.
559 - *
560 - * @return string
561 - */
562 - protected function replace_contents_with_marker_if_exists( $marker, $search, $re_replace_pattern, $content )
563 - {
564 - $found = false;
565 -
566 - $is_regex = autoptimizeUtils::str_is_valid_regex( $search );
567 - if ( $is_regex ) {
568 - $found = preg_match( $search, $content );
569 - } else {
570 - $found = ( false !== strpos( $content, $search ) );
571 - }
572 -
573 - if ( $found ) {
574 - $content = preg_replace_callback(
575 - $re_replace_pattern,
576 - function( $matches ) use ( $marker ) {
577 - return autoptimizeBase::build_marker( $marker, $matches[0] );
578 - },
579 - $content
580 - );
581 - }
582 -
583 - return $content;
584 - }
585 -
586 - /**
587 - * Complements `autoptimizeBase::replace_contents_with_marker_if_exists()`.
588 - *
589 - * @param string $marker Marker.
590 - * @param string $content Markup.
591 - *
592 - * @return string
593 - */
594 - protected function restore_marked_content( $marker, $content )
595 - {
596 - if ( false !== strpos( $content, $marker ) ) {
597 - $content = preg_replace_callback(
598 - '#%%' . $marker . AUTOPTIMIZE_HASH . '%%(.*?)%%' . $marker . '%%#is',
599 - function ( $matches ) {
600 - return base64_decode( $matches[1] );
601 - },
602 - $content
603 - );
604 - }
605 -
606 - return $content;
607 - }
608 -
609 - /**
610 - * Logs given `$data` for debugging purposes (when debug logging is on).
611 - *
612 - * @param mixed $data Data to log.
613 - *
614 - * @return void
615 - */
616 - protected function debug_log( $data )
617 - {
618 - if ( ! isset( $this->debug_log ) || ! $this->debug_log ) {
619 - return;
620 - }
621 -
622 - if ( ! is_string( $data ) && ! is_resource( $data ) ) {
623 - $data = var_export( $data, true );
624 - }
625 -
626 - error_log( $data );
627 - }
628 -
629 - /**
630 - * Checks if a single local css/js file can be minified and returns source if so.
631 - *
632 - * @param string $filepath Filepath.
633 - *
634 - * @return bool|string to be minified code or false.
635 - */
636 - protected function prepare_minify_single( $filepath )
637 - {
638 - // Decide what we're dealing with, return false if we don't know.
639 - if ( $this->str_ends_in( $filepath, '.js' ) ) {
640 - $type = 'js';
641 - } elseif ( $this->str_ends_in( $filepath, '.css' ) ) {
642 - $type = 'css';
643 - } else {
644 - return false;
645 - }
646 -
647 - // Bail if it looks like its already minifed (by having -min or .min
648 - // in filename) or if it looks like WP jquery.js (which is minified).
649 - $minified_variants = array(
650 - '-min.' . $type,
651 - '.min.' . $type,
652 - 'js/jquery/jquery.js',
653 - );
654 - foreach ( $minified_variants as $ending ) {
655 - if ( $this->str_ends_in( $filepath, $ending ) ) {
656 - return false;
657 - }
658 - }
659 -
660 - // Get file contents, bail if empty.
661 - $contents = file_get_contents( $filepath );
662 -
663 - return $contents;
664 - }
665 -
666 - /**
667 - * Given an autoptimizeCache instance returns the (maybe cdn-ed) url of
668 - * the cached file.
669 - *
670 - * @param autoptimizeCache $cache autoptimizeCache instance.
671 - *
672 - * @return string
673 - */
674 - protected function build_minify_single_url( autoptimizeCache $cache )
675 - {
676 - $url = AUTOPTIMIZE_CACHE_URL . $cache->getname();
677 -
678 - // CDN-replace the resulting URL if needed...
679 - $url = $this->url_replace_cdn( $url );
680 -
681 - return $url;
682 - }
683 -
684 - /**
685 - * Returns true if given $str ends with given $test.
686 - *
687 - * @param string $str String to check.
688 - * @param string $test Ending to match.
689 - *
690 - * @return bool
691 - */
692 - protected function str_ends_in( $str, $test )
693 - {
694 - // @codingStandardsIgnoreStart
695 - // substr_compare() is bugged on 5.5.11: https://3v4l.org/qGYBH
696 - // return ( 0 === substr_compare( $str, $test, -strlen( $test ) ) );
697 - // @codingStandardsIgnoreEnd
698 -
699 - $length = strlen( $test );
700 -
701 - return ( substr( $str, -$length, $length ) === $test );
702 - }
154 + protected function warn_html() {
155 + $this->content .= "<!--noptimize--><!-- Autoptimize found a problem with the HTML in your Theme, check if the title or body-tags are missing --><!--/noptimize-->";
156 + }
703 157 }