futtta /
autoptimize
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( |
||
|
0 ignored issues
–
show
|
|||
| 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( |
||
|
0 ignored issues
–
show
The use of
create_function is highly discouraged, better use a closure.
// 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) { |
|
| 176 | if ( strpos( $iehacks_in, '<!--[if' ) !== false ) { |
||
| 177 | $iehacks_out = preg_replace_callback( |
||
| 178 | '#<!--\[if.*?\[endif\]-->#is', |
||
| 179 | create_function( |
||
|
0 ignored issues
–
show
The use of
create_function is highly discouraged, better use a closure.
// 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) { |
|
| 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
The use of
create_function is highly discouraged, better use a closure.
// 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) { |
|
| 208 | if ( strpos( $comments_in, '<!--' ) !== false ) { |
||
| 209 | $comments_out = preg_replace_callback( |
||
| 210 | '#<!--.*?-->#is', |
||
| 211 | create_function( |
||
|
0 ignored issues
–
show
The use of
create_function is highly discouraged, better use a closure.
// 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) { |
|
| 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
The use of
create_function is highly discouraged, better use a closure.
// 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'.AUTOPTIMIZE_HASH.'%%(.*?)%%INJECTLATER%%\*\/#is', |
||
| 303 | create_function( |
||
|
0 ignored issues
–
show
The use of
create_function is highly discouraged, better use a closure.
// 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") { |
|
| 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)); |
||
| 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 |
create_functioncan pose a great security vulnerability as it is similar toeval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.