Completed
Push — master ( 821021...ec9c1e )
by frank
02:20
created

classes/autoptimizeBase.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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);
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(
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) {
160
        if ( strpos( $noptimize_in, '%%NOPTIMIZE%%' ) !== false ) { 
161
            $noptimize_out = preg_replace_callback(
162
                '#%%NOPTIMIZE'.AUTOPTIMIZE_HASH.'%%(.*?)%%NOPTIMIZE%%#is',
163
                create_function(
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) {
176
        if ( strpos( $iehacks_in, '<!--[if' ) !== false ) { 
177
            $iehacks_out = preg_replace_callback(
178
                '#<!--\[if.*?\[endif\]-->#is',
179
                create_function(
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) {
192
        if ( strpos( $iehacks_in, '%%IEHACK%%' ) !== false ) { 
193
            $iehacks_out = preg_replace_callback(
194
                '#%%IEHACK'.AUTOPTIMIZE_HASH.'%%(.*?)%%IEHACK%%#is',
195
                create_function(
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) {
208
        if ( strpos( $comments_in, '<!--' ) !== false ) {
209
            $comments_out = preg_replace_callback(
210
                '#<!--.*?-->#is',
211
                create_function(
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) {
224
        if ( strpos( $comments_in, '%%COMMENTS%%' ) !== false ) {
225
            $comments_out = preg_replace_callback(
226
                '#%%COMMENTS'.AUTOPTIMIZE_HASH.'%%(.*?)%%COMMENTS%%#is',
227
                create_function(
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) {
300
        if ( strpos( $in, '%%INJECTLATER%%' ) !== false ) {
301
            $out = preg_replace_callback(
302
                '#\/\*\!%%INJECTLATER'.AUTOPTIMIZE_HASH.'%%(.*?)%%INJECTLATER%%\*\/#is',
303
                create_function(
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
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
			} else if ($codeType === "css") {
381
                // make sure paths to background images/ imported css/ fonts .. are OK
382
                $_toMinify = $this->fixurls($pathIn,$_toMinify);
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class autoptimizeBase as the method fixurls() does only exist in the following sub-classes of autoptimizeBase: autoptimizeStyles. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
383
                if (class_exists('Minify_CSS_Compressor')) {
384
					$tmp_code = trim(Minify_CSS_Compressor::process($_toMinify));
385
                } else if(class_exists('CSSmin')) {
386
                    $cssmin = new CSSmin();
387
                    if (method_exists($cssmin,"run")) {
388
                        $tmp_code = trim($cssmin->run($_toMinify));
389
                    } elseif (@is_callable(array($cssmin,"minify"))) {
390
                        $tmp_code = trim(CssMin::minify($_toMinify));
391
                    }
392
                }
393
			}
394
			if (!empty($tmp_code)) {
395
				$_Minified = $tmp_code;
396
				unset($tmp_code);
397
			}
398
			// and then cache
399
			$_cache->cache($_Minified,$codeMime);
400
			$_CachedMinifiedUrl = AUTOPTIMIZE_CACHE_URL.$_cache->getname();
401
		}
402
		unset($_cache);
403
	
404
		// if CDN, then CDN
405
		$_CachedMinifiedUrl = $this->url_replace_cdn($_CachedMinifiedUrl);									
406
407
		return $_CachedMinifiedUrl;
408
	}
409
	
410
	protected function str_ends_in($haystack,$needle) {
411
		$needleLength = strlen($needle);
412
		$haystackLength = strlen($haystack);
413
		$lastPos=strrpos($haystack,$needle);
414
		if ($lastPos === $haystackLength - $needleLength) {
415
			return true;
416
		} else {
417
			return false;
418
		}
419
	}
420
}
421