Completed
Push — master ( 53ffad...1386e4 )
by frank
02:05
created

classes/autoptimizeBase.php (1 issue)

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_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%%".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%%(.*?)%%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%%".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%%(.*?)%%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%%".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%%(.*?)%%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) {
300
        if ( strpos( $in, '%%INJECTLATER%%' ) !== false ) {
301
            $out = preg_replace_callback(
302
                '#%%INJECTLATER%%(.*?)%%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
                    // specific stuff for JS-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
                    }
331
332
                    // return 
333
                    return "\n".$filecontent;'
334
                ),
335
                $in
336
            );
337
        } else {
338
            $out = $in;
339
        }
340
        return $out;
341
    }
342
}
343