You are here

function boost_is_cacheable in Boost 6

Same name and namespace in other branches
  1. 5 boost.api.inc \boost_is_cacheable()
  2. 7 boost.module \boost_is_cacheable()

Determines whether a given url can be cached or not by boost.

To avoid potentially troublesome situations, the user login page is never cached, nor are any admin pages.

Parameters

$path: Current URL

$path = $GLOBALS['_boost_path'] most of the time uses $GLOBALS['_boost_query'] as well

4 calls to boost_is_cacheable()
boost_block in ./boost.module
Implementation of hook_block().
boost_form_alter in ./boost.module
Implementation of hook_form_alter(). Performs alterations before a form is rendered.
boost_init in ./boost.module
Implementation of hook_init(). Performs page setup tasks if page not cached.
boost_views_generate_default_list in ./boost.module
Genrate a list of views based off of defaults.

File

./boost.module, line 2690
Provides static file caching for Drupal text output. Pages, Feeds, ect...

Code

function boost_is_cacheable($path) {
  global $base_root;
  $is_front = FALSE;
  if (empty($path)) {
    $is_front = TRUE;
    $path = variable_get('site_frontpage', 'node');
  }
  $normal_path = drupal_get_normal_path($path);

  // normalize path
  $full = $normal_path . '-' . $GLOBALS['_boost_query'];
  $decoded1 = urldecode($full);
  $decoded2 = urldecode($decoded1);
  while ($decoded1 != $decoded2) {
    $decoded1 = urldecode($decoded2);
    $decoded2 = urldecode($decoded1);
  }
  $decoded = $decoded2;
  unset($decoded2);
  unset($decoded1);
  $url = $base_root . request_uri();

  // Never cache
  //  the user login/registration/password/reset pages
  //  any admin pages
  //  comment reply pages
  //  boost_stats.php
  //  any shopping cart pages
  //  node add page
  //  openid login page
  //  filefield upload progress page
  //  URL variables that contain / or \
  //  if incoming URL contains '..' or null bytes or ://
  //  if url contains #
  // Limit the maximum directory nesting depth of the path
  // Do not cache if destination is set
  if ($normal_path == 'user' || preg_match('!^user/(login|register|password|reset)!', $normal_path) || preg_match('!^admin!', $normal_path) || preg_match('!^comment/reply!', $normal_path) || preg_match('!boost_stats.php$!', $normal_path) || preg_match('!^cart!', $normal_path) || preg_match('!^node/add!', $normal_path) || preg_match('!^openid!', $normal_path) || preg_match('!^filefield/progress/!', $normal_path) || strpos($GLOBALS['_boost_query'], '/') || strpos($GLOBALS['_boost_query'], "\\") || strpos($full, '..') !== FALSE || strpos($full, "\0") !== FALSE || strpos($decoded, '://') !== FALSE || strpos($decoded, '#') !== FALSE || strpos($decoded, '..') !== FALSE || strpos($decoded, "\0") !== FALSE || count(explode('/', $path)) > BOOST_MAX_PATH_DEPTH || !empty($_GET['destination'])) {
    return FALSE;
  }
  if (!BOOST_CACHE_XML && (preg_match('!/feed$!', $normal_path) || preg_match('!\\.xml$!', $normal_path))) {
    return FALSE;
  }
  if (!BOOST_CACHE_QUERY && ($GLOBALS['_boost_query'] != BOOST_CHAR || strstr($url, '?') !== FALSE)) {
    return FALSE;
  }

  // Don't cache path if it can't be served by apache.
  if (BOOST_ONLY_ASCII_PATH) {
    if (preg_match('@[^/a-z0-9_\\-&=,\\.:]@i', $path)) {
      return FALSE;
    }
  }

  // Check if this domain has been whitelisted for caching.
  $use_lists = variable_get('boost_domain_use_lists', BOOST_DOMAIN_NO_LISTS);
  if ($use_lists == BOOST_DOMAIN_WHITELIST_ONLY || $use_lists == BOOST_DOMAIN_BOTH_LISTS) {
    $is_whitelisted = FALSE;
    $whitelist = variable_get('boost_domain_whitelist', array());
    $current_domain = $_SERVER['HTTP_HOST'];

    /* It'd be possible (and involve less code overall) to use domain_lookup()
     * here instead of stuffing everything into the "boost_domain_whitelist"
     * variable, but this method will avoid the extra db query and hooks that
     * calling domain_lookup can cause during page load.
     */
    $is_whitelisted = isset($whitelist[$current_domain]);
    if (!$is_whitelisted) {

      // Loop through the list of wildcards, trying to match the current domain.
      $whitelist_wild = variable_get('boost_domain_whitelist_wild', array());
      $current_domain_array = explode('.', $current_domain);

      // www.bar.com -> array('www','bar','com')
      foreach ($whitelist_wild as $wildcard) {
        $wildcard_array = explode('.', $wildcard);

        // *.quux.qz -> array('*','quux','qz')
        // If the arrays aren't the same size, don't bother matching their contents.
        $wc_count = count($wildcard_array);
        if (count($current_domain_array) != $wc_count) {
          continue;
        }
        for ($i = 0; $i < $wc_count; $i++) {

          /* If the current element isn't * and doesn't match the pattern, skip
           * to the next wildcard. */
          if ($wildcard_array[$i] != '*' && $wildcard_array[$i] != $current_domain_array[$i]) {
            break;
          }

          /* If the loop hasn't terminated by now, all elements of the current
           * wildcard array were checked.  Mark this domain as whitelisted and
           * don't check any other whitelist elements.
           */
          if ($i == $wc_count - 1) {
            $is_whitelisted = TRUE;
            break 2;
          }
        }
      }
    }
    if (!$is_whitelisted && variable_get('boost_domain_whitelist_use_domain', FALSE) && function_exists('domain_alias_lookup')) {

      /* Either I call domain_alias_lookup (and deal with the cost), I ignore
       * its wildcard capabilities and stuff all aliases into
       * boost_domain_whitelist, or I implement something subtly incompabile. */
      $is_whitelisted = -1 != domain_alias_lookup($current_domain);
    }
    if (!$is_whitelisted) {
      return FALSE;
    }
  }

  // Check if this domain has been blacklisted for caching.
  if ($use_lists == BOOST_DOMAIN_BLACKLIST_ONLY || $use_lists == BOOST_DOMAIN_BOTH_LISTS) {
    $blacklist = variable_get('boost_domain_blacklist', array());
    if (isset($blacklist[$current_domain])) {
      return FALSE;
    }
  }

  // Check for reserved characters if on windows
  // http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
  // " * : < > |
  $chars = '"*:<>|';
  if (stristr(PHP_OS, 'WIN') && preg_match("/[" . $chars . "]/", $full)) {
    return FALSE;
  }

  // Don't cache if path is in the source; but allow the front page to be cached
  if (variable_get('boost_cache_url_alias_src', FALSE) && !$is_front && (int) db_result(db_query("SELECT count(*) FROM {url_alias} WHERE src = '%s'", $path)) > 0) {
    return FALSE;
  }

  // Invoke hook_boost_is_cacheable($path)
  foreach (module_implements('boost_is_cacheable') as $module) {
    if (($result = module_invoke($module, 'boost_is_cacheable', $path)) !== NULL) {
      if (!$result) {
        return FALSE;
      }
    }
  }

  // See http://api.drupal.org/api/function/block_list/6
  // Match the user's cacheability settings against the path
  if (BOOST_CACHEABILITY_PAGES) {
    if (BOOST_CACHEABILITY_OPTION < 2) {
      $page_match = drupal_match_path($path, BOOST_CACHEABILITY_PAGES);
      if ($path != $_GET['q']) {
        $page_match = $page_match || drupal_match_path($_GET['q'], BOOST_CACHEABILITY_PAGES);
      }

      // When BOOST_CACHEABILITY_OPTION has a value of 0, boost will cache
      // all pages except those listed in BOOST_CACHEABILITY_PAGES. When set
      // to 1, boost will cache only on those pages listed in BOOST_CACHEABILITY_PAGES.
      $page_match = !(BOOST_CACHEABILITY_OPTION xor $page_match);
    }
    else {
      $page_match = drupal_eval(BOOST_CACHEABILITY_PAGES);
    }
  }
  else {
    $page_match = TRUE;
  }
  return $page_match;
}