/** * OB callback * * @param string $buffer * @return string */ function ob_callback(&$buffer) { if ($buffer != '' && w3_is_xml($buffer)) { if ($this->can_minify2($buffer)) { /** * Replace script and style tags */ if (function_exists('is_feed') && !is_feed()) { w3_require_once(W3TC_INC_DIR . '/functions/extract.php'); $head_prepend = ''; $body_prepend = ''; $body_append = ''; $embed_extsrcjs = false; if ($this->_config->get_boolean('minify.auto')) { if ($this->_config->get_boolean('minify.js.enable')) { $ignore_js_files = $this->_config->get_array('minify.reject.files.js'); $embed_type = $this->_config->get_string('minify.js.header.embed_type'); $embed_type = $embed_type == 'extsrc' || $embed_type == 'asyncsrc' ? 'blocking' : $embed_type; $embed_pos = strpos($buffer, '<!-- W3TC-include-js-head -->'); $buffer = str_replace('<!-- W3TC-include-js-head -->', '', $buffer); if ($embed_pos === false) { preg_match('~<head(\\s+[^<>]+)*>~Ui', $buffer, $match, PREG_OFFSET_CAPTURE); $embed_pos = strlen($match[0][0]) + $match[0][1]; } $ignore_js_files = array_map('w3_normalize_file', $ignore_js_files); $files_to_minify = array(); $handled_scripts = array(); $script_tags = w3_extract_js2($buffer); $previous_file_was_ignored = false; foreach ($script_tags as $script_tag) { $tag_pos = strpos($buffer, $script_tag); $match = array(); preg_match('~<script\\s+[^<>]*src=["\']?([^"\']+)["\']?[^<>]*>\\s*</script>~is', $script_tag, $match); $file = $match[1]; $file = w3_normalize_file_minify2($file); $script_len = strlen($script_tag); if (!$this->_filter_files($file) || in_array($file, $handled_scripts)) { continue; } $handled_scripts[] = $file; $this->replaced_scripts[] = $file; if (in_array($file, $ignore_js_files)) { if ($tag_pos > $embed_pos) { if ($files_to_minify) { $script = $this->get_script_custom($files_to_minify, $embed_type); $buffer = substr_replace($buffer, $script, $embed_pos, 0); $files_to_minify = array(); $script_len = $script_len + strlen($script); } $embed_pos = $embed_pos + $script_len; $previous_file_was_ignored = true; } } else { $buffer = substr_replace($buffer, '', $tag_pos, $script_len); if ($embed_pos > $tag_pos) { $embed_pos -= $script_len; } elseif ($previous_file_was_ignored) { $embed_pos = $tag_pos; } $files_to_minify[] = $file; } } $script = $this->get_script_custom($files_to_minify, $embed_type); $buffer = substr_replace($buffer, $script, $embed_pos, 0); } if ($this->_config->get_boolean('minify.css.enable')) { $ignore_css_files = $this->_config->get_array('minify.reject.files.css'); $files_to_minify = array(); $embed_pos = strpos($buffer, '<!-- W3TC-include-css -->'); $buffer = str_replace('<!-- W3TC-include-css -->', '', $buffer); if ($embed_pos === false) { preg_match('~<head(\\s+[^<>]+)*>~Ui', $buffer, $match, PREG_OFFSET_CAPTURE); $embed_pos = strlen($match[0][0]) + $match[0][1]; } $ignore_css_files = array_map('w3_normalize_file', $ignore_css_files); $handled_styles = array(); $style_tags = w3_extract_css2($buffer); $previous_file_was_ignored = false; foreach ($style_tags as $style_tag_tuple) { $style_tag = $style_tag_tuple[0]; $tag_pos = strpos($buffer, $style_tag); $match = array(); $file = $style_tag_tuple[1]; $file = w3_normalize_file_minify2($file); $style_len = strlen($style_tag); if (!$this->_filter_files($file) || in_array($file, $handled_styles)) { continue; } $handled_styles[] = $file; $this->replaced_styles[] = $file; if (in_array($file, $ignore_css_files)) { if ($tag_pos > $embed_pos) { if ($files_to_minify) { $style = $this->get_style_custom($files_to_minify); $buffer = substr_replace($buffer, $style, $embed_pos, 0); $files_to_minify = array(); $style_len = $style_len + strlen($style); } $embed_pos = $embed_pos + $style_len; $previous_file_was_ignored = true; } } else { $buffer = substr_replace($buffer, '', $tag_pos, $style_len); if ($embed_pos > $tag_pos) { $embed_pos -= $style_len; } elseif ($previous_file_was_ignored) { $embed_pos = $tag_pos; } $files_to_minify[] = $file; } } $style = $this->get_style_custom($files_to_minify); $buffer = substr_replace($buffer, $style, $embed_pos, 0); } } else { if ($this->_config->get_boolean('minify.css.enable') && !in_array('include', $this->printed_styles)) { $style = $this->get_style_group('include'); if ($style) { if ($this->_custom_location_does_not_exist('/<!-- W3TC-include-css -->/', $buffer, $style)) { $head_prepend .= $style; } $this->remove_styles_group($buffer, 'include'); } } if ($this->_config->get_boolean('minify.js.enable')) { if (!in_array('include', $this->printed_scripts)) { $embed_type = $this->_config->get_string('minify.js.header.embed_type'); $script = $this->get_script_group('include', $embed_type); if ($script) { $embed_extsrcjs = $embed_type == 'extsrc' || $embed_type == 'asyncsrc' ? true : $embed_extsrcjs; if ($this->_custom_location_does_not_exist('/<!-- W3TC-include-js-head -->/', $buffer, $script)) { $head_prepend .= $script; } $this->remove_scripts_group($buffer, 'include', $embed_type); } } if (!in_array('include-body', $this->printed_scripts)) { $embed_type = $this->_config->get_string('minify.js.body.embed_type'); $script = $this->get_script_group('include-body', $embed_type); if ($script) { $embed_extsrcjs = $embed_type == 'extsrc' || $embed_type == 'asyncsrc' ? true : $embed_extsrcjs; if ($this->_custom_location_does_not_exist('/<!-- W3TC-include-js-body-start -->/', $buffer, $script)) { $body_prepend .= $script; } $this->remove_scripts_group($buffer, 'include-body', $embed_type); } } if (!in_array('include-footer', $this->printed_scripts)) { $embed_type = $this->_config->get_string('minify.js.footer.embed_type'); $script = $this->get_script_group('include-footer', $embed_type); if ($script) { $embed_extsrcjs = $embed_type == 'extsrc' || $embed_type == 'asyncsrc' ? true : $embed_extsrcjs; if ($this->_custom_location_does_not_exist('/<!-- W3TC-include-js-body-end -->/', $buffer, $script)) { $body_append .= $script; } $this->remove_scripts_group($buffer, 'include-footer', $embed_type); } } } } if ($head_prepend != '') { $buffer = preg_replace('~<head(\\s+[^<>]+)*>~Ui', '\\0' . $head_prepend, $buffer, 1); } if ($body_prepend != '') { $buffer = preg_replace('~<body(\\s+[^<>]+)*>~Ui', '\\0' . $body_prepend, $buffer, 1); } if ($body_append != '') { $buffer = preg_replace('~<\\/body>~', $body_append . '\\0', $buffer, 1); } if ($embed_extsrcjs) { $script = "\n<script type=\"text/javascript\">\n" . "var extsrc=null;\n" . '(function(){function j(){if(b&&g){document.write=k;document.writeln=l;var f=document.createElement("span");f.innerHTML=b;g.appendChild(f);b=""}}function d(){j();for(var f=document.getElementsByTagName("script"),c=0;c<f.length;c++){var e=f[c],h=e.getAttribute("asyncsrc");if(h){e.setAttribute("asyncsrc","");var a=document.createElement("script");a.async=!0;a.src=h;document.getElementsByTagName("head")[0].appendChild(a)}if(h=e.getAttribute("extsrc")){e.setAttribute("extsrc","");g=document.createElement("span");e.parentNode.insertBefore(g,e);document.write=function(a){b+=a};document.writeln=function(a){b+=a;b+="\\n"};a=document.createElement("script");a.async=!0;a.src=h;/msie/i.test(navigator.userAgent)&&!/opera/i.test(navigator.userAgent)?a.onreadystatechange=function(){("loaded"==this.readyState||"complete"==this.readyState)&&d()}:-1!=navigator.userAgent.indexOf("Firefox")||"onerror"in a?(a.onload=d,a.onerror=d):(a.onload=d,a.onreadystatechange=d);document.getElementsByTagName("head")[0].appendChild(a);return}}j();document.write=k;document.writeln=l;for(c=0;c<extsrc.complete.funcs.length;c++)extsrc.complete.funcs[c]()}function i(){arguments.callee.done||(arguments.callee.done=!0,d())}extsrc={complete:function(b){this.complete.funcs.push(b)}};extsrc.complete.funcs=[];var k=document.write,l=document.writeln,b="",g="";document.addEventListener&&document.addEventListener("DOMContentLoaded",i,!1);if(/WebKit/i.test(navigator.userAgent))var m=setInterval(function(){/loaded|complete/.test(document.readyState)&&(clearInterval(m),i())},10);window.onload=i})();' . "\n</script>\n"; $buffer = preg_replace('~<head(\\s+[^<>]+)*>~Ui', '\\0' . $script, $buffer, 1); } } /** * Minify HTML/Feed */ if ($this->_config->get_boolean('minify.html.enable')) { try { $this->minify_html($buffer); } catch (Exception $exception) { $this->error = $exception->getMessage(); } } } if ($this->_config->get_boolean('minify.debug')) { $buffer .= "\r\n\r\n" . $this->get_debug_info(); } } return $buffer; }
/** * Returns minify groups * * @param string $theme * @param string $template * @param string $type * @return array */ function get_groups($theme, $template, $type) { $result = array(); switch ($type) { case 'css': $groups = $this->_config->get_array('minify.css.groups'); break; case 'js': $groups = $this->_config->get_array('minify.js.groups'); break; default: return $result; } if (isset($groups[$theme]['default'])) { $locations = (array) $groups[$theme]['default']; } else { $locations = array(); } if ($template != 'default' && isset($groups[$theme][$template])) { $locations = array_merge_recursive($locations, (array) $groups[$theme][$template]); } foreach ($locations as $location => $config) { if (!empty($config['files'])) { foreach ((array) $config['files'] as $file) { $file = w3_normalize_file_minify2($file); if (w3_is_url($file)) { $precached_file = $this->_precache_file($file, $type); if ($precached_file) { $result[$location][$file] = $precached_file; } else { $this->error(sprintf('Unable to cache remote file: "%s"', $file)); } } else { $path = w3_get_document_root() . '/' . $file; if (file_exists($path)) { $result[$location][$file] = '//' . $file; } else { $this->error(sprintf('File "%s" doesn\'t exist', $path)); } } } } } return $result; }
/** * Returns custom files * * @param string $hash * @param string $type * @return array */ function get_custom_files($hash, $type) { $files = $this->uncompress_minify_files($hash, $type); $result = array(); if ($files) { foreach ($files as $file) { $file = w3_normalize_file_minify2($file); if (w3_is_url($file)) { $precached_file = $this->_precache_file($file, $type); if ($precached_file) { $result[] = $precached_file; } else { $this->error(sprintf('Unable to cache remote file: "%s"', $file)); } } else { $path = w3_get_document_root() . '/' . $file; if (file_exists($path)) { $result[] = $file; } else { $this->error(sprintf('File "%s" doesn\'t exist', $path)); } } } } else { $this->error(sprintf('Unable to fetch custom files list: "%s.%s"', $hash, $type), false, 404); } return $result; }
/** * Processes script tag * @param $script_tag * @return void */ private function process_script_tag($script_tag) { $tag_pos = strpos($this->buffer, $script_tag); $match = null; if (!preg_match('~<script\\s+[^<>]*src=["\']?([^"\'> ]+)["\'> ]~is', $script_tag, $match)) { $match = null; } if (is_null($match)) { if (preg_match('~</head>~is', $script_tag, $match)) { $this->group_type = 'body'; } // it's not external script, have to flush what we have before it $this->flush_collected(); return; } if ($tag_pos === false) { // script is external but not found, skip processing it return; } $file = $match[1]; $file = w3_normalize_file_minify2($file); if (!$this->minify_helpers->is_file_for_minification($file) || in_array($file, $this->ignore_js_files)) { $this->flush_collected(); return; } $this->debug_minified_urls[] = $file; $this->buffer = substr_replace($this->buffer, '', $tag_pos, strlen($script_tag)); // for head group - put minified file at the place of first script // for body - put at the place of last script, to make as more DOM // objects available as possible if (count($this->files_to_minify) <= 0 || $this->group_type == 'body') { $this->embed_pos = $tag_pos; } $this->files_to_minify[] = $file; }