Completed
Pull Request — master (#99)
by
unknown
03:03
created

autoptimizeBase::build_injectlater_marker()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
3
4
abstract class autoptimizeBase {
5
    protected $content = '';
6
    protected $tagWarning = false;
7
    
8
    public function __construct($content) {
9
        $this->content = $content;
10
    }
11
    
12
    //Reads the page and collects tags
13
    abstract public function read($justhead);
14
    
15
    //Joins and optimizes collected things
16
    abstract public function minify();
17
    
18
    //Caches the things
19
    abstract public function cache();
20
    
21
    //Returns the content
22
    abstract public function getcontent();
23
    
24
    //Converts an URL to a full path
25
    protected function getpath($url) {
26
        $url=apply_filters( 'autoptimize_filter_cssjs_alter_url', $url);
27
        
28
        if (strpos($url,'%')!==false) {
29
            $url=urldecode($url);
30
        }
31
32
        $siteHost=parse_url(AUTOPTIMIZE_WP_SITE_URL,PHP_URL_HOST);
33
        $contentHost=parse_url(AUTOPTIMIZE_WP_ROOT_URL,PHP_URL_HOST);
34
        
35
        // normalize
36
        if (strpos($url,'//')===0) {
37
            if (is_ssl()) {
38
                $url = "https:".$url;
39
            } else {
40
                $url = "http:".$url;
41
            }
42
        } else if ((strpos($url,'//')===false) && (strpos($url,$siteHost)===false)) {
43
            if (AUTOPTIMIZE_WP_SITE_URL === $siteHost) {
44
                $url = AUTOPTIMIZE_WP_SITE_URL.$url;
45
            } else {
46
                $subdir_levels=substr_count(preg_replace("/https?:\/\//","",AUTOPTIMIZE_WP_SITE_URL),"/");
47
                $url = AUTOPTIMIZE_WP_SITE_URL.str_repeat("/..",$subdir_levels).$url;
48
            }
49
        }
50
        
51
        if ($siteHost !== $contentHost) {
52
            $url=str_replace(AUTOPTIMIZE_WP_CONTENT_URL,AUTOPTIMIZE_WP_SITE_URL.AUTOPTIMIZE_WP_CONTENT_NAME,$url);
53
        }
54
55
        // first check; hostname wp site should be hostname of url
56
        $thisHost=@parse_url($url,PHP_URL_HOST);
57
        if ($thisHost !== $siteHost) {
58
            /* 
59
            * first try to get all domains from WPML (if available)
60
            * then explicitely declare $this->cdn_url as OK as well
61
            * then apply own filter autoptimize_filter_cssjs_multidomain takes an array of hostnames
62
            * each item in that array will be considered part of the same WP multisite installation
63
            */
64
            $multidomains = array();
65
            
66
            $multidomainsWPML = apply_filters('wpml_setting', array(), 'language_domains');
67
            if (!empty($multidomainsWPML)) {
68
                $multidomains = array_map(array($this,"ao_getDomain"),$multidomainsWPML);
69
            }
70
            
71
            if (!empty($this->cdn_url)) {
72
                $multidomains[]=parse_url($this->cdn_url,PHP_URL_HOST);
0 ignored issues
show
Bug introduced by
The property cdn_url does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
73
            }
74
            
75
            $multidomains = apply_filters('autoptimize_filter_cssjs_multidomain', $multidomains);
76
            
77
            if (!empty($multidomains)) {
78
                if (in_array($thisHost,$multidomains)) {
79
                    $url=str_replace($thisHost, parse_url(AUTOPTIMIZE_WP_SITE_URL,PHP_URL_HOST), $url);
80
                } else {
81
                    return false;
82
                }
83
            } else {
84
                return false;
85
            }
86
        }
87
        
88
        // try to remove "wp root url" from url while not minding http<>https
89
        $tmp_ao_root = preg_replace('/https?:/','',AUTOPTIMIZE_WP_ROOT_URL);
90
        if ($siteHost !== $contentHost) {
91
            // as we replaced the content-domain with the site-domain, we should match against that 
92
            $tmp_ao_root = preg_replace('/https?:/','',AUTOPTIMIZE_WP_SITE_URL);
93
        }
94
        $tmp_url = preg_replace('/https?:/','',$url);
95
        $path = str_replace($tmp_ao_root,'',$tmp_url);
96
        
97
        // if path starts with :// or //, this is not a URL in the WP context and we have to assume we can't aggregate
98
        if (preg_match('#^:?//#',$path)) {
99
            /** External script/css (adsense, etc) */
100
            return false;
101
        }
102
103
        // prepend with WP_ROOT_DIR to have full path to file
104
        $path = str_replace('//','/',WP_ROOT_DIR.$path);
105
        
106
        // final check: does file exist and is it readable
107
        if (file_exists($path) && is_file($path) && is_readable($path)) {
108
            return $path;
109
        } else {
110
            return false;
111
        }
112
    }
113
114
    // needed for WPML-filter
115
    protected function ao_getDomain($in) {
116
        // make sure the url starts with something vaguely resembling a protocol
117
        if ((strpos($in,"http")!==0) && (strpos($in,"//")!==0)) {
118
            $in="http://".$in;
119
        }
120
        
121
        // do the actual parse_url
122
        $out = parse_url($in,PHP_URL_HOST);
123
        
124
        // fallback if parse_url does not understand the url is in fact a url
125
        if (empty($out)) $out=$in;
126
        
127
        return $out;
128
    }
129
130
131
    // logger
132
    protected function ao_logger($logmsg,$appendHTML=true) {
133
        if ($appendHTML) {
134
            $logmsg="<!--noptimize--><!-- ".$logmsg." --><!--/noptimize-->";
135
            $this->content.=$logmsg;
136
        } else {
137
            error_log("Autoptimize: ".$logmsg);
138
        }
139
    }
140
141
    // hide everything between noptimize-comment tags
142
    protected function hide_noptimize($noptimize_in) {
143
        if ( preg_match( '/<!--\s?noptimize\s?-->/', $noptimize_in ) ) { 
144
            $noptimize_out = preg_replace_callback(
145
                '#<!--\s?noptimize\s?-->.*?<!--\s?/\s?noptimize\s?-->#is',
146
                create_function(
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
147
                    '$matches',
148
                    'return "%%NOPTIMIZE".AUTOPTIMIZE_HASH."%%".base64_encode($matches[0])."%%NOPTIMIZE%%";'
149
                ),
150
                $noptimize_in
151
            );
152
        } else {
153
            $noptimize_out = $noptimize_in;
154
        }
155
        return $noptimize_out;
156
    }
157
    
158
    // unhide noptimize-tags
159 View Code Duplication
    protected function restore_noptimize($noptimize_in) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
160
        if ( strpos( $noptimize_in, '%%NOPTIMIZE%%' ) !== false ) { 
161
            $noptimize_out = preg_replace_callback(
162
                '#%%NOPTIMIZE'.AUTOPTIMIZE_HASH.'%%(.*?)%%NOPTIMIZE%%#is',
163
                create_function(
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
164
                    '$matches',
165
                    'return base64_decode($matches[1]);'
166
                ),
167
                $noptimize_in
168
            );
169
        } else {
170
            $noptimize_out = $noptimize_in;
171
        }
172
        return $noptimize_out;
173
    }
174
175 View Code Duplication
    protected function hide_iehacks($iehacks_in) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
176
        if ( strpos( $iehacks_in, '<!--[if' ) !== false ) { 
177
            $iehacks_out = preg_replace_callback(
178
                '#<!--\[if.*?\[endif\]-->#is',
179
                create_function(
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
180
                    '$matches',
181
                    'return "%%IEHACK".AUTOPTIMIZE_HASH."%%".base64_encode($matches[0])."%%IEHACK%%";'
182
                ),
183
                $iehacks_in
184
            );
185
        } else {
186
            $iehacks_out = $iehacks_in;
187
        }
188
        return $iehacks_out;
189
    }
190
191 View Code Duplication
    protected function restore_iehacks($iehacks_in) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
192
        if ( strpos( $iehacks_in, '%%IEHACK%%' ) !== false ) { 
193
            $iehacks_out = preg_replace_callback(
194
                '#%%IEHACK'.AUTOPTIMIZE_HASH.'%%(.*?)%%IEHACK%%#is',
195
                create_function(
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
196
                    '$matches',
197
                    'return base64_decode($matches[1]);'
198
                ),
199
                $iehacks_in
200
            );
201
        } else {
202
            $iehacks_out=$iehacks_in;
203
        }
204
        return $iehacks_out;
205
    }
206
207 View Code Duplication
    protected function hide_comments($comments_in) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
208
        if ( strpos( $comments_in, '<!--' ) !== false ) {
209
            $comments_out = preg_replace_callback(
210
                '#<!--.*?-->#is',
211
                create_function(
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
212
                    '$matches',
213
                    'return "%%COMMENTS".AUTOPTIMIZE_HASH."%%".base64_encode($matches[0])."%%COMMENTS%%";'
214
                ),
215
                $comments_in
216
            );
217
        } else {
218
            $comments_out = $comments_in;
219
        }
220
        return $comments_out;
221
    }
222
223 View Code Duplication
    protected function restore_comments($comments_in) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
224
        if ( strpos( $comments_in, '%%COMMENTS%%' ) !== false ) {
225
            $comments_out = preg_replace_callback(
226
                '#%%COMMENTS'.AUTOPTIMIZE_HASH.'%%(.*?)%%COMMENTS%%#is',
227
                create_function(
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
228
                    '$matches',
229
                    'return base64_decode($matches[1]);'
230
                ),
231
                $comments_in
232
            );
233
        } else {
234
            $comments_out=$comments_in;
235
        }
236
        return $comments_out;
237
    }
238
239
    protected function url_replace_cdn( $url ) {
240
        // API filter to change base CDN URL
241
        $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', $this->cdn_url );
242
243
        if ( !empty($cdn_url) )  {
244
            // prepend domain-less absolute URL's
245
            if ( ( substr( $url, 0, 1 ) === '/' ) && ( substr( $url, 1, 1 ) !== '/' ) ) {
246
                $url = rtrim( $cdn_url, '/' ) . $url;
247
            } else {
248
                // get wordpress base URL
249
                $WPSiteBreakdown = parse_url( AUTOPTIMIZE_WP_SITE_URL );
250
                $WPBaseUrl       = $WPSiteBreakdown['scheme'] . '://' . $WPSiteBreakdown['host'];
251
                if ( ! empty( $WPSiteBreakdown['port'] ) ) {
252
                    $WPBaseUrl .= ":" . $WPSiteBreakdown['port'];
253
                }
254
                // replace full url's with scheme
255
                $tmp_url = str_replace( $WPBaseUrl, rtrim( $cdn_url, '/' ), $url );
256
                if ( $tmp_url === $url ) {
257
                    // last attempt; replace scheme-less URL's
258
                    $url = str_replace( preg_replace( '/https?:/', '', $WPBaseUrl ), rtrim( $cdn_url, '/' ), $url );
259
                } else {
260
                    $url = $tmp_url;
261
                }
262
            }
263
        }
264
265
        // allow API filter to alter URL after CDN replacement
266
        $url = apply_filters( 'autoptimize_filter_base_replace_cdn', $url );
267
        return $url;
268
    }
269
270
    protected function inject_in_html($payload,$replaceTag) {
271
        if (strpos($this->content,$replaceTag[0])!== false) {
272
            if ($replaceTag[1]==="after") {
273
                $replaceBlock=$replaceTag[0].$payload;
274
            } else if ($replaceTag[1]==="replace"){
275
                $replaceBlock=$payload;
276
            } else {
277
                $replaceBlock=$payload.$replaceTag[0];
278
            }
279
            $this->content = substr_replace($this->content,$replaceBlock,strpos($this->content,$replaceTag[0]),strlen($replaceTag[0]));
280
        } else {
281
            $this->content .= $payload;
282
            if (!$this->tagWarning) {
283
                $this->content .= "<!--noptimize--><!-- Autoptimize found a problem with the HTML in your Theme, tag \"".str_replace(array("<",">"),"",$replaceTag[0])."\" missing --><!--/noptimize-->";
284
                $this->tagWarning=true;
285
            }
286
        }
287
    }
288
    
289
    protected function isremovable($tag, $removables) {
290
        foreach ($removables as $match) {
291
            if (strpos($tag,$match)!==false) {
292
                return true;
293
            }
294
        }
295
        return false;
296
    }
297
    
298
    // inject already minified code in optimized JS/CSS
299 View Code Duplication
    protected function inject_minified($in) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
300
        if ( strpos( $in, '%%INJECTLATER%%' ) !== false ) {
301
            $out = preg_replace_callback(
302
                '#\/\*\!%%INJECTLATER'.AUTOPTIMIZE_HASH.'%%(.*?)%%INJECTLATER%%\*\/#is',
303
                create_function(
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
304
                    '$matches',
305
                    '$filepath=base64_decode(strtok($matches[1],"|"));
306
                    $filecontent=file_get_contents($filepath);
307
                    
308
                    // remove BOM
309
                    $filecontent = preg_replace("#\x{EF}\x{BB}\x{BF}#","",$filecontent);
310
311
                    // remove comments and blank lines
312
                    if (substr($filepath,-3,3)===".js") {
313
                        $filecontent=preg_replace("#^\s*\/\/.*$#Um","",$filecontent);
314
                    }
315
316
                    $filecontent=preg_replace("#^\s*\/\*[^!].*\*\/\s?#Um","",$filecontent);
317
                    $filecontent=preg_replace("#(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+#", "\n", $filecontent);
318
319
                    // differentiate between JS, CSS and other files
320
                    if (substr($filepath,-3,3)===".js") {
321
                        if ((substr($filecontent,-1,1)!==";")&&(substr($filecontent,-1,1)!=="}")) {
322
                            $filecontent.=";";
323
                        }
324
325
                        if (get_option("autoptimize_js_trycatch")==="on") {
326
                            $filecontent="try{".$filecontent."}catch(e){}";
327
                        }
328
                    } else if ((substr($filepath,-4,4)===".css")) {
329
                        $filecontent=autoptimizeStyles::fixurls($filepath,$filecontent);
330
                    } else {
331
                        $filecontent="";
332
                    }
333
334
                    // return 
335
                    return "\n".$filecontent;'
336
                ),
337
                $in
338
            );
339
        } else {
340
            $out = $in;
341
        }
342
        return $out;
343
    }
344
    
345
    protected function minify_single($pathIn) {
346
		// determine JS or CSS and set var (also mimetype), return false if neither
347
		if ( $this->str_ends_in($pathIn,".js") === true ) {
348
			$codeType="js";
349
			$codeMime="text/javascript";
350
		} else if ( $this->str_ends_in($pathIn,".css") === true ) {
351
			$codeType="css";
352
			$codeMime="text/css";			
353
		} else {
354
			return false;
355
		}
356
		
357
		// if min.js or min.css return false
358
		if (( $this->str_ends_in($pathIn,"-min.".$codeType) === true ) || ( $this->str_ends_in($pathIn,".min.".$codeType) === true ) || ( $this->str_ends_in($pathIn,"js/jquery/jquery.js") === true ) ) {
359
			return false;
360
		}
361
		
362
		// read file, return false if empty
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
363
		$_toMinify = file_get_contents($pathIn);
364
		if ( empty($_toMinify) ) return false;
365
		
366
		// check cache
367
		$_md5hash = "single_".md5($_toMinify);
368
		$_cache = new autoptimizeCache($_md5hash,$codeType);
369
		if ($_cache->check() ) {
370
			$_CachedMinifiedUrl = AUTOPTIMIZE_CACHE_URL.$_cache->getname();
371
		} else {
372
			// if not in cache first minify
373
			$_Minified = $_toMinify;
374
			if ($codeType === "js") {
375
				if (class_exists('JSMin') && apply_filters( 'autoptimize_js_do_minify' , true)) {
376
					if (@is_callable(array("JSMin","minify"))) {
377
						$tmp_code = trim(JSMin::minify($_toMinify));
378
					}
379
				}
380 View Code Duplication
			} else if ($codeType === "css") {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
381
                if (class_exists('Minify_CSS_Compressor')) {
382
					$tmp_code = trim(Minify_CSS_Compressor::process($_toMinify));
383
                } else if(class_exists('CSSmin')) {
384
                    $cssmin = new CSSmin();
385
                    if (method_exists($cssmin,"run")) {
386
                        $tmp_code = trim($cssmin->run($_toMinify));
387
                    } elseif (@is_callable(array($cssmin,"minify"))) {
388
                        $tmp_code = trim(CssMin::minify($_toMinify));
0 ignored issues
show
Bug introduced by
The method minify() cannot be called from this context as it is declared private in class CSSmin.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
Bug introduced by
The call to minify() misses a required argument $linebreak_pos.

This check looks for function calls that miss required arguments.

Loading history...
389
                    }
390
                }
391
			}
392
			if (!empty($tmp_code)) {
393
				$_Minified = $tmp_code;
394
				unset($tmp_code);
395
			}
396
			// and then cache
397
			$_cache->cache($_Minified,$codeMime);
398
			$_CachedMinifiedUrl = AUTOPTIMIZE_CACHE_URL.$_cache->getname();
399
		}
400
		unset($_cache);
401
	
402
		// if CDN, then CDN
403
		$_CachedMinifiedUrl = $this->url_replace_cdn($_CachedMinifiedUrl);									
404
405
		return $_CachedMinifiedUrl;
406
	}
407
	
408
	protected function str_ends_in($haystack,$needle) {
409
		$needleLength = strlen($needle);
410
		$haystackLength = strlen($haystack);
411
		$lastPos=strrpos($haystack,$needle);
412
		if ($lastPos === $haystackLength - $needleLength) {
413
			return true;
414
		} else {
415
			return false;
416
		}
417
	}
418
419
    /**
420
     * Specialized method to create the INJECTLATER marker.
421
     * These are somewhat "special", in the sense that they're additionally wrapped
422
     * within an "exclamation mark style" comment, so that they're not stripped out by minifiers.
423
     * They also currently contain the hash of the file's contents too (unlike other markers).
424
     *
425
     * @param string $filepath
426
     * @param string $hash
427
     * @return string
428
     */
429
    public static function build_injectlater_marker($filepath, $hash)
430
    {
431
        $contents = '/*!' . self::build_marker('INJECTLATER', $filepath, $hash) . '*/';
432
        return $contents;
433
    }
434
435
    /**
436
     * Creates and returns a `%%`-style named marker which holds
437
     * the base64 encoded `$data`.
438
     * If `$hash` is provided, it's appended to the base64 encoded string
439
     * using `|` as the separator (in order to support building the
440
     * somewhat special/different INJECTLATER marker).
441
     *
442
     * @param string $name Marker name
443
     * @param string $data Marker data which will be encoded in base64
444
     * @param string|null $hash Optional.
445
     *
446
     * @return string
447
     */
448
    public static function build_marker($name, $data, $hash = null)
449
    {
450
        // $name = strtoupper($name);
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
451
        // Start the marker, add the data
452
        $marker = '%%' . $name . AUTOPTIMIZE_HASH . '%%' . base64_encode( $data );
453
        // Add the hash if provided
454
        if ( null !== $hash ) {
455
            $marker .= '|' . $hash;
456
        }
457
        // Close the marker
458
        $marker .= '%%' . $name . '%%';
459
        return $marker;
460
    }
461
462
    /**
463
     * Returns true if the string is a valid regex.
464
     *
465
     * @param string $string
466
     *
467
     * @return bool
468
     */
469
    protected function str_is_valid_regex($string)
470
    {
471
        set_error_handler( function() {}, E_WARNING );
472
        $is_regex = ( false !== preg_match( $string, '' ) );
473
        restore_error_handler();
474
        return $is_regex;
475
    }
476
477
    /**
478
     * Searches for `$search` in `$content` (using either `preg_match()`
479
     * or `strpos()`, depending on whether `$search` is a valid regex pattern or not).
480
     * If something is found, it replaces `$content` using `$re_replace_pattern`,
481
     * effectively creating our named markers (`%%{$marker}%%`.
482
     * These are then at some point replaced back to their actual/original/modified
483
     * contents using `autoptimizeBase::restore_marked_content()`.
484
     *
485
     * @param string $marker Marker name (without percent characters)
486
     * @param string $search A string or full blown regex pattern to search for in $content. Uses `strpos()` or `preg_match()`
487
     * @param string $re_replace_pattern Regex pattern to use when replacing contents
488
     * @param string $content Content to work on
489
     *
490
     * @return string
491
     */
492
    protected function replace_contents_with_marker_if_exists($marker, $search, $re_replace_pattern, $content)
493
    {
494
        $found = false;
0 ignored issues
show
Unused Code introduced by
$found is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
495
        $is_regex = $this->str_is_valid_regex($search);
496
        if ( $is_regex ) {
497
            $found = preg_match( $search, $content );
498
        } else {
499
            $found = ( false !== strpos( $content, $search ) );
500
        }
501
        if ( $found ) {
502
            $content = preg_replace_callback(
503
                $re_replace_pattern,
504
                create_function(
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
505
                    '$matches',
506
                    'return autoptimizeBase::build_marker("' . $marker . '", $matches[0]);'
507
                ),
508
                $content
509
            );
510
        }
511
        return $content;
512
    }
513
514
    /**
515
     * Complements `autoptimizeBase::replace_contents_with_marker_if_exists()`
516
     *
517
     * @param string $marker
518
     * @param string $content
519
     * @return string
520
     */
521
    protected function restore_marked_content($marker, $content)
522
    {
523
        if ( false !== strpos( $content, $marker ) ) {
524
            $content = preg_replace_callback(
525
                '#%%' . $marker . AUTOPTIMIZE_HASH . '%%(.*?)%%' . $marker . '%%#is',
526
                create_function(
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
527
                    '$matches',
528
                    'return base64_decode($matches[1]);'
529
                ),
530
                $content
531
            );
532
        }
533
        return $content;
534
    }
535
}
536