Completed
Push — master ( 4d020d...670e37 )
by frank
02:48
created

autoptimizeBase::inject_minified()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 52
Code Lines 11

Duplication

Lines 43
Ratio 82.69 %

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 2
nop 1
dl 43
loc 52
rs 9.4929
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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%%".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%%(.*?)%%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%%".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%%(.*?)%%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%%".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%%(.*?)%%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%%(.*?)%%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
                    $filehash=strtok("|");
307
                    $filecontent=file_get_contents($filepath);
308
                    
309
                    if ( md5($filecontent) === $filehash ) {
310
                        error_log("hash ".$filehash." matches calculated ".md5($filecontent)." for ".$filepath.", proceeding");
311
                        // remove BOM
312
                        $filecontent = preg_replace("#\x{EF}\x{BB}\x{BF}#","",$filecontent);
313
314
                        // remove comments and blank lines
315
                        if (substr($filepath,-3,3)===".js") {
316
                            $filecontent=preg_replace("#^\s*\/\/.*$#Um","",$filecontent);
317
                        }
318
319
                        $filecontent=preg_replace("#^\s*\/\*[^!].*\*\/\s?#Um","",$filecontent);
320
                        $filecontent=preg_replace("#(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+#", "\n", $filecontent);
321
322
                        // differentiate between JS, CSS and other files
323
                        if (substr($filepath,-3,3)===".js") {
324
                            if ((substr($filecontent,-1,1)!==";")&&(substr($filecontent,-1,1)!=="}")) {
325
                                $filecontent.=";";
326
                            }
327
328
                            if (get_option("autoptimize_js_trycatch")==="on") {
329
                                $filecontent="try{".$filecontent."}catch(e){}";
330
                            }
331
                        } else if ((substr($filepath,-4,4)===".css")) {
332
                            $filecontent=autoptimizeStyles::fixurls($filepath,$filecontent);
333
                        } else {
334
                            $filecontent="";
335
                        }
336
                    } else {
337
                        error_log("hash ".$filehash." does not match calculated ".md5($filecontent)." for ".$filepath.", proceeding");
338
                        $filecontent="";
339
                    }
340
341
                    // return 
342
                    return "\n".$filecontent;'
343
                ),
344
                $in
345
            );
346
        } else {
347
            $out = $in;
348
        }
349
        return $out;
350
    }
351
    
352
    protected function minify_single($pathIn) {
353
		// determine JS or CSS and set var (also mimetype), return false if neither
354
		if ( $this->str_ends_in($pathIn,".js") === true ) {
355
			$codeType="js";
356
			$codeMime="text/javascript";
357
		} else if ( $this->str_ends_in($pathIn,".css") === true ) {
358
			$codeType="css";
359
			$codeMime="text/css";			
360
		} else {
361
			return false;
362
		}
363
		
364
		// if min.js or min.css return false
365
		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 ) ) {
366
			return false;
367
		}
368
		
369
		// 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...
370
		$_toMinify = file_get_contents($pathIn);
371
		if ( empty($_toMinify) ) return false;
372
		
373
		// check cache
374
		$_md5hash = "single_".md5($_toMinify);
375
		$_cache = new autoptimizeCache($_md5hash,$codeType);
376
		if ($_cache->check() ) {
377
			$_CachedMinifiedUrl = AUTOPTIMIZE_CACHE_URL.$_cache->getname();
378
		} else {
379
			// if not in cache first minify
380
			$_Minified = $_toMinify;
381
			if ($codeType === "js") {
382
				if (class_exists('JSMin') && apply_filters( 'autoptimize_js_do_minify' , true)) {
383
					if (@is_callable(array("JSMin","minify"))) {
384
						$tmp_code = trim(JSMin::minify($_toMinify));
385
					}
386
				}
387 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...
388
                if (class_exists('Minify_CSS_Compressor')) {
389
					$tmp_code = trim(Minify_CSS_Compressor::process($_toMinify));
390
                } else if(class_exists('CSSmin')) {
391
                    $cssmin = new CSSmin();
392
                    if (method_exists($cssmin,"run")) {
393
                        $tmp_code = trim($cssmin->run($_toMinify));
394
                    } elseif (@is_callable(array($cssmin,"minify"))) {
395
                        $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...
396
                    }
397
                }
398
			}
399
			if (!empty($tmp_code)) {
400
				$_Minified = $tmp_code;
401
				unset($tmp_code);
402
			}
403
			// and then cache
404
			$_cache->cache($_Minified,$codeMime);
405
			$_CachedMinifiedUrl = AUTOPTIMIZE_CACHE_URL.$_cache->getname();
406
		}
407
		unset($_cache);
408
	
409
		// if CDN, then CDN
410
		$_CachedMinifiedUrl = $this->url_replace_cdn($_CachedMinifiedUrl);									
411
412
		return $_CachedMinifiedUrl;
413
	}
414
	
415
	protected function str_ends_in($haystack,$needle) {
416
		$needleLength = strlen($needle);
417
		$haystackLength = strlen($haystack);
418
		$lastPos=strrpos($haystack,$needle);
419
		if ($lastPos === $haystackLength - $needleLength) {
420
			return true;
421
		} else {
422
			return false;
423
		}
424
	}
425
}
426