/**
  * Generates directives for file cache dir
  *
  * @param Config  $config
  * @return string
  */
 private function rules_cache_generate_nginx($config)
 {
     $cache_dir = Util_Rule::filename_to_uri(W3TC_CACHE_MINIFY_DIR);
     $browsercache = $config->get_boolean('browsercache.enabled');
     $compression = $browsercache && $config->get_boolean('browsercache.cssjs.compression');
     $expires = $browsercache && $config->get_boolean('browsercache.cssjs.expires');
     $lifetime = $browsercache ? $config->get_integer('browsercache.cssjs.lifetime') : 0;
     $cache_control = $browsercache && $config->get_boolean('browsercache.cssjs.cache.control');
     $w3tc = $browsercache && $config->get_integer('browsercache.cssjs.w3tc');
     $rules = '';
     $rules .= W3TC_MARKER_BEGIN_MINIFY_CACHE . "\n";
     $common_rules = '';
     if ($expires) {
         $common_rules .= "    expires modified " . $lifetime . "s;\n";
     }
     if ($w3tc) {
         $common_rules .= "    add_header X-Powered-By \"" . Util_Environment::w3tc_header($config) . "\";\n";
     }
     if ($compression) {
         $common_rules .= "    add_header Vary \"Accept-Encoding\";\n";
     }
     if ($cache_control) {
         $cache_policy = $config->get_string('browsercache.cssjs.cache.policy');
         switch ($cache_policy) {
             case 'cache':
                 $common_rules .= "    add_header Pragma \"public\";\n";
                 $common_rules .= "    add_header Cache-Control \"public\";\n";
                 break;
             case 'cache_public_maxage':
                 $common_rules .= "    add_header Pragma \"public\";\n";
                 $common_rules .= "    add_header Cache-Control \"max-age=" . $lifetime . ", public\";\n";
                 break;
             case 'cache_validation':
                 $common_rules .= "    add_header Pragma \"public\";\n";
                 $common_rules .= "    add_header Cache-Control \"public, must-revalidate, proxy-revalidate\";\n";
                 break;
             case 'cache_noproxy':
                 $common_rules .= "    add_header Pragma \"public\";\n";
                 $common_rules .= "    add_header Cache-Control \"private, must-revalidate\";\n";
                 break;
             case 'cache_maxage':
                 $common_rules .= "    add_header Pragma \"public\";\n";
                 $common_rules .= "    add_header Cache-Control \"max-age=" . $lifetime . ", public, must-revalidate, proxy-revalidate\";\n";
                 break;
             case 'no_cache':
                 $common_rules .= "    add_header Pragma \"no-cache\";\n";
                 $common_rules .= "    add_header Cache-Control \"max-age=0, private, no-store, no-cache, must-revalidate\";\n";
                 break;
         }
     }
     $rules .= "location ~ " . $cache_dir . ".*\\.js\$ {\n";
     $rules .= "    types {}\n";
     $rules .= "    default_type application/x-javascript;\n";
     $rules .= $common_rules;
     $rules .= "}\n";
     $rules .= "location ~ " . $cache_dir . ".*\\.css\$ {\n";
     $rules .= "    types {}\n";
     $rules .= "    default_type text/css;\n";
     $rules .= $common_rules;
     $rules .= "}\n";
     if ($compression) {
         $rules .= "location ~ " . $cache_dir . ".*js\\.gzip\$ {\n";
         $rules .= "    gzip off;\n";
         $rules .= "    types {}\n";
         $rules .= "    default_type application/x-javascript;\n";
         $rules .= $common_rules;
         $rules .= "    add_header Content-Encoding gzip;\n";
         $rules .= "}\n";
         $rules .= "location ~ " . $cache_dir . ".*css\\.gzip\$ {\n";
         $rules .= "    gzip off;\n";
         $rules .= "    types {}\n";
         $rules .= "    default_type text/css;\n";
         $rules .= $common_rules;
         $rules .= "    add_header Content-Encoding gzip;\n";
         $rules .= "}\n";
     }
     $rules .= W3TC_MARKER_END_MINIFY_CACHE . "\n";
     return $rules;
 }
 /**
  * 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;
 }
 /**
  * Returns headers for file
  *
  * @param array   $file CDN file array
  * @return array
  */
 function _get_headers($file, $block_expires = false)
 {
     $local_path = $file['local_path'];
     $mime_type = Util_Mime::get_mime_type($local_path);
     $last_modified = time();
     $link = $file['original_url'];
     $headers = array('Content-Type' => $mime_type, 'Last-Modified' => Util_Content::http_date($last_modified), 'Access-Control-Allow-Origin' => '*', 'Link' => '<' . $link . '>; rel="canonical"');
     if (isset($this->cache_config[$mime_type])) {
         if ($this->cache_config[$mime_type]['etag']) {
             $headers['ETag'] = '"' . @md5_file($local_path) . '"';
         }
         if ($this->cache_config[$mime_type]['w3tc']) {
             $headers['X-Powered-By'] = Util_Environment::w3tc_header($this->_config);
         }
         $expires_set = false;
         if (!$block_expires && $this->cache_config[$mime_type]['expires']) {
             $headers['Expires'] = Util_Content::http_date(time() + $this->cache_config[$mime_type]['lifetime']);
             $expires_set = true;
         }
         switch ($this->cache_config[$mime_type]['cache_control']) {
             case 'cache':
                 $headers = array_merge($headers, array('Pragma' => 'public', 'Cache-Control' => 'public'));
                 break;
             case 'cache_public_maxage':
                 $headers = array_merge($headers, array('Pragma' => 'public', 'Cache-Control' => ($expires_set ? '' : 'max-age=' . $this->cache_config[$mime_type]['lifetime'] . ', ') . 'public'));
                 break;
             case 'cache_validation':
                 $headers = array_merge($headers, array('Pragma' => 'public', 'Cache-Control' => 'public, must-revalidate, proxy-revalidate'));
                 break;
             case 'cache_noproxy':
                 $headers = array_merge($headers, array('Pragma' => 'public', 'Cache-Control' => 'private, must-revalidate'));
                 break;
             case 'cache_maxage':
                 $headers = array_merge($headers, array('Pragma' => 'public', 'Cache-Control' => ($expires_set ? '' : 'max-age=' . $this->cache_config[$mime_type]['lifetime'] . ', ') . 'public, must-revalidate, proxy-revalidate'));
                 break;
             case 'no_cache':
                 $headers = array_merge($headers, array('Pragma' => 'no-cache', 'Cache-Control' => 'max-age=0, private, no-store, no-cache, must-revalidate'));
                 break;
         }
     }
     return $headers;
 }
 /**
  * Adds cache rules for type to &$rules
  *
  * @param Config  $config
  * @param string  $rules
  * @param array   $mime_types
  * @param string  $section
  * @return void
  */
 private function _rules_cache_generate_nginx_for_type($config, &$rules, $mime_types, $section)
 {
     $expires = $config->get_boolean('browsercache.' . $section . '.expires');
     $cache_control = $config->get_boolean('browsercache.' . $section . '.cache.control');
     $w3tc = $config->get_boolean('browsercache.' . $section . '.w3tc');
     if ($expires || $cache_control || $w3tc) {
         $lifetime = $config->get_integer('browsercache.' . $section . '.lifetime');
         $extensions = array_keys($mime_types);
         // Remove ext from filesmatch if its the same as permalink extension
         $pext = strtolower(pathinfo(get_option('permalink_structure'), PATHINFO_EXTENSION));
         if ($pext) {
             $extensions = $this->_remove_extension_from_list($extensions, $pext);
         }
         $rules .= "location ~ \\.(" . implode('|', $extensions) . ")\$ {\n";
         if ($expires) {
             $rules .= "    expires " . $lifetime . "s;\n";
         }
         $add_header_rules = '';
         if ($cache_control) {
             $cache_policy = $config->get_string('browsercache.' . $section . '.cache.policy');
             switch ($cache_policy) {
                 case 'cache':
                     $add_header_rules .= "    add_header Pragma \"public\";\n";
                     $add_header_rules .= "    add_header Cache-Control \"public\";\n";
                     break;
                 case 'cache_public_maxage':
                     $add_header_rules .= "    add_header Pragma \"public\";\n";
                     $add_header_rules .= "    add_header Cache-Control \"max-age=" . $lifetime . ", public\";\n";
                     break;
                 case 'cache_validation':
                     $add_header_rules .= "    add_header Pragma \"public\";\n";
                     $add_header_rules .= "    add_header Cache-Control \"public, must-revalidate, proxy-revalidate\";\n";
                     break;
                 case 'cache_noproxy':
                     $add_header_rules .= "    add_header Pragma \"public\";\n";
                     $add_header_rules .= "    add_header Cache-Control \"private, must-revalidate\";\n";
                     break;
                 case 'cache_maxage':
                     $add_header_rules .= "    add_header Pragma \"public\";\n";
                     $add_header_rules .= "    add_header Cache-Control \"max-age=" . $lifetime . ", public, must-revalidate, proxy-revalidate\";\n";
                     break;
                 case 'no_cache':
                     $add_header_rules .= "    add_header Pragma \"no-cache\";\n";
                     $add_header_rules .= "    add_header Cache-Control \"max-age=0, private, no-store, no-cache, must-revalidate\";\n";
                     break;
             }
         }
         if ($w3tc) {
             $add_header_rules .= "    add_header X-Powered-By \"" . Util_Environment::w3tc_header($config) . "\";\n";
         }
         $rules .= $add_header_rules;
         $rules .= Dispatcher::on_browsercache_rules_generation_for_section($config, false, $section, $add_header_rules);
         if (!$config->get_boolean('browsercache.no404wp')) {
             $wp_uri = network_home_url('', 'relative');
             $wp_uri = rtrim($wp_uri, '/');
             $rules .= '    try_files $uri $uri/ $uri.html ' . $wp_uri . '/index.php?$args;' . "\n";
         }
         $rules .= "}\n";
     }
 }
 /**
  * Generates directives for file cache dir
  *
  * @param Config  $config
  * @return string
  */
 private function rules_cache_generate_nginx($config)
 {
     $cache_root = Util_Environment::normalize_path(W3TC_CACHE_PAGE_ENHANCED_DIR);
     $cache_dir = rtrim(str_replace(Util_Environment::document_root(), '', $cache_root), '/');
     if (Util_Environment::is_wpmu()) {
         $cache_dir = preg_replace('~/w3tc.*?/~', '/w3tc.*?/', $cache_dir, 1);
     }
     $browsercache = $config->get_boolean('browsercache.enabled');
     $compression = $browsercache && $config->get_boolean('browsercache.html.compression');
     $expires = $browsercache && $config->get_boolean('browsercache.html.expires');
     $lifetime = $browsercache ? $config->get_integer('browsercache.html.lifetime') : 0;
     $cache_control = $browsercache && $config->get_boolean('browsercache.html.cache.control');
     $w3tc = $browsercache && $config->get_integer('browsercache.html.w3tc');
     $common_rules = '';
     if ($expires) {
         $common_rules .= "    expires modified " . $lifetime . "s;\n";
     }
     if ($w3tc) {
         $common_rules .= "    add_header X-Powered-By \"" . Util_Environment::w3tc_header($config) . "\";\n";
     }
     if ($expires) {
         $common_rules .= "    add_header Vary \"Accept-Encoding, Cookie\";\n";
     }
     if ($cache_control) {
         $cache_policy = $config->get_string('browsercache.html.cache.policy');
         switch ($cache_policy) {
             case 'cache':
                 $common_rules .= "    add_header Pragma \"public\";\n";
                 $common_rules .= "    add_header Cache-Control \"public\";\n";
                 break;
             case 'cache_public_maxage':
                 $common_rules .= "    add_header Pragma \"public\";\n";
                 $common_rules .= "    add_header Cache-Control \"max-age=" . $lifetime . ", public\";\n";
                 break;
             case 'cache_validation':
                 $common_rules .= "    add_header Pragma \"public\";\n";
                 $common_rules .= "    add_header Cache-Control \"public, must-revalidate, proxy-revalidate\";\n";
                 break;
             case 'cache_noproxy':
                 $common_rules .= "    add_header Pragma \"public\";\n";
                 $common_rules .= "    add_header Cache-Control \"private, must-revalidate\";\n";
                 break;
             case 'cache_maxage':
                 $common_rules .= "    add_header Pragma \"public\";\n";
                 $common_rules .= "    add_header Cache-Control \"max-age=" . $lifetime . ", public, must-revalidate, proxy-revalidate\";\n";
                 break;
             case 'no_cache':
                 $common_rules .= "    add_header Pragma \"no-cache\";\n";
                 $common_rules .= "    add_header Cache-Control \"max-age=0, private, no-store, no-cache, must-revalidate\";\n";
                 break;
         }
     }
     $rules = '';
     $rules .= W3TC_MARKER_BEGIN_PGCACHE_CACHE . "\n";
     $rules .= "location ~ " . $cache_dir . ".*html\$ {\n";
     $rules .= $common_rules;
     $rules .= "}\n";
     if ($compression) {
         $rules .= "location ~ " . $cache_dir . ".*gzip\$ {\n";
         $rules .= "    gzip off;\n";
         $rules .= "    types {}\n";
         $rules .= "    default_type text/html;\n";
         $rules .= $common_rules;
         $rules .= "    add_header Content-Encoding gzip;\n";
         $rules .= "}\n";
     }
     $rules .= W3TC_MARKER_END_PGCACHE_CACHE . "\n";
     return $rules;
 }
 /**
  * Send headers
  */
 function send_headers()
 {
     @header('X-Powered-By: ' . Util_Environment::w3tc_header());
 }
 /**
  * Sends headers
  *
  * @param boolean $is_404
  * @param string  $etag
  * @param integer $time
  * @param string  $compression
  * @param array   $custom_headers
  * @return boolean
  */
 function _send_headers($is_404, $time, $etag, $compression, $custom_headers = array())
 {
     $exit = false;
     $headers = is_array($custom_headers) ? $custom_headers : array();
     $curr_time = time();
     $bc_lifetime = $this->_config->get_integer('browsercache.html.lifetime');
     $expires = (is_null($time) ? $curr_time : $time) + $bc_lifetime;
     $max_age = $expires > $curr_time ? $expires - $curr_time : 0;
     if ($is_404) {
         /**
          * Add 404 header
          */
         $headers = array_merge($headers, array('Status' => 'HTTP/1.1 404 Not Found'));
     } elseif (!is_null($time) && $this->_check_modified_since($time) || $this->_check_match($etag)) {
         /**
          * Add 304 header
          */
         $headers = array_merge($headers, array('Status' => 'HTTP/1.1 304 Not Modified'));
         /**
          * Don't send content if it isn't modified
          */
         $exit = true;
     }
     if ($this->_config->get_boolean('browsercache.enabled')) {
         if ($this->_config->get_boolean('browsercache.html.last_modified')) {
             $headers = array_merge($headers, array('Last-Modified' => Util_Content::http_date($time)));
         }
         if ($this->_config->get_boolean('browsercache.html.expires')) {
             $headers = array_merge($headers, array('Expires' => Util_Content::http_date($expires)));
         }
         if ($this->_config->get_boolean('browsercache.html.cache.control')) {
             switch ($this->_config->get_string('browsercache.html.cache.policy')) {
                 case 'cache':
                     $headers = array_merge($headers, array('Pragma' => 'public', 'Cache-Control' => 'public'));
                     break;
                 case 'cache_public_maxage':
                     $headers = array_merge($headers, array('Pragma' => 'public', 'Cache-Control' => sprintf('max-age=%d, public', $max_age)));
                     break;
                 case 'cache_validation':
                     $headers = array_merge($headers, array('Pragma' => 'public', 'Cache-Control' => 'public, must-revalidate, proxy-revalidate'));
                     break;
                 case 'cache_noproxy':
                     $headers = array_merge($headers, array('Pragma' => 'public', 'Cache-Control' => 'private, must-revalidate'));
                     break;
                 case 'cache_maxage':
                     $headers = array_merge($headers, array('Pragma' => 'public', 'Cache-Control' => sprintf('max-age=%d, public, must-revalidate, proxy-revalidate', $max_age)));
                     break;
                 case 'no_cache':
                     $headers = array_merge($headers, array('Pragma' => 'no-cache', 'Cache-Control' => 'max-age=0, private, no-store, no-cache, must-revalidate'));
                     break;
             }
         }
         if ($this->_config->get_boolean('browsercache.html.etag')) {
             $headers = array_merge($headers, array('ETag' => '"' . $etag . '"'));
         }
         if ($this->_config->get_boolean('browsercache.html.w3tc')) {
             $headers = array_merge($headers, array('X-Powered-By' => Util_Environment::w3tc_header()));
         }
     }
     $vary = '';
     //compressed && UAG
     if ($compression && $this->_get_mobile_group()) {
         $vary = 'Accept-Encoding,User-Agent,Cookie';
         $headers = array_merge($headers, array('Content-Encoding' => $compression));
         //compressed
     } elseif ($compression) {
         $vary = 'Accept-Encoding';
         $headers = array_merge($headers, array('Content-Encoding' => $compression));
         //uncompressed && UAG
     } elseif ($this->_get_mobile_group()) {
         $vary = 'User-Agent,Cookie';
     }
     //Add Cookie to vary if user logged in and not previously set
     if (!$this->_check_logged_in() && strpos($vary, 'Cookie') === false) {
         if ($vary) {
             $vary .= ',Cookie';
         } else {
             $vary = 'Cookie';
         }
     }
     /**
      * Add vary header
      */
     if ($vary) {
         $headers = array_merge($headers, array('Vary' => $vary));
     }
     /**
      * Disable caching for preview mode
      */
     if (Util_Environment::is_preview_mode()) {
         $headers = array_merge($headers, array('Pragma' => 'private', 'Cache-Control' => 'private'));
     }
     /**
      * Send headers to client
      */
     $result = $this->_headers($headers);
     if ($exit) {
         exit;
     }
     return $result;
 }
 /**
  * Send headers
  */
 function send_headers()
 {
     @header('X-Powered-By: ' . Util_Environment::w3tc_header($this->_config));
 }