/** * Set up groups of files as sources * * @param array $options controller and Minify options * @return array Minify options * */ public function setupSources($options) { // PHP insecure by default: realpath() and other FS functions can't handle null bytes. if (isset($_GET['files'])) { $_GET['files'] = str_replace("", '', (string) $_GET['files']); } self::_setupDefines(); if (MINIFY_USE_CACHE) { $cacheDir = defined('MINIFY_CACHE_DIR') ? MINIFY_CACHE_DIR : ''; Minify0_Minify::setCache($cacheDir); } $options['badRequestHeader'] = 'HTTP/1.0 404 Not Found'; $options['contentTypeCharset'] = MINIFY_ENCODING; // The following restrictions are to limit the URLs that minify will // respond to. Ideally there should be only one way to reference a file. if (!isset($_GET['files']) || !preg_match('/^[^,]+\\.(css|js)(,[^,]+\\.\\1)*$/', $_GET['files'], $m) || strpos($_GET['files'], '//') !== false || strpos($_GET['files'], '\\') !== false || preg_match('/(?:^|[^\\.])\\.\\//', $_GET['files'])) { return $options; } $files = explode(',', $_GET['files']); if (count($files) > MINIFY_MAX_FILES) { return $options; } // strings for prepending to relative/absolute paths $prependRelPaths = dirname($_SERVER['SCRIPT_FILENAME']) . DIRECTORY_SEPARATOR; $prependAbsPaths = $_SERVER['DOCUMENT_ROOT']; $goodFiles = array(); $hasBadSource = false; $allowDirs = isset($options['allowDirs']) ? $options['allowDirs'] : MINIFY_BASE_DIR; foreach ($files as $file) { // prepend appropriate string for abs/rel paths $file = ($file[0] === '/' ? $prependAbsPaths : $prependRelPaths) . $file; // make sure a real file! $file = realpath($file); // don't allow unsafe or duplicate files if (parent::_fileIsSafe($file, $allowDirs) && !in_array($file, $goodFiles)) { $goodFiles[] = $file; $srcOptions = array('filepath' => $file); $this->sources[] = new Minify_Source($srcOptions); } else { $hasBadSource = true; break; } } if ($hasBadSource) { $this->sources = array(); } if (!MINIFY_REWRITE_CSS_URLS) { $options['rewriteCssUris'] = false; } return $options; }
/** * Runs minify * * @param string|null $file * * @return void */ function process($file = NULL, $quiet = false) { /** * Check for rewrite test request */ $rewrite_marker = 'rewrite_test.css'; if (substr($file, strlen($file) - strlen($rewrite_marker)) == $rewrite_marker) { echo 'Minify OK'; exit; } $filelength_test_marker = 'XXX.css'; if (substr($file, strlen($file) - strlen($filelength_test_marker)) == $filelength_test_marker) { $cache = $this->_get_cache(); header('Content-type: text/css'); if (!$cache->store(basename($file), array('content' => 'content ok'))) { echo 'error storing'; } else { if (function_exists('gzencode') && $this->_config->get_boolean('browsercache.enabled') && $this->_config->get_boolean('browsercache.cssjs.compression')) { if (!$cache->store(basename($file) . '.gzip', array('content' => gzencode('content ok')))) { echo 'error storing'; exit; } } $v = $cache->fetch(basename($file)); if ($v['content'] == 'content ok') { echo 'content ok'; } else { echo 'error storing'; } } exit; } // remove querystring if (preg_match('~(.+)(\\?x[0-9]{5})$~', $file, $m)) { $file = $m[1]; } // remove blog_id $levels = ''; if (defined('W3TC_BLOG_LEVELS')) { for ($n = 0; $n < W3TC_BLOG_LEVELS; $n++) { $levels .= '[0-9]+\\/'; } } if (preg_match('~^(' . $levels . '[0-9]+)\\/(.+)$~', $file, $matches)) { $file = $matches[2]; } // normalize according to browsercache $file = Dispatcher::requested_minify_filename($this->_config, $file); // parse file $hash = ''; $matches = null; $location = ''; $type = ''; if (preg_match('~^' . MINIFY_AUTO_FILENAME_REGEX . '$~', $file, $matches)) { list(, $hash, $type) = $matches; } elseif (preg_match('~^' . MINIFY_MANUAL_FILENAME_REGEX . '$~', $file, $matches)) { list(, $theme, $template, $location, , , $type) = $matches; } else { return $this->finish_with_error(sprintf('Bad file param format: "%s"', $file), $quiet, false); } /** * Set cache engine */ $cache = $this->_get_cache(); \Minify0_Minify::setCache($cache); /** * Set cache ID */ $cache_id = $this->get_cache_id($file); \Minify0_Minify::setCacheId($file); /** * Set logger */ \Minify_Logger::setLogger(array($this, 'debug_error')); /** * Set options */ $browsercache = $this->_config->get_boolean('browsercache.enabled'); $serve_options = array_merge($this->_config->get_array('minify.options'), array('debug' => $this->_config->get_boolean('minify.debug'), 'maxAge' => $this->_config->get_integer('browsercache.cssjs.lifetime'), 'encodeOutput' => $browsercache && !defined('W3TC_PAGECACHE_OUTPUT_COMPRESSION_OFF') && !$quiet && $this->_config->get_boolean('browsercache.cssjs.compression'), 'bubbleCssImports' => $this->_config->get_string('minify.css.imports') == 'bubble', 'processCssImports' => $this->_config->get_string('minify.css.imports') == 'process', 'cacheHeaders' => array('use_etag' => $browsercache && $this->_config->get_boolean('browsercache.cssjs.etag'), 'expires_enabled' => $browsercache && $this->_config->get_boolean('browsercache.cssjs.expires'), 'cacheheaders_enabled' => $browsercache && $this->_config->get_boolean('browsercache.cssjs.cache.control'), 'cacheheaders' => $this->_config->get_string('browsercache.cssjs.cache.policy')), 'quiet' => $quiet)); /** * Set sources */ if ($hash) { $_GET['f_array'] = $this->minify_filename_to_filenames_for_minification($hash, $type); $_GET['ext'] = $type; } else { $_GET['g'] = $location; $serve_options['minApp']['groups'] = $this->get_groups($theme, $template, $type); } /** * Set minifier */ $w3_minifier = Dispatcher::component('Minify_ContentMinifier'); if ($type == 'js') { $minifier_type = 'application/x-javascript'; switch (true) { case ($hash || $location == 'include') && $this->_config->get_boolean('minify.js.combine.header'): case $location == 'include-body' && $this->_config->get_boolean('minify.js.combine.body'): case $location == 'include-footer' && $this->_config->get_boolean('minify.js.combine.footer'): $engine = 'combinejs'; break; default: $engine = $this->_config->get_string('minify.js.engine'); if (!$w3_minifier->exists($engine) || !$w3_minifier->available($engine)) { $engine = 'js'; } break; } } elseif ($type == 'css') { $minifier_type = 'text/css'; if (($hash || $location == 'include') && $this->_config->get_boolean('minify.css.combine')) { $engine = 'combinecss'; } else { $engine = $this->_config->get_string('minify.css.engine'); if (!$w3_minifier->exists($engine) || !$w3_minifier->available($engine)) { $engine = 'css'; } } } /** * Initialize minifier */ $w3_minifier->init($engine); $serve_options['minifiers'][$minifier_type] = $w3_minifier->get_minifier($engine); $serve_options['minifierOptions'][$minifier_type] = $w3_minifier->get_options($engine); /** * Send X-Powered-By header */ if (!$quiet && $browsercache && $this->_config->get_boolean('browsercache.cssjs.w3tc')) { @header('X-Powered-By: ' . Util_Environment::w3tc_header()); } if (empty($_GET['f_array']) && empty($_GET['g'])) { return $this->finish_with_error('Nothing to minify', $quiet, false); } /** * Minify! */ $return = array(); try { $return = \Minify0_Minify::serve('MinApp', $serve_options); } catch (\Exception $exception) { return $this->finish_with_error($exception->getMessage(), $quiet); } if (!is_null(\Minify0_Minify::$recoverableError)) { $this->_handle_error(\Minify0_Minify::$recoverableError); } $state = Dispatcher::config_state_master(); if (!$this->_error_occurred && $state->get_boolean('minify.show_note_minify_error')) { $error_file = $state->get_string('minify.error.file'); if ($error_file == $file) { $state->set('minify.show_note_minify_error', false); $state->save(); } } return $return; }