You are here

cdn.fallback.inc in CDN 6.2

Same filename and directory in other branches
  1. 7.2 cdn.fallback.inc

Fallback when hook_file_url_alter() is not available (i.e. when the core patch is not installed or when not using a patched Drupal distribution): use the Parallel module's logic (with some adaptations to be able to use the CDN module's logic (in particular: cdn_file_url_alter()) to alter file URLs via the theme layer. Some of the functions are also used when altering rendered nodes so that their images are served from the CDN.

File

cdn.fallback.inc
View source
<?php

/**
 * @file
 * Fallback when hook_file_url_alter() is not available (i.e. when the core
 * patch is not installed or when not using a patched Drupal distribution):
 * use the Parallel module's logic (with some adaptations to be able to use
 * the CDN module's logic (in particular: cdn_file_url_alter()) to alter file
 * URLs via the theme layer.
 * Some of the functions are also used when altering rendered nodes so that
 * their images are served from the CDN.
 */

/**
 * Implementation of hook_theme_registry_alter().
 *
 * Make CDN's page preprocess function run *after* everything else's, so that
 * a theme can't call drupal_get_js() and mess everything up.
 *
 * @param &$theme_registry
 *   The entire cache of theme registry information, post-processing.
 */
function _cdn_fallback_theme_registry_alter(&$theme_registry) {
  if (isset($theme_registry['page'])) {

    // If CDN's preprocess function is there already, remove it.
    if ($key = array_search('cdn_preprocess_page', $theme_registry['page']['preprocess functions'])) {
      unset($theme_registry['page']['preprocess functions'][$key]);
    }

    // Now tack it on at the end so it runs after everything else.
    $theme_registry['page']['preprocess functions'][] = 'cdn_preprocess_page';
  }
}

/**
 * Implementation of template_preprocess_page().
 */
function cdn_preprocess_page(&$variables) {

  // CSS.
  cdn_html_alter_css_urls($variables['styles']);

  // JS.
  cdn_html_alter_js_urls($variables['scripts']);
  cdn_html_alter_js_urls($variables['closure']);

  // Images.
  $skip_keys = array(
    'styles',
    'scripts',
    'zebra',
    'id',
    'directory',
    'layout',
    'head_title',
    'base_path',
    'front_page',
    'head',
    'body_classes',
  );
  foreach ($variables as $key => $value) {
    if (!in_array($key, $skip_keys) && is_string($value) && !empty($value)) {
      cdn_html_alter_image_urls($variables[$key]);
    }
  }
}

/**
 * Alter CSS file URLs in a piece of HTML.
 */
function cdn_html_alter_css_urls(&$html) {
  $url_prefix_regex = _cdn_generate_url_prefix_regex();
  $pattern = "#href=\"(({$url_prefix_regex})(.*?\\.css)(\\?.*)?)\"#";
  _cdn_html_alter_file_url($html, $pattern, 0, 3, 4, 'href="', '"');
}

/**
 * Alter JS file URLs in a piece of HTML.
 */
function cdn_html_alter_js_urls(&$html) {
  $url_prefix_regex = _cdn_generate_url_prefix_regex();
  $pattern = "#src=\"(({$url_prefix_regex})(.*?\\.js)(\\?.*)?)\"#";
  _cdn_html_alter_file_url($html, $pattern, 0, 3, 4, 'src="', '"');
}

/**
 * Alter image file URLs in a piece of HTML.
 */
function cdn_html_alter_image_urls(&$html) {
  $url_prefix_regex = _cdn_generate_url_prefix_regex();

  // TRICKY: order matters!
  // Image file URLs of <a> tags that wrap <img> tags.
  $pattern = "#((<a\\s+|<a\\s+[^>]*\\s+)href\\s*=\\s*[\"|'])({$url_prefix_regex})([^\"|^'|^\\?]*)()(\\?[^\"|^']*)?";
  $pattern .= "(";

  // Capture everything after the path.
  $pattern .= "([\"|'][^>]*)>";

  // End of opening <a> tag.
  $pattern .= "((<img\\s+|<img\\s+[^>]*\\s+)src\\s*=\\s*[\"|'])([^\"|^']*)([\"|'])";

  // Wrapped <img> tag.
  $pattern .= ")#i";
  _cdn_html_alter_file_url($html, $pattern, 0, 4, 5, 1, 7, 11);

  // Image file URLs in <img> tags.
  $pattern = "#((<img\\s+|<img\\s+[^>]*\\s+)src\\s*=\\s*[\"|'])({$url_prefix_regex})([^\"|^'|^\\?]*)()(\\?[^\"|^']*)?([\"|'])#i";
  _cdn_html_alter_file_url($html, $pattern, 0, 4, 5, 1, 7);
}

/**
 * Generate the URL prefix regular expression, that supports all possible
 * types of file URLs: root-relative, protocol-relative and absolute URLs.
 */
function _cdn_generate_url_prefix_regex() {
  global $base_url;
  static $url_prefix_regex;
  if (!isset($url_prefix_regex)) {
    $url_prefixes = array(
      preg_quote(base_path()) . '(?!/)',
      // Root-relative URL.
      // Note:  root-relative URL that isn't a protocol-relative URL. The
      // negative lookahead for a trailing slash is relaly only necessary
      // when this site is installed in the document root (i.e. when the base
      // path equals "/"), because this would otherwise match *all* protocol-
      // relative URLs, also those that already point to the CDN.
      preg_quote('//' . $_SERVER['HTTP_HOST'] . base_path()),
      // Protocol-relative URL.
      preg_quote($base_url . '/'),
    );
    $regexes = array();
    $farfuture = preg_quote('cdn/farfuture/');
    foreach ($url_prefixes as $url_prefix) {
      $regexes[] = $url_prefix . '(?!' . $farfuture . ')';
    }

    // The URL prefix regex that will match all URLs to the current site,
    // except for those that already point to Far Future expiration URLs.
    $url_prefix_regex = implode('|', $regexes);
  }
  return $url_prefix_regex;
}

/**
 * Alter the file URLs in a piece of HTML given a regexp pattern and some
 * additional parameters.
 *
 * @param &$html
 *   The HTML in which file URLs will be altered.
 * @param $pattern
 *   A regular expression pattern to apply to the subject.
 * @param $search_index
 *   The index of the search string in the array of regexp matches.
 * @param $path_index
 *   The index of the file path in the array of regexp matches.
 * @param $querystring_index
 *   The index of (an optional) query string in the array of regexp matches.
 * @param $prefix
 *   $search_index will be replaced by $prefix, plus the altered file URL,
 *   plus the @suffix. If numeric, then it is assumed to be the index of the
 *   prefix in the array of regexp matches.
 * @param $suffix
 *   See $prefix.
 * @param $comparison_index
 *   The index of a comparison path whose file extension should match the file
 *   extension of the path located at $path_index.
 */
function _cdn_html_alter_file_url(&$html, $pattern, $search_index, $path_index, $querystring_index, $prefix, $suffix, $comparison_index = FALSE) {

  // Find a match against the given pattern.
  preg_match_all($pattern, $html, $matches);

  // Generate replacements to alter file URLs.
  $searches = array();
  $replacements = array();
  for ($i = 0; $i < count($matches[0]); $i++) {
    $search = $matches[$search_index][$i];
    $path = $matches[$path_index][$i];
    $prefix_string = is_numeric($prefix) ? $matches[$prefix][$i] : $prefix;
    $suffix_string = is_numeric($suffix) ? $matches[$suffix][$i] : $suffix;

    // Compare the filename in the path with that of another index. The file
    // URL only is rewritten if it matches.
    if ($comparison_index) {
      $comparison = $matches[$comparison_index][$i];

      // Calculate length of extension.
      $path_ext_pos = strrpos($path, '.');
      $ext_length = -1 * (strlen($path) - $path_ext_pos);
      if (substr($path, $ext_length) !== substr($comparison, $ext_length)) {
        continue;
      }
    }

    // Store the current path as the old path, then let cdn_file_url_alter()
    // do its magic by invoking all file_url_alter hooks. When the path hasn't
    // changed and is not already root-relative or protocol-relative, then
    // generate a file URL as Drupal core would: prepend the base path.
    $old_path = $path;
    drupal_alter('file_url', $path);
    if ($path == $old_path && drupal_substr($path, 0, 1) != '/' && drupal_substr($path, 0, 2) != '//') {
      $path = base_path() . $path;
    }
    $searches[] = $search;
    $replacements[] = $prefix_string . $path . $matches[$querystring_index][$i] . $suffix_string;
  }

  // Apply the generated replacements ton the subject.
  $html = str_replace($searches, $replacements, $html);
}

Functions

Namesort descending Description
cdn_html_alter_css_urls Alter CSS file URLs in a piece of HTML.
cdn_html_alter_image_urls Alter image file URLs in a piece of HTML.
cdn_html_alter_js_urls Alter JS file URLs in a piece of HTML.
cdn_preprocess_page Implementation of template_preprocess_page().
_cdn_fallback_theme_registry_alter Implementation of hook_theme_registry_alter().
_cdn_generate_url_prefix_regex Generate the URL prefix regular expression, that supports all possible types of file URLs: root-relative, protocol-relative and absolute URLs.
_cdn_html_alter_file_url Alter the file URLs in a piece of HTML given a regexp pattern and some additional parameters.